@aphexcms/cms-core 7.0.0 → 8.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/documents.d.ts +19 -0
- package/dist/api/documents.d.ts.map +1 -1
- package/dist/api/documents.js +21 -0
- package/dist/api/schemas/documents.d.ts +3 -0
- package/dist/api/schemas/documents.d.ts.map +1 -1
- package/dist/api/schemas/documents.js +12 -0
- package/dist/cli/generate-types.d.ts.map +1 -1
- package/dist/cli/generate-types.js +133 -19
- package/dist/cli/generate-types.js.map +1 -1
- package/dist/components/AdminApp.svelte +106 -52
- package/dist/components/AdminApp.svelte.d.ts.map +1 -1
- package/dist/components/admin/DocumentEditor.svelte +65 -2
- package/dist/components/admin/DocumentEditor.svelte.d.ts.map +1 -1
- package/dist/components/admin/confirm-dialog/ConfirmDialogHost.svelte +8 -6
- package/dist/components/admin/confirm-dialog/ConfirmDialogHost.svelte.d.ts.map +1 -1
- package/dist/components/admin/fields/ArrayField.svelte +149 -2
- package/dist/components/admin/fields/ArrayField.svelte.d.ts.map +1 -1
- package/dist/components/admin/fields/ReferenceField.svelte +198 -125
- package/dist/components/admin/fields/ReferenceField.svelte.d.ts +9 -2
- package/dist/components/admin/fields/ReferenceField.svelte.d.ts.map +1 -1
- package/dist/components/layout/Sidebar.svelte +1 -1
- package/dist/components/layout/sidebar/AppSidebar.svelte +2 -1
- package/dist/components/layout/sidebar/AppSidebar.svelte.d.ts.map +1 -1
- package/dist/components/layout/sidebar/NavMain.svelte +9 -2
- package/dist/components/layout/sidebar/NavMain.svelte.d.ts +2 -0
- package/dist/components/layout/sidebar/NavMain.svelte.d.ts.map +1 -1
- package/dist/db/interfaces/index.d.ts +3 -1
- package/dist/db/interfaces/index.d.ts.map +1 -1
- package/dist/db/interfaces/reference.d.ts +43 -0
- package/dist/db/interfaces/reference.d.ts.map +1 -0
- package/dist/db/interfaces/reference.js +4 -0
- package/dist/db/utils/reference-resolver.d.ts +4 -6
- package/dist/db/utils/reference-resolver.d.ts.map +1 -1
- package/dist/db/utils/reference-resolver.js +33 -31
- package/dist/document-refresh.svelte.d.ts +3 -0
- package/dist/document-refresh.svelte.d.ts.map +1 -0
- package/dist/document-refresh.svelte.js +21 -0
- package/dist/graphql/resolvers.d.ts.map +1 -1
- package/dist/graphql/resolvers.js +61 -1
- package/dist/graphql/schema.d.ts.map +1 -1
- package/dist/graphql/schema.js +10 -0
- package/dist/lib/api/documents.d.ts +19 -0
- package/dist/lib/api/documents.d.ts.map +1 -1
- package/dist/lib/api/documents.js +21 -0
- package/dist/lib/api/documents.js.map +1 -1
- package/dist/lib/api/schemas/documents.d.ts +3 -0
- package/dist/lib/api/schemas/documents.d.ts.map +1 -1
- package/dist/lib/api/schemas/documents.js +12 -0
- package/dist/lib/api/schemas/documents.js.map +1 -1
- package/dist/lib/db/interfaces/index.d.ts +3 -1
- package/dist/lib/db/interfaces/index.d.ts.map +1 -1
- package/dist/lib/db/interfaces/reference.d.ts +43 -0
- package/dist/lib/db/interfaces/reference.d.ts.map +1 -0
- package/dist/lib/db/interfaces/reference.js +5 -0
- package/dist/lib/db/interfaces/reference.js.map +1 -0
- package/dist/lib/db/utils/reference-resolver.d.ts +4 -6
- package/dist/lib/db/utils/reference-resolver.d.ts.map +1 -1
- package/dist/lib/db/utils/reference-resolver.js +33 -31
- package/dist/lib/db/utils/reference-resolver.js.map +1 -1
- package/dist/lib/document-refresh.svelte.d.ts +3 -0
- package/dist/lib/document-refresh.svelte.d.ts.map +1 -0
- package/dist/lib/document-refresh.svelte.js +22 -0
- package/dist/lib/document-refresh.svelte.js.map +1 -0
- package/dist/lib/graphql/resolvers.d.ts.map +1 -1
- package/dist/lib/graphql/resolvers.js +61 -1
- package/dist/lib/graphql/resolvers.js.map +1 -1
- package/dist/lib/graphql/schema.d.ts.map +1 -1
- package/dist/lib/graphql/schema.js +10 -0
- package/dist/lib/graphql/schema.js.map +1 -1
- package/dist/lib/local-api/collection-api.d.ts +10 -1
- package/dist/lib/local-api/collection-api.d.ts.map +1 -1
- package/dist/lib/local-api/collection-api.js +39 -1
- package/dist/lib/local-api/collection-api.js.map +1 -1
- package/dist/lib/local-api/index.d.ts +29 -0
- package/dist/lib/local-api/index.d.ts.map +1 -1
- package/dist/lib/local-api/index.js +66 -2
- package/dist/lib/local-api/index.js.map +1 -1
- package/dist/lib/schema-utils/validator.js +21 -11
- package/dist/lib/schema-utils/validator.js.map +1 -1
- package/dist/lib/server/api/index.d.ts.map +1 -1
- package/dist/lib/server/api/index.js +3 -1
- package/dist/lib/server/api/index.js.map +1 -1
- package/dist/lib/server/api/routes/documents-by-id.d.ts.map +1 -1
- package/dist/lib/server/api/routes/documents-by-id.js +23 -0
- package/dist/lib/server/api/routes/documents-by-id.js.map +1 -1
- package/dist/lib/server/api/routes/documents.d.ts.map +1 -1
- package/dist/lib/server/api/routes/documents.js +29 -1
- package/dist/lib/server/api/routes/documents.js.map +1 -1
- package/dist/lib/services/references-service.d.ts +35 -0
- package/dist/lib/services/references-service.d.ts.map +1 -0
- package/dist/lib/services/references-service.js +60 -0
- package/dist/lib/services/references-service.js.map +1 -0
- package/dist/lib/types/schemas.d.ts +8 -0
- package/dist/lib/types/schemas.d.ts.map +1 -1
- package/dist/lib/utils/preview.d.ts +2 -3
- package/dist/lib/utils/preview.d.ts.map +1 -1
- package/dist/lib/utils/preview.js +35 -8
- package/dist/lib/utils/preview.js.map +1 -1
- package/dist/lib/utils/reference-walk.d.ts +8 -0
- package/dist/lib/utils/reference-walk.d.ts.map +1 -0
- package/dist/lib/utils/reference-walk.js +43 -0
- package/dist/lib/utils/reference-walk.js.map +1 -0
- package/dist/local-api/collection-api.d.ts +10 -1
- package/dist/local-api/collection-api.d.ts.map +1 -1
- package/dist/local-api/collection-api.js +39 -1
- package/dist/local-api/index.d.ts +29 -0
- package/dist/local-api/index.d.ts.map +1 -1
- package/dist/local-api/index.js +66 -2
- package/dist/schema-utils/validator.js +21 -11
- package/dist/server/api/index.d.ts.map +1 -1
- package/dist/server/api/index.js +3 -1
- package/dist/server/api/routes/documents-by-id.d.ts.map +1 -1
- package/dist/server/api/routes/documents-by-id.js +23 -0
- package/dist/server/api/routes/documents.d.ts.map +1 -1
- package/dist/server/api/routes/documents.js +29 -1
- package/dist/services/references-service.d.ts +35 -0
- package/dist/services/references-service.d.ts.map +1 -0
- package/dist/services/references-service.js +59 -0
- package/dist/types/schemas.d.ts +8 -0
- package/dist/types/schemas.d.ts.map +1 -1
- package/dist/utils/preview.d.ts +2 -3
- package/dist/utils/preview.d.ts.map +1 -1
- package/dist/utils/preview.js +35 -8
- package/dist/utils/reference-walk.d.ts +8 -0
- package/dist/utils/reference-walk.d.ts.map +1 -0
- package/dist/utils/reference-walk.js +42 -0
- package/package.json +3 -3
|
@@ -276,11 +276,13 @@
|
|
|
276
276
|
const COLLAPSED_WIDTH = 60; // Width of collapsed panels
|
|
277
277
|
const TYPES_EXPANDED = 350;
|
|
278
278
|
const DOCS_EXPANDED = 350;
|
|
279
|
-
|
|
280
279
|
let layoutConfig = $derived.by(() => {
|
|
281
280
|
const start = performance.now();
|
|
281
|
+
// Version panel is fixed-width (280px), not a full editor — deduct it
|
|
282
|
+
// from available space instead of counting it as an editor slot.
|
|
282
283
|
const totalEditors =
|
|
283
|
-
(currentView === 'editor' ? 1 : 0) +
|
|
284
|
+
(currentView === 'editor' ? 1 : 0) +
|
|
285
|
+
(editorStack.length > 0 ? 1 : 0);
|
|
284
286
|
|
|
285
287
|
if (totalEditors === 0) {
|
|
286
288
|
return {
|
|
@@ -367,19 +369,20 @@
|
|
|
367
369
|
let remainingWidth = windowWidth - typesWidth - docsWidth;
|
|
368
370
|
let maxExpandedEditors = Math.floor(remainingWidth / MIN_EDITOR_WIDTH);
|
|
369
371
|
|
|
370
|
-
// If we can't fit all editors, start collapsing panels
|
|
372
|
+
// If we can't fit all editors, start collapsing panels.
|
|
373
|
+
// Types sidebar collapses first — the docs list is more useful when
|
|
374
|
+
// actively editing (shows siblings in the same collection).
|
|
371
375
|
if (maxExpandedEditors < totalEditors) {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
docsExpanded = false;
|
|
376
|
+
typesWidth = COLLAPSED_WIDTH;
|
|
377
|
+
typesExpanded = false;
|
|
375
378
|
remainingWidth = windowWidth - typesWidth - docsWidth;
|
|
376
379
|
maxExpandedEditors = Math.floor(remainingWidth / MIN_EDITOR_WIDTH);
|
|
377
380
|
}
|
|
378
381
|
|
|
379
|
-
// If still not enough space, collapse
|
|
382
|
+
// If still not enough space, collapse docs list too
|
|
380
383
|
if (maxExpandedEditors < totalEditors) {
|
|
381
|
-
|
|
382
|
-
|
|
384
|
+
docsWidth = selectedDocumentType ? COLLAPSED_WIDTH : 0;
|
|
385
|
+
docsExpanded = false;
|
|
383
386
|
remainingWidth = windowWidth - typesWidth - docsWidth;
|
|
384
387
|
maxExpandedEditors = Math.floor(remainingWidth / MIN_EDITOR_WIDTH);
|
|
385
388
|
}
|
|
@@ -488,6 +491,12 @@
|
|
|
488
491
|
|
|
489
492
|
if (currentView !== 'editor') return { visible: false, expanded: false };
|
|
490
493
|
|
|
494
|
+
// In focus mode, only the active editor shows — if active is a stacked
|
|
495
|
+
// editor, the primary hides.
|
|
496
|
+
if (focusModeOn && activeEditorIndex !== 0) {
|
|
497
|
+
return { visible: true, expanded: false };
|
|
498
|
+
}
|
|
499
|
+
|
|
491
500
|
const primaryIndex = 0;
|
|
492
501
|
const isExpanded = layoutConfig.expandedIndices.includes(primaryIndex);
|
|
493
502
|
|
|
@@ -536,6 +545,7 @@
|
|
|
536
545
|
const action = url.searchParams.get('action');
|
|
537
546
|
const docId = url.searchParams.get('docId');
|
|
538
547
|
const stackParam = url.searchParams.get('stack');
|
|
548
|
+
const historyParam = url.searchParams.get('history');
|
|
539
549
|
|
|
540
550
|
cmsLogger.debug('[URL Effect]', 'Params:', {
|
|
541
551
|
docType,
|
|
@@ -602,6 +612,18 @@
|
|
|
602
612
|
}
|
|
603
613
|
}
|
|
604
614
|
|
|
615
|
+
// Restore version history panel from URL
|
|
616
|
+
if (historyParam === '1' && !showVersionPanel) {
|
|
617
|
+
showVersionPanel = true;
|
|
618
|
+
versionPanelDocId = stackParam
|
|
619
|
+
? editorStack[editorStack.length - 1]?.documentId ?? docId
|
|
620
|
+
: docId;
|
|
621
|
+
} else if (!historyParam && showVersionPanel) {
|
|
622
|
+
showVersionPanel = false;
|
|
623
|
+
versionPanelDocId = null;
|
|
624
|
+
versionPreviewData = null;
|
|
625
|
+
}
|
|
626
|
+
|
|
605
627
|
if (docType) {
|
|
606
628
|
if (selectedDocumentType !== docType) {
|
|
607
629
|
selectedDocumentType = docType;
|
|
@@ -678,6 +700,7 @@
|
|
|
678
700
|
params.delete('docId');
|
|
679
701
|
params.delete('action');
|
|
680
702
|
params.delete('stack');
|
|
703
|
+
params.delete('history');
|
|
681
704
|
await goto(`/admin?${params.toString()}`, { replaceState: false });
|
|
682
705
|
mobileView = 'documents';
|
|
683
706
|
}
|
|
@@ -688,6 +711,7 @@
|
|
|
688
711
|
params.set('action', 'create');
|
|
689
712
|
params.delete('docId');
|
|
690
713
|
params.delete('stack');
|
|
714
|
+
params.delete('history');
|
|
691
715
|
await goto(`/admin?${params.toString()}`, { replaceState: false });
|
|
692
716
|
mobileView = 'editor';
|
|
693
717
|
}
|
|
@@ -717,7 +741,7 @@
|
|
|
717
741
|
if (fromDocId && fromDocType) {
|
|
718
742
|
// Navigate back to the document we came from
|
|
719
743
|
await navigateToEditDocument(fromDocId, fromDocType, false);
|
|
720
|
-
} else if (selectedDocumentType) {
|
|
744
|
+
} else if (selectedDocumentType && !currentTypeIsSingleton) {
|
|
721
745
|
// Navigate back to document list
|
|
722
746
|
const params = new SvelteURLSearchParams(page.url.searchParams);
|
|
723
747
|
params.set('docType', selectedDocumentType);
|
|
@@ -725,6 +749,7 @@
|
|
|
725
749
|
params.delete('action');
|
|
726
750
|
params.delete('stack');
|
|
727
751
|
params.delete('focus');
|
|
752
|
+
params.delete('history');
|
|
728
753
|
await goto(`/admin?${params.toString()}`, { replaceState: false });
|
|
729
754
|
mobileView = 'documents';
|
|
730
755
|
} else {
|
|
@@ -735,33 +760,43 @@
|
|
|
735
760
|
params.delete('action');
|
|
736
761
|
params.delete('stack');
|
|
737
762
|
params.delete('focus');
|
|
763
|
+
params.delete('history');
|
|
738
764
|
await goto(`/admin?${params.toString()}`, { replaceState: false });
|
|
739
765
|
mobileView = 'types';
|
|
740
766
|
}
|
|
741
767
|
}
|
|
742
768
|
|
|
743
|
-
// Handle opening reference in new editor panel
|
|
744
769
|
function handleOpenVersionHistory(docId: string) {
|
|
745
770
|
showVersionPanel = true;
|
|
746
771
|
versionPanelDocId = docId;
|
|
772
|
+
const params = new SvelteURLSearchParams(page.url.searchParams);
|
|
773
|
+
params.set('history', '1');
|
|
774
|
+
goto(`/admin?${params.toString()}`, { replaceState: true });
|
|
747
775
|
}
|
|
748
776
|
|
|
749
777
|
function handleCloseVersionPanel() {
|
|
750
778
|
showVersionPanel = false;
|
|
751
779
|
versionPanelDocId = null;
|
|
752
780
|
versionPreviewData = null;
|
|
781
|
+
const params = new SvelteURLSearchParams(page.url.searchParams);
|
|
782
|
+
params.delete('history');
|
|
783
|
+
goto(`/admin?${params.toString()}`, { replaceState: true });
|
|
753
784
|
}
|
|
754
785
|
|
|
755
786
|
// Close version panel when navigating away
|
|
756
787
|
let prevDocType = $state(selectedDocumentType);
|
|
757
788
|
let prevDocId = $state(editingDocumentId);
|
|
789
|
+
let initialNavDone = $state(false);
|
|
758
790
|
$effect(() => {
|
|
759
791
|
if (selectedDocumentType !== prevDocType || editingDocumentId !== prevDocId) {
|
|
760
792
|
prevDocType = selectedDocumentType;
|
|
761
793
|
prevDocId = editingDocumentId;
|
|
762
|
-
if (showVersionPanel) {
|
|
763
|
-
|
|
794
|
+
if (initialNavDone && showVersionPanel) {
|
|
795
|
+
showVersionPanel = false;
|
|
796
|
+
versionPanelDocId = null;
|
|
797
|
+
versionPreviewData = null;
|
|
764
798
|
}
|
|
799
|
+
initialNavDone = true;
|
|
765
800
|
}
|
|
766
801
|
});
|
|
767
802
|
|
|
@@ -785,38 +820,40 @@
|
|
|
785
820
|
return;
|
|
786
821
|
}
|
|
787
822
|
|
|
788
|
-
// On desktop
|
|
823
|
+
// On desktop — push onto the reference history stack. The UI only ever
|
|
824
|
+
// shows one stacked panel (the last entry). The back button pops the
|
|
825
|
+
// stack instead of closing, so you can walk back through the chain.
|
|
789
826
|
if (editingDocumentId === documentId) {
|
|
790
|
-
// Already open as the primary editor — just focus it
|
|
791
827
|
activeEditorIndex = 0;
|
|
792
828
|
return;
|
|
793
829
|
}
|
|
794
|
-
const existingIndex = editorStack.findIndex((item) => item.documentId === documentId);
|
|
795
|
-
if (existingIndex !== -1) {
|
|
796
|
-
// Already open in the stack — focus that editor (stack index 0 = activeEditorIndex 1)
|
|
797
|
-
activeEditorIndex = existingIndex + 1;
|
|
798
|
-
return;
|
|
799
|
-
}
|
|
800
830
|
|
|
801
|
-
const
|
|
831
|
+
const newEntry = { documentId, documentType, isCreating: false };
|
|
802
832
|
|
|
803
|
-
//
|
|
804
|
-
|
|
833
|
+
// If clicking a ref from the primary editor (activeEditorIndex === 0)
|
|
834
|
+
// and a stack already exists, the user is picking a different ref from
|
|
835
|
+
// the same array — replace the whole stack with the new pick.
|
|
836
|
+
// If clicking from within the stacked panel, push deeper.
|
|
837
|
+
const newStack =
|
|
838
|
+
activeEditorIndex === 0 && editorStack.length > 0
|
|
839
|
+
? [newEntry]
|
|
840
|
+
: [...editorStack, newEntry];
|
|
805
841
|
|
|
806
|
-
//
|
|
842
|
+
// URL tracks the full chain for refresh support
|
|
843
|
+
const stackParam = newStack.map((item) => `${item.documentType}:${item.documentId}`).join(',');
|
|
807
844
|
const params = new SvelteURLSearchParams(page.url.searchParams);
|
|
808
845
|
params.set('stack', stackParam);
|
|
809
846
|
await goto(`/admin?${params.toString()}`, { replaceState: false });
|
|
810
847
|
|
|
811
|
-
//
|
|
812
|
-
activeEditorIndex =
|
|
848
|
+
// The stacked panel is always index 1 (only one panel rendered)
|
|
849
|
+
activeEditorIndex = 1;
|
|
813
850
|
}
|
|
814
851
|
|
|
815
|
-
//
|
|
816
|
-
|
|
817
|
-
|
|
852
|
+
// Back button on the stacked panel — pop one level. If the stack
|
|
853
|
+
// becomes empty, the panel closes entirely.
|
|
854
|
+
async function handleStackedEditorBack() {
|
|
855
|
+
const newStack = editorStack.slice(0, -1);
|
|
818
856
|
|
|
819
|
-
// Update URL
|
|
820
857
|
const params = new SvelteURLSearchParams(page.url.searchParams);
|
|
821
858
|
if (newStack.length > 0) {
|
|
822
859
|
const stackParam = newStack
|
|
@@ -828,8 +865,16 @@
|
|
|
828
865
|
}
|
|
829
866
|
await goto(`/admin?${params.toString()}`, { replaceState: false });
|
|
830
867
|
|
|
831
|
-
|
|
832
|
-
|
|
868
|
+
activeEditorIndex = newStack.length > 0 ? 1 : 0;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
// Hard close — removes the stacked panel entirely (used by delete action)
|
|
872
|
+
async function handleCloseStackedEditor(_index: number) {
|
|
873
|
+
const params = new SvelteURLSearchParams(page.url.searchParams);
|
|
874
|
+
params.delete('stack');
|
|
875
|
+
params.delete('history');
|
|
876
|
+
await goto(`/admin?${params.toString()}`, { replaceState: false });
|
|
877
|
+
activeEditorIndex = 0;
|
|
833
878
|
}
|
|
834
879
|
|
|
835
880
|
// Set active editor when clicking on a strip
|
|
@@ -976,6 +1021,7 @@
|
|
|
976
1021
|
params.delete('docId');
|
|
977
1022
|
params.delete('action');
|
|
978
1023
|
params.delete('stack');
|
|
1024
|
+
params.delete('history');
|
|
979
1025
|
await goto(`/admin?${params.toString()}`, { replaceState: false });
|
|
980
1026
|
}}
|
|
981
1027
|
class="text-muted-foreground hover:text-foreground flex items-center gap-2 text-sm"
|
|
@@ -1592,7 +1638,7 @@
|
|
|
1592
1638
|
{isReadOnly}
|
|
1593
1639
|
/>
|
|
1594
1640
|
</div>
|
|
1595
|
-
{#if !primaryEditorState.expanded}
|
|
1641
|
+
{#if !primaryEditorState.expanded && !focusModeOn}
|
|
1596
1642
|
<!-- Collapsed Primary Editor Strip -->
|
|
1597
1643
|
<button
|
|
1598
1644
|
onclick={() => setActiveEditor(0)}
|
|
@@ -1613,25 +1659,33 @@
|
|
|
1613
1659
|
{/if}
|
|
1614
1660
|
{/if}
|
|
1615
1661
|
|
|
1616
|
-
<!-- Stacked Reference
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1662
|
+
<!-- Stacked Reference Panel — only the last entry in the stack
|
|
1663
|
+
is rendered. Back button pops the stack (walks back through
|
|
1664
|
+
the ref chain); closing entirely on the last pop. -->
|
|
1665
|
+
{#if editorStack.length > 0}
|
|
1666
|
+
{@const currentRef = editorStack[editorStack.length - 1]!}
|
|
1667
|
+
{@const isExpanded = focusModeOn
|
|
1668
|
+
? activeEditorIndex === 1
|
|
1669
|
+
: layoutConfig.expandedIndices.includes(1)}
|
|
1620
1670
|
|
|
1621
1671
|
{#if isExpanded}
|
|
1622
1672
|
<div
|
|
1623
1673
|
class="border-rule h-full flex-1 overflow-x-hidden overflow-y-auto border-l transition-all duration-200"
|
|
1624
|
-
style="min-width: 0;"
|
|
1674
|
+
style="min-width: 0;{focusModeOn || showVersionPanel ? '' : ' max-width: 50%;'}"
|
|
1625
1675
|
>
|
|
1626
1676
|
<DocumentEditor
|
|
1627
1677
|
{schemas}
|
|
1628
|
-
documentType={
|
|
1629
|
-
documentId={
|
|
1630
|
-
isCreating={
|
|
1631
|
-
onBack={
|
|
1678
|
+
documentType={currentRef.documentType}
|
|
1679
|
+
documentId={currentRef.documentId}
|
|
1680
|
+
isCreating={currentRef.isCreating}
|
|
1681
|
+
onBack={handleStackedEditorBack}
|
|
1632
1682
|
onOpenReference={handleOpenReference}
|
|
1633
1683
|
onOpenVersionHistory={handleOpenVersionHistory}
|
|
1634
|
-
|
|
1684
|
+
onToggleFocus={() => {
|
|
1685
|
+
activeEditorIndex = 1;
|
|
1686
|
+
toggleFocusMode();
|
|
1687
|
+
}}
|
|
1688
|
+
externalVersionPreview={versionPanelDocId === currentRef.documentId
|
|
1635
1689
|
? versionPreviewData
|
|
1636
1690
|
: null}
|
|
1637
1691
|
onSaved={async () => {}}
|
|
@@ -1655,35 +1709,35 @@
|
|
|
1655
1709
|
}
|
|
1656
1710
|
}}
|
|
1657
1711
|
onDeleted={async () => {
|
|
1658
|
-
handleCloseStackedEditor(
|
|
1712
|
+
handleCloseStackedEditor(0);
|
|
1659
1713
|
}}
|
|
1660
1714
|
{isReadOnly}
|
|
1661
1715
|
/>
|
|
1662
1716
|
</div>
|
|
1663
|
-
{:else}
|
|
1717
|
+
{:else if !focusModeOn}
|
|
1664
1718
|
<!-- Collapsed Stacked Editor Strip -->
|
|
1665
1719
|
<button
|
|
1666
|
-
onclick={() => setActiveEditor(
|
|
1720
|
+
onclick={() => setActiveEditor(1)}
|
|
1667
1721
|
class="border-rule hover:bg-muted/50 flex h-full w-[60px] cursor-pointer flex-col border-l transition-colors"
|
|
1668
|
-
title="Click to expand {
|
|
1722
|
+
title="Click to expand {currentRef.documentType}"
|
|
1669
1723
|
>
|
|
1670
1724
|
<div class="flex h-full flex-1 items-start justify-center p-2 pt-8 text-left">
|
|
1671
1725
|
<div
|
|
1672
1726
|
class="text-foreground text-sm font-medium whitespace-nowrap [writing-mode:vertical-rl]"
|
|
1673
1727
|
>
|
|
1674
|
-
{
|
|
1675
|
-
|
|
1728
|
+
{currentRef.documentType.charAt(0).toUpperCase() +
|
|
1729
|
+
currentRef.documentType.slice(1)}
|
|
1676
1730
|
</div>
|
|
1677
1731
|
</div>
|
|
1678
1732
|
</button>
|
|
1679
1733
|
{/if}
|
|
1680
|
-
{/
|
|
1734
|
+
{/if}
|
|
1681
1735
|
{/if}
|
|
1682
1736
|
|
|
1683
1737
|
<!-- Version History Panel -->
|
|
1684
1738
|
{#if showVersionPanel && versionPanelDocId}
|
|
1685
1739
|
<div
|
|
1686
|
-
class="border-rule h-full w-[280px]
|
|
1740
|
+
class="border-rule h-full w-[280px] shrink-0 overflow-y-auto border-l transition-all duration-200"
|
|
1687
1741
|
>
|
|
1688
1742
|
<DocumentVersionPanel
|
|
1689
1743
|
bind:this={versionPanelRef}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AdminApp.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/AdminApp.svelte.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AA4BnE,UAAU,KAAK;IACd,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,aAAa,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC5E,WAAW,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IACvE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,CAAC,EAAE;QAAE,KAAK,EAAE,WAAW,GAAG,QAAQ,GAAG,OAAO,CAAA;KAAE,CAAC;IACxD,eAAe,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,eAAe,CAAC,EAAE,sBAAsB,GAAG,IAAI,CAAC;CAChD;
|
|
1
|
+
{"version":3,"file":"AdminApp.svelte.d.ts","sourceRoot":"","sources":["../../src/lib/components/AdminApp.svelte.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AA4BnE,UAAU,KAAK;IACd,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,aAAa,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC5E,WAAW,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC;IACvE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,oEAAoE;IACpE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,CAAC,EAAE;QAAE,KAAK,EAAE,WAAW,GAAG,QAAQ,GAAG,OAAO,CAAA;KAAE,CAAC;IACxD,eAAe,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,eAAe,CAAC,EAAE,sBAAsB,GAAG,IAAI,CAAC;CAChD;AA6iDF,QAAA,MAAM,QAAQ,2CAAwC,CAAC;AACvD,KAAK,QAAQ,GAAG,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC;AAC5C,eAAe,QAAQ,CAAC"}
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
import { setSaveStateContext } from '../../save-state-context.svelte';
|
|
14
14
|
import { usePermissions } from '../../permissions-context.svelte';
|
|
15
15
|
import { getDefaultValueForFieldType } from '../../utils/field-defaults';
|
|
16
|
+
import { notifyDocumentChanged } from '../../document-refresh.svelte';
|
|
17
|
+
import { collectReferenceIds } from '../../utils/reference-walk';
|
|
16
18
|
import { cmsLogger } from '../../utils/logger';
|
|
17
19
|
import { toast } from 'svelte-sonner';
|
|
18
20
|
import { confirmDialog } from './confirm-dialog/confirm-dialog.svelte';
|
|
@@ -645,6 +647,7 @@
|
|
|
645
647
|
if (response?.success) {
|
|
646
648
|
lastSaved = new Date();
|
|
647
649
|
hasUnsavedChanges = false;
|
|
650
|
+
if (response.data?.id) notifyDocumentChanged(response.data.id);
|
|
648
651
|
if (isAutoSave) {
|
|
649
652
|
// Trigger validation on all fields after auto-save
|
|
650
653
|
validateAllFields(); // Update validation status
|
|
@@ -716,6 +719,47 @@
|
|
|
716
719
|
return;
|
|
717
720
|
}
|
|
718
721
|
|
|
722
|
+
// Referential integrity guard: every referenced document must itself be
|
|
723
|
+
// published. Without this, publishing a doc that points at drafts would
|
|
724
|
+
// expose dangling references in the published perspective. One batched
|
|
725
|
+
// HTTP call regardless of ref count.
|
|
726
|
+
const refIds = collectReferenceIds(documentData, schema, schemas);
|
|
727
|
+
if (refIds.length > 0) {
|
|
728
|
+
let fetched: any[] = [];
|
|
729
|
+
try {
|
|
730
|
+
const res = await documents.getMany(refIds);
|
|
731
|
+
if (res.success && res.data) fetched = res.data;
|
|
732
|
+
} catch {
|
|
733
|
+
// fall through — missing fetched IDs become "blockers" below
|
|
734
|
+
}
|
|
735
|
+
const fetchedById = new Map(fetched.map((d) => [d.id, d]));
|
|
736
|
+
const checks = refIds.map((id) => ({ id, doc: fetchedById.get(id) ?? null }));
|
|
737
|
+
const blockers = checks.filter(
|
|
738
|
+
(c) => !c.doc || (c.doc as any)._meta?.status !== 'published'
|
|
739
|
+
);
|
|
740
|
+
if (blockers.length > 0) {
|
|
741
|
+
const titles = blockers
|
|
742
|
+
.slice(0, 3)
|
|
743
|
+
.map((b) => {
|
|
744
|
+
if (!b.doc) return `Missing (${b.id.slice(0, 8)})`;
|
|
745
|
+
const d = b.doc as any;
|
|
746
|
+
const label = d.title ?? d.name ?? d.heading ?? d.label ?? b.id;
|
|
747
|
+
const type = d._meta?.type;
|
|
748
|
+
return type ? `"${label}" (${type})` : `"${label}"`;
|
|
749
|
+
})
|
|
750
|
+
.join(', ');
|
|
751
|
+
const remainder = blockers.length > 3 ? ` and ${blockers.length - 3} more` : '';
|
|
752
|
+
saveError = `Cannot publish — unpublished references: ${titles}${remainder}`;
|
|
753
|
+
toast.error(
|
|
754
|
+
`${blockers.length} referenced document${blockers.length === 1 ? '' : 's'} ${blockers.length === 1 ? 'is' : 'are'} not published`,
|
|
755
|
+
{
|
|
756
|
+
description: 'Publish the referenced documents first, then try again.'
|
|
757
|
+
}
|
|
758
|
+
);
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
|
|
719
763
|
saving = true;
|
|
720
764
|
saveError = null;
|
|
721
765
|
|
|
@@ -733,6 +777,7 @@
|
|
|
733
777
|
fullDocument = response.data;
|
|
734
778
|
lastSaved = new Date();
|
|
735
779
|
publishSuccess = new Date();
|
|
780
|
+
notifyDocumentChanged(documentId);
|
|
736
781
|
cmsLogger.debug('[Document Editor]', '✅ Document published successfully');
|
|
737
782
|
cmsLogger.debug('[Document Editor]', '📄 New published hash:', response.data.publishedHash);
|
|
738
783
|
|
|
@@ -790,10 +835,27 @@
|
|
|
790
835
|
async function unpublishDocument() {
|
|
791
836
|
if (!documentId || saving) return;
|
|
792
837
|
|
|
838
|
+
// Surface published back-references so the user knows what will end up
|
|
839
|
+
// with dangling refs in the published perspective. Best-effort —
|
|
840
|
+
// network errors fall through to the standard confirm.
|
|
841
|
+
let backRefDescription =
|
|
842
|
+
'It will be removed from published queries, but the data is preserved and you can re-publish anytime.';
|
|
843
|
+
try {
|
|
844
|
+
const backRefRes = await documents.getBackReferences(documentId);
|
|
845
|
+
if (backRefRes.success && backRefRes.data) {
|
|
846
|
+
const publishedBackRefs = backRefRes.data.filter((r) => r.status === 'published');
|
|
847
|
+
if (publishedBackRefs.length > 0) {
|
|
848
|
+
const count = publishedBackRefs.length;
|
|
849
|
+
backRefDescription = `${count} published document${count === 1 ? '' : 's'} reference${count === 1 ? 's' : ''} this one — their references will be left dangling in the published perspective until you re-publish them. Continue?`;
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
} catch {
|
|
853
|
+
// Silently fall through to the generic confirm; ref index may be unpopulated.
|
|
854
|
+
}
|
|
855
|
+
|
|
793
856
|
const confirmUnpublish = await confirmDialog({
|
|
794
857
|
title: 'Unpublish this document?',
|
|
795
|
-
description:
|
|
796
|
-
'It will be removed from published queries, but the data is preserved and you can re-publish anytime.',
|
|
858
|
+
description: backRefDescription,
|
|
797
859
|
confirmText: 'Unpublish',
|
|
798
860
|
variant: 'destructive'
|
|
799
861
|
});
|
|
@@ -809,6 +871,7 @@
|
|
|
809
871
|
...fullDocument,
|
|
810
872
|
_meta: { ...fullDocument?._meta, status: 'unpublished' }
|
|
811
873
|
};
|
|
874
|
+
notifyDocumentChanged(documentId);
|
|
812
875
|
toast.success('Document unpublished — you can re-publish anytime');
|
|
813
876
|
if (onUnpublished && documentId) {
|
|
814
877
|
onUnpublished(documentId);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DocumentEditor.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/admin/DocumentEditor.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"DocumentEditor.svelte.d.ts","sourceRoot":"","sources":["../../../src/lib/components/admin/DocumentEditor.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAexD,UAAU,KAAK;IACd,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,OAAO,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,WAAW,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1D,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,WAAW,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,aAAa,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,eAAe,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACrE,oBAAoB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,sBAAsB,CAAC,EAAE;QACxB,aAAa,EAAE,MAAM,CAAC;QACtB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC1B,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,IAAI,CAAC;IACT,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,6EAA6E;IAC7E,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAkiDF,QAAA,MAAM,cAAc,2CAAwC,CAAC;AAC7D,KAAK,cAAc,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AACxD,eAAe,cAAc,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import * as AlertDialog from '@aphexcms/ui/shadcn/alert-dialog';
|
|
3
|
-
import {
|
|
3
|
+
import { buttonVariants } from '@aphexcms/ui/shadcn/button';
|
|
4
4
|
import { confirmDialogState, resolveConfirmDialog } from './confirm-dialog.svelte';
|
|
5
5
|
|
|
6
6
|
function handleOpenChange(open: boolean) {
|
|
@@ -21,15 +21,17 @@
|
|
|
21
21
|
{/if}
|
|
22
22
|
</AlertDialog.Header>
|
|
23
23
|
<AlertDialog.Footer>
|
|
24
|
-
<
|
|
24
|
+
<AlertDialog.Cancel onclick={() => resolveConfirmDialog(false)}>
|
|
25
25
|
{confirmDialogState.cancelText}
|
|
26
|
-
</
|
|
27
|
-
<
|
|
28
|
-
|
|
26
|
+
</AlertDialog.Cancel>
|
|
27
|
+
<AlertDialog.Action
|
|
28
|
+
class={confirmDialogState.variant === 'destructive'
|
|
29
|
+
? buttonVariants({ variant: 'destructive' })
|
|
30
|
+
: undefined}
|
|
29
31
|
onclick={() => resolveConfirmDialog(true)}
|
|
30
32
|
>
|
|
31
33
|
{confirmDialogState.confirmText}
|
|
32
|
-
</
|
|
34
|
+
</AlertDialog.Action>
|
|
33
35
|
</AlertDialog.Footer>
|
|
34
36
|
</AlertDialog.Content>
|
|
35
37
|
</AlertDialog.Root>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConfirmDialogHost.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/admin/confirm-dialog/ConfirmDialogHost.svelte.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ConfirmDialogHost.svelte.d.ts","sourceRoot":"","sources":["../../../../src/lib/components/admin/confirm-dialog/ConfirmDialogHost.svelte.ts"],"names":[],"mappings":"AA4CA,UAAU,kCAAkC,CAAC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,MAAM,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,QAAQ,GAAG,MAAM;IACpM,KAAK,OAAO,EAAE,OAAO,QAAQ,EAAE,2BAA2B,CAAC,KAAK,CAAC,GAAG,OAAO,QAAQ,EAAE,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC;IACjK,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,KAAK,CAAA;KAAC,GAAG,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAC;QAAC,GAAG,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IACtG,YAAY,CAAC,EAAE,QAAQ,CAAC;CAC3B;AAKD,QAAA,MAAM,iBAAiB;;kBAA+E,CAAC;AACrF,KAAK,iBAAiB,GAAG,YAAY,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAClE,eAAe,iBAAiB,CAAC"}
|