@harnessio/backstage-plugin-harness-iacm 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.esm.js +622 -50
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import React, { useState, useMemo, useCallback } from 'react';
|
|
2
2
|
import { Routes, Route } from 'react-router';
|
|
3
|
-
import { makeStyles, Button,
|
|
3
|
+
import { makeStyles, Button, Typography, CircularProgress, Box, IconButton, Divider, TextField, InputAdornment, Drawer, FormControl, InputLabel, Select, ListSubheader, MenuItem, FormHelperText, Tabs, Tab } from '@material-ui/core';
|
|
4
4
|
import { Grid } from '@mui/material';
|
|
5
5
|
import { useApi, discoveryApiRef, createRouteRef, createPlugin, createRoutableExtension } from '@backstage/core-plugin-api';
|
|
6
6
|
import useAsyncRetry from 'react-use/lib/useAsyncRetry';
|
|
7
7
|
import { useEntity } from '@backstage/plugin-catalog-react';
|
|
8
8
|
import { match } from 'path-to-regexp';
|
|
9
9
|
import { Table, EmptyState, MissingAnnotationEmptyState } from '@backstage/core-components';
|
|
10
|
-
import
|
|
10
|
+
import ReplayIcon from '@material-ui/icons/Replay';
|
|
11
11
|
import CopyIcon from '@material-ui/icons/FileCopyOutlined';
|
|
12
12
|
import VisibilityIcon from '@material-ui/icons/Visibility';
|
|
13
13
|
import VisibilityOffIcon from '@material-ui/icons/VisibilityOff';
|
|
14
|
+
import DeleteIcon from '@material-ui/icons/Delete';
|
|
15
|
+
import LensIcon from '@material-ui/icons/Lens';
|
|
16
|
+
import CloseIcon from '@material-ui/icons/Close';
|
|
17
|
+
import SearchIcon from '@material-ui/icons/Search';
|
|
14
18
|
|
|
15
19
|
var AsyncStatus = /* @__PURE__ */ ((AsyncStatus2) => {
|
|
16
20
|
AsyncStatus2[AsyncStatus2["Init"] = 0] = "Init";
|
|
@@ -301,7 +305,7 @@ const Kubernetes = () => /* @__PURE__ */ React.createElement(
|
|
|
301
305
|
)
|
|
302
306
|
);
|
|
303
307
|
|
|
304
|
-
const useStyles$
|
|
308
|
+
const useStyles$5 = makeStyles(() => ({
|
|
305
309
|
iconButton: {
|
|
306
310
|
color: "#0A6EBE",
|
|
307
311
|
width: 15,
|
|
@@ -309,7 +313,7 @@ const useStyles$2 = makeStyles(() => ({
|
|
|
309
313
|
}
|
|
310
314
|
}));
|
|
311
315
|
const CopyToClipboard = ({ copyValue }) => {
|
|
312
|
-
const classes = useStyles$
|
|
316
|
+
const classes = useStyles$5();
|
|
313
317
|
const copy = (content) => async () => {
|
|
314
318
|
try {
|
|
315
319
|
await navigator.clipboard.writeText(content || "");
|
|
@@ -320,7 +324,7 @@ const CopyToClipboard = ({ copyValue }) => {
|
|
|
320
324
|
return /* @__PURE__ */ React.createElement(Button, { onClick: copy(copyValue), variant: "text" }, /* @__PURE__ */ React.createElement(CopyIcon, { className: classes.iconButton }));
|
|
321
325
|
};
|
|
322
326
|
|
|
323
|
-
const useStyles$
|
|
327
|
+
const useStyles$4 = makeStyles((theme) => ({
|
|
324
328
|
container: {
|
|
325
329
|
width: "100%"
|
|
326
330
|
},
|
|
@@ -345,10 +349,8 @@ const useStyles$1 = makeStyles((theme) => ({
|
|
|
345
349
|
paddingRight: theme.spacing(0.5)
|
|
346
350
|
}
|
|
347
351
|
}));
|
|
348
|
-
const useGetWorkspaceTableColumns = ({
|
|
349
|
-
|
|
350
|
-
}) => {
|
|
351
|
-
const classes = useStyles$1();
|
|
352
|
+
const useGetWorkspaceTableColumns = () => {
|
|
353
|
+
const classes = useStyles$4();
|
|
352
354
|
const getProviderIcon = (name) => {
|
|
353
355
|
if (!name)
|
|
354
356
|
return /* @__PURE__ */ React.createElement(Aws, null);
|
|
@@ -368,16 +370,7 @@ const useGetWorkspaceTableColumns = ({
|
|
|
368
370
|
title: "Provider",
|
|
369
371
|
field: "col1",
|
|
370
372
|
width: "22%",
|
|
371
|
-
render: (row) => /* @__PURE__ */ React.createElement(
|
|
372
|
-
Link,
|
|
373
|
-
{
|
|
374
|
-
href: baseUrl,
|
|
375
|
-
target: "_blank",
|
|
376
|
-
className: classes.flexCenter,
|
|
377
|
-
key: row.id
|
|
378
|
-
},
|
|
379
|
-
/* @__PURE__ */ React.createElement("b", null, row.provider)
|
|
380
|
-
),
|
|
373
|
+
render: (row) => /* @__PURE__ */ React.createElement(Typography, { className: classes.smallGreyText }, row.provider),
|
|
381
374
|
customFilterAndSearch: (term, row) => {
|
|
382
375
|
var _a;
|
|
383
376
|
return ((_a = row.provider) != null ? _a : "").toLowerCase().includes(term.toLowerCase());
|
|
@@ -430,7 +423,7 @@ const useGetWorkspaceTableColumns = ({
|
|
|
430
423
|
}
|
|
431
424
|
}
|
|
432
425
|
],
|
|
433
|
-
[
|
|
426
|
+
[classes]
|
|
434
427
|
);
|
|
435
428
|
const outputsColumns = useMemo(
|
|
436
429
|
() => [
|
|
@@ -477,10 +470,71 @@ const useGetWorkspaceTableColumns = ({
|
|
|
477
470
|
);
|
|
478
471
|
return {
|
|
479
472
|
resourceColumns,
|
|
473
|
+
dataSourceColumns: resourceColumns,
|
|
474
|
+
// dataSource is also a resource column are same.
|
|
480
475
|
outputsColumns
|
|
481
476
|
};
|
|
482
477
|
};
|
|
483
478
|
|
|
479
|
+
const getWorkspaceTableConfig = (workspaceDataType, columns) => {
|
|
480
|
+
switch (workspaceDataType) {
|
|
481
|
+
case WorkspaceDataType.ResourceType:
|
|
482
|
+
return {
|
|
483
|
+
columns: columns.resourceColumns,
|
|
484
|
+
title: "Workspace Resources"
|
|
485
|
+
};
|
|
486
|
+
case WorkspaceDataType.OutputType:
|
|
487
|
+
return {
|
|
488
|
+
columns: columns.outputsColumns,
|
|
489
|
+
title: "Workspace Outputs"
|
|
490
|
+
};
|
|
491
|
+
case WorkspaceDataType.DataSourceType:
|
|
492
|
+
return {
|
|
493
|
+
columns: columns.dataSourceColumns,
|
|
494
|
+
title: "Workspace Data Sources"
|
|
495
|
+
};
|
|
496
|
+
default:
|
|
497
|
+
return { columns: [], title: "" };
|
|
498
|
+
}
|
|
499
|
+
};
|
|
500
|
+
|
|
501
|
+
const useStyles$3 = makeStyles((theme) => ({
|
|
502
|
+
emptyContainer: {
|
|
503
|
+
display: "flex",
|
|
504
|
+
flexDirection: "column",
|
|
505
|
+
alignItems: "center",
|
|
506
|
+
justifyContent: "center",
|
|
507
|
+
padding: theme.spacing(8, 2),
|
|
508
|
+
minHeight: 200
|
|
509
|
+
},
|
|
510
|
+
emptyText: {
|
|
511
|
+
color: theme.palette.text.secondary,
|
|
512
|
+
marginTop: theme.spacing(2)
|
|
513
|
+
},
|
|
514
|
+
loadingContainer: {
|
|
515
|
+
display: "flex",
|
|
516
|
+
justifyContent: "center",
|
|
517
|
+
alignItems: "center",
|
|
518
|
+
padding: theme.spacing(4),
|
|
519
|
+
minHeight: 200
|
|
520
|
+
}
|
|
521
|
+
}));
|
|
522
|
+
const TableEmptyState = ({
|
|
523
|
+
status,
|
|
524
|
+
hasData
|
|
525
|
+
}) => {
|
|
526
|
+
const localClasses = useStyles$3();
|
|
527
|
+
const isLoading = status === AsyncStatus.Init || status === AsyncStatus.Loading;
|
|
528
|
+
const isEmpty = status === AsyncStatus.Success && !hasData;
|
|
529
|
+
if (isLoading) {
|
|
530
|
+
return /* @__PURE__ */ React.createElement("div", { className: localClasses.loadingContainer }, /* @__PURE__ */ React.createElement(CircularProgress, null));
|
|
531
|
+
}
|
|
532
|
+
if (isEmpty) {
|
|
533
|
+
return /* @__PURE__ */ React.createElement(Box, { className: localClasses.emptyContainer }, /* @__PURE__ */ React.createElement(Typography, { variant: "h6", color: "textSecondary" }, "No data available"), /* @__PURE__ */ React.createElement(Typography, { variant: "body2", className: localClasses.emptyText }, "There are no items to display in this table."));
|
|
534
|
+
}
|
|
535
|
+
return null;
|
|
536
|
+
};
|
|
537
|
+
|
|
484
538
|
const WorkspaceTable = ({
|
|
485
539
|
setRefresh,
|
|
486
540
|
refresh,
|
|
@@ -491,12 +545,16 @@ const WorkspaceTable = ({
|
|
|
491
545
|
totalElements,
|
|
492
546
|
handleChangeRowsPerPage,
|
|
493
547
|
classes,
|
|
494
|
-
|
|
495
|
-
|
|
548
|
+
workspaceDataType,
|
|
549
|
+
onRowClick,
|
|
550
|
+
status
|
|
496
551
|
}) => {
|
|
497
|
-
const
|
|
498
|
-
|
|
499
|
-
|
|
552
|
+
const columnsData = useGetWorkspaceTableColumns();
|
|
553
|
+
const { columns, title } = useMemo(
|
|
554
|
+
() => getWorkspaceTableConfig(workspaceDataType, columnsData),
|
|
555
|
+
[workspaceDataType, columnsData]
|
|
556
|
+
);
|
|
557
|
+
const hasData = currTableData && currTableData.length > 0;
|
|
500
558
|
return /* @__PURE__ */ React.createElement(
|
|
501
559
|
Table,
|
|
502
560
|
{
|
|
@@ -505,14 +563,16 @@ const WorkspaceTable = ({
|
|
|
505
563
|
filtering: false,
|
|
506
564
|
emptyRowsWhenPaging: false,
|
|
507
565
|
pageSize,
|
|
508
|
-
|
|
566
|
+
search: true,
|
|
567
|
+
pageSizeOptions: [10, 25, 50],
|
|
568
|
+
rowStyle: { cursor: onRowClick ? "pointer" : "default" }
|
|
509
569
|
},
|
|
510
570
|
key: "id'",
|
|
511
571
|
data: currTableData != null ? currTableData : [],
|
|
512
|
-
columns
|
|
572
|
+
columns,
|
|
513
573
|
actions: [
|
|
514
574
|
{
|
|
515
|
-
icon: () => /* @__PURE__ */ React.createElement(
|
|
575
|
+
icon: () => /* @__PURE__ */ React.createElement(ReplayIcon, null),
|
|
516
576
|
tooltip: "Refresh Data",
|
|
517
577
|
isFreeAction: true,
|
|
518
578
|
onClick: () => {
|
|
@@ -520,8 +580,16 @@ const WorkspaceTable = ({
|
|
|
520
580
|
}
|
|
521
581
|
}
|
|
522
582
|
],
|
|
523
|
-
|
|
524
|
-
|
|
583
|
+
onRowClick: onRowClick ? (_event, _rowData) => onRowClick(_rowData) : void 0,
|
|
584
|
+
emptyContent: /* @__PURE__ */ React.createElement(
|
|
585
|
+
TableEmptyState,
|
|
586
|
+
{
|
|
587
|
+
status,
|
|
588
|
+
hasData: !!hasData,
|
|
589
|
+
classes
|
|
590
|
+
}
|
|
591
|
+
),
|
|
592
|
+
title,
|
|
525
593
|
page,
|
|
526
594
|
onPageChange: handleChangePage,
|
|
527
595
|
totalCount: totalElements,
|
|
@@ -530,6 +598,453 @@ const WorkspaceTable = ({
|
|
|
530
598
|
);
|
|
531
599
|
};
|
|
532
600
|
|
|
601
|
+
const getCurrTableData = (workspaceDataType, data) => {
|
|
602
|
+
switch (workspaceDataType) {
|
|
603
|
+
case WorkspaceDataType.ResourceType:
|
|
604
|
+
return data.resources || [];
|
|
605
|
+
case WorkspaceDataType.DataSourceType:
|
|
606
|
+
return data.dataSources || [];
|
|
607
|
+
case WorkspaceDataType.OutputType:
|
|
608
|
+
return data.outputs || [];
|
|
609
|
+
default:
|
|
610
|
+
return [];
|
|
611
|
+
}
|
|
612
|
+
};
|
|
613
|
+
const getTotalElements = (workspaceDataType, data) => {
|
|
614
|
+
var _a, _b, _c;
|
|
615
|
+
switch (workspaceDataType) {
|
|
616
|
+
case WorkspaceDataType.ResourceType:
|
|
617
|
+
return ((_a = data.resources) == null ? void 0 : _a.length) || 0;
|
|
618
|
+
case WorkspaceDataType.DataSourceType:
|
|
619
|
+
return ((_b = data.dataSources) == null ? void 0 : _b.length) || 0;
|
|
620
|
+
case WorkspaceDataType.OutputType:
|
|
621
|
+
return ((_c = data.outputs) == null ? void 0 : _c.length) || 0;
|
|
622
|
+
default:
|
|
623
|
+
return 0;
|
|
624
|
+
}
|
|
625
|
+
};
|
|
626
|
+
|
|
627
|
+
const useStyles$2 = makeStyles((theme) => ({
|
|
628
|
+
drawerContent: {
|
|
629
|
+
width: 1e3,
|
|
630
|
+
display: "flex",
|
|
631
|
+
flexDirection: "column",
|
|
632
|
+
height: "100%",
|
|
633
|
+
padding: theme.spacing(2),
|
|
634
|
+
overflow: "hidden"
|
|
635
|
+
},
|
|
636
|
+
drawerHeader: {
|
|
637
|
+
display: "flex",
|
|
638
|
+
alignItems: "center",
|
|
639
|
+
justifyContent: "space-between",
|
|
640
|
+
paddingLeft: theme.spacing(1),
|
|
641
|
+
paddingRight: theme.spacing(1),
|
|
642
|
+
flexShrink: 0
|
|
643
|
+
},
|
|
644
|
+
drawerTitle: {
|
|
645
|
+
fontWeight: "bold",
|
|
646
|
+
flex: 1
|
|
647
|
+
},
|
|
648
|
+
drawerSubHeader: {
|
|
649
|
+
display: "flex",
|
|
650
|
+
alignItems: "center",
|
|
651
|
+
padding: theme.spacing(1),
|
|
652
|
+
gap: theme.spacing(1),
|
|
653
|
+
flexShrink: 0
|
|
654
|
+
},
|
|
655
|
+
subHeaderItem: {
|
|
656
|
+
display: "flex",
|
|
657
|
+
alignItems: "center",
|
|
658
|
+
gap: theme.spacing(0.5)
|
|
659
|
+
},
|
|
660
|
+
subHeaderLabel: {
|
|
661
|
+
color: theme.palette.text.secondary
|
|
662
|
+
},
|
|
663
|
+
subHeaderValue: {
|
|
664
|
+
fontWeight: 600,
|
|
665
|
+
color: theme.palette.text.primary
|
|
666
|
+
},
|
|
667
|
+
subHeaderDivider: {
|
|
668
|
+
height: 16,
|
|
669
|
+
margin: `0 ${theme.spacing(0.5)}`
|
|
670
|
+
},
|
|
671
|
+
drawerBody: {
|
|
672
|
+
flex: 1,
|
|
673
|
+
minHeight: 0,
|
|
674
|
+
paddingLeft: theme.spacing(2),
|
|
675
|
+
paddingRight: theme.spacing(2),
|
|
676
|
+
paddingBottom: theme.spacing(2),
|
|
677
|
+
overflowY: "auto",
|
|
678
|
+
overflowX: "hidden"
|
|
679
|
+
},
|
|
680
|
+
searchField: {
|
|
681
|
+
marginBottom: theme.spacing(2)
|
|
682
|
+
},
|
|
683
|
+
searchFieldSticky: {
|
|
684
|
+
position: "sticky",
|
|
685
|
+
top: 0,
|
|
686
|
+
backgroundColor: theme.palette.background.paper,
|
|
687
|
+
zIndex: 10,
|
|
688
|
+
paddingTop: theme.spacing(2),
|
|
689
|
+
paddingBottom: theme.spacing(1),
|
|
690
|
+
marginBottom: theme.spacing(2),
|
|
691
|
+
marginLeft: theme.spacing(-2),
|
|
692
|
+
marginRight: theme.spacing(-2),
|
|
693
|
+
paddingLeft: theme.spacing(2),
|
|
694
|
+
paddingRight: theme.spacing(2)
|
|
695
|
+
},
|
|
696
|
+
valueHeader: {
|
|
697
|
+
fontWeight: 600,
|
|
698
|
+
textTransform: "uppercase",
|
|
699
|
+
marginBottom: theme.spacing(1),
|
|
700
|
+
color: theme.palette.text.secondary
|
|
701
|
+
},
|
|
702
|
+
attributeRow: {
|
|
703
|
+
backgroundColor: theme.palette.background.paper,
|
|
704
|
+
border: `1px solid ${theme.palette.divider}`,
|
|
705
|
+
borderRadius: 4,
|
|
706
|
+
marginBottom: theme.spacing(1),
|
|
707
|
+
padding: theme.spacing(1.5),
|
|
708
|
+
paddingBottom: theme.spacing(1),
|
|
709
|
+
position: "relative"
|
|
710
|
+
},
|
|
711
|
+
attributeRowDrift: {
|
|
712
|
+
backgroundColor: theme.palette.type === "dark" ? theme.palette.background.paper : "#fff3e0",
|
|
713
|
+
borderColor: "#ffb74d"
|
|
714
|
+
},
|
|
715
|
+
attributeKey: {
|
|
716
|
+
fontWeight: 500,
|
|
717
|
+
marginBottom: theme.spacing(0.75),
|
|
718
|
+
color: theme.palette.text.primary,
|
|
719
|
+
display: "flex",
|
|
720
|
+
alignItems: "center",
|
|
721
|
+
gap: theme.spacing(0.5),
|
|
722
|
+
fontFamily: "inherit"
|
|
723
|
+
},
|
|
724
|
+
attributeValue: {
|
|
725
|
+
fontWeight: 400,
|
|
726
|
+
color: theme.palette.text.primary,
|
|
727
|
+
flex: 1,
|
|
728
|
+
wordBreak: "break-word",
|
|
729
|
+
fontFamily: "inherit"
|
|
730
|
+
},
|
|
731
|
+
jsonValue: {
|
|
732
|
+
padding: theme.spacing(1),
|
|
733
|
+
borderRadius: 4,
|
|
734
|
+
overflow: "auto",
|
|
735
|
+
marginTop: theme.spacing(0.5),
|
|
736
|
+
border: `1px solid ${theme.palette.divider}`,
|
|
737
|
+
fontFamily: "inherit"
|
|
738
|
+
},
|
|
739
|
+
deletedBadge: {
|
|
740
|
+
fontWeight: 600,
|
|
741
|
+
textTransform: "uppercase",
|
|
742
|
+
backgroundColor: theme.palette.type === "dark" ? "rgba(244, 67, 54, 0.2)" : "#ffebee",
|
|
743
|
+
color: theme.palette.type === "dark" ? "#ffcdd2" : theme.palette.text.primary,
|
|
744
|
+
padding: "2px 6px",
|
|
745
|
+
borderRadius: 4,
|
|
746
|
+
display: "inline-flex",
|
|
747
|
+
alignItems: "center",
|
|
748
|
+
gap: 4,
|
|
749
|
+
marginLeft: theme.spacing(0.5)
|
|
750
|
+
},
|
|
751
|
+
valueComparison: {
|
|
752
|
+
marginTop: theme.spacing(1)
|
|
753
|
+
},
|
|
754
|
+
valueLabel: {
|
|
755
|
+
fontWeight: 600,
|
|
756
|
+
marginRight: theme.spacing(1),
|
|
757
|
+
color: theme.palette.text.primary
|
|
758
|
+
},
|
|
759
|
+
divider: {
|
|
760
|
+
margin: 0
|
|
761
|
+
},
|
|
762
|
+
copyButtonWrapper: {
|
|
763
|
+
position: "absolute",
|
|
764
|
+
top: theme.spacing(1),
|
|
765
|
+
right: 0,
|
|
766
|
+
zIndex: 1
|
|
767
|
+
},
|
|
768
|
+
iconContainer: {
|
|
769
|
+
marginRight: theme.spacing(1),
|
|
770
|
+
display: "inline-flex",
|
|
771
|
+
alignItems: "center"
|
|
772
|
+
},
|
|
773
|
+
iconContainerInline: {
|
|
774
|
+
display: "inline-flex",
|
|
775
|
+
alignItems: "center",
|
|
776
|
+
marginRight: theme.spacing(0.5)
|
|
777
|
+
}
|
|
778
|
+
}));
|
|
779
|
+
|
|
780
|
+
const isValueUnknown = (value) => {
|
|
781
|
+
return value === null || value === void 0 || value === "";
|
|
782
|
+
};
|
|
783
|
+
const formatValue = (value) => {
|
|
784
|
+
if (isValueUnknown(value)) {
|
|
785
|
+
return "Unknown";
|
|
786
|
+
}
|
|
787
|
+
if (typeof value === "object") {
|
|
788
|
+
return JSON.stringify(value, null, 2);
|
|
789
|
+
}
|
|
790
|
+
return String(value);
|
|
791
|
+
};
|
|
792
|
+
const filterAttributes = (attributes, driftAttributes, searchValue) => {
|
|
793
|
+
if (!attributes)
|
|
794
|
+
return [];
|
|
795
|
+
const attributesArray = Object.entries(attributes).map(([key, value]) => ({
|
|
796
|
+
key,
|
|
797
|
+
value,
|
|
798
|
+
driftValue: driftAttributes[key],
|
|
799
|
+
hasDrift: !!driftAttributes[key]
|
|
800
|
+
}));
|
|
801
|
+
if (!searchValue)
|
|
802
|
+
return attributesArray;
|
|
803
|
+
const lowerSearch = searchValue.toLowerCase();
|
|
804
|
+
return attributesArray.filter(
|
|
805
|
+
(item) => item.key.toLowerCase().includes(lowerSearch) || JSON.stringify(item.value).toLowerCase().includes(lowerSearch) || item.driftValue && JSON.stringify(item.driftValue).toLowerCase().includes(lowerSearch)
|
|
806
|
+
);
|
|
807
|
+
};
|
|
808
|
+
|
|
809
|
+
const getDriftIcon = (driftStatus) => {
|
|
810
|
+
switch (driftStatus == null ? void 0 : driftStatus.toLowerCase()) {
|
|
811
|
+
case "drifted":
|
|
812
|
+
return /* @__PURE__ */ React.createElement(ReplayIcon, { style: { fontSize: 18, color: "#ff9800" } });
|
|
813
|
+
case "changed":
|
|
814
|
+
return /* @__PURE__ */ React.createElement(ReplayIcon, { style: { fontSize: 18, color: "#ff9800" } });
|
|
815
|
+
case "deleted":
|
|
816
|
+
return /* @__PURE__ */ React.createElement(DeleteIcon, { style: { fontSize: 18, color: "#9e9e9e" } });
|
|
817
|
+
case "unchanged":
|
|
818
|
+
return /* @__PURE__ */ React.createElement(LensIcon, { style: { fontSize: 18, color: "#9e9e9e" } });
|
|
819
|
+
default:
|
|
820
|
+
return null;
|
|
821
|
+
}
|
|
822
|
+
};
|
|
823
|
+
|
|
824
|
+
const Header = ({ title, icon, onClose }) => {
|
|
825
|
+
const classes = useStyles$2();
|
|
826
|
+
return /* @__PURE__ */ React.createElement(Box, { className: classes.drawerHeader }, /* @__PURE__ */ React.createElement(Box, { display: "flex", alignItems: "center" }, icon && /* @__PURE__ */ React.createElement(Box, { className: classes.iconContainer }, icon), /* @__PURE__ */ React.createElement(Typography, { variant: "h6", className: classes.drawerTitle }, title)), /* @__PURE__ */ React.createElement(
|
|
827
|
+
IconButton,
|
|
828
|
+
{
|
|
829
|
+
onClick: onClose,
|
|
830
|
+
"aria-label": "close drawer",
|
|
831
|
+
edge: "end",
|
|
832
|
+
style: { padding: 0 }
|
|
833
|
+
},
|
|
834
|
+
/* @__PURE__ */ React.createElement(CloseIcon, null)
|
|
835
|
+
));
|
|
836
|
+
};
|
|
837
|
+
|
|
838
|
+
const SubHeader = ({ name, provider, module }) => {
|
|
839
|
+
const classes = useStyles$2();
|
|
840
|
+
if (!name && !provider && !module)
|
|
841
|
+
return null;
|
|
842
|
+
return /* @__PURE__ */ React.createElement(Box, { className: classes.drawerSubHeader }, /* @__PURE__ */ React.createElement(Box, { className: classes.subHeaderItem }, /* @__PURE__ */ React.createElement(Typography, { className: classes.subHeaderLabel }, "Name:"), /* @__PURE__ */ React.createElement(Typography, { className: classes.subHeaderValue }, name || "-")), /* @__PURE__ */ React.createElement(
|
|
843
|
+
Divider,
|
|
844
|
+
{
|
|
845
|
+
orientation: "vertical",
|
|
846
|
+
className: classes.subHeaderDivider,
|
|
847
|
+
flexItem: true
|
|
848
|
+
}
|
|
849
|
+
), /* @__PURE__ */ React.createElement(Box, { className: classes.subHeaderItem }, /* @__PURE__ */ React.createElement(Typography, { className: classes.subHeaderLabel }, "Provider:"), /* @__PURE__ */ React.createElement(Typography, { className: classes.subHeaderValue }, provider || "-")), /* @__PURE__ */ React.createElement(
|
|
850
|
+
Divider,
|
|
851
|
+
{
|
|
852
|
+
orientation: "vertical",
|
|
853
|
+
className: classes.subHeaderDivider,
|
|
854
|
+
flexItem: true
|
|
855
|
+
}
|
|
856
|
+
), /* @__PURE__ */ React.createElement(Box, { className: classes.subHeaderItem }, /* @__PURE__ */ React.createElement(Typography, { className: classes.subHeaderLabel }, "Module:"), /* @__PURE__ */ React.createElement(Typography, { className: classes.subHeaderValue }, module || "-")));
|
|
857
|
+
};
|
|
858
|
+
|
|
859
|
+
const SearchField = ({ value, onChange }) => {
|
|
860
|
+
const classes = useStyles$2();
|
|
861
|
+
const handleClear = () => {
|
|
862
|
+
onChange("");
|
|
863
|
+
};
|
|
864
|
+
return /* @__PURE__ */ React.createElement(Box, { className: classes.searchFieldSticky }, /* @__PURE__ */ React.createElement(
|
|
865
|
+
TextField,
|
|
866
|
+
{
|
|
867
|
+
placeholder: "Search",
|
|
868
|
+
variant: "outlined",
|
|
869
|
+
size: "small",
|
|
870
|
+
fullWidth: true,
|
|
871
|
+
value,
|
|
872
|
+
onChange: (e) => onChange(e.target.value),
|
|
873
|
+
InputProps: {
|
|
874
|
+
startAdornment: /* @__PURE__ */ React.createElement(InputAdornment, { position: "start" }, /* @__PURE__ */ React.createElement(SearchIcon, { fontSize: "small" })),
|
|
875
|
+
endAdornment: value && /* @__PURE__ */ React.createElement(InputAdornment, { position: "end" }, /* @__PURE__ */ React.createElement(
|
|
876
|
+
IconButton,
|
|
877
|
+
{
|
|
878
|
+
size: "small",
|
|
879
|
+
onClick: handleClear,
|
|
880
|
+
"aria-label": "clear search",
|
|
881
|
+
edge: "end"
|
|
882
|
+
},
|
|
883
|
+
/* @__PURE__ */ React.createElement(CloseIcon, { fontSize: "small" })
|
|
884
|
+
))
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
));
|
|
888
|
+
};
|
|
889
|
+
|
|
890
|
+
const useStyles$1 = makeStyles((theme) => ({
|
|
891
|
+
jsonValue: {
|
|
892
|
+
padding: theme.spacing(1),
|
|
893
|
+
borderRadius: 4,
|
|
894
|
+
overflow: "auto",
|
|
895
|
+
marginTop: theme.spacing(0.5),
|
|
896
|
+
border: `1px solid ${theme.palette.divider}`,
|
|
897
|
+
fontFamily: "inherit",
|
|
898
|
+
backgroundColor: theme.palette.type === "dark" ? theme.palette.background.default : "#F3F3FA"
|
|
899
|
+
},
|
|
900
|
+
jsonValueDrift: {
|
|
901
|
+
padding: theme.spacing(1),
|
|
902
|
+
borderRadius: 4,
|
|
903
|
+
overflow: "auto",
|
|
904
|
+
marginTop: theme.spacing(0.5),
|
|
905
|
+
border: `1px solid ${theme.palette.divider}`,
|
|
906
|
+
fontFamily: "inherit",
|
|
907
|
+
backgroundColor: theme.palette.type === "dark" ? theme.palette.background.default : "#fff3e0"
|
|
908
|
+
},
|
|
909
|
+
attributeValue: {
|
|
910
|
+
fontSize: "1rem",
|
|
911
|
+
fontWeight: 400,
|
|
912
|
+
color: theme.palette.text.primary,
|
|
913
|
+
flex: 1,
|
|
914
|
+
wordBreak: "break-word",
|
|
915
|
+
fontFamily: "inherit"
|
|
916
|
+
},
|
|
917
|
+
valueLabel: {
|
|
918
|
+
fontWeight: 600,
|
|
919
|
+
marginRight: theme.spacing(1),
|
|
920
|
+
color: theme.palette.text.primary
|
|
921
|
+
},
|
|
922
|
+
copyButtonWrapper: {
|
|
923
|
+
position: "absolute",
|
|
924
|
+
top: 0,
|
|
925
|
+
right: 0,
|
|
926
|
+
zIndex: 1
|
|
927
|
+
},
|
|
928
|
+
stringValue: {
|
|
929
|
+
padding: "8px",
|
|
930
|
+
borderRadius: 4,
|
|
931
|
+
border: `1px solid ${theme.palette.divider}`,
|
|
932
|
+
fontFamily: "inherit",
|
|
933
|
+
backgroundColor: theme.palette.type === "dark" ? theme.palette.background.default : "#F3F3FA"
|
|
934
|
+
},
|
|
935
|
+
stringValueDrift: {
|
|
936
|
+
padding: "8px",
|
|
937
|
+
borderRadius: 4,
|
|
938
|
+
border: `1px solid ${theme.palette.divider}`,
|
|
939
|
+
fontFamily: "inherit",
|
|
940
|
+
backgroundColor: theme.palette.type === "dark" ? theme.palette.background.default : "#fff3e0"
|
|
941
|
+
}
|
|
942
|
+
}));
|
|
943
|
+
const formatValueDisplay = (value, classes, isDrift = false) => {
|
|
944
|
+
if (typeof value === "object") {
|
|
945
|
+
return /* @__PURE__ */ React.createElement("pre", { className: isDrift ? classes.jsonValueDrift : classes.jsonValue }, JSON.stringify(value, null, 2));
|
|
946
|
+
}
|
|
947
|
+
return /* @__PURE__ */ React.createElement("div", { className: isDrift ? classes.stringValueDrift : classes.stringValue }, isValueUnknown(value) ? "Unknown" : String(value));
|
|
948
|
+
};
|
|
949
|
+
const ValueDisplay = ({
|
|
950
|
+
value,
|
|
951
|
+
isDrift = false,
|
|
952
|
+
showCopy = true,
|
|
953
|
+
label,
|
|
954
|
+
copyTopOffset
|
|
955
|
+
}) => {
|
|
956
|
+
const classes = useStyles$1();
|
|
957
|
+
return /* @__PURE__ */ React.createElement(Box, { style: { position: "relative", width: "100%" } }, showCopy && !isValueUnknown(value) && /* @__PURE__ */ React.createElement(
|
|
958
|
+
Box,
|
|
959
|
+
{
|
|
960
|
+
className: classes.copyButtonWrapper,
|
|
961
|
+
style: copyTopOffset ? { top: copyTopOffset } : {}
|
|
962
|
+
},
|
|
963
|
+
/* @__PURE__ */ React.createElement(CopyToClipboard, { copyValue: formatValue(value) })
|
|
964
|
+
), label && /* @__PURE__ */ React.createElement(Typography, { className: classes.valueLabel }, label), formatValueDisplay(value, classes, isDrift));
|
|
965
|
+
};
|
|
966
|
+
|
|
967
|
+
const AttributeList = ({
|
|
968
|
+
attributes,
|
|
969
|
+
driftStatus,
|
|
970
|
+
isDeleted,
|
|
971
|
+
allDeleted
|
|
972
|
+
}) => {
|
|
973
|
+
const classes = useStyles$2();
|
|
974
|
+
if (attributes.length === 0) {
|
|
975
|
+
return /* @__PURE__ */ React.createElement(Typography, { variant: "body2", color: "textSecondary" }, "No attributes found");
|
|
976
|
+
}
|
|
977
|
+
return /* @__PURE__ */ React.createElement(React.Fragment, null, attributes.map((item, index) => {
|
|
978
|
+
const hasDrift = item.hasDrift;
|
|
979
|
+
const driftValue = item.driftValue;
|
|
980
|
+
const attributeIcon = hasDrift && driftStatus ? getDriftIcon(driftStatus) : null;
|
|
981
|
+
return /* @__PURE__ */ React.createElement(
|
|
982
|
+
Box,
|
|
983
|
+
{
|
|
984
|
+
key: `${item.key}-${index}`,
|
|
985
|
+
className: hasDrift ? `${classes.attributeRow} ${classes.attributeRowDrift}` : classes.attributeRow
|
|
986
|
+
},
|
|
987
|
+
/* @__PURE__ */ React.createElement(Typography, { component: "div", className: classes.attributeKey }, attributeIcon && /* @__PURE__ */ React.createElement("span", { className: classes.iconContainerInline }, attributeIcon), item.key, (isDeleted || allDeleted && hasDrift) && /* @__PURE__ */ React.createElement("span", { className: classes.deletedBadge }, /* @__PURE__ */ React.createElement(DeleteIcon, { style: { fontSize: 12 } }), "DELETED")),
|
|
988
|
+
hasDrift && driftValue ? /* @__PURE__ */ React.createElement(Box, { className: classes.valueComparison }, /* @__PURE__ */ React.createElement(
|
|
989
|
+
ValueDisplay,
|
|
990
|
+
{
|
|
991
|
+
value: driftValue,
|
|
992
|
+
isDrift: true,
|
|
993
|
+
label: "Actual Value:",
|
|
994
|
+
copyTopOffset: "25px"
|
|
995
|
+
}
|
|
996
|
+
), /* @__PURE__ */ React.createElement(
|
|
997
|
+
ValueDisplay,
|
|
998
|
+
{
|
|
999
|
+
value: item.value,
|
|
1000
|
+
isDrift: true,
|
|
1001
|
+
label: "Expected Value:",
|
|
1002
|
+
copyTopOffset: "25px"
|
|
1003
|
+
}
|
|
1004
|
+
)) : /* @__PURE__ */ React.createElement(ValueDisplay, { value: item.value })
|
|
1005
|
+
);
|
|
1006
|
+
}));
|
|
1007
|
+
};
|
|
1008
|
+
|
|
1009
|
+
const ResourceDetailDrawer = ({
|
|
1010
|
+
open,
|
|
1011
|
+
onClose,
|
|
1012
|
+
width = 1e3,
|
|
1013
|
+
resource,
|
|
1014
|
+
title = ""
|
|
1015
|
+
}) => {
|
|
1016
|
+
const classes = useStyles$2();
|
|
1017
|
+
const [searchValue, setSearchValue] = useState("");
|
|
1018
|
+
const driftStatus = resource == null ? void 0 : resource.drift_status;
|
|
1019
|
+
const driftAttributes = useMemo(
|
|
1020
|
+
() => (resource == null ? void 0 : resource.drift_attributes) || {},
|
|
1021
|
+
[resource]
|
|
1022
|
+
);
|
|
1023
|
+
const isDeleted = driftStatus === "deleted";
|
|
1024
|
+
const allDeleted = isDeleted && Object.keys(driftAttributes).length > 0;
|
|
1025
|
+
const headerIcon = driftStatus ? getDriftIcon(driftStatus) : null;
|
|
1026
|
+
const filteredAttributes = useMemo(
|
|
1027
|
+
() => filterAttributes(resource == null ? void 0 : resource.attributes, driftAttributes, searchValue),
|
|
1028
|
+
[resource == null ? void 0 : resource.attributes, searchValue, driftAttributes]
|
|
1029
|
+
);
|
|
1030
|
+
return /* @__PURE__ */ React.createElement(Drawer, { anchor: "right", open, onClose }, /* @__PURE__ */ React.createElement("div", { className: classes.drawerContent, style: { width } }, /* @__PURE__ */ React.createElement(Header, { title, icon: headerIcon, onClose }), /* @__PURE__ */ React.createElement(
|
|
1031
|
+
SubHeader,
|
|
1032
|
+
{
|
|
1033
|
+
name: resource == null ? void 0 : resource.name,
|
|
1034
|
+
provider: resource == null ? void 0 : resource.provider,
|
|
1035
|
+
module: resource == null ? void 0 : resource.module
|
|
1036
|
+
}
|
|
1037
|
+
), /* @__PURE__ */ React.createElement(Divider, { className: classes.divider }), /* @__PURE__ */ React.createElement("div", { className: classes.drawerBody }, resource && /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(SearchField, { value: searchValue, onChange: setSearchValue }), /* @__PURE__ */ React.createElement(Typography, { className: classes.valueHeader }, "VALUE"), /* @__PURE__ */ React.createElement(
|
|
1038
|
+
AttributeList,
|
|
1039
|
+
{
|
|
1040
|
+
attributes: filteredAttributes,
|
|
1041
|
+
driftStatus,
|
|
1042
|
+
isDeleted,
|
|
1043
|
+
allDeleted
|
|
1044
|
+
}
|
|
1045
|
+
)))));
|
|
1046
|
+
};
|
|
1047
|
+
|
|
533
1048
|
const useStyles = makeStyles((theme) => ({
|
|
534
1049
|
container: {
|
|
535
1050
|
width: "100%"
|
|
@@ -570,11 +1085,13 @@ const useStyles = makeStyles((theme) => ({
|
|
|
570
1085
|
workspaceItem: { padding: "0.75rem", fontSize: "1rem" }
|
|
571
1086
|
}));
|
|
572
1087
|
var WorkspaceDataType = /* @__PURE__ */ ((WorkspaceDataType2) => {
|
|
573
|
-
WorkspaceDataType2[
|
|
574
|
-
WorkspaceDataType2[
|
|
1088
|
+
WorkspaceDataType2["ResourceType"] = "Resource";
|
|
1089
|
+
WorkspaceDataType2["DataSourceType"] = "DataSource";
|
|
1090
|
+
WorkspaceDataType2["OutputType"] = "Output";
|
|
575
1091
|
return WorkspaceDataType2;
|
|
576
1092
|
})(WorkspaceDataType || {});
|
|
577
1093
|
function WorkspaceList() {
|
|
1094
|
+
var _a, _b, _c;
|
|
578
1095
|
const [refresh, setRefresh] = useState(false);
|
|
579
1096
|
const classes = useStyles();
|
|
580
1097
|
const discoveryApi = useApi(discoveryApiRef);
|
|
@@ -587,21 +1104,20 @@ function WorkspaceList() {
|
|
|
587
1104
|
return harnessWorkspaceUrlObject[Object.keys(harnessWorkspaceUrlObject)[0]];
|
|
588
1105
|
});
|
|
589
1106
|
const [page, setPage] = useState(0);
|
|
590
|
-
const [pageSize, setPageSize] = useState(
|
|
1107
|
+
const [pageSize, setPageSize] = useState(10);
|
|
591
1108
|
const [selectedTab, setSelectedTab] = React.useState(
|
|
592
|
-
|
|
1109
|
+
"Resource" /* ResourceType */
|
|
593
1110
|
);
|
|
1111
|
+
const [selectedRowData, setSelectedRowData] = useState(null);
|
|
594
1112
|
const handleChange = (_event, resourceType) => {
|
|
595
1113
|
setSelectedTab(resourceType);
|
|
596
1114
|
};
|
|
597
|
-
const {
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
cleanedString: urlForWorkspace
|
|
604
|
-
} = useResourceSlugFromEntity(
|
|
1115
|
+
const drawerTitle = useMemo(() => {
|
|
1116
|
+
const driftStatus = (selectedRowData == null ? void 0 : selectedRowData.drift_status) || "";
|
|
1117
|
+
const capitalizedStatus = driftStatus ? driftStatus.charAt(0).toUpperCase() + driftStatus.slice(1) : "";
|
|
1118
|
+
return `${capitalizedStatus} ${selectedTab === "Resource" /* ResourceType */ ? "Resources" : "Data Sources"}`;
|
|
1119
|
+
}, [selectedRowData, selectedTab]);
|
|
1120
|
+
const { projectId, orgId, accountId, envFromUrl, workspaceId } = useResourceSlugFromEntity(
|
|
605
1121
|
isWorkspaceAnnotationPresent,
|
|
606
1122
|
selectedResourceUrl
|
|
607
1123
|
);
|
|
@@ -614,7 +1130,23 @@ function WorkspaceList() {
|
|
|
614
1130
|
envFromUrl,
|
|
615
1131
|
workspace: workspaceId || null
|
|
616
1132
|
});
|
|
617
|
-
const { resources, outputs } = workspaceData || {};
|
|
1133
|
+
const { resources, outputs, data_sources: dataSources } = workspaceData || {};
|
|
1134
|
+
const workspaceDataObj = useMemo(
|
|
1135
|
+
() => ({
|
|
1136
|
+
resources,
|
|
1137
|
+
outputs,
|
|
1138
|
+
dataSources
|
|
1139
|
+
}),
|
|
1140
|
+
[resources, outputs, dataSources]
|
|
1141
|
+
);
|
|
1142
|
+
const currTableData = useMemo(
|
|
1143
|
+
() => getCurrTableData(selectedTab, workspaceDataObj),
|
|
1144
|
+
[selectedTab, workspaceDataObj]
|
|
1145
|
+
);
|
|
1146
|
+
const totalElements = useMemo(
|
|
1147
|
+
() => getTotalElements(selectedTab, workspaceDataObj),
|
|
1148
|
+
[selectedTab, workspaceDataObj]
|
|
1149
|
+
);
|
|
618
1150
|
const handleWorkspaceChange = (event) => {
|
|
619
1151
|
setSelectedProjectUrl(event.target.value);
|
|
620
1152
|
setSelectedResourceUrl(harnessWorkspaceUrlObject[event.target.value]);
|
|
@@ -633,6 +1165,17 @@ function WorkspaceList() {
|
|
|
633
1165
|
},
|
|
634
1166
|
[setPage, setPageSize]
|
|
635
1167
|
);
|
|
1168
|
+
const handleRowClick = useCallback(
|
|
1169
|
+
(data) => {
|
|
1170
|
+
if (selectedTab === "Output" /* OutputType */)
|
|
1171
|
+
return;
|
|
1172
|
+
setSelectedRowData(data);
|
|
1173
|
+
},
|
|
1174
|
+
[selectedTab]
|
|
1175
|
+
);
|
|
1176
|
+
const handleDrawerClose = useCallback(() => {
|
|
1177
|
+
setSelectedRowData(null);
|
|
1178
|
+
}, []);
|
|
636
1179
|
const newWorkspaceDropdown = /* @__PURE__ */ React.createElement(FormControl, { fullWidth: true }, /* @__PURE__ */ React.createElement(
|
|
637
1180
|
InputLabel,
|
|
638
1181
|
{
|
|
@@ -689,24 +1232,53 @@ function WorkspaceList() {
|
|
|
689
1232
|
onChange: handleChange,
|
|
690
1233
|
"aria-label": "workspace_list_tabs"
|
|
691
1234
|
},
|
|
692
|
-
/* @__PURE__ */ React.createElement(
|
|
693
|
-
|
|
1235
|
+
/* @__PURE__ */ React.createElement(
|
|
1236
|
+
Tab,
|
|
1237
|
+
{
|
|
1238
|
+
label: `Resources (${(_a = resources == null ? void 0 : resources.length) != null ? _a : 0})`,
|
|
1239
|
+
value: "Resource" /* ResourceType */
|
|
1240
|
+
}
|
|
1241
|
+
),
|
|
1242
|
+
/* @__PURE__ */ React.createElement(
|
|
1243
|
+
Tab,
|
|
1244
|
+
{
|
|
1245
|
+
label: `Data Sources (${(_b = dataSources == null ? void 0 : dataSources.length) != null ? _b : 0})`,
|
|
1246
|
+
value: "DataSource" /* DataSourceType */
|
|
1247
|
+
}
|
|
1248
|
+
),
|
|
1249
|
+
/* @__PURE__ */ React.createElement(
|
|
1250
|
+
Tab,
|
|
1251
|
+
{
|
|
1252
|
+
label: `Outputs (${(_c = outputs == null ? void 0 : outputs.length) != null ? _c : 0})`,
|
|
1253
|
+
value: "Output" /* OutputType */
|
|
1254
|
+
}
|
|
1255
|
+
)
|
|
694
1256
|
), /* @__PURE__ */ React.createElement(
|
|
695
1257
|
WorkspaceTable,
|
|
696
1258
|
{
|
|
697
1259
|
setRefresh,
|
|
698
1260
|
refresh,
|
|
699
1261
|
pageSize,
|
|
700
|
-
currTableData
|
|
1262
|
+
currTableData,
|
|
701
1263
|
page,
|
|
702
1264
|
handleChangePage,
|
|
703
|
-
totalElements
|
|
1265
|
+
totalElements,
|
|
704
1266
|
handleChangeRowsPerPage,
|
|
705
1267
|
classes,
|
|
706
|
-
|
|
707
|
-
|
|
1268
|
+
workspaceDataType: selectedTab,
|
|
1269
|
+
onRowClick: handleRowClick,
|
|
1270
|
+
status: state
|
|
1271
|
+
}
|
|
1272
|
+
)), /* @__PURE__ */ React.createElement(
|
|
1273
|
+
ResourceDetailDrawer,
|
|
1274
|
+
{
|
|
1275
|
+
open: !!selectedRowData,
|
|
1276
|
+
resource: selectedRowData,
|
|
1277
|
+
onClose: handleDrawerClose,
|
|
1278
|
+
title: drawerTitle,
|
|
1279
|
+
width: 1200
|
|
708
1280
|
}
|
|
709
|
-
))
|
|
1281
|
+
));
|
|
710
1282
|
}
|
|
711
1283
|
|
|
712
1284
|
const isHarnessIacmAvailable = (entity) => {
|