@finos/legend-application-studio 28.19.69 → 28.19.71
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/lib/components/editor/editor-group/dataProduct/DataProductEditor.d.ts +5 -0
- package/lib/components/editor/editor-group/dataProduct/DataProductEditor.d.ts.map +1 -1
- package/lib/components/editor/editor-group/dataProduct/DataProductEditor.js +38 -5
- package/lib/components/editor/editor-group/dataProduct/DataProductEditor.js.map +1 -1
- package/lib/components/editor/editor-group/project-configuration-editor/ProjectDependencyEditor.d.ts.map +1 -1
- package/lib/components/editor/editor-group/project-configuration-editor/ProjectDependencyEditor.js +338 -26
- package/lib/components/editor/editor-group/project-configuration-editor/ProjectDependencyEditor.js.map +1 -1
- package/lib/components/editor/side-bar/DevMetadataPanel.d.ts.map +1 -1
- package/lib/components/editor/side-bar/DevMetadataPanel.js +150 -32
- package/lib/components/editor/side-bar/DevMetadataPanel.js.map +1 -1
- package/lib/index.css +2 -2
- package/lib/index.css.map +1 -1
- package/lib/package.json +2 -1
- package/lib/stores/editor/EditorGraphState.d.ts.map +1 -1
- package/lib/stores/editor/EditorGraphState.js +7 -1
- package/lib/stores/editor/EditorGraphState.js.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.d.ts +11 -1
- package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.js +25 -2
- package/lib/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.js.map +1 -1
- package/lib/stores/editor/editor-state/project-configuration-editor-state/ProjectConfigurationEditorState.d.ts +2 -0
- package/lib/stores/editor/editor-state/project-configuration-editor-state/ProjectConfigurationEditorState.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/project-configuration-editor-state/ProjectConfigurationEditorState.js +19 -0
- package/lib/stores/editor/editor-state/project-configuration-editor-state/ProjectConfigurationEditorState.js.map +1 -1
- package/lib/stores/editor/editor-state/project-configuration-editor-state/ProjectDependencyEditorState.d.ts +16 -1
- package/lib/stores/editor/editor-state/project-configuration-editor-state/ProjectDependencyEditorState.d.ts.map +1 -1
- package/lib/stores/editor/editor-state/project-configuration-editor-state/ProjectDependencyEditorState.js +112 -1
- package/lib/stores/editor/editor-state/project-configuration-editor-state/ProjectDependencyEditorState.js.map +1 -1
- package/lib/stores/editor/sidebar-state/dev-metadata/DevMetadataState.d.ts +8 -5
- package/lib/stores/editor/sidebar-state/dev-metadata/DevMetadataState.d.ts.map +1 -1
- package/lib/stores/editor/sidebar-state/dev-metadata/DevMetadataState.js +18 -28
- package/lib/stores/editor/sidebar-state/dev-metadata/DevMetadataState.js.map +1 -1
- package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.d.ts +1 -1
- package/lib/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.d.ts.map +1 -1
- package/package.json +11 -10
- package/src/components/editor/editor-group/dataProduct/DataProductEditor.tsx +131 -4
- package/src/components/editor/editor-group/project-configuration-editor/ProjectDependencyEditor.tsx +599 -53
- package/src/components/editor/side-bar/DevMetadataPanel.tsx +613 -73
- package/src/stores/editor/EditorGraphState.ts +11 -4
- package/src/stores/editor/editor-state/element-editor-state/dataProduct/DataProductEditorState.ts +35 -0
- package/src/stores/editor/editor-state/project-configuration-editor-state/ProjectConfigurationEditorState.ts +26 -0
- package/src/stores/editor/editor-state/project-configuration-editor-state/ProjectDependencyEditorState.ts +178 -1
- package/src/stores/editor/sidebar-state/dev-metadata/DevMetadataState.ts +28 -39
- package/src/stores/graph-modifier/DSL_DataProduct_GraphModifierHelper.ts +1 -1
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
import { observer } from 'mobx-react-lite';
|
|
18
18
|
import { useEditorStore } from '../EditorStoreProvider.js';
|
|
19
|
-
import { useEffect } from 'react';
|
|
19
|
+
import { forwardRef, useEffect, useState, type ReactNode } from 'react';
|
|
20
20
|
import {
|
|
21
21
|
PanelFormSection,
|
|
22
22
|
PanelFormValidatedTextField,
|
|
@@ -32,56 +32,363 @@ import {
|
|
|
32
32
|
ModalHeader,
|
|
33
33
|
Modal,
|
|
34
34
|
ModalTitle,
|
|
35
|
+
PanelDivider,
|
|
36
|
+
CircleNotchIcon,
|
|
37
|
+
PauseCircleIcon,
|
|
38
|
+
TimesCircleIcon,
|
|
39
|
+
BanIcon,
|
|
40
|
+
QuestionCircleIcon,
|
|
41
|
+
MenuContent,
|
|
42
|
+
MenuContentItem,
|
|
43
|
+
ContextMenu,
|
|
44
|
+
PanelForm,
|
|
45
|
+
PanelFormBooleanField,
|
|
46
|
+
TrashIcon,
|
|
47
|
+
PlusIcon,
|
|
48
|
+
CogIcon,
|
|
35
49
|
} from '@finos/legend-art';
|
|
36
50
|
import { CODE_EDITOR_LANGUAGE } from '@finos/legend-code-editor';
|
|
37
51
|
import { CodeEditor } from '@finos/legend-lego/code-editor';
|
|
38
|
-
import {
|
|
52
|
+
import {
|
|
53
|
+
type BuildLog,
|
|
54
|
+
type BuildPhaseActionState,
|
|
55
|
+
BuildPhaseStatus,
|
|
56
|
+
type DeployProjectResponse,
|
|
57
|
+
LogType,
|
|
58
|
+
MetadataRequestOptions,
|
|
59
|
+
} from '@finos/legend-graph';
|
|
60
|
+
import { flowResult } from 'mobx';
|
|
39
61
|
|
|
40
|
-
const
|
|
62
|
+
const BuildOverrideEditor = observer(
|
|
41
63
|
(props: {
|
|
42
|
-
|
|
43
|
-
|
|
64
|
+
buildOverrides: Record<string, string>;
|
|
65
|
+
onUpdate: (overrides: Record<string, string>) => void;
|
|
44
66
|
}) => {
|
|
45
|
-
const {
|
|
67
|
+
const { buildOverrides, onUpdate } = props;
|
|
68
|
+
const [newKey, setNewKey] = useState('');
|
|
69
|
+
const [newValue, setNewValue] = useState('');
|
|
70
|
+
|
|
71
|
+
const handleAddOverride = () => {
|
|
72
|
+
if (newKey.trim() && newValue.trim()) {
|
|
73
|
+
onUpdate({
|
|
74
|
+
...buildOverrides,
|
|
75
|
+
[newKey.trim()]: newValue.trim(),
|
|
76
|
+
});
|
|
77
|
+
setNewKey('');
|
|
78
|
+
setNewValue('');
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const handleDeleteOverride = (key: string) => {
|
|
83
|
+
const updatedOverrides = { ...buildOverrides };
|
|
84
|
+
delete updatedOverrides[key];
|
|
85
|
+
onUpdate(updatedOverrides);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const handleUpdateOverride = (key: string, value: string) => {
|
|
89
|
+
onUpdate({
|
|
90
|
+
...buildOverrides,
|
|
91
|
+
[key]: value,
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<div className="build-override-editor">
|
|
97
|
+
<div className="build-override-editor__header">
|
|
98
|
+
<span className="build-override-editor__title">Build Overrides</span>
|
|
99
|
+
<span className="build-override-editor__description">
|
|
100
|
+
Key-value pairs to override build parameters
|
|
101
|
+
</span>
|
|
102
|
+
</div>
|
|
103
|
+
|
|
104
|
+
{/* Existing overrides */}
|
|
105
|
+
<div className="build-override-editor__list">
|
|
106
|
+
{Object.entries(buildOverrides).map(([key, value]) => (
|
|
107
|
+
<div key={key} className="build-override-editor__item">
|
|
108
|
+
<div className="build-override-editor__item__fields">
|
|
109
|
+
<PanelFormValidatedTextField
|
|
110
|
+
name={`override-key-${key}`}
|
|
111
|
+
prompt="Key"
|
|
112
|
+
value={key}
|
|
113
|
+
update={(val) => {
|
|
114
|
+
if (val && val !== key && val.trim()) {
|
|
115
|
+
const newOverrides = { ...buildOverrides };
|
|
116
|
+
delete newOverrides[key];
|
|
117
|
+
newOverrides[val.trim()] = value;
|
|
118
|
+
onUpdate(newOverrides);
|
|
119
|
+
}
|
|
120
|
+
}}
|
|
121
|
+
/>
|
|
122
|
+
<PanelFormValidatedTextField
|
|
123
|
+
name={`override-value-${key}`}
|
|
124
|
+
prompt="Value"
|
|
125
|
+
value={value}
|
|
126
|
+
update={(val) => handleUpdateOverride(key, val ?? '')}
|
|
127
|
+
/>
|
|
128
|
+
</div>
|
|
129
|
+
<button
|
|
130
|
+
className="build-override-editor__delete-btn"
|
|
131
|
+
onClick={() => handleDeleteOverride(key)}
|
|
132
|
+
title="Delete override"
|
|
133
|
+
>
|
|
134
|
+
<TrashIcon />
|
|
135
|
+
</button>
|
|
136
|
+
</div>
|
|
137
|
+
))}
|
|
138
|
+
</div>
|
|
139
|
+
|
|
140
|
+
{/* Add new override */}
|
|
141
|
+
<div className="build-override-editor__add">
|
|
142
|
+
<div className="build-override-editor__add__title">
|
|
143
|
+
Add New Override
|
|
144
|
+
</div>
|
|
145
|
+
<div className="build-override-editor__add__fields">
|
|
146
|
+
<PanelFormValidatedTextField
|
|
147
|
+
name="new-override-key"
|
|
148
|
+
prompt="Key"
|
|
149
|
+
value={newKey}
|
|
150
|
+
update={(val: string | undefined) => setNewKey(val ?? '')}
|
|
151
|
+
/>
|
|
152
|
+
<PanelFormValidatedTextField
|
|
153
|
+
name="new-override-value"
|
|
154
|
+
prompt="Value"
|
|
155
|
+
value={newValue}
|
|
156
|
+
update={(val: string | undefined) => setNewValue(val ?? '')}
|
|
157
|
+
/>
|
|
158
|
+
<button
|
|
159
|
+
className="build-override-editor__add-btn"
|
|
160
|
+
onClick={handleAddOverride}
|
|
161
|
+
disabled={!newKey.trim() || !newValue.trim()}
|
|
162
|
+
title="Add override"
|
|
163
|
+
>
|
|
164
|
+
<PlusIcon />
|
|
165
|
+
</button>
|
|
166
|
+
</div>
|
|
167
|
+
</div>
|
|
168
|
+
</div>
|
|
169
|
+
);
|
|
170
|
+
},
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
const DevMetadataOptionsModal = observer(
|
|
174
|
+
(props: {
|
|
175
|
+
isOpen: boolean;
|
|
176
|
+
onClose: () => void;
|
|
177
|
+
options: MetadataRequestOptions;
|
|
178
|
+
onSave: (options: MetadataRequestOptions) => void;
|
|
179
|
+
}) => {
|
|
180
|
+
const { isOpen, onClose, options, onSave } = props;
|
|
181
|
+
const editorStore = useEditorStore();
|
|
182
|
+
const applicationStore = editorStore.applicationStore;
|
|
183
|
+
|
|
184
|
+
const [includeArtifacts, setIncludeArtifacts] = useState(
|
|
185
|
+
options.includeArtifacts ?? false,
|
|
186
|
+
);
|
|
187
|
+
const [buildOverrides, setBuildOverrides] = useState(
|
|
188
|
+
options.buildOverrides ?? {},
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
useEffect(() => {
|
|
192
|
+
if (isOpen) {
|
|
193
|
+
setIncludeArtifacts(options.includeArtifacts ?? false);
|
|
194
|
+
setBuildOverrides(options.buildOverrides ?? {});
|
|
195
|
+
}
|
|
196
|
+
}, [isOpen, options]);
|
|
197
|
+
|
|
198
|
+
const handleSave = () => {
|
|
199
|
+
const updatedOptions = new MetadataRequestOptions();
|
|
200
|
+
updatedOptions.includeArtifacts = includeArtifacts;
|
|
201
|
+
updatedOptions.buildOverrides =
|
|
202
|
+
Object.keys(buildOverrides).length > 0 ? buildOverrides : undefined;
|
|
203
|
+
onSave(updatedOptions);
|
|
204
|
+
onClose();
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
const handleCancel = () => {
|
|
208
|
+
setIncludeArtifacts(options.includeArtifacts ?? false);
|
|
209
|
+
setBuildOverrides(options.buildOverrides ?? {});
|
|
210
|
+
onClose();
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
if (!isOpen) {
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return (
|
|
218
|
+
<Dialog
|
|
219
|
+
open={isOpen}
|
|
220
|
+
onClose={handleCancel}
|
|
221
|
+
classes={{
|
|
222
|
+
root: 'editor-modal__root-container',
|
|
223
|
+
container: 'editor-modal__container',
|
|
224
|
+
paper: 'editor-modal__content',
|
|
225
|
+
}}
|
|
226
|
+
>
|
|
227
|
+
<Modal
|
|
228
|
+
darkMode={
|
|
229
|
+
!applicationStore.layoutService.TEMPORARY__isLightColorThemeEnabled
|
|
230
|
+
}
|
|
231
|
+
className="editor-modal dev-metadata-options-modal"
|
|
232
|
+
>
|
|
233
|
+
<ModalHeader>
|
|
234
|
+
<ModalTitle title="Deployment Configuration" />
|
|
235
|
+
</ModalHeader>
|
|
236
|
+
<ModalBody className="dev-metadata-options-modal__body">
|
|
237
|
+
<PanelForm>
|
|
238
|
+
<PanelFormSection>
|
|
239
|
+
<div className="panel__content__form__section__header__label">
|
|
240
|
+
Artifact Settings
|
|
241
|
+
</div>
|
|
242
|
+
<PanelFormBooleanField
|
|
243
|
+
name="includeArtifacts"
|
|
244
|
+
prompt="Include Artifacts"
|
|
245
|
+
value={includeArtifacts}
|
|
246
|
+
update={(val: boolean | undefined) =>
|
|
247
|
+
setIncludeArtifacts(Boolean(val))
|
|
248
|
+
}
|
|
249
|
+
isReadOnly={false}
|
|
250
|
+
/>
|
|
251
|
+
<div className="panel__content__form__section__desc">
|
|
252
|
+
When enabled, includes generated artifacts in the deployment
|
|
253
|
+
</div>
|
|
254
|
+
</PanelFormSection>
|
|
255
|
+
|
|
256
|
+
<PanelFormSection>
|
|
257
|
+
<BuildOverrideEditor
|
|
258
|
+
buildOverrides={buildOverrides}
|
|
259
|
+
onUpdate={setBuildOverrides}
|
|
260
|
+
/>
|
|
261
|
+
</PanelFormSection>
|
|
262
|
+
</PanelForm>
|
|
263
|
+
</ModalBody>
|
|
264
|
+
<ModalFooter>
|
|
265
|
+
<ModalFooterButton
|
|
266
|
+
text="Cancel"
|
|
267
|
+
onClick={handleCancel}
|
|
268
|
+
type="secondary"
|
|
269
|
+
/>
|
|
270
|
+
<ModalFooterButton
|
|
271
|
+
text="Save Configuration"
|
|
272
|
+
onClick={handleSave}
|
|
273
|
+
type="primary"
|
|
274
|
+
/>
|
|
275
|
+
</ModalFooter>
|
|
276
|
+
</Modal>
|
|
277
|
+
</Dialog>
|
|
278
|
+
);
|
|
279
|
+
},
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
const getPhaseStatusIcon = (status: BuildPhaseStatus): ReactNode => {
|
|
283
|
+
switch (status) {
|
|
284
|
+
case BuildPhaseStatus.NOT_STARTED:
|
|
285
|
+
return (
|
|
286
|
+
<div
|
|
287
|
+
title="Phase not started"
|
|
288
|
+
className="deployment-phase__status__indicator deployment-phase__status__indicator--not-started"
|
|
289
|
+
>
|
|
290
|
+
<PauseCircleIcon />
|
|
291
|
+
</div>
|
|
292
|
+
);
|
|
293
|
+
case BuildPhaseStatus.IN_PROGRESS:
|
|
294
|
+
return (
|
|
295
|
+
<div
|
|
296
|
+
title="Phase in progress"
|
|
297
|
+
className="deployment-phase__status__indicator deployment-phase__status__indicator--in-progress"
|
|
298
|
+
>
|
|
299
|
+
<CircleNotchIcon />
|
|
300
|
+
</div>
|
|
301
|
+
);
|
|
302
|
+
case BuildPhaseStatus.SUCCESS:
|
|
303
|
+
return (
|
|
304
|
+
<div
|
|
305
|
+
title="Phase succeeded"
|
|
306
|
+
className="deployment-phase__status__indicator deployment-phase__status__indicator--success"
|
|
307
|
+
>
|
|
308
|
+
<CheckCircleIcon />
|
|
309
|
+
</div>
|
|
310
|
+
);
|
|
311
|
+
case BuildPhaseStatus.FAIL:
|
|
312
|
+
return (
|
|
313
|
+
<div
|
|
314
|
+
title="Phase failed"
|
|
315
|
+
className="deployment-phase__status__indicator deployment-phase__status__indicator--failed"
|
|
316
|
+
>
|
|
317
|
+
<TimesCircleIcon />
|
|
318
|
+
</div>
|
|
319
|
+
);
|
|
320
|
+
case BuildPhaseStatus.SKIPPED:
|
|
321
|
+
return (
|
|
322
|
+
<div
|
|
323
|
+
title="Phase skipped"
|
|
324
|
+
className="deployment-phase__status__indicator deployment-phase__status__indicator--skipped"
|
|
325
|
+
>
|
|
326
|
+
<BanIcon />
|
|
327
|
+
</div>
|
|
328
|
+
);
|
|
329
|
+
default:
|
|
330
|
+
return (
|
|
331
|
+
<div
|
|
332
|
+
title="Phase status unknown"
|
|
333
|
+
className="deployment-phase__status__indicator deployment-phase__status__indicator--unknown"
|
|
334
|
+
>
|
|
335
|
+
<QuestionCircleIcon />
|
|
336
|
+
</div>
|
|
337
|
+
);
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
const PhaseLogsViewer = observer(
|
|
342
|
+
(props: { phase: BuildPhaseActionState; onClose: () => void }) => {
|
|
343
|
+
const { phase, onClose } = props;
|
|
344
|
+
const editorStore = useEditorStore();
|
|
345
|
+
const applicationStore = editorStore.applicationStore;
|
|
346
|
+
|
|
347
|
+
const formatLogs = (logs: BuildLog[]): string => {
|
|
348
|
+
return logs
|
|
349
|
+
.map((log) => {
|
|
350
|
+
const prefix = log.logType ? `[${log.logType}]` : '';
|
|
351
|
+
const title = log.title ? `${log.title}: ` : '';
|
|
352
|
+
return `${prefix} ${title}${log.log}`;
|
|
353
|
+
})
|
|
354
|
+
.join('\n');
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
const logs = phase.logs ? formatLogs(phase.logs) : 'No logs available';
|
|
358
|
+
|
|
46
359
|
return (
|
|
47
360
|
<Dialog
|
|
48
361
|
open={true}
|
|
362
|
+
onClose={onClose}
|
|
49
363
|
classes={{
|
|
50
|
-
root: '
|
|
51
|
-
container: '
|
|
52
|
-
paper: '
|
|
364
|
+
root: 'editor-modal__root-container',
|
|
365
|
+
container: 'editor-modal__container',
|
|
366
|
+
paper: 'editor-modal__content',
|
|
53
367
|
}}
|
|
54
368
|
>
|
|
55
|
-
<Modal
|
|
369
|
+
<Modal
|
|
370
|
+
darkMode={
|
|
371
|
+
!applicationStore.layoutService.TEMPORARY__isLightColorThemeEnabled
|
|
372
|
+
}
|
|
373
|
+
className="editor-modal"
|
|
374
|
+
>
|
|
56
375
|
<ModalHeader>
|
|
57
|
-
<ModalTitle
|
|
58
|
-
icon={<CheckCircleIcon className="ingestion-modal--success" />}
|
|
59
|
-
title="Push Response"
|
|
60
|
-
></ModalTitle>
|
|
376
|
+
<ModalTitle title={`Logs for Phase: ${phase.phase}`} />
|
|
61
377
|
</ModalHeader>
|
|
62
378
|
<ModalBody>
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
isReadOnly={true}
|
|
72
|
-
language={CODE_EDITOR_LANGUAGE.JSON}
|
|
73
|
-
extraEditorOptions={{
|
|
74
|
-
wordWrap: 'on',
|
|
75
|
-
}}
|
|
76
|
-
hideActionBar={true}
|
|
77
|
-
/>
|
|
78
|
-
</div>
|
|
79
|
-
</div>
|
|
379
|
+
<CodeEditor
|
|
380
|
+
inputValue={logs}
|
|
381
|
+
isReadOnly={true}
|
|
382
|
+
language={CODE_EDITOR_LANGUAGE.TEXT}
|
|
383
|
+
extraEditorOptions={{
|
|
384
|
+
wordWrap: 'on',
|
|
385
|
+
}}
|
|
386
|
+
/>
|
|
80
387
|
</ModalBody>
|
|
81
388
|
<ModalFooter>
|
|
82
389
|
<ModalFooterButton
|
|
83
|
-
onClick={closeModal}
|
|
84
390
|
text="Close"
|
|
391
|
+
onClick={onClose}
|
|
85
392
|
type="secondary"
|
|
86
393
|
/>
|
|
87
394
|
</ModalFooter>
|
|
@@ -91,23 +398,198 @@ const DevMetadataResultModal = observer(
|
|
|
91
398
|
},
|
|
92
399
|
);
|
|
93
400
|
|
|
401
|
+
const PhaseContextMenu = observer(
|
|
402
|
+
forwardRef<
|
|
403
|
+
HTMLDivElement,
|
|
404
|
+
{
|
|
405
|
+
phase: BuildPhaseActionState;
|
|
406
|
+
onViewLogs: () => void;
|
|
407
|
+
}
|
|
408
|
+
>(function PhaseContextMenu(props, ref) {
|
|
409
|
+
const { phase, onViewLogs } = props;
|
|
410
|
+
const hasLogs = phase.logs && phase.logs.length > 0;
|
|
411
|
+
|
|
412
|
+
return (
|
|
413
|
+
<MenuContent>
|
|
414
|
+
{hasLogs && (
|
|
415
|
+
<MenuContentItem onClick={onViewLogs}>
|
|
416
|
+
View Logs ({phase.logs?.length} entries)
|
|
417
|
+
</MenuContentItem>
|
|
418
|
+
)}
|
|
419
|
+
</MenuContent>
|
|
420
|
+
);
|
|
421
|
+
}),
|
|
422
|
+
);
|
|
423
|
+
|
|
424
|
+
const DeploymentPhaseNode = observer(
|
|
425
|
+
(props: {
|
|
426
|
+
phase: BuildPhaseActionState;
|
|
427
|
+
onViewLogs: (phase: BuildPhaseActionState) => void;
|
|
428
|
+
}) => {
|
|
429
|
+
const { phase, onViewLogs } = props;
|
|
430
|
+
const statusIcon = getPhaseStatusIcon(phase.status);
|
|
431
|
+
const hasLogs = phase.logs && phase.logs.length > 0;
|
|
432
|
+
const errorLogs =
|
|
433
|
+
phase.logs?.filter((log) => log.logType === LogType.ERROR).length ?? 0;
|
|
434
|
+
const warnLogs =
|
|
435
|
+
phase.logs?.filter((log) => log.logType === LogType.WARN).length ?? 0;
|
|
436
|
+
|
|
437
|
+
return (
|
|
438
|
+
<ContextMenu
|
|
439
|
+
content={
|
|
440
|
+
<PhaseContextMenu
|
|
441
|
+
phase={phase}
|
|
442
|
+
onViewLogs={() => onViewLogs(phase)}
|
|
443
|
+
/>
|
|
444
|
+
}
|
|
445
|
+
menuProps={{ elevation: 7 }}
|
|
446
|
+
>
|
|
447
|
+
<div className="deployment-phase__node">
|
|
448
|
+
<div className="deployment-phase__node__icon">{statusIcon}</div>
|
|
449
|
+
<div className="deployment-phase__node__content">
|
|
450
|
+
<div className="deployment-phase__node__title">{phase.phase}</div>
|
|
451
|
+
<div className="deployment-phase__node__details">
|
|
452
|
+
<span
|
|
453
|
+
className={`deployment-phase__status deployment-phase__status--${phase.status.toLowerCase()}`}
|
|
454
|
+
>
|
|
455
|
+
{phase.status}
|
|
456
|
+
</span>
|
|
457
|
+
{phase.message && (
|
|
458
|
+
<span className="deployment-phase__message">
|
|
459
|
+
{phase.message}
|
|
460
|
+
</span>
|
|
461
|
+
)}
|
|
462
|
+
{hasLogs && (
|
|
463
|
+
<span className="deployment-phase__logs-count">
|
|
464
|
+
{errorLogs > 0 && (
|
|
465
|
+
<span className="logs-count logs-count--error">
|
|
466
|
+
{errorLogs} errors
|
|
467
|
+
</span>
|
|
468
|
+
)}
|
|
469
|
+
{warnLogs > 0 && (
|
|
470
|
+
<span className="logs-count logs-count--warn">
|
|
471
|
+
{warnLogs} warnings
|
|
472
|
+
</span>
|
|
473
|
+
)}
|
|
474
|
+
<span className="logs-count logs-count--total">
|
|
475
|
+
{phase.logs?.length} logs
|
|
476
|
+
</span>
|
|
477
|
+
</span>
|
|
478
|
+
)}
|
|
479
|
+
</div>
|
|
480
|
+
</div>
|
|
481
|
+
</div>
|
|
482
|
+
</ContextMenu>
|
|
483
|
+
);
|
|
484
|
+
},
|
|
485
|
+
);
|
|
486
|
+
|
|
487
|
+
const DeploymentStatusPanel = observer(
|
|
488
|
+
(props: { deploymentResponse: DeployProjectResponse }) => {
|
|
489
|
+
const { deploymentResponse } = props;
|
|
490
|
+
const [selectedPhaseForLogs, setSelectedPhaseForLogs] =
|
|
491
|
+
useState<BuildPhaseActionState | null>(null);
|
|
492
|
+
|
|
493
|
+
const handleViewLogs = (phase: BuildPhaseActionState) => {
|
|
494
|
+
setSelectedPhaseForLogs(phase);
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
const closeLogsViewer = () => {
|
|
498
|
+
setSelectedPhaseForLogs(null);
|
|
499
|
+
};
|
|
500
|
+
|
|
501
|
+
return (
|
|
502
|
+
<div className="deployment-status-panel">
|
|
503
|
+
<div className="deployment-status-panel__header">
|
|
504
|
+
<div className="deployment-status-panel__title">
|
|
505
|
+
Deployment Status
|
|
506
|
+
</div>
|
|
507
|
+
<div
|
|
508
|
+
className={`deployment-status-panel__final-status deployment-status-panel__final-status--${deploymentResponse.finalStatus.toLowerCase()}`}
|
|
509
|
+
>
|
|
510
|
+
{getPhaseStatusIcon(deploymentResponse.finalStatus)}
|
|
511
|
+
<span>{deploymentResponse.finalStatus}</span>
|
|
512
|
+
</div>
|
|
513
|
+
</div>
|
|
514
|
+
|
|
515
|
+
<PanelDivider />
|
|
516
|
+
|
|
517
|
+
{/* Project Details */}
|
|
518
|
+
<div className="deployment-status-panel__project-details">
|
|
519
|
+
<div className="deployment-status-panel__section-title">
|
|
520
|
+
Project Details
|
|
521
|
+
</div>
|
|
522
|
+
<div className="deployment-status-panel__details-grid">
|
|
523
|
+
<div className="detail-item">
|
|
524
|
+
<span className="detail-label">Group ID:</span>
|
|
525
|
+
<span className="detail-value">
|
|
526
|
+
{deploymentResponse.projectDetails.groupId}
|
|
527
|
+
</span>
|
|
528
|
+
</div>
|
|
529
|
+
<div className="detail-item">
|
|
530
|
+
<span className="detail-label">Artifact ID:</span>
|
|
531
|
+
<span className="detail-value">
|
|
532
|
+
{deploymentResponse.projectDetails.artifactId}
|
|
533
|
+
</span>
|
|
534
|
+
</div>
|
|
535
|
+
<div className="detail-item">
|
|
536
|
+
<span className="detail-label">Version:</span>
|
|
537
|
+
<span className="detail-value">
|
|
538
|
+
{deploymentResponse.projectDetails.version}
|
|
539
|
+
</span>
|
|
540
|
+
</div>
|
|
541
|
+
</div>
|
|
542
|
+
</div>
|
|
543
|
+
|
|
544
|
+
<PanelDivider />
|
|
545
|
+
|
|
546
|
+
{/* Phases */}
|
|
547
|
+
{deploymentResponse.phaseStates &&
|
|
548
|
+
deploymentResponse.phaseStates.length > 0 && (
|
|
549
|
+
<div className="deployment-status-panel__phases">
|
|
550
|
+
<div className="deployment-status-panel__section-title">
|
|
551
|
+
Deployment Phases ({deploymentResponse.phaseStates.length})
|
|
552
|
+
</div>
|
|
553
|
+
<div className="deployment-phases-list">
|
|
554
|
+
{deploymentResponse.phaseStates.map((phase) => (
|
|
555
|
+
<DeploymentPhaseNode
|
|
556
|
+
key={`${phase.phase}`}
|
|
557
|
+
phase={phase}
|
|
558
|
+
onViewLogs={handleViewLogs}
|
|
559
|
+
/>
|
|
560
|
+
))}
|
|
561
|
+
</div>
|
|
562
|
+
</div>
|
|
563
|
+
)}
|
|
564
|
+
|
|
565
|
+
{/* Logs Viewer Modal */}
|
|
566
|
+
{selectedPhaseForLogs && (
|
|
567
|
+
<PhaseLogsViewer
|
|
568
|
+
phase={selectedPhaseForLogs}
|
|
569
|
+
onClose={closeLogsViewer}
|
|
570
|
+
/>
|
|
571
|
+
)}
|
|
572
|
+
</div>
|
|
573
|
+
);
|
|
574
|
+
},
|
|
575
|
+
);
|
|
576
|
+
|
|
94
577
|
export const DevMetadataPanel = observer(() => {
|
|
95
578
|
const editorStore = useEditorStore();
|
|
96
579
|
const devMetadataState = editorStore.devMetadataState;
|
|
97
|
-
|
|
98
|
-
useEffect(() => {
|
|
99
|
-
devMetadataState.init();
|
|
100
|
-
}, [devMetadataState]);
|
|
580
|
+
const [isOptionsModalOpen, setIsOptionsModalOpen] = useState(false);
|
|
101
581
|
|
|
102
582
|
const handlePush = (): void => {
|
|
103
|
-
devMetadataState.push()
|
|
583
|
+
flowResult(devMetadataState.push()).catch(
|
|
584
|
+
editorStore.applicationStore.alertUnhandledError,
|
|
585
|
+
);
|
|
104
586
|
};
|
|
105
587
|
|
|
106
|
-
const
|
|
107
|
-
devMetadataState.
|
|
588
|
+
const handleSaveOptions = (newOptions: MetadataRequestOptions): void => {
|
|
589
|
+
devMetadataState.setOptions(newOptions);
|
|
108
590
|
};
|
|
109
591
|
|
|
110
|
-
const
|
|
592
|
+
const isPushing = devMetadataState.pushState.isInProgress;
|
|
111
593
|
|
|
112
594
|
return (
|
|
113
595
|
<Panel>
|
|
@@ -119,50 +601,108 @@ export const DevMetadataPanel = observer(() => {
|
|
|
119
601
|
</div>
|
|
120
602
|
</PanelHeader>
|
|
121
603
|
<PanelContent>
|
|
122
|
-
<
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
604
|
+
<PanelFormSection>
|
|
605
|
+
<div className="dev-metadata-panel__project-info">
|
|
606
|
+
<div className="dev-metadata-panel__info-header">
|
|
607
|
+
Project Information
|
|
608
|
+
</div>
|
|
609
|
+
<div className="dev-metadata-panel__info-content">
|
|
610
|
+
<div className="dev-metadata-panel__info-row">
|
|
611
|
+
<span className="dev-metadata-panel__info-label">
|
|
612
|
+
Group ID:
|
|
613
|
+
</span>
|
|
614
|
+
<span className="dev-metadata-panel__info-value">
|
|
615
|
+
{devMetadataState.projectGAV?.groupId ?? 'Not available'}
|
|
616
|
+
</span>
|
|
617
|
+
</div>
|
|
618
|
+
<div className="dev-metadata-panel__info-row">
|
|
619
|
+
<span className="dev-metadata-panel__info-label">
|
|
620
|
+
Artifact ID:
|
|
621
|
+
</span>
|
|
622
|
+
<span className="dev-metadata-panel__info-value">
|
|
623
|
+
{devMetadataState.projectGAV?.artifactId ?? 'Not available'}
|
|
624
|
+
</span>
|
|
625
|
+
</div>
|
|
626
|
+
</div>
|
|
627
|
+
</div>
|
|
628
|
+
</PanelFormSection>
|
|
629
|
+
|
|
630
|
+
<PanelDivider />
|
|
631
|
+
<PanelFormSection>
|
|
632
|
+
<div className="dev-metadata-panel__push-section">
|
|
633
|
+
<div className="dev-metadata-panel__push-header">
|
|
634
|
+
<div className="dev-metadata-panel__push-title-row">
|
|
635
|
+
<div className="panel__content__form__section__header__label">
|
|
636
|
+
Deploy Metadata
|
|
637
|
+
</div>
|
|
638
|
+
<button
|
|
639
|
+
className="dev-metadata-panel__settings-btn"
|
|
640
|
+
onClick={() => setIsOptionsModalOpen(true)}
|
|
641
|
+
title="Configure deployment options"
|
|
642
|
+
disabled={isPushing}
|
|
643
|
+
>
|
|
644
|
+
<CogIcon />
|
|
645
|
+
</button>
|
|
646
|
+
</div>
|
|
647
|
+
<div className="dev-metadata-panel__push-description">
|
|
648
|
+
{isPushing
|
|
649
|
+
? 'Pushing metadata to dev environment...'
|
|
650
|
+
: 'Push current workspace metadata to dev'}
|
|
651
|
+
</div>
|
|
133
652
|
</div>
|
|
134
|
-
<PanelFormValidatedTextField
|
|
135
|
-
value={devMetadataState.did}
|
|
136
|
-
update={handleDidChange}
|
|
137
|
-
placeholder="Enter DID..."
|
|
138
|
-
/>
|
|
139
|
-
</PanelFormSection>
|
|
140
|
-
<PanelFormSection>
|
|
141
653
|
<button
|
|
654
|
+
onClick={handlePush}
|
|
142
655
|
type="submit"
|
|
143
|
-
className={clsx('btn btn--primary
|
|
144
|
-
'btn--
|
|
656
|
+
className={clsx('btn btn--primary dev-metadata-panel__push-btn', {
|
|
657
|
+
'btn--loading': isPushing,
|
|
658
|
+
'btn--disabled': isPushing,
|
|
145
659
|
})}
|
|
146
|
-
disabled={
|
|
660
|
+
disabled={isPushing}
|
|
147
661
|
title={
|
|
148
|
-
|
|
149
|
-
? '
|
|
150
|
-
: 'Push to
|
|
662
|
+
isPushing
|
|
663
|
+
? 'Pushing metadata...'
|
|
664
|
+
: 'Push metadata to development environment'
|
|
151
665
|
}
|
|
152
666
|
>
|
|
153
667
|
<div className="btn__content">
|
|
154
|
-
|
|
668
|
+
{isPushing && (
|
|
669
|
+
<CircleNotchIcon className="dev-metadata-panel__push-btn__spinner" />
|
|
670
|
+
)}
|
|
671
|
+
<div className="btn__content__label">
|
|
672
|
+
{isPushing ? 'Pushing...' : 'Push to Dev'}
|
|
673
|
+
</div>
|
|
155
674
|
</div>
|
|
156
675
|
</button>
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
676
|
+
|
|
677
|
+
{isPushing && (
|
|
678
|
+
<div className="dev-metadata-panel__loading-overlay">
|
|
679
|
+
<div className="dev-metadata-panel__loading-content">
|
|
680
|
+
<CircleNotchIcon className="dev-metadata-panel__loading-spinner" />
|
|
681
|
+
<div className="dev-metadata-panel__loading-text">
|
|
682
|
+
Deploying metadata to development environment...
|
|
683
|
+
</div>
|
|
684
|
+
</div>
|
|
685
|
+
</div>
|
|
686
|
+
)}
|
|
687
|
+
</div>
|
|
688
|
+
</PanelFormSection>
|
|
689
|
+
<PanelFormSection>
|
|
690
|
+
{devMetadataState.result && (
|
|
691
|
+
<>
|
|
692
|
+
<PanelDivider />
|
|
693
|
+
<DeploymentStatusPanel
|
|
694
|
+
deploymentResponse={devMetadataState.result}
|
|
695
|
+
/>
|
|
696
|
+
</>
|
|
697
|
+
)}
|
|
698
|
+
</PanelFormSection>
|
|
699
|
+
<DevMetadataOptionsModal
|
|
700
|
+
isOpen={isOptionsModalOpen}
|
|
701
|
+
onClose={() => setIsOptionsModalOpen(false)}
|
|
702
|
+
options={devMetadataState.options}
|
|
703
|
+
onSave={handleSaveOptions}
|
|
164
704
|
/>
|
|
165
|
-
|
|
705
|
+
</PanelContent>
|
|
166
706
|
</Panel>
|
|
167
707
|
);
|
|
168
708
|
});
|