@optimizely/ocp-local-env 1.0.0-beta.8 → 1.0.1
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/README.md +18 -133
- package/dist/package.json +17 -9
- package/dist/public/bundle.fa87c838198caf8c051a.js +3 -0
- package/dist/public/{bundle.0a495807b6ef336cb500.js.LICENSE.txt → bundle.fa87c838198caf8c051a.js.LICENSE.txt} +13 -3
- package/dist/public/bundle.fa87c838198caf8c051a.js.map +1 -0
- package/dist/public/index.html +1 -1
- package/dist/src/cli.js +2 -2
- package/dist/src/cli.js.map +1 -1
- package/dist/src/executor/FunctionExecutor.js +8 -5
- package/dist/src/executor/FunctionExecutor.js.map +1 -1
- package/dist/src/executor/JobExecutor.js +0 -17
- package/dist/src/executor/JobExecutor.js.map +1 -1
- package/dist/src/executor/LifecycleExecutor.js +11 -2
- package/dist/src/executor/LifecycleExecutor.js.map +1 -1
- package/dist/src/executor/watcher.d.ts +6 -0
- package/dist/src/executor/watcher.js +45 -0
- package/dist/src/executor/watcher.js.map +1 -1
- package/dist/src/local_engine/LocalJobApi.d.ts +31 -2
- package/dist/src/local_engine/LocalJobApi.js +42 -17
- package/dist/src/local_engine/LocalJobApi.js.map +1 -1
- package/dist/src/local_engine/LocalNotifier.d.ts +3 -2
- package/dist/src/local_engine/LocalNotifier.js +7 -0
- package/dist/src/local_engine/LocalNotifier.js.map +1 -1
- package/dist/src/local_engine/LocalSourceApi.d.ts +40 -0
- package/dist/src/local_engine/LocalSourceApi.js +69 -0
- package/dist/src/local_engine/LocalSourceApi.js.map +1 -0
- package/dist/src/local_engine/local-engine-child-base.d.ts +0 -12
- package/dist/src/local_engine/local-engine-child-base.js +0 -127
- package/dist/src/local_engine/local-engine-child-base.js.map +1 -1
- package/dist/src/local_engine/local-engine-client.d.ts +19 -29
- package/dist/src/local_engine/local-engine-client.js +45 -94
- package/dist/src/local_engine/local-engine-client.js.map +1 -1
- package/dist/src/local_engine/local-engine-types.d.ts +13 -50
- package/dist/src/local_engine/local-engine-unified.d.ts +6 -13
- package/dist/src/local_engine/local-engine-unified.js +108 -222
- package/dist/src/local_engine/local-engine-unified.js.map +1 -1
- package/dist/src/local_engine/localSDKConfig.d.ts +6 -0
- package/dist/src/local_engine/localSDKConfig.js +66 -1
- package/dist/src/local_engine/localSDKConfig.js.map +1 -1
- package/dist/src/local_engine/storage/BaseKVStoreWrapper.d.ts +1 -2
- package/dist/src/local_engine/storage/BaseKVStoreWrapper.js.map +1 -1
- package/dist/src/local_engine/storage/LocalConfigStore.d.ts +7 -13
- package/dist/src/local_engine/storage/LocalConfigStore.js +9 -31
- package/dist/src/local_engine/storage/LocalConfigStore.js.map +1 -1
- package/dist/src/local_engine/storage/LocalKVStore.d.ts +4 -0
- package/dist/src/local_engine/storage/LocalKVStore.js +23 -0
- package/dist/src/local_engine/storage/LocalKVStore.js.map +1 -1
- package/dist/src/local_engine/storage/LocalSettingsStore.d.ts +7 -1
- package/dist/src/local_engine/storage/LocalSettingsStore.js +46 -4
- package/dist/src/local_engine/storage/LocalSettingsStore.js.map +1 -1
- package/dist/src/local_engine/storage/SourceDataStore.d.ts +16 -14
- package/dist/src/local_engine/storage/SourceDataStore.js +57 -57
- package/dist/src/local_engine/storage/SourceDataStore.js.map +1 -1
- package/dist/src/local_engine/utils.d.ts +2 -0
- package/dist/src/local_engine/utils.js +4 -2
- package/dist/src/local_engine/utils.js.map +1 -1
- package/dist/src/server/api/deploy.d.ts +20 -0
- package/dist/src/server/api/deploy.js +399 -0
- package/dist/src/server/api/deploy.js.map +1 -0
- package/dist/src/server/api/destinations.js +1 -1
- package/dist/src/server/api/destinations.js.map +1 -1
- package/dist/src/server/api/env.d.ts +2 -0
- package/dist/src/server/api/env.js +28 -0
- package/dist/src/server/api/env.js.map +1 -0
- package/dist/src/server/api/functions.js +13 -12
- package/dist/src/server/api/functions.js.map +1 -1
- package/dist/src/server/api/opalTools.d.ts +4 -0
- package/dist/src/server/api/opalTools.js +81 -0
- package/dist/src/server/api/opalTools.js.map +1 -0
- package/dist/src/server/api/schema.d.ts +6 -0
- package/dist/src/server/api/schema.js +95 -0
- package/dist/src/server/api/schema.js.map +1 -0
- package/dist/src/server/api/sources.d.ts +1 -2
- package/dist/src/server/api/sources.js +16 -275
- package/dist/src/server/api/sources.js.map +1 -1
- package/dist/src/server/api/v1.js +67 -70
- package/dist/src/server/api/v1.js.map +1 -1
- package/dist/src/server/api.d.ts +4 -0
- package/dist/src/server/api.js +133 -11
- package/dist/src/server/api.js.map +1 -1
- package/dist/src/server/app-discovery.js +37 -4
- package/dist/src/server/app-discovery.js.map +1 -1
- package/dist/src/server/app-env.d.ts +21 -0
- package/dist/src/server/app-env.js +122 -0
- package/dist/src/server/app-env.js.map +1 -0
- package/dist/src/server/browserFocus.d.ts +5 -0
- package/dist/src/server/browserFocus.js +39 -0
- package/dist/src/server/browserFocus.js.map +1 -0
- package/dist/src/server/config.d.ts +3 -0
- package/dist/src/server/config.js +7 -0
- package/dist/src/server/config.js.map +1 -1
- package/dist/src/server/mockDataGenerator.d.ts +1 -2
- package/dist/src/server/mockDataGenerator.js +77 -35
- package/dist/src/server/mockDataGenerator.js.map +1 -1
- package/dist/src/server/mockToolDataGenerator.d.ts +12 -0
- package/dist/src/server/mockToolDataGenerator.js +393 -0
- package/dist/src/server/mockToolDataGenerator.js.map +1 -0
- package/dist/src/server.js +152 -168
- package/dist/src/server.js.map +1 -1
- package/dist/src/types/app.d.ts +1 -3
- package/dist/src/types/app.js.map +1 -1
- package/dist/src/ui/components/App.js +311 -50
- package/dist/src/ui/components/App.js.map +1 -1
- package/dist/src/ui/components/DeployModal.d.ts +16 -0
- package/dist/src/ui/components/DeployModal.js +75 -0
- package/dist/src/ui/components/DeployModal.js.map +1 -0
- package/dist/src/ui/components/DestinationBatchEditor.d.ts +9 -1
- package/dist/src/ui/components/DestinationBatchEditor.js +30 -16
- package/dist/src/ui/components/DestinationBatchEditor.js.map +1 -1
- package/dist/src/ui/components/DestinationsView.js +5 -1
- package/dist/src/ui/components/DestinationsView.js.map +1 -1
- package/dist/src/ui/components/EntityNotAvailable.d.ts +15 -0
- package/dist/src/ui/components/EntityNotAvailable.js +27 -0
- package/dist/src/ui/components/EntityNotAvailable.js.map +1 -0
- package/dist/src/ui/components/EnvViewer.d.ts +8 -0
- package/dist/src/ui/components/EnvViewer.js +35 -0
- package/dist/src/ui/components/EnvViewer.js.map +1 -0
- package/dist/src/ui/components/FunctionsView.d.ts +2 -6
- package/dist/src/ui/components/FunctionsView.js +106 -124
- package/dist/src/ui/components/FunctionsView.js.map +1 -1
- package/dist/src/ui/components/JobsView.js +28 -5
- package/dist/src/ui/components/JobsView.js.map +1 -1
- package/dist/src/ui/components/KVStoreViewer.js +5 -5
- package/dist/src/ui/components/KVStoreViewer.js.map +1 -1
- package/dist/src/ui/components/KeyValueEditor.d.ts +15 -0
- package/dist/src/ui/components/KeyValueEditor.js +12 -0
- package/dist/src/ui/components/KeyValueEditor.js.map +1 -0
- package/dist/src/ui/components/NotificationViewer.d.ts +2 -11
- package/dist/src/ui/components/NotificationViewer.js +69 -15
- package/dist/src/ui/components/NotificationViewer.js.map +1 -1
- package/dist/src/ui/components/OdpSchemaView.d.ts +3 -0
- package/dist/src/ui/components/OdpSchemaView.js +58 -0
- package/dist/src/ui/components/OdpSchemaView.js.map +1 -0
- package/dist/src/ui/components/OpalToolsView.d.ts +9 -0
- package/dist/src/ui/components/OpalToolsView.js +399 -0
- package/dist/src/ui/components/OpalToolsView.js.map +1 -0
- package/dist/src/ui/components/ResponseViewer.d.ts +39 -0
- package/dist/src/ui/components/ResponseViewer.js +43 -0
- package/dist/src/ui/components/ResponseViewer.js.map +1 -0
- package/dist/src/ui/components/SecretsStoreViewer.js +3 -2
- package/dist/src/ui/components/SecretsStoreViewer.js.map +1 -1
- package/dist/src/ui/components/SettingsStoreViewer.js +3 -2
- package/dist/src/ui/components/SettingsStoreViewer.js.map +1 -1
- package/dist/src/ui/components/SourceEmittedDataPanel.d.ts +8 -0
- package/dist/src/ui/components/SourceEmittedDataPanel.js +103 -0
- package/dist/src/ui/components/SourceEmittedDataPanel.js.map +1 -0
- package/dist/src/ui/components/SourcesView.js +4 -8
- package/dist/src/ui/components/SourcesView.js.map +1 -1
- package/dist/src/ui/components/StoreViewer.js +2 -1
- package/dist/src/ui/components/StoreViewer.js.map +1 -1
- package/dist/src/ui/components/TabbedConsole.d.ts +11 -0
- package/dist/src/ui/components/TabbedConsole.js +134 -44
- package/dist/src/ui/components/TabbedConsole.js.map +1 -1
- package/dist/src/ui/components/ToolSettingsView.d.ts +7 -0
- package/dist/src/ui/components/ToolSettingsView.js +25 -0
- package/dist/src/ui/components/ToolSettingsView.js.map +1 -0
- package/dist/src/ui/components/common/EyeIcon.js +2 -1
- package/dist/src/ui/components/common/EyeIcon.js.map +1 -1
- package/dist/src/ui/hooks/useKeyValuePairs.d.ts +52 -0
- package/dist/src/ui/hooks/useKeyValuePairs.js +66 -0
- package/dist/src/ui/hooks/useKeyValuePairs.js.map +1 -0
- package/dist/src/ui/index.js +4 -2
- package/dist/src/ui/index.js.map +1 -1
- package/dist/src/ui/store/formStateSlice.d.ts +71 -0
- package/dist/src/ui/store/formStateSlice.js +159 -0
- package/dist/src/ui/store/formStateSlice.js.map +1 -0
- package/dist/src/ui/store/hooks.d.ts +6 -0
- package/dist/src/ui/store/hooks.js +8 -0
- package/dist/src/ui/store/hooks.js.map +1 -0
- package/dist/src/ui/store/index.d.ts +11 -0
- package/dist/src/ui/store/index.js +107 -0
- package/dist/src/ui/store/index.js.map +1 -0
- package/dist/src/ui/types/common.d.ts +33 -0
- package/dist/src/ui/types/common.js +6 -0
- package/dist/src/ui/types/common.js.map +1 -0
- package/package.json +17 -9
- package/dist/public/bundle.0a495807b6ef336cb500.js +0 -3
- package/dist/public/bundle.0a495807b6ef336cb500.js.map +0 -1
- package/dist/src/executor/SourceExecutor.d.ts +0 -32
- package/dist/src/executor/SourceExecutor.js +0 -163
- package/dist/src/executor/SourceExecutor.js.map +0 -1
- package/dist/src/local_engine/storage/SourceJobExecutionStore.d.ts +0 -25
- package/dist/src/local_engine/storage/SourceJobExecutionStore.js +0 -61
- package/dist/src/local_engine/storage/SourceJobExecutionStore.js.map +0 -1
- package/dist/src/ui/components/SourceDataViewer.d.ts +0 -8
- package/dist/src/ui/components/SourceDataViewer.js +0 -84
- package/dist/src/ui/components/SourceDataViewer.js.map +0 -1
- package/dist/src/ui/components/SourceJobsSection.d.ts +0 -8
- package/dist/src/ui/components/SourceJobsSection.js +0 -99
- package/dist/src/ui/components/SourceJobsSection.js.map +0 -1
- package/dist/src/ui/components/SourceLifecycleSection.d.ts +0 -7
- package/dist/src/ui/components/SourceLifecycleSection.js +0 -58
- package/dist/src/ui/components/SourceLifecycleSection.js.map +0 -1
- package/dist/src/ui/components/SourceWebhookEditor.d.ts +0 -8
- package/dist/src/ui/components/SourceWebhookEditor.js +0 -168
- package/dist/src/ui/components/SourceWebhookEditor.js.map +0 -1
|
@@ -11,7 +11,13 @@ const JobsView_1 = __importDefault(require("./JobsView"));
|
|
|
11
11
|
const TabbedConsole_1 = __importDefault(require("./TabbedConsole"));
|
|
12
12
|
const DestinationsView_1 = require("./DestinationsView");
|
|
13
13
|
const SourcesView_1 = require("./SourcesView");
|
|
14
|
+
const OpalToolsView_1 = __importDefault(require("./OpalToolsView"));
|
|
15
|
+
const ToolSettingsView_1 = __importDefault(require("./ToolSettingsView"));
|
|
16
|
+
const OdpSchemaView_1 = __importDefault(require("./OdpSchemaView"));
|
|
14
17
|
const useQueryParams_1 = require("../hooks/useQueryParams");
|
|
18
|
+
const store_1 = require("../store");
|
|
19
|
+
const axiom_icons_1 = require("@optimizely/axiom-icons");
|
|
20
|
+
const DeployModal_1 = require("./DeployModal");
|
|
15
21
|
const IFRAME_RESIZER_MESSAGES_PREFIX = "[iFrameSizer]app_directory_frame_directory";
|
|
16
22
|
const IFRAME_RESIZER_READY_MESSAGE = `${IFRAME_RESIZER_MESSAGES_PREFIX}:8:false:false:32:true:true:null:bodyOffset:null:null:0:false:parent:scroll:true`;
|
|
17
23
|
// Ex.: [iFrameSizer]app_directory_frame_directory:7096:1955:mutationObserver
|
|
@@ -41,16 +47,39 @@ const App = () => {
|
|
|
41
47
|
const [buildStatus, setBuildStatus] = (0, react_1.useState)(null);
|
|
42
48
|
const [storeTimestamps, setStoreTimestamps] = (0, react_1.useState)(null);
|
|
43
49
|
const [appInstalled, setAppInstalled] = (0, react_1.useState)(false);
|
|
50
|
+
// Install version counter - increments on each install to force UI refresh
|
|
51
|
+
const [installVersion, setInstallVersion] = (0, react_1.useState)(0);
|
|
44
52
|
const [notificationCount, setNotificationCount] = (0, react_1.useState)(0);
|
|
45
53
|
const [config, setConfig] = (0, react_1.useState)({
|
|
46
54
|
showZaiusAdminSections: false
|
|
47
55
|
});
|
|
48
|
-
const [
|
|
56
|
+
const [permanentlyDisconnected, setPermanentlyDisconnected] = (0, react_1.useState)(false);
|
|
57
|
+
const [appChanged, setAppChanged] = (0, react_1.useState)(null);
|
|
58
|
+
const [sourceDataVersion, setSourceDataVersion] = (0, react_1.useState)(0);
|
|
59
|
+
const [sourceDataTotalEmitted, setSourceDataTotalEmitted] = (0, react_1.useState)(0);
|
|
60
|
+
const [notificationVersion, setNotificationVersion] = (0, react_1.useState)(0);
|
|
61
|
+
const [envVersion, setEnvVersion] = (0, react_1.useState)(0);
|
|
62
|
+
const [deployStatus, setDeployStatus] = (0, react_1.useState)({ deployInProgress: false, lastDeploySuccess: null });
|
|
63
|
+
const [deployLogs, setDeployLogs] = (0, react_1.useState)([]);
|
|
64
|
+
const [deployVersion, setDeployVersion] = (0, react_1.useState)(0);
|
|
65
|
+
const [showDeployModal, setShowDeployModal] = (0, react_1.useState)(false);
|
|
66
|
+
const [deployModalData, setDeployModalData] = (0, react_1.useState)(null);
|
|
67
|
+
// Reference to store disconnect timer for 30-second timeout
|
|
68
|
+
const disconnectTimerRef = (0, react_1.useRef)(null);
|
|
69
|
+
// Reference to store initial app info for change detection
|
|
70
|
+
const initialAppInfoRef = (0, react_1.useRef)(null);
|
|
71
|
+
// Initialize Redux store with app name when appInfo is available
|
|
72
|
+
(0, react_1.useEffect)(() => {
|
|
73
|
+
if (appInfo?.name) {
|
|
74
|
+
(0, store_1.initializeStore)(appInfo.name);
|
|
75
|
+
}
|
|
76
|
+
}, [appInfo?.name]);
|
|
49
77
|
// Reference to store polling interval IDs
|
|
50
78
|
const pollingIntervals = (0, react_1.useRef)({
|
|
51
|
-
logs: null,
|
|
52
79
|
status: null,
|
|
53
80
|
});
|
|
81
|
+
// Reference to store EventSource for cleanup on page unload
|
|
82
|
+
const eventSourceRef = (0, react_1.useRef)(null);
|
|
54
83
|
// Reference to the settings iframe
|
|
55
84
|
const settingsIframeRef = (0, react_1.useRef)(null);
|
|
56
85
|
const setIframeRef = (iframe) => {
|
|
@@ -76,7 +105,38 @@ const App = () => {
|
|
|
76
105
|
}
|
|
77
106
|
}
|
|
78
107
|
})}`;
|
|
79
|
-
settingsIframeRef.current.contentWindow.postMessage(userFeaturesMessage,
|
|
108
|
+
settingsIframeRef.current.contentWindow.postMessage(userFeaturesMessage, window.location.origin);
|
|
109
|
+
// Send prismContext with mock organization ID to prevent "Organization ID is missing" errors
|
|
110
|
+
const prismContextMessage = `[iFrameSizer]message:${JSON.stringify({
|
|
111
|
+
method: 'prismContext',
|
|
112
|
+
params: {
|
|
113
|
+
productName: 'local-dev',
|
|
114
|
+
subProductName: 'ocp-local-env',
|
|
115
|
+
trackerId: 'local-development-tracker-id',
|
|
116
|
+
scope: 1,
|
|
117
|
+
originalUser: {
|
|
118
|
+
id: 1,
|
|
119
|
+
email: 'local-dev@example.com',
|
|
120
|
+
name: 'Local Developer',
|
|
121
|
+
isOptiId: false,
|
|
122
|
+
isInternalUser: true,
|
|
123
|
+
optiIdAccessToken: 'local-dev-mock-token'
|
|
124
|
+
},
|
|
125
|
+
organization: {
|
|
126
|
+
id: 1,
|
|
127
|
+
name: 'Local Development Org',
|
|
128
|
+
masterCustomerId: 'local-master-customer',
|
|
129
|
+
turnstileOrganizationId: 'local-test-org'
|
|
130
|
+
},
|
|
131
|
+
account: {
|
|
132
|
+
id: 1,
|
|
133
|
+
name: 'Local Development Account',
|
|
134
|
+
instanceId: 'local-test-instance',
|
|
135
|
+
isOptiHub: false
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
})}`;
|
|
139
|
+
settingsIframeRef.current.contentWindow.postMessage(prismContextMessage, window.location.origin);
|
|
80
140
|
console.log("Sent ready event to iframe after 2 second delay");
|
|
81
141
|
}
|
|
82
142
|
}, 2000);
|
|
@@ -101,15 +161,19 @@ const App = () => {
|
|
|
101
161
|
};
|
|
102
162
|
// Set up polling on component mount
|
|
103
163
|
(0, react_1.useEffect)(() => {
|
|
104
|
-
//
|
|
164
|
+
// Don't set up new connections if permanently disconnected
|
|
165
|
+
if (permanentlyDisconnected) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
// Initial data load (logs come via SSE initialLogs event)
|
|
105
169
|
fetchConfig();
|
|
106
170
|
fetchAppInfo();
|
|
107
171
|
fetchStatus();
|
|
108
|
-
fetchConsoleLogs();
|
|
109
172
|
fetchInstallationStatus();
|
|
110
173
|
fetchNotificationCount();
|
|
111
174
|
// Set up SSE connection for real-time build status updates
|
|
112
175
|
const eventSource = new EventSource('/devserver/api/events');
|
|
176
|
+
eventSourceRef.current = eventSource;
|
|
113
177
|
eventSource.onmessage = (event) => {
|
|
114
178
|
const data = JSON.parse(event.data);
|
|
115
179
|
switch (data.type) {
|
|
@@ -123,6 +187,10 @@ const App = () => {
|
|
|
123
187
|
lastBuildTimestamp: null,
|
|
124
188
|
lastBuildError: null
|
|
125
189
|
});
|
|
190
|
+
// Reset deploy success status on code change (build start)
|
|
191
|
+
if (!deployStatus.deployInProgress) {
|
|
192
|
+
setDeployStatus(prev => ({ ...prev, lastDeploySuccess: null }));
|
|
193
|
+
}
|
|
126
194
|
break;
|
|
127
195
|
case 'buildSuccess':
|
|
128
196
|
setBuildStatus({
|
|
@@ -131,8 +199,7 @@ const App = () => {
|
|
|
131
199
|
lastBuildTimestamp: data.timestamp,
|
|
132
200
|
lastBuildError: null
|
|
133
201
|
});
|
|
134
|
-
// Refresh
|
|
135
|
-
fetchConsoleLogs();
|
|
202
|
+
// Refresh store timestamps after build (logs come via SSE)
|
|
136
203
|
fetchStatus();
|
|
137
204
|
break;
|
|
138
205
|
case 'buildError':
|
|
@@ -142,7 +209,6 @@ const App = () => {
|
|
|
142
209
|
lastBuildTimestamp: data.timestamp,
|
|
143
210
|
lastBuildError: data.error
|
|
144
211
|
});
|
|
145
|
-
fetchConsoleLogs();
|
|
146
212
|
break;
|
|
147
213
|
case 'status':
|
|
148
214
|
// Initial status on connection
|
|
@@ -153,10 +219,112 @@ const App = () => {
|
|
|
153
219
|
lastBuildError: data.lastBuildError
|
|
154
220
|
});
|
|
155
221
|
break;
|
|
222
|
+
case 'log':
|
|
223
|
+
// Append new log, keep last 500
|
|
224
|
+
setLogs(prev => [...prev.slice(-499), data.entry]);
|
|
225
|
+
break;
|
|
226
|
+
case 'initialLogs':
|
|
227
|
+
setLogs(data.logs || []);
|
|
228
|
+
// Handle app change detection (only compare app names, not paths)
|
|
229
|
+
if (data.app && data.app.name) {
|
|
230
|
+
if (!initialAppInfoRef.current) {
|
|
231
|
+
initialAppInfoRef.current = { name: data.app.name, path: data.app.path };
|
|
232
|
+
}
|
|
233
|
+
else if (initialAppInfoRef.current.name !== data.app.name) {
|
|
234
|
+
setAppChanged({ oldApp: initialAppInfoRef.current.name, newApp: data.app.name });
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
break;
|
|
238
|
+
case 'logsCleared':
|
|
239
|
+
setLogs([]);
|
|
240
|
+
break;
|
|
241
|
+
case 'serverShutdown':
|
|
242
|
+
// Server is shutting down - immediately show disconnect overlay
|
|
243
|
+
eventSource.close();
|
|
244
|
+
eventSourceRef.current = null;
|
|
245
|
+
setPermanentlyDisconnected(true);
|
|
246
|
+
// Update tab title to indicate disconnection
|
|
247
|
+
document.title = '[DISCONNECTED] ' + document.title;
|
|
248
|
+
break;
|
|
249
|
+
case 'connectionEvicted':
|
|
250
|
+
// Connection evicted due to limit - show disconnect overlay
|
|
251
|
+
eventSource.close();
|
|
252
|
+
eventSourceRef.current = null;
|
|
253
|
+
setPermanentlyDisconnected(true);
|
|
254
|
+
// Update tab title to indicate disconnection
|
|
255
|
+
document.title = '[DISCONNECTED] ' + document.title;
|
|
256
|
+
break;
|
|
257
|
+
case 'sourceDataChanged':
|
|
258
|
+
// Source data was emitted — increment version to trigger re-fetch in panel
|
|
259
|
+
setSourceDataVersion(v => v + 1);
|
|
260
|
+
setSourceDataTotalEmitted(data.totalEmitted ?? 0);
|
|
261
|
+
break;
|
|
262
|
+
case 'notificationChanged':
|
|
263
|
+
// Notification was created — increment version to trigger re-fetch in panel
|
|
264
|
+
setNotificationVersion(v => v + 1);
|
|
265
|
+
fetchNotificationCount();
|
|
266
|
+
break;
|
|
267
|
+
case 'envChanged':
|
|
268
|
+
setEnvVersion(v => v + 1);
|
|
269
|
+
break;
|
|
270
|
+
case 'installSuccess':
|
|
271
|
+
// App was installed via API - update state and increment version
|
|
272
|
+
console.log('SSE: App installed via API');
|
|
273
|
+
setAppInstalled(true);
|
|
274
|
+
setInstallVersion(v => v + 1); // Increment to force UI refresh
|
|
275
|
+
setConnected(true);
|
|
276
|
+
break;
|
|
277
|
+
case 'uninstallSuccess':
|
|
278
|
+
// App was uninstalled via API - update state
|
|
279
|
+
console.log('SSE: App uninstalled via API');
|
|
280
|
+
setAppInstalled(false);
|
|
281
|
+
setConnected(false);
|
|
282
|
+
break;
|
|
283
|
+
case 'deployStart':
|
|
284
|
+
setDeployStatus({ deployInProgress: true, lastDeploySuccess: null });
|
|
285
|
+
// Add a separator between deploy runs instead of clearing logs
|
|
286
|
+
setDeployLogs(prev => prev.length > 0
|
|
287
|
+
? [...prev, '───────────────────────────────────────']
|
|
288
|
+
: prev);
|
|
289
|
+
setDeployVersion(v => v + 1);
|
|
290
|
+
break;
|
|
291
|
+
case 'deployLog':
|
|
292
|
+
setDeployLogs(prev => [...prev, data.line]);
|
|
293
|
+
setDeployVersion(v => v + 1);
|
|
294
|
+
break;
|
|
295
|
+
case 'deploySuccess':
|
|
296
|
+
setDeployStatus({ deployInProgress: false, lastDeploySuccess: true });
|
|
297
|
+
setDeployVersion(v => v + 1);
|
|
298
|
+
// Refresh app info to update version display in nav
|
|
299
|
+
fetchAppInfo();
|
|
300
|
+
break;
|
|
301
|
+
case 'deployError':
|
|
302
|
+
setDeployStatus({ deployInProgress: false, lastDeploySuccess: false });
|
|
303
|
+
if (data.error) {
|
|
304
|
+
setDeployLogs(prev => [...prev, `Error: ${data.error}`]);
|
|
305
|
+
}
|
|
306
|
+
setDeployVersion(v => v + 1);
|
|
307
|
+
break;
|
|
308
|
+
case 'deployStatus':
|
|
309
|
+
// Initial deploy status on connection
|
|
310
|
+
setDeployStatus({
|
|
311
|
+
deployInProgress: data.deployInProgress || false,
|
|
312
|
+
lastDeploySuccess: data.lastDeploySuccess ?? null
|
|
313
|
+
});
|
|
314
|
+
break;
|
|
156
315
|
}
|
|
157
316
|
};
|
|
158
317
|
eventSource.onerror = () => {
|
|
159
318
|
setConnected(false);
|
|
319
|
+
// Start 30-second timer if not already started
|
|
320
|
+
if (!disconnectTimerRef.current && !permanentlyDisconnected) {
|
|
321
|
+
disconnectTimerRef.current = setTimeout(() => {
|
|
322
|
+
// Permanently disconnect - close EventSource and show message
|
|
323
|
+
eventSource.close();
|
|
324
|
+
eventSourceRef.current = null;
|
|
325
|
+
setPermanentlyDisconnected(true);
|
|
326
|
+
}, 30000);
|
|
327
|
+
}
|
|
160
328
|
// Fallback to polling if SSE fails
|
|
161
329
|
if (!pollingIntervals.current.status) {
|
|
162
330
|
pollingIntervals.current.status = setInterval(fetchStatus, 3000);
|
|
@@ -164,25 +332,43 @@ const App = () => {
|
|
|
164
332
|
};
|
|
165
333
|
eventSource.onopen = () => {
|
|
166
334
|
setConnected(true);
|
|
335
|
+
// Clear disconnect timer if we reconnected in time
|
|
336
|
+
if (disconnectTimerRef.current) {
|
|
337
|
+
clearTimeout(disconnectTimerRef.current);
|
|
338
|
+
disconnectTimerRef.current = null;
|
|
339
|
+
}
|
|
340
|
+
// Check if app has changed (server restarted with different app)
|
|
341
|
+
// Only check if we had a previous app loaded
|
|
342
|
+
if (initialAppInfoRef.current) {
|
|
343
|
+
fetchAppInfo(true);
|
|
344
|
+
}
|
|
167
345
|
// Stop fallback polling if it was started
|
|
168
346
|
if (pollingIntervals.current.status) {
|
|
169
347
|
clearInterval(pollingIntervals.current.status);
|
|
170
348
|
pollingIntervals.current.status = null;
|
|
171
349
|
}
|
|
172
350
|
};
|
|
173
|
-
//
|
|
174
|
-
|
|
351
|
+
// Close SSE on page unload/refresh to prevent connection accumulation
|
|
352
|
+
// This is critical for Firefox which has a strict 6-connection limit per domain
|
|
353
|
+
const handleBeforeUnload = () => {
|
|
354
|
+
if (eventSourceRef.current) {
|
|
355
|
+
eventSourceRef.current.close();
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
window.addEventListener('beforeunload', handleBeforeUnload);
|
|
175
359
|
// Cleanup
|
|
176
360
|
return () => {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
clearInterval(pollingIntervals.current.logs);
|
|
361
|
+
if (disconnectTimerRef.current) {
|
|
362
|
+
clearTimeout(disconnectTimerRef.current);
|
|
180
363
|
}
|
|
364
|
+
eventSource.close();
|
|
365
|
+
eventSourceRef.current = null;
|
|
366
|
+
window.removeEventListener('beforeunload', handleBeforeUnload);
|
|
181
367
|
if (pollingIntervals.current.status) {
|
|
182
368
|
clearInterval(pollingIntervals.current.status);
|
|
183
369
|
}
|
|
184
370
|
};
|
|
185
|
-
}, []);
|
|
371
|
+
}, [permanentlyDisconnected]);
|
|
186
372
|
// Listen for events from the iframe
|
|
187
373
|
(0, react_1.useEffect)(() => {
|
|
188
374
|
const deserializeResizerMessage = (data) => {
|
|
@@ -216,11 +402,11 @@ const App = () => {
|
|
|
216
402
|
const message = deserializeResizerMessage(event.data);
|
|
217
403
|
// Handle getTracker message
|
|
218
404
|
if (message.method === "getTracker") {
|
|
219
|
-
const
|
|
405
|
+
const response = serializeResizerMessage({
|
|
220
406
|
method: "setTracker",
|
|
221
407
|
params: "local-development-tracker-id",
|
|
222
408
|
});
|
|
223
|
-
settingsIframeRef.current?.contentWindow?.postMessage(
|
|
409
|
+
settingsIframeRef.current?.contentWindow?.postMessage(response, event.origin);
|
|
224
410
|
console.log("getTracker sent");
|
|
225
411
|
}
|
|
226
412
|
// Handle installation lifecycle events
|
|
@@ -231,6 +417,7 @@ const App = () => {
|
|
|
231
417
|
case "install_success":
|
|
232
418
|
console.log("Installation successful, updating app state");
|
|
233
419
|
setAppInstalled(true);
|
|
420
|
+
setInstallVersion(v => v + 1); // Increment to force UI refresh
|
|
234
421
|
setConnected(true);
|
|
235
422
|
break;
|
|
236
423
|
case "uninstall_success":
|
|
@@ -262,11 +449,25 @@ const App = () => {
|
|
|
262
449
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
263
450
|
}, []);
|
|
264
451
|
// Fetch app info from the API
|
|
265
|
-
const fetchAppInfo = async () => {
|
|
452
|
+
const fetchAppInfo = async (checkForChanges = false) => {
|
|
266
453
|
try {
|
|
267
454
|
const response = await fetch("/devserver/api/app");
|
|
268
455
|
if (response.ok) {
|
|
269
456
|
const data = await response.json();
|
|
457
|
+
// Store initial app info on first successful fetch
|
|
458
|
+
if (!initialAppInfoRef.current && data.name) {
|
|
459
|
+
initialAppInfoRef.current = { name: data.name, path: data.path };
|
|
460
|
+
}
|
|
461
|
+
// Check if app has changed (different app being served) - only compare names
|
|
462
|
+
if (checkForChanges && initialAppInfoRef.current && data.name) {
|
|
463
|
+
if (initialAppInfoRef.current.name !== data.name) {
|
|
464
|
+
setAppChanged({
|
|
465
|
+
oldApp: initialAppInfoRef.current.name,
|
|
466
|
+
newApp: data.name
|
|
467
|
+
});
|
|
468
|
+
return; // Don't update appInfo - show the change notification instead
|
|
469
|
+
}
|
|
470
|
+
}
|
|
270
471
|
setAppInfo(data);
|
|
271
472
|
setConnected(true);
|
|
272
473
|
}
|
|
@@ -300,34 +501,11 @@ const App = () => {
|
|
|
300
501
|
setConnected(false);
|
|
301
502
|
}
|
|
302
503
|
};
|
|
303
|
-
// Fetch console logs from the API
|
|
304
|
-
const fetchConsoleLogs = async () => {
|
|
305
|
-
try {
|
|
306
|
-
const response = await fetch("/devserver/api/console/logs?limit=50");
|
|
307
|
-
if (response.ok) {
|
|
308
|
-
const data = await response.json();
|
|
309
|
-
if (data.logs && data.logs.length > 0) {
|
|
310
|
-
setLogs(data.logs); // Pass raw LogEntry[] directly
|
|
311
|
-
}
|
|
312
|
-
else {
|
|
313
|
-
setLogs([]);
|
|
314
|
-
}
|
|
315
|
-
setConnected(true);
|
|
316
|
-
}
|
|
317
|
-
else {
|
|
318
|
-
setConnected(false);
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
catch (error) {
|
|
322
|
-
console.error("Error fetching console logs:", error);
|
|
323
|
-
setConnected(false);
|
|
324
|
-
}
|
|
325
|
-
};
|
|
326
504
|
// Clear console logs
|
|
327
505
|
const clearConsoleLogs = async () => {
|
|
328
506
|
try {
|
|
329
507
|
await fetch("/devserver/api/console/logs", { method: "DELETE" });
|
|
330
|
-
|
|
508
|
+
// SSE logsCleared event will update the UI
|
|
331
509
|
}
|
|
332
510
|
catch (error) {
|
|
333
511
|
console.error("Error clearing logs:", error);
|
|
@@ -385,9 +563,8 @@ const App = () => {
|
|
|
385
563
|
},
|
|
386
564
|
});
|
|
387
565
|
if (response.ok) {
|
|
388
|
-
// Immediately fetch new status
|
|
566
|
+
// Immediately fetch new status (logs come via SSE)
|
|
389
567
|
fetchStatus();
|
|
390
|
-
fetchConsoleLogs();
|
|
391
568
|
}
|
|
392
569
|
else {
|
|
393
570
|
console.error("Failed to trigger build");
|
|
@@ -397,16 +574,100 @@ const App = () => {
|
|
|
397
574
|
console.error("Error triggering build:", error);
|
|
398
575
|
}
|
|
399
576
|
};
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
577
|
+
// Compute deploy button CSS modifier class based on current deploy status
|
|
578
|
+
const getDeployStatusClass = () => {
|
|
579
|
+
if (deployStatus.deployInProgress)
|
|
580
|
+
return 'deploying';
|
|
581
|
+
if (deployStatus.lastDeploySuccess === true)
|
|
582
|
+
return 'deploy-success';
|
|
583
|
+
if (deployStatus.lastDeploySuccess === false)
|
|
584
|
+
return 'deploy-error';
|
|
585
|
+
return '';
|
|
586
|
+
};
|
|
587
|
+
// Append a deploy log message and increment the version counter
|
|
588
|
+
const appendDeployLog = (message) => {
|
|
589
|
+
setDeployLogs(prev => [...prev, message]);
|
|
590
|
+
setDeployVersion(v => v + 1);
|
|
591
|
+
};
|
|
592
|
+
// Trigger a deploy
|
|
593
|
+
const triggerDeploy = async () => {
|
|
594
|
+
try {
|
|
595
|
+
// First, resolve the version from Rivendell
|
|
596
|
+
const resolveResponse = await fetch("/devserver/api/deploy/resolve-version", {
|
|
597
|
+
method: "POST",
|
|
598
|
+
headers: { "Content-Type": "application/json" },
|
|
599
|
+
});
|
|
600
|
+
if (!resolveResponse.ok) {
|
|
601
|
+
const errorData = await resolveResponse.json().catch(() => ({}));
|
|
602
|
+
appendDeployLog(`Error resolving version: ${errorData.error || 'Unknown error'}`);
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
605
|
+
const versionData = await resolveResponse.json();
|
|
606
|
+
if (versionData.searchError) {
|
|
607
|
+
appendDeployLog(`Warning: Rivendell search failed (${versionData.searchError}), bumping version locally`);
|
|
608
|
+
}
|
|
609
|
+
if (versionData.isDevVersion && (0, DeployModal_1.shouldSkipDevConfirmation)()) {
|
|
610
|
+
// Dev version with "do not show again" enabled: deploy immediately
|
|
611
|
+
startDeploy(versionData.suggestedVersion);
|
|
612
|
+
}
|
|
613
|
+
else {
|
|
614
|
+
// Show confirmation modal
|
|
615
|
+
setDeployModalData({
|
|
616
|
+
currentVersion: versionData.currentVersion,
|
|
617
|
+
suggestedVersion: versionData.suggestedVersion,
|
|
618
|
+
isDevVersion: versionData.isDevVersion
|
|
619
|
+
});
|
|
620
|
+
setShowDeployModal(true);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
catch (error) {
|
|
624
|
+
console.error("Error triggering deploy:", error);
|
|
625
|
+
appendDeployLog(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
626
|
+
}
|
|
627
|
+
};
|
|
628
|
+
// Start the deploy with a specific version
|
|
629
|
+
const startDeploy = async (version) => {
|
|
630
|
+
setShowDeployModal(false);
|
|
631
|
+
try {
|
|
632
|
+
const response = await fetch("/devserver/api/deploy/start", {
|
|
633
|
+
method: "POST",
|
|
634
|
+
headers: { "Content-Type": "application/json" },
|
|
635
|
+
body: JSON.stringify({ version }),
|
|
636
|
+
});
|
|
637
|
+
if (!response.ok) {
|
|
638
|
+
const errorData = await response.json().catch(() => ({}));
|
|
639
|
+
appendDeployLog(`Error starting deploy: ${errorData.error || 'Unknown error'}`);
|
|
640
|
+
}
|
|
641
|
+
// Success: SSE events will handle state updates
|
|
642
|
+
}
|
|
643
|
+
catch (error) {
|
|
644
|
+
console.error("Error starting deploy:", error);
|
|
645
|
+
appendDeployLog(`Error: ${error instanceof Error ? error.message : String(error)}`);
|
|
646
|
+
}
|
|
647
|
+
};
|
|
648
|
+
return ((0, jsx_runtime_1.jsxs)("div", { className: "app postman-layout", children: [(0, jsx_runtime_1.jsxs)("header", { className: "top-nav", children: [(0, jsx_runtime_1.jsx)("div", { className: "nav-left", children: (0, jsx_runtime_1.jsx)("div", { className: "app-title", children: (0, jsx_runtime_1.jsx)("h1", { children: "OCP Local Environment" }) }) }), appInfo && ((0, jsx_runtime_1.jsx)("div", { className: "nav-center", children: (0, jsx_runtime_1.jsxs)("div", { className: "app-info-nav", children: [(0, jsx_runtime_1.jsx)("span", { className: "app-name", children: appInfo.displayName || appInfo.name }), (0, jsx_runtime_1.jsxs)("span", { className: "app-version", children: ["v", appInfo.version] })] }) })), (0, jsx_runtime_1.jsxs)("div", { className: "nav-right", children: [(0, jsx_runtime_1.jsxs)("button", { className: `deploy-btn ${getDeployStatusClass()}`, onClick: triggerDeploy, disabled: deployStatus.deployInProgress || !!buildStatus?.buildInProgress, title: "Deploy app version to OCP", children: [(0, jsx_runtime_1.jsx)("span", { className: "deploy-status-dot" }), deployStatus.deployInProgress ? "Deploying..." :
|
|
649
|
+
deployStatus.lastDeploySuccess === true ? "Deployed" : "Deploy"] }), (0, jsx_runtime_1.jsxs)("button", { className: `rebuild-btn ${buildStatus?.buildInProgress ? 'building' :
|
|
650
|
+
buildStatus?.lastBuildSuccess === true ? 'success' :
|
|
651
|
+
buildStatus?.lastBuildSuccess === false ? 'error' : ''}`, onClick: triggerBuild, disabled: buildStatus?.buildInProgress, children: [(0, jsx_runtime_1.jsx)("span", { className: "rebuild-status-dot" }), buildStatus?.buildInProgress ? "Building..." : "Rebuild"] }), config.hasSchemaFiles && ((0, jsx_runtime_1.jsxs)("div", { className: "odp-status-badge", children: [(0, jsx_runtime_1.jsx)("span", { className: `odp-status-dot ${config.odpKeyConfigured ? 'configured' : 'not-configured'}` }), "ODP/OCP", (0, jsx_runtime_1.jsx)("span", { className: "odp-tooltip", children: config.odpKeyConfigured
|
|
652
|
+
? 'ODP API Key is configured'
|
|
653
|
+
: 'ODP API Key is not configured — set it in Tool Settings' })] })), (0, jsx_runtime_1.jsx)("div", { className: "nav-separator-vertical" }), (0, jsx_runtime_1.jsxs)("a", { href: "https://github.com/optimizely/ocp-developer-feedback/issues/new/choose", target: "_blank", rel: "noopener noreferrer", className: "feedback-btn", title: "Provide Feedback", children: [(0, jsx_runtime_1.jsx)(axiom_icons_1.IconPenField, { size: "14" }), "Feedback"] }), (0, jsx_runtime_1.jsxs)("a", { href: "https://docs.developers.optimizely.com/optimizely-connect-platform/docs/local-testing", target: "_blank", rel: "noopener noreferrer", className: "docs-btn", title: "Documentation", children: [(0, jsx_runtime_1.jsx)(axiom_icons_1.IconBookOpen, { size: "14" }), " Docs"] })] })] }), (0, jsx_runtime_1.jsxs)("div", { className: "main-layout", children: [(0, jsx_runtime_1.jsx)("aside", { className: "sidebar", children: (0, jsx_runtime_1.jsxs)("nav", { className: "sidebar-nav", children: [(0, jsx_runtime_1.jsxs)("button", { className: `nav-item ${activeView === "settings" ? "active" : ""}`, onClick: () => navigatePreservingConsole('/settings'), children: [(0, jsx_runtime_1.jsx)(axiom_icons_1.IconGear, { size: "2xs" }), (0, jsx_runtime_1.jsx)("span", { className: "nav-label", children: "App Settings" })] }), appInfo && appInfo.functions && appInfo.functions.length > 0 && ((0, jsx_runtime_1.jsxs)("button", { className: `nav-item ${activeView === "functions" ? "active" : ""}`, onClick: () => navigatePreservingConsole('/functions'), children: [(0, jsx_runtime_1.jsx)(axiom_icons_1.IconBolt, { size: "2xs" }), (0, jsx_runtime_1.jsx)("span", { className: "nav-label", children: "Functions" })] })), appInfo && appInfo.jobs && appInfo.jobs.length > 0 && ((0, jsx_runtime_1.jsxs)("button", { className: `nav-item ${activeView === "jobs" ? "active" : ""}`, onClick: () => navigatePreservingConsole('/jobs'), children: [(0, jsx_runtime_1.jsx)(axiom_icons_1.IconCubes, { size: "2xs" }), (0, jsx_runtime_1.jsx)("span", { className: "nav-label", children: "Jobs" })] })), appInfo && appInfo.destinations && appInfo.destinations.length > 0 && ((0, jsx_runtime_1.jsxs)("button", { className: `nav-item ${activeView === "destinations" ? "active" : ""}`, onClick: () => navigatePreservingConsole('/destinations'), children: [(0, jsx_runtime_1.jsx)(axiom_icons_1.IconUpload, { size: "2xs" }), (0, jsx_runtime_1.jsx)("span", { className: "nav-label", children: "Destinations" })] })), appInfo && appInfo.sources && appInfo.sources.length > 0 && ((0, jsx_runtime_1.jsxs)("button", { className: `nav-item ${activeView === "sources" ? "active" : ""}`, onClick: () => navigatePreservingConsole('/sources'), children: [(0, jsx_runtime_1.jsx)(axiom_icons_1.IconDownload, { size: "2xs" }), (0, jsx_runtime_1.jsx)("span", { className: "nav-label", children: "Sources" })] })), appInfo && appInfo.opalTools && appInfo.opalTools.length > 0 && ((0, jsx_runtime_1.jsxs)("button", { className: `nav-item ${activeView === "opal-tools" ? "active" : ""}`, onClick: () => navigatePreservingConsole('/opal-tools'), children: [(0, jsx_runtime_1.jsx)(axiom_icons_1.IconScrewdriverWrench, { size: "2xs" }), (0, jsx_runtime_1.jsx)("span", { className: "nav-label", children: "Opal Tools" })] })), config.hasSchemaFiles && ((0, jsx_runtime_1.jsxs)("button", { className: `nav-item ${activeView === "odp-schema" ? "active" : ""}`, onClick: () => navigatePreservingConsole('/odp-schema'), children: [(0, jsx_runtime_1.jsx)(axiom_icons_1.IconMemoPad, { size: "2xs" }), (0, jsx_runtime_1.jsx)("span", { className: "nav-label", children: "ODP Schema" })] })), (0, jsx_runtime_1.jsx)("div", { className: "nav-separator", style: { height: '1px', background: '#3e3e42', margin: '4px 0' } }), (0, jsx_runtime_1.jsxs)("button", { className: `nav-item ${activeView === "tool-settings" ? "active" : ""}`, onClick: () => navigatePreservingConsole('/tool-settings'), children: [(0, jsx_runtime_1.jsx)(axiom_icons_1.IconGear, { size: "2xs" }), (0, jsx_runtime_1.jsx)("span", { className: "nav-label", children: "Tool Settings" })] })] }) }), (0, jsx_runtime_1.jsxs)("main", { className: "content-area", children: [activeView !== "jobs" && activeView !== "functions" && activeView !== "opal-tools" && activeView !== "destinations" && activeView !== "tool-settings" && activeView !== "odp-schema" && ((0, jsx_runtime_1.jsxs)("div", { className: "content-header", children: [(0, jsx_runtime_1.jsxs)("h2", { children: [activeView === "settings" && "App Settings", activeView === "sources" && "Sources"] }), appInfo && !appInfo.isValid && ((0, jsx_runtime_1.jsxs)("div", { className: "validation-errors-banner", children: [(0, jsx_runtime_1.jsx)("span", { className: "error-icon", children: "\u26A0\uFE0F" }), (0, jsx_runtime_1.jsx)("span", { children: "App has validation errors" })] }))] })), (0, jsx_runtime_1.jsx)("div", { className: "content-body", children: (0, jsx_runtime_1.jsxs)(react_router_dom_1.Routes, { children: [(0, jsx_runtime_1.jsx)(react_router_dom_1.Route, { path: "/", element: (0, jsx_runtime_1.jsx)(react_router_dom_1.Navigate, { to: "/settings", replace: true }) }), (0, jsx_runtime_1.jsx)(react_router_dom_1.Route, { path: "/settings", element: (0, jsx_runtime_1.jsxs)("div", { className: "settings-view", children: [appInfo && !appInfo.isValid && appInfo.errors && appInfo.errors.length > 0 && ((0, jsx_runtime_1.jsxs)("div", { className: "validation-errors", children: [(0, jsx_runtime_1.jsx)("h4", { children: "Validation Errors:" }), (0, jsx_runtime_1.jsx)("ul", { children: appInfo.errors.map((err, idx) => ((0, jsx_runtime_1.jsx)("li", { children: err }, idx))) })] })), buildStatus?.buildInProgress || (buildStatus?.lastBuildSuccess === null && buildStatus?.lastBuildTimestamp === null) ? ((0, jsx_runtime_1.jsx)("div", { className: "settings-loading-container", children: (0, jsx_runtime_1.jsxs)("div", { className: "placeholder-content", children: [(0, jsx_runtime_1.jsx)("h3", { children: "Building App..." }), (0, jsx_runtime_1.jsx)("p", { children: "Please wait while the app is being built." }), (0, jsx_runtime_1.jsx)("div", { className: "spinner" })] }) })) : buildStatus?.lastBuildSuccess === false ? ((0, jsx_runtime_1.jsx)("div", { className: "settings-loading-container", children: (0, jsx_runtime_1.jsxs)("div", { className: "placeholder-content", children: [(0, jsx_runtime_1.jsx)("h3", { children: "Build Failed" }), (0, jsx_runtime_1.jsx)("p", { children: "The app failed to build. Please check the console for errors." }), buildStatus.lastBuildError && ((0, jsx_runtime_1.jsx)("pre", { className: "error-details", children: buildStatus.lastBuildError }))] }) })) : ((0, jsx_runtime_1.jsx)("div", { className: "settings-iframe-container", children: (0, jsx_runtime_1.jsx)("iframe", { id: "app_directory_frame", style: {
|
|
405
654
|
width: "100%",
|
|
406
655
|
height: "100%",
|
|
407
656
|
border: "none",
|
|
408
657
|
overflow: "hidden",
|
|
409
|
-
}, ref: setIframeRef, src: `${window.location.origin}/app/${appInfo?.name || "unknown"}`, onLoad: handleIframeLoad }) }))] }) }), (0, jsx_runtime_1.jsx)(react_router_dom_1.Route, { path: "/functions/*", element: (0, jsx_runtime_1.jsx)(FunctionsView_1.default, { appInstalled: appInstalled, buildStatus: buildStatus }) }), (0, jsx_runtime_1.jsx)(react_router_dom_1.Route, { path: "/jobs/*", element: (0, jsx_runtime_1.jsx)(JobsView_1.default, { appInstalled: appInstalled, buildStatus: buildStatus }) }), (0, jsx_runtime_1.jsx)(react_router_dom_1.Route, { path: "/destinations/*", element: !appInfo ? ((0, jsx_runtime_1.jsx)("div", { className: "destinations-view", children: (0, jsx_runtime_1.jsx)("div", { className: "placeholder-content", children: (0, jsx_runtime_1.jsx)("p", { children: "Loading..." }) }) })) : appInfo.destinations && appInfo.destinations.length > 0 ? ((0, jsx_runtime_1.jsx)(DestinationsView_1.DestinationsView, { apiBaseUrl: "/devserver/api", appInstalled: appInstalled, buildStatus: buildStatus })) : ((0, jsx_runtime_1.jsx)(react_router_dom_1.Navigate, { to: "/settings", replace: true })) }), (0, jsx_runtime_1.jsx)(react_router_dom_1.Route, { path: "/sources/*", element: !appInfo ? ((0, jsx_runtime_1.jsx)("div", { className: "sources-view", children: (0, jsx_runtime_1.jsx)("div", { className: "placeholder-content", children: (0, jsx_runtime_1.jsx)("p", { children: "Loading..." }) }) })) : appInfo.sources && appInfo.sources.length > 0 ? ((0, jsx_runtime_1.jsx)(SourcesView_1.SourcesView, { apiBaseUrl: "/devserver/api", appInstalled: appInstalled, buildStatus: buildStatus })) : ((0, jsx_runtime_1.jsx)(react_router_dom_1.Navigate, { to: "/settings", replace: true })) }), (0, jsx_runtime_1.jsx)(react_router_dom_1.Route, { path: "
|
|
658
|
+
}, ref: setIframeRef, src: `${window.location.origin}/app/${appInfo?.name || "unknown"}`, onLoad: handleIframeLoad }) }))] }) }), (0, jsx_runtime_1.jsx)(react_router_dom_1.Route, { path: "/functions/*", element: !appInfo ? ((0, jsx_runtime_1.jsx)("div", { className: "functions-view", children: (0, jsx_runtime_1.jsx)("div", { className: "placeholder-content", children: (0, jsx_runtime_1.jsx)("p", { children: "Loading..." }) }) })) : appInfo.functions && appInfo.functions.length > 0 ? ((0, jsx_runtime_1.jsx)(FunctionsView_1.default, { appInstalled: appInstalled, buildStatus: buildStatus, installVersion: installVersion })) : ((0, jsx_runtime_1.jsx)(react_router_dom_1.Navigate, { to: "/settings", replace: true })) }), (0, jsx_runtime_1.jsx)(react_router_dom_1.Route, { path: "/jobs/*", element: !appInfo ? ((0, jsx_runtime_1.jsx)("div", { className: "jobs-view", children: (0, jsx_runtime_1.jsx)("div", { className: "placeholder-content", children: (0, jsx_runtime_1.jsx)("p", { children: "Loading..." }) }) })) : appInfo.jobs && appInfo.jobs.length > 0 ? ((0, jsx_runtime_1.jsx)(JobsView_1.default, { appInstalled: appInstalled, buildStatus: buildStatus })) : ((0, jsx_runtime_1.jsx)(react_router_dom_1.Navigate, { to: "/settings", replace: true })) }), (0, jsx_runtime_1.jsx)(react_router_dom_1.Route, { path: "/destinations/*", element: !appInfo ? ((0, jsx_runtime_1.jsx)("div", { className: "destinations-view", children: (0, jsx_runtime_1.jsx)("div", { className: "placeholder-content", children: (0, jsx_runtime_1.jsx)("p", { children: "Loading..." }) }) })) : appInfo.destinations && appInfo.destinations.length > 0 ? ((0, jsx_runtime_1.jsx)(DestinationsView_1.DestinationsView, { apiBaseUrl: "/devserver/api", appInstalled: appInstalled, buildStatus: buildStatus })) : ((0, jsx_runtime_1.jsx)(react_router_dom_1.Navigate, { to: "/settings", replace: true })) }), (0, jsx_runtime_1.jsx)(react_router_dom_1.Route, { path: "/sources/*", element: !appInfo ? ((0, jsx_runtime_1.jsx)("div", { className: "sources-view", children: (0, jsx_runtime_1.jsx)("div", { className: "placeholder-content", children: (0, jsx_runtime_1.jsx)("p", { children: "Loading..." }) }) })) : appInfo.sources && appInfo.sources.length > 0 ? ((0, jsx_runtime_1.jsx)(SourcesView_1.SourcesView, { apiBaseUrl: "/devserver/api", appInstalled: appInstalled, buildStatus: buildStatus })) : ((0, jsx_runtime_1.jsx)(react_router_dom_1.Navigate, { to: "/settings", replace: true })) }), (0, jsx_runtime_1.jsx)(react_router_dom_1.Route, { path: "/opal-tools/*", element: !appInfo ? ((0, jsx_runtime_1.jsx)("div", { className: "functions-view", children: (0, jsx_runtime_1.jsx)("div", { className: "placeholder-content", children: (0, jsx_runtime_1.jsx)("p", { children: "Loading..." }) }) })) : appInfo.opalTools && appInfo.opalTools.length > 0 ? ((0, jsx_runtime_1.jsx)(OpalToolsView_1.default, { appInstalled: appInstalled, buildStatus: buildStatus, installVersion: installVersion })) : ((0, jsx_runtime_1.jsx)(react_router_dom_1.Navigate, { to: "/settings", replace: true })) }), (0, jsx_runtime_1.jsx)(react_router_dom_1.Route, { path: "/odp-schema", element: config.hasSchemaFiles ? ((0, jsx_runtime_1.jsx)(OdpSchemaView_1.default, {})) : ((0, jsx_runtime_1.jsx)(react_router_dom_1.Navigate, { to: "/settings", replace: true })) }), (0, jsx_runtime_1.jsx)(react_router_dom_1.Route, { path: "/tool-settings", element: (0, jsx_runtime_1.jsx)(ToolSettingsView_1.default, { odpApiKey: config.odpApiKey || '', onSave: async (odpApiKey) => {
|
|
659
|
+
try {
|
|
660
|
+
await fetch('/devserver/api/config/odp', {
|
|
661
|
+
method: 'POST',
|
|
662
|
+
headers: { 'Content-Type': 'application/json' },
|
|
663
|
+
body: JSON.stringify({ odpApiKey }),
|
|
664
|
+
});
|
|
665
|
+
fetchConfig();
|
|
666
|
+
}
|
|
667
|
+
catch (error) {
|
|
668
|
+
console.error('Error saving ODP config:', error);
|
|
669
|
+
}
|
|
670
|
+
} }) }), (0, jsx_runtime_1.jsx)(react_router_dom_1.Route, { path: "*", element: (0, jsx_runtime_1.jsxs)("div", { className: "not-found-view", style: {
|
|
410
671
|
display: 'flex',
|
|
411
672
|
flexDirection: 'column',
|
|
412
673
|
alignItems: 'center',
|
|
@@ -421,7 +682,7 @@ const App = () => {
|
|
|
421
682
|
color: 'white',
|
|
422
683
|
border: 'none',
|
|
423
684
|
borderRadius: '4px'
|
|
424
|
-
}, children: "Go to Settings" })] }) })] }) })] })] }), (0, jsx_runtime_1.jsx)(TabbedConsole_1.default, { logs: logs, onClearLogs: clearConsoleLogs, storeTimestamps: storeTimestamps, onRefreshStores: fetchStatus, notificationCount: notificationCount })] }));
|
|
685
|
+
}, children: "Go to Settings" })] }) })] }) })] })] }), (0, jsx_runtime_1.jsx)(TabbedConsole_1.default, { logs: logs, onClearLogs: clearConsoleLogs, storeTimestamps: storeTimestamps, onRefreshStores: fetchStatus, notificationCount: notificationCount, hasSources: !!(appInfo?.sources && appInfo.sources.length > 0), sourceDataVersion: sourceDataVersion, sourceDataTotalEmitted: sourceDataTotalEmitted, notificationVersion: notificationVersion, envVersion: envVersion, deployLogs: deployLogs, deployVersion: deployVersion, deployStatus: deployStatus }), (0, jsx_runtime_1.jsx)(DeployModal_1.DeployModal, { isOpen: showDeployModal, onClose: () => setShowDeployModal(false), currentVersion: deployModalData?.currentVersion || '', suggestedVersion: deployModalData?.suggestedVersion || '', isDevVersion: deployModalData?.isDevVersion || false, onDeploy: startDeploy }), permanentlyDisconnected && ((0, jsx_runtime_1.jsx)("div", { className: "disconnect-overlay", children: (0, jsx_runtime_1.jsxs)("div", { className: "disconnect-message", children: [(0, jsx_runtime_1.jsx)("h2", { children: "Server Disconnected" }), (0, jsx_runtime_1.jsx)("p", { children: "The development server has been stopped or is unreachable." }), (0, jsx_runtime_1.jsx)("button", { onClick: () => window.location.reload(), children: "Reconnect" })] }) })), appChanged && ((0, jsx_runtime_1.jsx)("div", { className: "disconnect-overlay", children: (0, jsx_runtime_1.jsxs)("div", { className: "disconnect-message app-changed", children: [(0, jsx_runtime_1.jsx)("h2", { children: "Different App Detected" }), (0, jsx_runtime_1.jsxs)("p", { children: ["The server is now running a different app.", (0, jsx_runtime_1.jsx)("br", {}), (0, jsx_runtime_1.jsxs)("span", { className: "app-change-details", children: [(0, jsx_runtime_1.jsx)("strong", { children: appChanged.oldApp }), " \u2192 ", (0, jsx_runtime_1.jsx)("strong", { children: appChanged.newApp })] })] }), (0, jsx_runtime_1.jsx)("button", { onClick: () => window.location.reload(), children: "Load New App" })] }) }))] }));
|
|
425
686
|
};
|
|
426
687
|
exports.default = App;
|
|
427
688
|
//# sourceMappingURL=App.js.map
|