mirror of
https://github.com/docmost/docmost.git
synced 2026-06-10 01:52:43 +08:00
fix(bases): strip all property-id refs from view config on delete
This commit is contained in:
@@ -74,4 +74,53 @@ describe('stripPropertyFromViewConfig', () => {
|
||||
sorts: [{ propertyId: 'p-keep', direction: 'asc' as const }],
|
||||
});
|
||||
});
|
||||
|
||||
it('strips visiblePropertyIds entries pointing at the deleted property', () => {
|
||||
const config = {
|
||||
visiblePropertyIds: ['p-deleted', 'p-keep'],
|
||||
};
|
||||
expect(stripPropertyFromViewConfig(config, 'p-deleted')).toEqual({
|
||||
visiblePropertyIds: ['p-keep'],
|
||||
});
|
||||
});
|
||||
|
||||
it('strips hiddenPropertyIds entries pointing at the deleted property', () => {
|
||||
const config = {
|
||||
hiddenPropertyIds: ['p-deleted', 'p-keep'],
|
||||
};
|
||||
expect(stripPropertyFromViewConfig(config, 'p-deleted')).toEqual({
|
||||
hiddenPropertyIds: ['p-keep'],
|
||||
});
|
||||
});
|
||||
|
||||
it('strips propertyOrder entries pointing at the deleted property', () => {
|
||||
const config = {
|
||||
propertyOrder: ['p-other', 'p-deleted', 'p-keep'],
|
||||
};
|
||||
expect(stripPropertyFromViewConfig(config, 'p-deleted')).toEqual({
|
||||
propertyOrder: ['p-other', 'p-keep'],
|
||||
});
|
||||
});
|
||||
|
||||
it('removes propertyWidths entry for the deleted property', () => {
|
||||
const config = {
|
||||
propertyWidths: { 'p-deleted': 120, 'p-keep': 200 },
|
||||
};
|
||||
expect(stripPropertyFromViewConfig(config, 'p-deleted')).toEqual({
|
||||
propertyWidths: { 'p-keep': 200 },
|
||||
});
|
||||
});
|
||||
|
||||
it('removes the visiblePropertyIds/propertyWidths keys when they become empty', () => {
|
||||
const config = {
|
||||
visiblePropertyIds: ['p-deleted'],
|
||||
hiddenPropertyIds: ['p-deleted'],
|
||||
propertyOrder: ['p-deleted'],
|
||||
propertyWidths: { 'p-deleted': 120 },
|
||||
sorts: [{ propertyId: 'p-keep', direction: 'asc' as const }],
|
||||
};
|
||||
expect(stripPropertyFromViewConfig(config, 'p-deleted')).toEqual({
|
||||
sorts: [{ propertyId: 'p-keep', direction: 'asc' as const }],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -30,6 +30,7 @@ import {
|
||||
parseTypeOptions,
|
||||
validateTypeOptions,
|
||||
isSystemPropertyType,
|
||||
ViewConfig,
|
||||
} from '../base.schemas';
|
||||
import { generateJitteredKeyBetween } from 'fractional-indexing-jittered';
|
||||
import { QueueJob, QueueName } from '../../../integrations/queue/constants';
|
||||
@@ -534,21 +535,17 @@ export class BasePropertyService {
|
||||
trx,
|
||||
});
|
||||
for (const view of views) {
|
||||
const before = (view.config ?? {}) as Record<string, unknown>;
|
||||
const next = stripPropertyFromViewConfig(
|
||||
view.config as any,
|
||||
view.config as ViewConfig,
|
||||
dto.propertyId,
|
||||
);
|
||||
const after = next as Record<string, unknown>;
|
||||
if (
|
||||
Object.keys(before).length === Object.keys(after).length &&
|
||||
Object.keys(before).every((k) => k in after) &&
|
||||
JSON.stringify(before) === JSON.stringify(after)
|
||||
) {
|
||||
if (JSON.stringify(view.config ?? {}) === JSON.stringify(next)) {
|
||||
continue;
|
||||
}
|
||||
await this.baseViewRepo.updateView(
|
||||
view.id,
|
||||
// `config` column is typed `Json` by Kysely; ViewConfig is a Zod
|
||||
// inferred shape that isn't structurally assignable to `Json`.
|
||||
{ config: next as any },
|
||||
{ workspaceId, trx },
|
||||
);
|
||||
@@ -582,6 +579,11 @@ export class BasePropertyService {
|
||||
`Enqueue of cell-gc failed for property ${dto.propertyId}; reverting soft-delete`,
|
||||
err as Error,
|
||||
);
|
||||
// Best-effort revert: restores `deletedAt: null` on the property. The
|
||||
// view-config cleanup and schema-bump that ran inside the earlier
|
||||
// `executeTx` are NOT reverted — restoring those would require capturing
|
||||
// the original configs before the transaction. Rare path (queue down);
|
||||
// acceptable today.
|
||||
try {
|
||||
await this.basePropertyRepo.updateProperty(dto.propertyId, {
|
||||
deletedAt: null,
|
||||
|
||||
@@ -53,5 +53,29 @@ export function stripPropertyFromViewConfig(
|
||||
delete next.choiceOrder;
|
||||
}
|
||||
|
||||
if (config.visiblePropertyIds) {
|
||||
const kept = config.visiblePropertyIds.filter((id) => id !== propertyId);
|
||||
if (kept.length > 0) next.visiblePropertyIds = kept;
|
||||
else delete next.visiblePropertyIds;
|
||||
}
|
||||
|
||||
if (config.hiddenPropertyIds) {
|
||||
const kept = config.hiddenPropertyIds.filter((id) => id !== propertyId);
|
||||
if (kept.length > 0) next.hiddenPropertyIds = kept;
|
||||
else delete next.hiddenPropertyIds;
|
||||
}
|
||||
|
||||
if (config.propertyOrder) {
|
||||
const kept = config.propertyOrder.filter((id) => id !== propertyId);
|
||||
if (kept.length > 0) next.propertyOrder = kept;
|
||||
else delete next.propertyOrder;
|
||||
}
|
||||
|
||||
if (config.propertyWidths && propertyId in config.propertyWidths) {
|
||||
const { [propertyId]: _removed, ...rest } = config.propertyWidths;
|
||||
if (Object.keys(rest).length > 0) next.propertyWidths = rest;
|
||||
else delete next.propertyWidths;
|
||||
}
|
||||
|
||||
return next as ViewConfig;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user