astro-tractstack 2.0.41 → 2.0.43
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/index.js +8 -2
- package/package.json +1 -1
- package/templates/src/components/compositor/Node.tsx +4 -1
- package/templates/src/components/compositor/preview/PanesPreviewGenerator.tsx +5 -1
- package/templates/src/components/edit/SettingsPanel.tsx +1 -3
- package/templates/src/components/edit/pane/AddPanePanel_new.tsx +6 -10
- package/templates/src/components/edit/pane/AddPanePanel_reuse.tsx +6 -2
- package/templates/src/components/edit/pane/PanePanel_path.tsx +4 -3
- package/templates/src/components/edit/panels/StyleParentPanel.tsx +0 -2
- package/templates/src/components/edit/state/SaveModal.tsx +250 -79
- package/templates/src/components/edit/storyfragment/StoryFragmentConfigPanel.tsx +27 -16
- package/templates/src/components/edit/storyfragment/StoryFragmentPanel_menu.tsx +5 -7
- package/templates/src/components/edit/widgets/BeliefWidget.tsx +4 -1
- package/templates/src/components/edit/widgets/IdentifyAsWidget.tsx +5 -1
- package/templates/src/components/edit/widgets/InteractiveDisclosureWidget.tsx +5 -1
- package/templates/src/components/edit/widgets/ToggleWidget.tsx +4 -1
- package/templates/src/components/fields/BackgroundImage.tsx +4 -1
- package/templates/src/components/fields/ImageUpload.tsx +4 -1
- package/templates/src/components/form/ActionBuilderField.tsx +5 -1
- package/templates/src/components/storykeep/Dashboard_Analytics.tsx +4 -2
- package/templates/src/components/storykeep/state/BrandingWrapper.tsx +13 -1
- package/templates/src/components/storykeep/widgets/HydrateWizard.tsx +84 -0
- package/templates/src/components/storykeep/widgets/{SetupWizard.tsx → InitWizard.tsx} +4 -3
- package/templates/src/components/widgets/Impression.tsx +3 -1
- package/templates/src/hooks/useSearch.ts +5 -3
- package/templates/src/layouts/Layout.astro +1 -23
- package/templates/src/pages/[...slug]/edit.astro +0 -1
- package/templates/src/pages/api/auth/decode.ts +2 -4
- package/templates/src/pages/api/auth/login.ts +4 -5
- package/templates/src/pages/api/auth/logout.ts +22 -7
- package/templates/src/pages/api/auth/profile.ts +4 -2
- package/templates/src/pages/api/sandbox.ts +3 -5
- package/templates/src/pages/api/tailwind.ts +6 -9
- package/templates/src/pages/storykeep/branding.astro +18 -1
- package/templates/src/pages/storykeep/init.astro +25 -23
- package/templates/src/stores/analytics.ts +5 -14
- package/templates/src/stores/nodes.ts +1 -6
- package/templates/src/stores/orphanAnalysis.ts +5 -40
- package/templates/src/types/compositorTypes.ts +1 -1
- package/templates/src/types/tractstack.ts +2 -0
- package/templates/src/utils/actions/actionButton.ts +3 -1
- package/templates/src/utils/api/brandHelpers.ts +1 -0
- package/templates/src/utils/api/setupHelpers.ts +177 -20
- package/templates/src/utils/api.ts +14 -26
- package/templates/src/utils/compositor/nodesHelper.ts +5 -1
- package/templates/src/utils/layout.ts +85 -75
- package/templates/src/utils/tenantResolver.ts +1 -1
- package/utils/inject-files.ts +8 -2
package/dist/index.js
CHANGED
|
@@ -2068,9 +2068,15 @@ async function w(t, e, c) {
|
|
|
2068
2068
|
},
|
|
2069
2069
|
{
|
|
2070
2070
|
src: t(
|
|
2071
|
-
"../templates/src/components/storykeep/widgets/
|
|
2071
|
+
"../templates/src/components/storykeep/widgets/HydrateWizard.tsx"
|
|
2072
2072
|
),
|
|
2073
|
-
dest: "src/components/storykeep/widgets/
|
|
2073
|
+
dest: "src/components/storykeep/widgets/HydrateWizard.tsx"
|
|
2074
|
+
},
|
|
2075
|
+
{
|
|
2076
|
+
src: t(
|
|
2077
|
+
"../templates/src/components/storykeep/widgets/InitWizard.tsx"
|
|
2078
|
+
),
|
|
2079
|
+
dest: "src/components/storykeep/widgets/InitWizard.tsx"
|
|
2074
2080
|
},
|
|
2075
2081
|
{
|
|
2076
2082
|
src: t("../templates/src/pages/storykeep/init.astro"),
|
package/package.json
CHANGED
|
@@ -198,7 +198,10 @@ const getElement = (
|
|
|
198
198
|
panelType="storyfragment"
|
|
199
199
|
ctx={getCtx(props)}
|
|
200
200
|
>
|
|
201
|
-
<StoryFragmentConfigPanel
|
|
201
|
+
<StoryFragmentConfigPanel
|
|
202
|
+
nodeId={props.nodeId}
|
|
203
|
+
isSandboxMode={props.isSandboxMode || false}
|
|
204
|
+
/>
|
|
202
205
|
</PanelVisibilityWrapper>
|
|
203
206
|
<StoryFragment {...sharedProps} />
|
|
204
207
|
</>
|
|
@@ -26,6 +26,10 @@ export const PanesPreviewGenerator = ({
|
|
|
26
26
|
onError,
|
|
27
27
|
}: PanesPreviewGeneratorProps) => {
|
|
28
28
|
const [isGenerating, setIsGenerating] = useState(false);
|
|
29
|
+
const tenantId =
|
|
30
|
+
window.TRACTSTACK_CONFIG?.tenantId ||
|
|
31
|
+
import.meta.env.PUBLIC_TENANTID ||
|
|
32
|
+
'default';
|
|
29
33
|
|
|
30
34
|
useEffect(() => {
|
|
31
35
|
if (requests.length === 0) return;
|
|
@@ -68,7 +72,7 @@ export const PanesPreviewGenerator = ({
|
|
|
68
72
|
requestMap.set(previewPayload.id, request.id);
|
|
69
73
|
}
|
|
70
74
|
|
|
71
|
-
const api = new TractStackAPI();
|
|
75
|
+
const api = new TractStackAPI(tenantId);
|
|
72
76
|
const response = await api.post('/api/v1/fragments/preview', {
|
|
73
77
|
panes: previewPayloads,
|
|
74
78
|
});
|
|
@@ -4,14 +4,12 @@ import XMarkIcon from '@heroicons/react/24/outline/XMarkIcon';
|
|
|
4
4
|
import { settingsPanelStore } from '@/stores/storykeep';
|
|
5
5
|
import { getCtx } from '@/stores/nodes';
|
|
6
6
|
import PanelSwitch from './PanelSwitch';
|
|
7
|
-
import type { BrandConfig } from '@/types/tractstack';
|
|
8
7
|
|
|
9
8
|
interface SettingsPanelProps {
|
|
10
|
-
config: BrandConfig;
|
|
11
9
|
availableCodeHooks: string[];
|
|
12
10
|
}
|
|
13
11
|
|
|
14
|
-
const SettingsPanel = ({
|
|
12
|
+
const SettingsPanel = ({ availableCodeHooks }: SettingsPanelProps) => {
|
|
15
13
|
const [panelTitle, setPanelTitle] = useState('Settings');
|
|
16
14
|
const signal = useStore(settingsPanelStore);
|
|
17
15
|
const ctx = getCtx();
|
|
@@ -24,7 +24,7 @@ import { DirectInjectStep } from './steps/DirectInjectStep';
|
|
|
24
24
|
import BooleanToggle from '@/components/form/BooleanToggle';
|
|
25
25
|
import EnumSelect from '@/components/form/EnumSelect';
|
|
26
26
|
import type { StoryFragmentNode } from '@/types/compositorTypes';
|
|
27
|
-
import { TractStackAPI } from '@/utils/api';
|
|
27
|
+
import { TractStackAPI } from '@/utils/api';
|
|
28
28
|
|
|
29
29
|
type Step =
|
|
30
30
|
| 'initial'
|
|
@@ -40,21 +40,17 @@ type InitialChoice = 'library' | 'ai' | 'blank';
|
|
|
40
40
|
type LayoutChoice = 'standard' | 'grid';
|
|
41
41
|
type ColumnPresetKey = 'left' | 'right';
|
|
42
42
|
|
|
43
|
-
interface GenerationResponse {
|
|
44
|
-
success: boolean;
|
|
45
|
-
data?: { response: string | object };
|
|
46
|
-
error?: string;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
43
|
const callAskLemurAPI = async (
|
|
50
44
|
prompt: string,
|
|
51
45
|
context: string,
|
|
52
46
|
expectJson: boolean,
|
|
53
47
|
isSandboxMode: boolean
|
|
54
48
|
): Promise<string> => {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
49
|
+
const tenantId =
|
|
50
|
+
window.TRACTSTACK_CONFIG?.tenantId ||
|
|
51
|
+
import.meta.env.PUBLIC_TENANTID ||
|
|
52
|
+
'default';
|
|
53
|
+
const api = new TractStackAPI(tenantId);
|
|
58
54
|
|
|
59
55
|
const requestBody = {
|
|
60
56
|
prompt,
|
|
@@ -34,6 +34,10 @@ const AddPaneReUsePanel = ({
|
|
|
34
34
|
first,
|
|
35
35
|
setMode,
|
|
36
36
|
}: AddPaneReUsePanelProps) => {
|
|
37
|
+
const tenantId =
|
|
38
|
+
window.TRACTSTACK_CONFIG?.tenantId ||
|
|
39
|
+
import.meta.env.PUBLIC_TENANTID ||
|
|
40
|
+
'default';
|
|
37
41
|
const [previews, setPreviews] = useState<PreviewItem[]>([]);
|
|
38
42
|
const [query, setQuery] = useState('');
|
|
39
43
|
const [availablePanes, setAvailablePanes] = useState<FullContentMapItem[]>(
|
|
@@ -128,7 +132,7 @@ const AddPaneReUsePanel = ({
|
|
|
128
132
|
const fetchFragments = async () => {
|
|
129
133
|
try {
|
|
130
134
|
const paneIds = visiblePreviews.map((preview) => preview.pane.id);
|
|
131
|
-
const api = new TractStackAPI();
|
|
135
|
+
const api = new TractStackAPI(tenantId);
|
|
132
136
|
|
|
133
137
|
const response = await api.post('/api/v1/fragments/panes', { paneIds });
|
|
134
138
|
|
|
@@ -199,7 +203,7 @@ const AddPaneReUsePanel = ({
|
|
|
199
203
|
if (!selectedPaneId) return;
|
|
200
204
|
|
|
201
205
|
try {
|
|
202
|
-
const api = new TractStackAPI();
|
|
206
|
+
const api = new TractStackAPI(tenantId);
|
|
203
207
|
const response = await api.get(
|
|
204
208
|
`/api/v1/nodes/panes/${selectedPaneId}/template`
|
|
205
209
|
);
|
|
@@ -27,7 +27,10 @@ const PaneMagicPathPanel = ({ nodeId, setMode }: PaneMagicPathPanelProps) => {
|
|
|
27
27
|
const [availableBeliefs, setAvailableBeliefs] = useState<BeliefNode[]>([]);
|
|
28
28
|
const [isLoading, setIsLoading] = useState(true);
|
|
29
29
|
const [error, setError] = useState<string | null>(null);
|
|
30
|
-
|
|
30
|
+
const tenantId =
|
|
31
|
+
window.TRACTSTACK_CONFIG?.tenantId ||
|
|
32
|
+
import.meta.env.PUBLIC_TENANTID ||
|
|
33
|
+
'default';
|
|
31
34
|
|
|
32
35
|
const ctx = getCtx();
|
|
33
36
|
const allNodes = ctx.allNodes.get();
|
|
@@ -46,7 +49,6 @@ const PaneMagicPathPanel = ({ nodeId, setMode }: PaneMagicPathPanelProps) => {
|
|
|
46
49
|
setIsLoading(true);
|
|
47
50
|
const goBackend =
|
|
48
51
|
import.meta.env.PUBLIC_GO_BACKEND || 'http://localhost:8080';
|
|
49
|
-
const tenantId = import.meta.env.PUBLIC_TENANTID || 'default';
|
|
50
52
|
|
|
51
53
|
// Get all belief IDs first
|
|
52
54
|
const idsResponse = await fetch(`${goBackend}/api/v1/nodes/beliefs`, {
|
|
@@ -156,7 +158,6 @@ const PaneMagicPathPanel = ({ nodeId, setMode }: PaneMagicPathPanelProps) => {
|
|
|
156
158
|
|
|
157
159
|
const goBackend =
|
|
158
160
|
import.meta.env.PUBLIC_GO_BACKEND || 'http://localhost:8080';
|
|
159
|
-
const tenantId = import.meta.env.PUBLIC_TENANTID || 'default';
|
|
160
161
|
|
|
161
162
|
const response = await fetch(
|
|
162
163
|
`${goBackend}/api/v1/nodes/beliefs/${beliefId}`,
|
|
@@ -73,7 +73,6 @@ const StyleParentPanel = ({
|
|
|
73
73
|
return;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
// --- STABILIZATION FIX START ---
|
|
77
76
|
let effectiveNode = initialNode;
|
|
78
77
|
if (isMarkdownPaneFragmentNode(initialNode) && initialNode.parentId) {
|
|
79
78
|
const parent = ctx.allNodes.get().get(initialNode.parentId);
|
|
@@ -81,7 +80,6 @@ const StyleParentPanel = ({
|
|
|
81
80
|
effectiveNode = parent as GridLayoutNode;
|
|
82
81
|
}
|
|
83
82
|
}
|
|
84
|
-
// --- STABILIZATION FIX END ---
|
|
85
83
|
|
|
86
84
|
const targets: StyleableTarget[] = [];
|
|
87
85
|
const isGrid = isGridLayoutNode(effectiveNode);
|
|
@@ -13,22 +13,25 @@ import {
|
|
|
13
13
|
pendingHomePageSlugStore,
|
|
14
14
|
} from '@/stores/storykeep';
|
|
15
15
|
import { startLoadingAnimation } from '@/utils/helpers';
|
|
16
|
+
import { processClassesForViewports } from '@/utils/compositor/reduceNodesClassNames';
|
|
16
17
|
import type {
|
|
17
18
|
FlatNode,
|
|
18
19
|
BaseNode,
|
|
19
20
|
PaneNode,
|
|
20
21
|
StoryFragmentNode,
|
|
21
22
|
MarkdownPaneFragmentNode,
|
|
23
|
+
GridLayoutNode,
|
|
22
24
|
} from '@/types/compositorTypes';
|
|
23
25
|
|
|
24
26
|
type SaveStage =
|
|
25
27
|
| 'PREPARING'
|
|
26
28
|
| 'SAVING_PENDING_FILES'
|
|
27
29
|
| 'PROCESSING_OG_IMAGES'
|
|
30
|
+
| 'COOKING_NODES'
|
|
31
|
+
| 'PROCESSING_STYLES'
|
|
28
32
|
| 'SAVING_PANES'
|
|
29
33
|
| 'SAVING_STORY_FRAGMENTS'
|
|
30
34
|
| 'LINKING_FILES'
|
|
31
|
-
| 'PROCESSING_STYLES'
|
|
32
35
|
| 'UPDATING_HOME_PAGE'
|
|
33
36
|
| 'COMPLETED'
|
|
34
37
|
| 'ERROR';
|
|
@@ -46,6 +49,7 @@ interface SaveModalProps {
|
|
|
46
49
|
isContext: boolean;
|
|
47
50
|
onClose: () => void;
|
|
48
51
|
isSandboxMode?: boolean;
|
|
52
|
+
hydrate?: boolean;
|
|
49
53
|
}
|
|
50
54
|
|
|
51
55
|
const PROGRESS_PHASES = {
|
|
@@ -56,6 +60,7 @@ const PROGRESS_PHASES = {
|
|
|
56
60
|
};
|
|
57
61
|
|
|
58
62
|
const INDETERMINATE_STAGES: SaveStage[] = [
|
|
63
|
+
'COOKING_NODES',
|
|
59
64
|
'SAVING_PANES',
|
|
60
65
|
'LINKING_FILES',
|
|
61
66
|
'PROCESSING_STYLES',
|
|
@@ -109,6 +114,7 @@ export default function SaveModal({
|
|
|
109
114
|
isContext,
|
|
110
115
|
onClose,
|
|
111
116
|
isSandboxMode = false,
|
|
117
|
+
hydrate = false,
|
|
112
118
|
}: SaveModalProps) {
|
|
113
119
|
const [stage, setStage] = useState<SaveStage>('PREPARING');
|
|
114
120
|
const [progress, setProgress] = useState(0);
|
|
@@ -127,7 +133,10 @@ export default function SaveModal({
|
|
|
127
133
|
const pendingHomePageSlug = pendingHomePageSlugStore.get();
|
|
128
134
|
const goBackend =
|
|
129
135
|
import.meta.env.PUBLIC_GO_BACKEND || 'http://localhost:8080';
|
|
130
|
-
const tenantId =
|
|
136
|
+
const tenantId =
|
|
137
|
+
window.TRACTSTACK_CONFIG?.tenantId ||
|
|
138
|
+
import.meta.env.PUBLIC_TENANTID ||
|
|
139
|
+
'default';
|
|
131
140
|
|
|
132
141
|
const addDebugMessage = (message: string) => {
|
|
133
142
|
const timestamp = new Date().toLocaleTimeString();
|
|
@@ -388,6 +397,203 @@ export default function SaveModal({
|
|
|
388
397
|
dirtyPanes.length + dirtyStoryFragments.length;
|
|
389
398
|
let completedProcessingSteps = 0;
|
|
390
399
|
|
|
400
|
+
// --- NEW COOKING STAGE ---
|
|
401
|
+
if (allDirtyNodes.length > 0) {
|
|
402
|
+
setStage('COOKING_NODES');
|
|
403
|
+
setIsIndeterminateStage(true);
|
|
404
|
+
addDebugMessage('Cooking nodes for whitelist extraction...');
|
|
405
|
+
|
|
406
|
+
const cookingUpdates: BaseNode[] = [];
|
|
407
|
+
|
|
408
|
+
allDirtyNodes.forEach((liveNode) => {
|
|
409
|
+
try {
|
|
410
|
+
let updatedNode: BaseNode | null = null;
|
|
411
|
+
|
|
412
|
+
// Pattern 1: TagElements -> elementCss
|
|
413
|
+
if (liveNode.nodeType === 'TagElement') {
|
|
414
|
+
const flatNode = liveNode as FlatNode;
|
|
415
|
+
const computedCSS = ctx.getNodeClasses(flatNode.id, 'auto', 0);
|
|
416
|
+
if (flatNode.elementCss !== computedCSS) {
|
|
417
|
+
updatedNode = {
|
|
418
|
+
...liveNode,
|
|
419
|
+
elementCss: computedCSS,
|
|
420
|
+
} as FlatNode;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
// Pattern 2: Markdown Nodes -> parentCss & gridCss
|
|
424
|
+
else if (liveNode.nodeType === 'Markdown') {
|
|
425
|
+
const markdownNode = liveNode as MarkdownPaneFragmentNode;
|
|
426
|
+
let needsUpdate = false;
|
|
427
|
+
const nextNode = { ...markdownNode };
|
|
428
|
+
|
|
429
|
+
// parentCss
|
|
430
|
+
if (markdownNode.parentClasses) {
|
|
431
|
+
const computedParentCss = markdownNode.parentClasses.map(
|
|
432
|
+
(_: any, index: number) =>
|
|
433
|
+
ctx.getNodeClasses(liveNode.id, 'auto', index)
|
|
434
|
+
);
|
|
435
|
+
if (
|
|
436
|
+
JSON.stringify(markdownNode.parentCss) !==
|
|
437
|
+
JSON.stringify(computedParentCss)
|
|
438
|
+
) {
|
|
439
|
+
nextNode.parentCss = computedParentCss;
|
|
440
|
+
needsUpdate = true;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// gridCss
|
|
445
|
+
if (markdownNode.gridClasses) {
|
|
446
|
+
const [allClasses] = processClassesForViewports(
|
|
447
|
+
markdownNode.gridClasses,
|
|
448
|
+
{},
|
|
449
|
+
1
|
|
450
|
+
);
|
|
451
|
+
if (allClasses && allClasses.length > 0) {
|
|
452
|
+
const computedGridCss = allClasses[0];
|
|
453
|
+
if (markdownNode.gridCss !== computedGridCss) {
|
|
454
|
+
nextNode.gridCss = computedGridCss;
|
|
455
|
+
needsUpdate = true;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
if (needsUpdate) updatedNode = nextNode;
|
|
461
|
+
}
|
|
462
|
+
// Pattern 3: GridLayout Nodes -> parentCss & gridCss
|
|
463
|
+
else if (liveNode.nodeType === 'GridLayoutNode') {
|
|
464
|
+
const gridNode = liveNode as GridLayoutNode;
|
|
465
|
+
let needsUpdate = false;
|
|
466
|
+
const nextNode = { ...gridNode };
|
|
467
|
+
|
|
468
|
+
// parentCss
|
|
469
|
+
if (gridNode.parentClasses) {
|
|
470
|
+
const computedParentCss = gridNode.parentClasses.map(
|
|
471
|
+
(_: any, index: number) =>
|
|
472
|
+
ctx.getNodeClasses(liveNode.id, 'auto', index)
|
|
473
|
+
);
|
|
474
|
+
if (
|
|
475
|
+
JSON.stringify(gridNode.parentCss) !==
|
|
476
|
+
JSON.stringify(computedParentCss)
|
|
477
|
+
) {
|
|
478
|
+
nextNode.parentCss = computedParentCss.join(` `);
|
|
479
|
+
needsUpdate = true;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// gridCss
|
|
484
|
+
if (gridNode.gridColumns) {
|
|
485
|
+
const { mobile, tablet, desktop } = gridNode.gridColumns;
|
|
486
|
+
let computedGridCss = `grid grid-cols-${mobile}`;
|
|
487
|
+
if (tablet !== mobile) {
|
|
488
|
+
computedGridCss += ` md:grid-cols-${tablet}`;
|
|
489
|
+
}
|
|
490
|
+
if (desktop !== tablet) {
|
|
491
|
+
computedGridCss += ` xl:grid-cols-${desktop}`;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
if (gridNode.gridCss !== computedGridCss) {
|
|
495
|
+
nextNode.gridCss = computedGridCss;
|
|
496
|
+
needsUpdate = true;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
if (needsUpdate) updatedNode = nextNode;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
if (updatedNode) {
|
|
504
|
+
cookingUpdates.push(updatedNode);
|
|
505
|
+
}
|
|
506
|
+
} catch (e) {
|
|
507
|
+
console.warn(`Failed to cook node ${liveNode.id}`, e);
|
|
508
|
+
}
|
|
509
|
+
});
|
|
510
|
+
|
|
511
|
+
if (cookingUpdates.length > 0) {
|
|
512
|
+
ctx.modifyNodes(cookingUpdates, {
|
|
513
|
+
notify: false,
|
|
514
|
+
recordHistory: false,
|
|
515
|
+
});
|
|
516
|
+
addDebugMessage(`Cooked ${cookingUpdates.length} nodes.`);
|
|
517
|
+
}
|
|
518
|
+
setIsIndeterminateStage(false);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// --- PROCESSING STYLES ---
|
|
522
|
+
// Moved before SAVING_PANES to ensure the whitelist is generated from the cooked, exhaustive inventory
|
|
523
|
+
setStage('PROCESSING_STYLES');
|
|
524
|
+
setIsIndeterminateStage(true);
|
|
525
|
+
const baseFinalizationProgress =
|
|
526
|
+
PROGRESS_PHASES.PREPARATION +
|
|
527
|
+
PROGRESS_PHASES.UPLOADS +
|
|
528
|
+
PROGRESS_PHASES.PROCESSING;
|
|
529
|
+
setProgress(
|
|
530
|
+
baseFinalizationProgress + PROGRESS_PHASES.FINALIZATION / 2
|
|
531
|
+
);
|
|
532
|
+
addDebugMessage(`Processing styles...`);
|
|
533
|
+
|
|
534
|
+
try {
|
|
535
|
+
const { dirtyPaneIds, classes: dirtyClasses } =
|
|
536
|
+
ctx.getDirtyNodesClassData();
|
|
537
|
+
|
|
538
|
+
const astroEndpoint = `/api/tailwind`;
|
|
539
|
+
const astroPayload = { dirtyPaneIds, dirtyClasses };
|
|
540
|
+
const astroResponse = await fetch(astroEndpoint, {
|
|
541
|
+
method: 'POST',
|
|
542
|
+
headers: {
|
|
543
|
+
'Content-Type': 'application/json',
|
|
544
|
+
'X-Tenant-ID': tenantId,
|
|
545
|
+
},
|
|
546
|
+
credentials: 'include',
|
|
547
|
+
body: JSON.stringify(astroPayload),
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
if (!astroResponse.ok) {
|
|
551
|
+
throw new Error(
|
|
552
|
+
`CSS generation failed! status: ${astroResponse.status}`
|
|
553
|
+
);
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
const astroResult = await astroResponse.json();
|
|
557
|
+
|
|
558
|
+
if (!astroResult.success || !astroResult.generatedCss) {
|
|
559
|
+
throw new Error('CSS generation failed: no CSS returned');
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
addDebugMessage(
|
|
563
|
+
`CSS generated: ${astroResult.generatedCss.length} bytes for ${dirtyClasses.length} classes`
|
|
564
|
+
);
|
|
565
|
+
|
|
566
|
+
const goEndpoint = `${goBackend}/api/v1/tailwind/update`;
|
|
567
|
+
const goPayload = { frontendCss: astroResult.generatedCss };
|
|
568
|
+
const goResponse = await fetch(goEndpoint, {
|
|
569
|
+
method: 'POST',
|
|
570
|
+
headers: {
|
|
571
|
+
'Content-Type': 'application/json',
|
|
572
|
+
'X-Tenant-ID': tenantId,
|
|
573
|
+
},
|
|
574
|
+
credentials: 'include',
|
|
575
|
+
body: JSON.stringify(goPayload),
|
|
576
|
+
});
|
|
577
|
+
|
|
578
|
+
if (!goResponse.ok) {
|
|
579
|
+
throw new Error(`CSS save failed! status: ${goResponse.status}`);
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
const goResult = await goResponse.json();
|
|
583
|
+
addDebugMessage(
|
|
584
|
+
`CSS saved successfully: stylesVer ${goResult.stylesVer}`
|
|
585
|
+
);
|
|
586
|
+
} catch (error) {
|
|
587
|
+
const errorMsg =
|
|
588
|
+
error instanceof Error ? error.message : 'Unknown error';
|
|
589
|
+
addDebugMessage(`Styles processing failed: ${errorMsg}`);
|
|
590
|
+
throw new Error(`Failed to process styles: ${errorMsg}`);
|
|
591
|
+
} finally {
|
|
592
|
+
setIsIndeterminateStage(false);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// --- SAVING PANES ---
|
|
596
|
+
// Runs after styles to ensure DB gets minimal, correct payload
|
|
391
597
|
if (dirtyPanes.length > 0) {
|
|
392
598
|
setStage('SAVING_PANES');
|
|
393
599
|
setIsIndeterminateStage(true);
|
|
@@ -400,6 +606,7 @@ export default function SaveModal({
|
|
|
400
606
|
transformLivePaneForSave(ctx, paneNode.id, isContext)
|
|
401
607
|
);
|
|
402
608
|
|
|
609
|
+
// Update context with minimal strings (idempotent, restoring runtime state)
|
|
403
610
|
bulkPayload.forEach((payload) => {
|
|
404
611
|
payload.optionsPayload.nodes.forEach((transformedNode) => {
|
|
405
612
|
const liveNode = ctx.allNodes.get().get(transformedNode.id);
|
|
@@ -453,8 +660,6 @@ export default function SaveModal({
|
|
|
453
660
|
`Processing ${dirtyPanes.length} panes via -> POST ${endpoint}`
|
|
454
661
|
);
|
|
455
662
|
|
|
456
|
-
//console.log(`bulkPayload`, bulkPayload)
|
|
457
|
-
|
|
458
663
|
try {
|
|
459
664
|
const response = await fetch(endpoint, {
|
|
460
665
|
method: 'POST',
|
|
@@ -516,7 +721,7 @@ export default function SaveModal({
|
|
|
516
721
|
const payload = await transformStoryFragmentForSave(
|
|
517
722
|
ctx,
|
|
518
723
|
fragment.id,
|
|
519
|
-
|
|
724
|
+
tenantId
|
|
520
725
|
);
|
|
521
726
|
|
|
522
727
|
if (uploadedOGPaths[fragment.id]) {
|
|
@@ -583,14 +788,11 @@ export default function SaveModal({
|
|
|
583
788
|
}
|
|
584
789
|
}
|
|
585
790
|
|
|
586
|
-
const baseFinalizationProgress =
|
|
587
|
-
PROGRESS_PHASES.PREPARATION +
|
|
588
|
-
PROGRESS_PHASES.UPLOADS +
|
|
589
|
-
PROGRESS_PHASES.PROCESSING;
|
|
590
|
-
|
|
591
791
|
if (dirtyPanes.length > 0) {
|
|
592
792
|
setStage('LINKING_FILES');
|
|
593
793
|
setIsIndeterminateStage(true);
|
|
794
|
+
// ... Linking files logic continues ...
|
|
795
|
+
// Note: Linking files remains after saving panes because it relies on panes existing in DB
|
|
594
796
|
setProgress(baseFinalizationProgress);
|
|
595
797
|
addDebugMessage('Starting file-pane relationship linking...');
|
|
596
798
|
|
|
@@ -644,74 +846,6 @@ export default function SaveModal({
|
|
|
644
846
|
setIsIndeterminateStage(false);
|
|
645
847
|
}
|
|
646
848
|
|
|
647
|
-
setStage('PROCESSING_STYLES');
|
|
648
|
-
setIsIndeterminateStage(true);
|
|
649
|
-
setProgress(
|
|
650
|
-
baseFinalizationProgress + PROGRESS_PHASES.FINALIZATION / 2
|
|
651
|
-
);
|
|
652
|
-
addDebugMessage(`Processing styles...`);
|
|
653
|
-
|
|
654
|
-
try {
|
|
655
|
-
const { dirtyPaneIds, classes: dirtyClasses } =
|
|
656
|
-
ctx.getDirtyNodesClassData();
|
|
657
|
-
|
|
658
|
-
const astroEndpoint = `/api/tailwind`;
|
|
659
|
-
const astroPayload = { dirtyPaneIds, dirtyClasses };
|
|
660
|
-
const astroResponse = await fetch(astroEndpoint, {
|
|
661
|
-
method: 'POST',
|
|
662
|
-
headers: {
|
|
663
|
-
'Content-Type': 'application/json',
|
|
664
|
-
'X-Tenant-ID': tenantId,
|
|
665
|
-
},
|
|
666
|
-
credentials: 'include',
|
|
667
|
-
body: JSON.stringify(astroPayload),
|
|
668
|
-
});
|
|
669
|
-
|
|
670
|
-
if (!astroResponse.ok) {
|
|
671
|
-
throw new Error(
|
|
672
|
-
`CSS generation failed! status: ${astroResponse.status}`
|
|
673
|
-
);
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
const astroResult = await astroResponse.json();
|
|
677
|
-
|
|
678
|
-
if (!astroResult.success || !astroResult.generatedCss) {
|
|
679
|
-
throw new Error('CSS generation failed: no CSS returned');
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
addDebugMessage(
|
|
683
|
-
`CSS generated: ${astroResult.generatedCss.length} bytes for ${dirtyClasses.length} classes`
|
|
684
|
-
);
|
|
685
|
-
|
|
686
|
-
const goEndpoint = `${goBackend}/api/v1/tailwind/update`;
|
|
687
|
-
const goPayload = { frontendCss: astroResult.generatedCss };
|
|
688
|
-
const goResponse = await fetch(goEndpoint, {
|
|
689
|
-
method: 'POST',
|
|
690
|
-
headers: {
|
|
691
|
-
'Content-Type': 'application/json',
|
|
692
|
-
'X-Tenant-ID': tenantId,
|
|
693
|
-
},
|
|
694
|
-
credentials: 'include',
|
|
695
|
-
body: JSON.stringify(goPayload),
|
|
696
|
-
});
|
|
697
|
-
|
|
698
|
-
if (!goResponse.ok) {
|
|
699
|
-
throw new Error(`CSS save failed! status: ${goResponse.status}`);
|
|
700
|
-
}
|
|
701
|
-
|
|
702
|
-
const goResult = await goResponse.json();
|
|
703
|
-
addDebugMessage(
|
|
704
|
-
`CSS saved successfully: stylesVer ${goResult.stylesVer}`
|
|
705
|
-
);
|
|
706
|
-
} catch (error) {
|
|
707
|
-
const errorMsg =
|
|
708
|
-
error instanceof Error ? error.message : 'Unknown error';
|
|
709
|
-
addDebugMessage(`Styles processing failed: ${errorMsg}`);
|
|
710
|
-
throw new Error(`Failed to process styles: ${errorMsg}`);
|
|
711
|
-
} finally {
|
|
712
|
-
setIsIndeterminateStage(false);
|
|
713
|
-
}
|
|
714
|
-
|
|
715
849
|
if (pendingHomePageSlug) {
|
|
716
850
|
setStage('UPDATING_HOME_PAGE');
|
|
717
851
|
setIsIndeterminateStage(true);
|
|
@@ -774,6 +908,30 @@ export default function SaveModal({
|
|
|
774
908
|
}
|
|
775
909
|
}
|
|
776
910
|
|
|
911
|
+
if (hydrate) {
|
|
912
|
+
addDebugMessage('Finalizing setup (Kill Switch)...');
|
|
913
|
+
try {
|
|
914
|
+
const response = await fetch(`${goBackend}/api/v1/setup/complete`, {
|
|
915
|
+
method: 'POST',
|
|
916
|
+
headers: {
|
|
917
|
+
'Content-Type': 'application/json',
|
|
918
|
+
'X-Tenant-ID': tenantId,
|
|
919
|
+
},
|
|
920
|
+
credentials: 'include',
|
|
921
|
+
body: JSON.stringify({}),
|
|
922
|
+
});
|
|
923
|
+
|
|
924
|
+
if (!response.ok) {
|
|
925
|
+
throw new Error(`Kill Switch failed: ${response.status}`);
|
|
926
|
+
}
|
|
927
|
+
addDebugMessage('Hydration token cleared.');
|
|
928
|
+
} catch (e) {
|
|
929
|
+
console.error('Kill switch error:', e);
|
|
930
|
+
// We don't throw here to ensure the user still gets to the dashboard
|
|
931
|
+
addDebugMessage('Warning: Failed to clear hydration token.');
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
|
|
777
935
|
setStage('COMPLETED');
|
|
778
936
|
setProgress(100);
|
|
779
937
|
addDebugMessage('Save process completed successfully!');
|
|
@@ -822,6 +980,9 @@ export default function SaveModal({
|
|
|
822
980
|
case 'PROCESSING_OG_IMAGES':
|
|
823
981
|
description = `Processing social images${getProgressText()}`;
|
|
824
982
|
break;
|
|
983
|
+
case 'COOKING_NODES':
|
|
984
|
+
description = 'Preparing content styles...';
|
|
985
|
+
break;
|
|
825
986
|
case 'SAVING_PANES':
|
|
826
987
|
description = `${actionText} pane content...`;
|
|
827
988
|
break;
|
|
@@ -1031,7 +1192,17 @@ export default function SaveModal({
|
|
|
1031
1192
|
|
|
1032
1193
|
{(stage === 'COMPLETED' || stage === 'ERROR') && (
|
|
1033
1194
|
<div className="flex justify-end gap-2">
|
|
1034
|
-
{stage === 'COMPLETED' && (
|
|
1195
|
+
{hydrate && stage === 'COMPLETED' && (
|
|
1196
|
+
<button
|
|
1197
|
+
onClick={() =>
|
|
1198
|
+
(window.location.href = '/storykeep/branding')
|
|
1199
|
+
}
|
|
1200
|
+
className={`rounded bg-cyan-600 px-4 py-2 text-white transition-colors hover:bg-cyan-700`}
|
|
1201
|
+
>
|
|
1202
|
+
Continue
|
|
1203
|
+
</button>
|
|
1204
|
+
)}
|
|
1205
|
+
{!hydrate && stage === 'COMPLETED' && (
|
|
1035
1206
|
<>
|
|
1036
1207
|
<a
|
|
1037
1208
|
href={visitPageUrl}
|
|
@@ -26,7 +26,13 @@ import {
|
|
|
26
26
|
type StoryFragmentNode,
|
|
27
27
|
} from '@/types/compositorTypes';
|
|
28
28
|
|
|
29
|
-
const StoryFragmentConfigPanel = ({
|
|
29
|
+
const StoryFragmentConfigPanel = ({
|
|
30
|
+
nodeId,
|
|
31
|
+
isSandboxMode,
|
|
32
|
+
}: {
|
|
33
|
+
nodeId: string;
|
|
34
|
+
isSandboxMode: boolean;
|
|
35
|
+
}) => {
|
|
30
36
|
const brandColors = brandConfigStore.get()?.BRAND_COLOURS || '';
|
|
31
37
|
const [isNodeAvailable, setIsNodeAvailable] = useState(false);
|
|
32
38
|
const [storyfragmentNode, setStoryfragmentNode] =
|
|
@@ -185,21 +191,26 @@ const StoryFragmentConfigPanel = ({ nodeId }: { nodeId: string }) => {
|
|
|
185
191
|
<div className="mb-4">
|
|
186
192
|
<div className="w-full rounded-b-md bg-white p-4">
|
|
187
193
|
<div className="flex flex-wrap items-center gap-2">
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
194
|
+
{!isSandboxMode && (
|
|
195
|
+
<>
|
|
196
|
+
<button
|
|
197
|
+
onClick={() => setMode(StoryFragmentMode.OG)}
|
|
198
|
+
className="text-md min-h-9 rounded border border-cyan-200 bg-white px-3 text-cyan-700 shadow-sm transition-colors hover:bg-cyan-700 hover:text-white focus:bg-cyan-700 focus:text-white"
|
|
199
|
+
>
|
|
200
|
+
Title:{' '}
|
|
201
|
+
<span className="font-bold">{storyfragmentNode.title}</span>
|
|
202
|
+
</button>
|
|
203
|
+
<button
|
|
204
|
+
onClick={() => setMode(StoryFragmentMode.SLUG)}
|
|
205
|
+
className="text-md h-9 rounded border border-cyan-200 bg-white px-3 text-cyan-700 shadow-sm transition-colors hover:bg-cyan-700 hover:text-white focus:bg-cyan-700 focus:text-white"
|
|
206
|
+
>
|
|
207
|
+
Slug:{' '}
|
|
208
|
+
<span className="font-bold">{storyfragmentNode.slug}</span>
|
|
209
|
+
</button>
|
|
210
|
+
</>
|
|
211
|
+
)}
|
|
212
|
+
|
|
213
|
+
{!isSandboxMode && !isTemplate && (
|
|
203
214
|
<>
|
|
204
215
|
<button
|
|
205
216
|
onClick={() => setMode(StoryFragmentMode.MENU)}
|