@pagerduty/backstage-plugin 0.19.0 → 0.21.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.
Files changed (49) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/alpha/pages.esm.js +41 -4
  3. package/dist/alpha/pages.esm.js.map +1 -1
  4. package/dist/alpha/plugin.esm.js +4 -3
  5. package/dist/alpha/plugin.esm.js.map +1 -1
  6. package/dist/alpha.d.ts +105 -26
  7. package/dist/api/client.esm.js +145 -3
  8. package/dist/api/client.esm.js.map +1 -1
  9. package/dist/components/PagerDutyPage/AutomaticMappingsDialog.esm.js +86 -40
  10. package/dist/components/PagerDutyPage/AutomaticMappingsDialog.esm.js.map +1 -1
  11. package/dist/components/PagerDutyPage/ConfigurationPage.esm.js +119 -0
  12. package/dist/components/PagerDutyPage/ConfigurationPage.esm.js.map +1 -0
  13. package/dist/components/PagerDutyPage/CustomFieldModal.esm.js +152 -0
  14. package/dist/components/PagerDutyPage/CustomFieldModal.esm.js.map +1 -0
  15. package/dist/components/PagerDutyPage/CustomFields/ButtonTabs.esm.js +51 -0
  16. package/dist/components/PagerDutyPage/CustomFields/ButtonTabs.esm.js.map +1 -0
  17. package/dist/components/PagerDutyPage/CustomFields/CustomFieldsEmptyState.esm.js +46 -0
  18. package/dist/components/PagerDutyPage/CustomFields/CustomFieldsEmptyState.esm.js.map +1 -0
  19. package/dist/components/PagerDutyPage/CustomFields/CustomFieldsTabPanel.esm.js +154 -0
  20. package/dist/components/PagerDutyPage/CustomFields/CustomFieldsTabPanel.esm.js.map +1 -0
  21. package/dist/components/PagerDutyPage/CustomFields/DeleteCustomFieldDialog.esm.js +63 -0
  22. package/dist/components/PagerDutyPage/CustomFields/DeleteCustomFieldDialog.esm.js.map +1 -0
  23. package/dist/components/PagerDutyPage/CustomFields/SyncLogsFilters.esm.js +126 -0
  24. package/dist/components/PagerDutyPage/CustomFields/SyncLogsFilters.esm.js.map +1 -0
  25. package/dist/components/PagerDutyPage/CustomFields/SyncLogsTab.esm.js +285 -0
  26. package/dist/components/PagerDutyPage/CustomFields/SyncLogsTab.esm.js.map +1 -0
  27. package/dist/components/PagerDutyPage/CustomFields/customFieldErrors.esm.js +13 -0
  28. package/dist/components/PagerDutyPage/CustomFields/customFieldErrors.esm.js.map +1 -0
  29. package/dist/components/PagerDutyPage/CustomFields.esm.js +192 -0
  30. package/dist/components/PagerDutyPage/CustomFields.esm.js.map +1 -0
  31. package/dist/components/PagerDutyPage/MappingsDialog.esm.js +2 -0
  32. package/dist/components/PagerDutyPage/MappingsDialog.esm.js.map +1 -1
  33. package/dist/components/PagerDutyPage/MappingsTable/MappingsTable.esm.js +1 -1
  34. package/dist/components/PagerDutyPage/MappingsTable/MappingsTable.esm.js.map +1 -1
  35. package/dist/components/PagerDutyPage/MappingsTable/MappingsTableContent.esm.js +15 -3
  36. package/dist/components/PagerDutyPage/MappingsTable/MappingsTableContent.esm.js.map +1 -1
  37. package/dist/components/PagerDutyPage/MappingsTable/NameCell.esm.js +35 -0
  38. package/dist/components/PagerDutyPage/MappingsTable/NameCell.esm.js.map +1 -0
  39. package/dist/components/PagerDutyPage/MappingsTable/TableSkeleton.esm.js +26 -29
  40. package/dist/components/PagerDutyPage/MappingsTable/TableSkeleton.esm.js.map +1 -1
  41. package/dist/components/PagerDutyPage/ServiceMappingPage.esm.js +22 -0
  42. package/dist/components/PagerDutyPage/ServiceMappingPage.esm.js.map +1 -0
  43. package/dist/components/PagerDutyPage/index.esm.js +12 -127
  44. package/dist/components/PagerDutyPage/index.esm.js.map +1 -1
  45. package/dist/index.d.ts +60 -8
  46. package/dist/package.json.esm.js +1 -1
  47. package/package.json +17 -17
  48. package/dist/alpha/nav-items.esm.js +0 -21
  49. package/dist/alpha/nav-items.esm.js.map +0 -1
@@ -0,0 +1,152 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { useState, useEffect } from 'react';
3
+ import { Dialog, DialogHeader, DialogBody, Box, Text, Flex, TextField, DialogFooter, Button } from '@backstage/ui';
4
+ import { makeStyles, createStyles } from '@material-ui/core/styles';
5
+
6
+ const useStyles = makeStyles(
7
+ (theme) => createStyles({
8
+ generalErrorBox: {
9
+ backgroundColor: "rgba(211, 47, 47, 0.08)",
10
+ borderRadius: theme.shape.borderRadius,
11
+ padding: `${theme.spacing(1)}px ${theme.spacing(1.5)}px`,
12
+ marginBottom: theme.spacing(2)
13
+ },
14
+ fieldErrorText: {
15
+ color: theme.palette.error.main,
16
+ fontSize: "0.75rem",
17
+ margin: `${theme.spacing(0.5)}px 0 0 0`
18
+ },
19
+ descriptionLabel: {
20
+ display: "block",
21
+ fontSize: "0.875rem",
22
+ marginBottom: theme.spacing(0.75)
23
+ },
24
+ textarea: {
25
+ width: "100%",
26
+ boxSizing: "border-box",
27
+ padding: `${theme.spacing(1)}px ${theme.spacing(1.5)}px`,
28
+ fontSize: "0.875rem",
29
+ border: `1px solid ${theme.palette.divider}`,
30
+ borderRadius: theme.shape.borderRadius,
31
+ resize: "vertical",
32
+ fontFamily: "inherit",
33
+ color: "inherit",
34
+ backgroundColor: "transparent",
35
+ "&:disabled": {
36
+ backgroundColor: theme.palette.action.disabledBackground
37
+ }
38
+ }
39
+ })
40
+ );
41
+ const CustomFieldModal = ({
42
+ open,
43
+ saving,
44
+ error,
45
+ onClose,
46
+ onSave,
47
+ mode = "add",
48
+ initialValues
49
+ }) => {
50
+ const classes = useStyles();
51
+ const [formData, setFormData] = useState(
52
+ initialValues ?? { name: "", entityPath: "", description: "" }
53
+ );
54
+ const [localErrors, setLocalErrors] = useState({});
55
+ useEffect(() => {
56
+ if (open) {
57
+ setFormData(initialValues ?? { name: "", entityPath: "", description: "" });
58
+ setLocalErrors({});
59
+ }
60
+ }, [open]);
61
+ useEffect(() => {
62
+ setLocalErrors(error ?? {});
63
+ }, [error]);
64
+ const handleFormChange = (field) => (value) => {
65
+ setFormData((prev) => ({ ...prev, [field]: value }));
66
+ if (field in localErrors) {
67
+ setLocalErrors((prev) => ({ ...prev, [field]: void 0 }));
68
+ }
69
+ };
70
+ const handleClose = () => {
71
+ setFormData({ name: "", entityPath: "", description: "" });
72
+ setLocalErrors({});
73
+ onClose();
74
+ };
75
+ const handleSave = async () => {
76
+ await onSave(formData);
77
+ };
78
+ const getSaveLabel = () => {
79
+ return mode === "edit" ? "Save" : "Add";
80
+ };
81
+ const saveLabel = getSaveLabel();
82
+ return /* @__PURE__ */ jsxs(
83
+ Dialog,
84
+ {
85
+ isOpen: open,
86
+ onOpenChange: (isOpen) => !isOpen && handleClose(),
87
+ width: 500,
88
+ children: [
89
+ /* @__PURE__ */ jsx(DialogHeader, { children: mode === "edit" ? "Edit Custom Field" : "Add New Custom Field" }),
90
+ /* @__PURE__ */ jsxs(DialogBody, { children: [
91
+ localErrors.general && /* @__PURE__ */ jsx(Box, { className: classes.generalErrorBox, children: /* @__PURE__ */ jsx(Text, { variant: "body-small", color: "danger", children: localErrors.general }) }),
92
+ /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: "4", children: [
93
+ /* @__PURE__ */ jsxs(Box, { children: [
94
+ /* @__PURE__ */ jsx(
95
+ TextField,
96
+ {
97
+ label: "Name",
98
+ value: formData.name,
99
+ onChange: handleFormChange("name"),
100
+ isDisabled: saving,
101
+ isInvalid: !!localErrors.name
102
+ }
103
+ ),
104
+ localErrors.name && /* @__PURE__ */ jsx(Text, { as: "p", className: classes.fieldErrorText, children: localErrors.name })
105
+ ] }),
106
+ /* @__PURE__ */ jsxs(Box, { children: [
107
+ /* @__PURE__ */ jsx(
108
+ TextField,
109
+ {
110
+ label: "Entity Path",
111
+ value: formData.entityPath,
112
+ onChange: handleFormChange("entityPath"),
113
+ isDisabled: saving,
114
+ isInvalid: !!localErrors.entityPath
115
+ }
116
+ ),
117
+ localErrors.entityPath && /* @__PURE__ */ jsx(Text, { as: "p", className: classes.fieldErrorText, children: localErrors.entityPath })
118
+ ] }),
119
+ /* @__PURE__ */ jsxs(Box, { children: [
120
+ /* @__PURE__ */ jsx(Text, { as: "label", className: classes.descriptionLabel, children: "Description" }),
121
+ /* @__PURE__ */ jsx(
122
+ "textarea",
123
+ {
124
+ value: formData.description,
125
+ onChange: (e) => handleFormChange("description")(e.target.value),
126
+ disabled: saving,
127
+ rows: 5,
128
+ className: classes.textarea
129
+ }
130
+ )
131
+ ] })
132
+ ] })
133
+ ] }),
134
+ /* @__PURE__ */ jsx(DialogFooter, { children: /* @__PURE__ */ jsxs(Flex, { gap: "2", justify: "end", children: [
135
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", isDisabled: saving, onClick: handleClose, children: "Cancel" }),
136
+ /* @__PURE__ */ jsx(
137
+ Button,
138
+ {
139
+ variant: "primary",
140
+ onClick: handleSave,
141
+ isDisabled: !formData.name || !formData.entityPath || saving,
142
+ children: saveLabel
143
+ }
144
+ )
145
+ ] }) })
146
+ ]
147
+ }
148
+ );
149
+ };
150
+
151
+ export { CustomFieldModal };
152
+ //# sourceMappingURL=CustomFieldModal.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CustomFieldModal.esm.js","sources":["../../../src/components/PagerDutyPage/CustomFieldModal.tsx"],"sourcesContent":["import { useState, useEffect } from 'react';\nimport {\n Box,\n Button,\n Dialog,\n DialogBody,\n DialogFooter,\n DialogHeader,\n Flex,\n Text,\n TextField,\n} from '@backstage/ui';\nimport { makeStyles, createStyles } from '@material-ui/core/styles';\nimport { BackstageTheme } from '@backstage/theme';\n\nconst useStyles = makeStyles<BackstageTheme>(theme =>\n createStyles({\n generalErrorBox: {\n backgroundColor: 'rgba(211, 47, 47, 0.08)',\n borderRadius: theme.shape.borderRadius,\n padding: `${theme.spacing(1)}px ${theme.spacing(1.5)}px`,\n marginBottom: theme.spacing(2),\n },\n fieldErrorText: {\n color: theme.palette.error.main,\n fontSize: '0.75rem',\n margin: `${theme.spacing(0.5)}px 0 0 0`,\n },\n descriptionLabel: {\n display: 'block',\n fontSize: '0.875rem',\n marginBottom: theme.spacing(0.75),\n },\n textarea: {\n width: '100%',\n boxSizing: 'border-box' as const,\n padding: `${theme.spacing(1)}px ${theme.spacing(1.5)}px`,\n fontSize: '0.875rem',\n border: `1px solid ${theme.palette.divider}`,\n borderRadius: theme.shape.borderRadius,\n resize: 'vertical' as const,\n fontFamily: 'inherit',\n color: 'inherit',\n backgroundColor: 'transparent',\n '&:disabled': {\n backgroundColor: theme.palette.action.disabledBackground,\n },\n },\n }),\n);\n\ninterface FormData {\n name: string;\n entityPath: string;\n description: string;\n}\n\n/** @public */\nexport interface FieldErrors {\n name?: string;\n entityPath?: string;\n general?: string;\n}\n\ninterface CustomFieldModalProps {\n open: boolean;\n saving: boolean;\n error: FieldErrors | null;\n onClose: () => void;\n onSave: (data: FormData) => Promise<void>;\n mode?: 'add' | 'edit';\n initialValues?: FormData;\n}\n\n/** @public */\nexport const CustomFieldModal = ({\n open,\n saving,\n error,\n onClose,\n onSave,\n mode = 'add',\n initialValues,\n}: CustomFieldModalProps) => {\n const classes = useStyles();\n const [formData, setFormData] = useState<FormData>(\n initialValues ?? { name: '', entityPath: '', description: '' },\n );\n const [localErrors, setLocalErrors] = useState<FieldErrors>({});\n\n useEffect(() => {\n if (open) {\n setFormData(initialValues ?? { name: '', entityPath: '', description: '' });\n setLocalErrors({});\n }\n // initialValues is intentionally excluded: the form must only reset when the\n // modal opens, not on every re-render of the parent that creates a new object\n // reference while the modal is already open (e.g. while saving).\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [open]);\n\n useEffect(() => {\n setLocalErrors(error ?? {});\n }, [error]);\n\n const handleFormChange = (field: keyof FormData) => (value: string) => {\n setFormData(prev => ({ ...prev, [field]: value }));\n if (field in localErrors) {\n setLocalErrors(prev => ({ ...prev, [field]: undefined }));\n }\n };\n\n const handleClose = () => {\n setFormData({ name: '', entityPath: '', description: '' });\n setLocalErrors({});\n onClose();\n };\n\n const handleSave = async () => {\n await onSave(formData);\n };\n\n const getSaveLabel = () => {\n return mode === 'edit' ? 'Save' : 'Add';\n };\n const saveLabel = getSaveLabel();\n\n return (\n <Dialog\n isOpen={open}\n onOpenChange={isOpen => !isOpen && handleClose()}\n width={500}\n >\n <DialogHeader>\n {mode === 'edit' ? 'Edit Custom Field' : 'Add New Custom Field'}\n </DialogHeader>\n <DialogBody>\n {localErrors.general && (\n <Box className={classes.generalErrorBox}>\n <Text variant=\"body-small\" color=\"danger\">\n {localErrors.general}\n </Text>\n </Box>\n )}\n <Flex direction=\"column\" gap=\"4\">\n <Box>\n <TextField\n label=\"Name\"\n value={formData.name}\n onChange={handleFormChange('name')}\n isDisabled={saving}\n isInvalid={!!localErrors.name}\n />\n {localErrors.name && (\n <Text as=\"p\" className={classes.fieldErrorText}>\n {localErrors.name}\n </Text>\n )}\n </Box>\n <Box>\n <TextField\n label=\"Entity Path\"\n value={formData.entityPath}\n onChange={handleFormChange('entityPath')}\n isDisabled={saving}\n isInvalid={!!localErrors.entityPath}\n />\n {localErrors.entityPath && (\n <Text as=\"p\" className={classes.fieldErrorText}>\n {localErrors.entityPath}\n </Text>\n )}\n </Box>\n <Box>\n <Text as=\"label\" className={classes.descriptionLabel}>\n Description\n </Text>\n <textarea\n value={formData.description}\n onChange={e => handleFormChange('description')(e.target.value)}\n disabled={saving}\n rows={5}\n className={classes.textarea}\n />\n </Box>\n </Flex>\n </DialogBody>\n <DialogFooter>\n <Flex gap=\"2\" justify=\"end\">\n <Button variant=\"secondary\" isDisabled={saving} onClick={handleClose}>\n Cancel\n </Button>\n <Button\n variant=\"primary\"\n onClick={handleSave}\n isDisabled={!formData.name || !formData.entityPath || saving}\n >\n {saveLabel}\n </Button>\n </Flex>\n </DialogFooter>\n </Dialog>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { Flex, Button } from '@backstage/ui';
3
+ import { makeStyles } from '@material-ui/core';
4
+
5
+ const useStyles = makeStyles(() => ({
6
+ buttonFirst: {
7
+ borderTopRightRadius: "0px !important",
8
+ borderBottomRightRadius: "0px !important"
9
+ },
10
+ buttonMiddle: {
11
+ borderRadius: "0px !important"
12
+ },
13
+ buttonLast: {
14
+ borderTopLeftRadius: "0px !important",
15
+ borderBottomLeftRadius: "0px !important"
16
+ }
17
+ }));
18
+ function ButtonTabs({
19
+ items,
20
+ value,
21
+ onChange
22
+ }) {
23
+ const classes = useStyles();
24
+ return /* @__PURE__ */ jsx(Flex, { gap: "0", align: "center", children: items.map((item, index) => {
25
+ const isActive = item.key === value;
26
+ const isFirst = index === 0;
27
+ const isLast = index === items.length - 1;
28
+ const isSingle = isFirst && isLast;
29
+ let className;
30
+ if (!isSingle) {
31
+ if (isFirst) className = classes.buttonFirst;
32
+ else if (isLast) className = classes.buttonLast;
33
+ else className = classes.buttonMiddle;
34
+ }
35
+ return /* @__PURE__ */ jsx(
36
+ Button,
37
+ {
38
+ variant: isActive ? "primary" : "secondary",
39
+ size: "small",
40
+ onClick: () => onChange(item.key),
41
+ "aria-pressed": isActive,
42
+ className,
43
+ children: item.label
44
+ },
45
+ item.key
46
+ );
47
+ }) });
48
+ }
49
+
50
+ export { ButtonTabs };
51
+ //# sourceMappingURL=ButtonTabs.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ButtonTabs.esm.js","sources":["../../../../src/components/PagerDutyPage/CustomFields/ButtonTabs.tsx"],"sourcesContent":["import { ReactNode } from 'react';\nimport { Button, Flex } from '@backstage/ui';\nimport { makeStyles } from '@material-ui/core';\n\n/** @public */\nexport type ButtonTabItem<TKey extends string = string> = {\n key: TKey;\n label: ReactNode;\n};\n\ninterface ButtonTabsProps<TKey extends string = string> {\n items: ButtonTabItem<TKey>[];\n value: TKey;\n onChange: (key: TKey) => void;\n}\n\nconst useStyles = makeStyles(() => ({\n buttonFirst: {\n borderTopRightRadius: '0px !important',\n borderBottomRightRadius: '0px !important',\n },\n buttonMiddle: {\n borderRadius: '0px !important',\n },\n buttonLast: {\n borderTopLeftRadius: '0px !important',\n borderBottomLeftRadius: '0px !important',\n },\n}));\n\n/** @public */\nexport function ButtonTabs<TKey extends string = string>({\n items,\n value,\n onChange,\n}: ButtonTabsProps<TKey>) {\n const classes = useStyles();\n\n return (\n <Flex gap=\"0\" align=\"center\">\n {items.map((item, index) => {\n const isActive = item.key === value;\n const isFirst = index === 0;\n const isLast = index === items.length - 1;\n const isSingle = isFirst && isLast;\n\n let className: string | undefined;\n if (!isSingle) {\n if (isFirst) className = classes.buttonFirst;\n else if (isLast) className = classes.buttonLast;\n else className = classes.buttonMiddle;\n }\n\n return (\n <Button\n key={item.key}\n variant={isActive ? 'primary' : 'secondary'}\n size=\"small\"\n onClick={() => onChange(item.key)}\n aria-pressed={isActive}\n className={className}\n >\n {item.label}\n </Button>\n );\n })}\n </Flex>\n );\n}\n"],"names":[],"mappings":";;;;AAgBA,MAAM,SAAA,GAAY,WAAW,OAAO;AAAA,EAClC,WAAA,EAAa;AAAA,IACX,oBAAA,EAAsB,gBAAA;AAAA,IACtB,uBAAA,EAAyB;AAAA,GAC3B;AAAA,EACA,YAAA,EAAc;AAAA,IACZ,YAAA,EAAc;AAAA,GAChB;AAAA,EACA,UAAA,EAAY;AAAA,IACV,mBAAA,EAAqB,gBAAA;AAAA,IACrB,sBAAA,EAAwB;AAAA;AAE5B,CAAA,CAAE,CAAA;AAGK,SAAS,UAAA,CAAyC;AAAA,EACvD,KAAA;AAAA,EACA,KAAA;AAAA,EACA;AACF,CAAA,EAA0B;AACxB,EAAA,MAAM,UAAU,SAAA,EAAU;AAE1B,EAAA,uBACE,GAAA,CAAC,IAAA,EAAA,EAAK,GAAA,EAAI,GAAA,EAAI,KAAA,EAAM,UACjB,QAAA,EAAA,KAAA,CAAM,GAAA,CAAI,CAAC,IAAA,EAAM,KAAA,KAAU;AAC1B,IAAA,MAAM,QAAA,GAAW,KAAK,GAAA,KAAQ,KAAA;AAC9B,IAAA,MAAM,UAAU,KAAA,KAAU,CAAA;AAC1B,IAAA,MAAM,MAAA,GAAS,KAAA,KAAU,KAAA,CAAM,MAAA,GAAS,CAAA;AACxC,IAAA,MAAM,WAAW,OAAA,IAAW,MAAA;AAE5B,IAAA,IAAI,SAAA;AACJ,IAAA,IAAI,CAAC,QAAA,EAAU;AACb,MAAA,IAAI,OAAA,cAAqB,OAAA,CAAQ,WAAA;AAAA,WAAA,IACxB,MAAA,cAAoB,OAAA,CAAQ,UAAA;AAAA,uBACpB,OAAA,CAAQ,YAAA;AAAA,IAC3B;AAEA,IAAA,uBACE,GAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QAEC,OAAA,EAAS,WAAW,SAAA,GAAY,WAAA;AAAA,QAChC,IAAA,EAAK,OAAA;AAAA,QACL,OAAA,EAAS,MAAM,QAAA,CAAS,IAAA,CAAK,GAAG,CAAA;AAAA,QAChC,cAAA,EAAc,QAAA;AAAA,QACd,SAAA;AAAA,QAEC,QAAA,EAAA,IAAA,CAAK;AAAA,OAAA;AAAA,MAPD,IAAA,CAAK;AAAA,KAQZ;AAAA,EAEJ,CAAC,CAAA,EACH,CAAA;AAEJ;;;;"}
@@ -0,0 +1,46 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { Flex, TextField, Text } from '@backstage/ui';
3
+ import { ArrowForward } from '@mui/icons-material';
4
+ import { makeStyles, createStyles } from '@material-ui/core/styles';
5
+
6
+ const useStyles = makeStyles(
7
+ (theme) => createStyles({
8
+ container: {
9
+ padding: theme.spacing(6),
10
+ width: "100%",
11
+ textAlign: "center"
12
+ },
13
+ inputWrapper: {
14
+ width: "8rem",
15
+ filter: "brightness(0.88)"
16
+ },
17
+ inputWrapperDark: {
18
+ width: "8rem",
19
+ filter: "brightness(0.5)"
20
+ }
21
+ })
22
+ );
23
+ function CustomFieldsEmptyState({ message }) {
24
+ const classes = useStyles();
25
+ return /* @__PURE__ */ jsxs(
26
+ Flex,
27
+ {
28
+ direction: "column",
29
+ align: "center",
30
+ justify: "center",
31
+ gap: "3",
32
+ className: classes.container,
33
+ children: [
34
+ /* @__PURE__ */ jsxs(Flex, { align: "center", gap: "3", "aria-hidden": true, children: [
35
+ /* @__PURE__ */ jsx("div", { className: classes.inputWrapper, children: /* @__PURE__ */ jsx(TextField, { value: "", isDisabled: true, "aria-label": "" }) }),
36
+ /* @__PURE__ */ jsx(ArrowForward, { fontSize: "small" }),
37
+ /* @__PURE__ */ jsx("div", { className: classes.inputWrapperDark, children: /* @__PURE__ */ jsx(TextField, { value: "", isDisabled: true, "aria-label": "" }) })
38
+ ] }),
39
+ /* @__PURE__ */ jsx(Text, { variant: "body-medium", color: "secondary", children: message })
40
+ ]
41
+ }
42
+ );
43
+ }
44
+
45
+ export { CustomFieldsEmptyState };
46
+ //# sourceMappingURL=CustomFieldsEmptyState.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CustomFieldsEmptyState.esm.js","sources":["../../../../src/components/PagerDutyPage/CustomFields/CustomFieldsEmptyState.tsx"],"sourcesContent":["import { Flex, Text, TextField } from '@backstage/ui';\nimport { ArrowForward } from '@mui/icons-material';\nimport { makeStyles, createStyles } from '@material-ui/core/styles';\nimport { BackstageTheme } from '@backstage/theme';\n\nconst useStyles = makeStyles<BackstageTheme>(theme =>\n createStyles({\n container: {\n padding: theme.spacing(6),\n width: '100%',\n textAlign: 'center',\n },\n inputWrapper: {\n width: '8rem',\n filter: 'brightness(0.88)'\n },\n inputWrapperDark: {\n width: '8rem',\n filter: 'brightness(0.5)',\n },\n }),\n);\n\ninterface CustomFieldsEmptyStateProps {\n message: string;\n}\n\nexport function CustomFieldsEmptyState({ message }: CustomFieldsEmptyStateProps) {\n const classes = useStyles();\n return (\n <Flex\n direction=\"column\"\n align=\"center\"\n justify=\"center\"\n gap=\"3\"\n className={classes.container}\n >\n <Flex align=\"center\" gap=\"3\" aria-hidden>\n <div className={classes.inputWrapper}>\n <TextField value=\"\" isDisabled aria-label=\"\" />\n </div>\n <ArrowForward fontSize=\"small\" />\n <div className={classes.inputWrapperDark}>\n <TextField value=\"\" isDisabled aria-label=\"\" />\n </div>\n </Flex>\n <Text variant=\"body-medium\" color=\"secondary\">\n {message}\n </Text>\n </Flex>\n );\n}\n"],"names":[],"mappings":";;;;;AAKA,MAAM,SAAA,GAAY,UAAA;AAAA,EAA2B,WAC3C,YAAA,CAAa;AAAA,IACX,SAAA,EAAW;AAAA,MACT,OAAA,EAAS,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA;AAAA,MACxB,KAAA,EAAO,MAAA;AAAA,MACP,SAAA,EAAW;AAAA,KACb;AAAA,IACA,YAAA,EAAc;AAAA,MACZ,KAAA,EAAO,MAAA;AAAA,MACP,MAAA,EAAQ;AAAA,KACV;AAAA,IACA,gBAAA,EAAkB;AAAA,MAChB,KAAA,EAAO,MAAA;AAAA,MACP,MAAA,EAAQ;AAAA;AACV,GACD;AACH,CAAA;AAMO,SAAS,sBAAA,CAAuB,EAAE,OAAA,EAAQ,EAAgC;AAC/E,EAAA,MAAM,UAAU,SAAA,EAAU;AAC1B,EAAA,uBACE,IAAA;AAAA,IAAC,IAAA;AAAA,IAAA;AAAA,MACC,SAAA,EAAU,QAAA;AAAA,MACV,KAAA,EAAM,QAAA;AAAA,MACN,OAAA,EAAQ,QAAA;AAAA,MACR,GAAA,EAAI,GAAA;AAAA,MACJ,WAAW,OAAA,CAAQ,SAAA;AAAA,MAEnB,QAAA,EAAA;AAAA,wBAAA,IAAA,CAAC,QAAK,KAAA,EAAM,QAAA,EAAS,GAAA,EAAI,GAAA,EAAI,eAAW,IAAA,EACtC,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,OAAA,CAAQ,YAAA,EACtB,QAAA,kBAAA,GAAA,CAAC,SAAA,EAAA,EAAU,KAAA,EAAM,EAAA,EAAG,UAAA,EAAU,IAAA,EAAC,YAAA,EAAW,EAAA,EAAG,CAAA,EAC/C,CAAA;AAAA,0BACA,GAAA,CAAC,YAAA,EAAA,EAAa,QAAA,EAAS,OAAA,EAAQ,CAAA;AAAA,0BAC/B,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,OAAA,CAAQ,gBAAA,EACtB,QAAA,kBAAA,GAAA,CAAC,SAAA,EAAA,EAAU,KAAA,EAAM,EAAA,EAAG,UAAA,EAAU,IAAA,EAAC,YAAA,EAAW,IAAG,CAAA,EAC/C;AAAA,SAAA,EACF,CAAA;AAAA,4BACC,IAAA,EAAA,EAAK,OAAA,EAAQ,aAAA,EAAc,KAAA,EAAM,aAC/B,QAAA,EAAA,OAAA,EACH;AAAA;AAAA;AAAA,GACF;AAEJ;;;;"}
@@ -0,0 +1,154 @@
1
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
+ import { useState, useCallback, useMemo } from 'react';
3
+ import { useQueryClient, useQuery } from '@tanstack/react-query';
4
+ import { CellText, MenuTrigger, ButtonIcon, Menu, MenuItem, Table } from '@backstage/ui';
5
+ import { MoreVert, Edit, ToggleOn, ToggleOff, Delete } from '@mui/icons-material';
6
+ import Snackbar from '@mui/material/Snackbar';
7
+ import { Alert } from '@material-ui/lab';
8
+ import { useApi } from '@backstage/core-plugin-api';
9
+ import { pagerDutyApiRef } from '../../../api/client.esm.js';
10
+ import { CustomFieldModal } from '../CustomFieldModal.esm.js';
11
+ import { TableSkeleton } from '../MappingsTable/TableSkeleton.esm.js';
12
+ import { useAccountContext } from '../AccountContext.esm.js';
13
+ import { toFieldErrors } from './customFieldErrors.esm.js';
14
+ import { CustomFieldsEmptyState } from './CustomFieldsEmptyState.esm.js';
15
+ import { DeleteCustomFieldDialog } from './DeleteCustomFieldDialog.esm.js';
16
+
17
+ const CustomFieldsTabPanel = () => {
18
+ const pagerDutyApi = useApi(pagerDutyApiRef);
19
+ const queryClient = useQueryClient();
20
+ const { selectedAccount } = useAccountContext();
21
+ const account = selectedAccount || void 0;
22
+ const [selectedCustomField, setSelectedCustomField] = useState(null);
23
+ const [isEditModalOpen, setIsEditModalOpen] = useState(false);
24
+ const [editSaving, setEditSaving] = useState(false);
25
+ const [editError, setEditError] = useState(null);
26
+ const [toggleError, setToggleError] = useState(null);
27
+ const [fieldToDelete, setFieldToDelete] = useState(null);
28
+ const { data: customFieldsData, isLoading } = useQuery({
29
+ queryKey: ["pagerduty", "customFields", account ?? ""],
30
+ queryFn: () => pagerDutyApi.getCustomFields(account)
31
+ });
32
+ const customFields = customFieldsData?.customFields ?? [];
33
+ const handleOpenEditModal = useCallback((field) => {
34
+ setSelectedCustomField(field);
35
+ setEditError(null);
36
+ setIsEditModalOpen(true);
37
+ }, []);
38
+ const handleCloseEditModal = () => {
39
+ setIsEditModalOpen(false);
40
+ setSelectedCustomField(null);
41
+ setEditError(null);
42
+ };
43
+ const handleUpdateCustomField = async (formData) => {
44
+ if (!selectedCustomField) return;
45
+ const fieldId = selectedCustomField.id;
46
+ setEditSaving(true);
47
+ setEditError(null);
48
+ const result = await pagerDutyApi.updateCustomField(fieldId, formData, account);
49
+ if (result.status === "ok") {
50
+ queryClient.invalidateQueries({ queryKey: ["pagerduty", "customFields", account ?? ""] });
51
+ setIsEditModalOpen(false);
52
+ setSelectedCustomField(null);
53
+ } else {
54
+ setEditError(toFieldErrors(result.error));
55
+ }
56
+ setEditSaving(false);
57
+ };
58
+ const handleToggleEnabled = useCallback(async (field) => {
59
+ const nextEnabled = !field.pagerdutyCustomFieldEnabled;
60
+ const result = await pagerDutyApi.setCustomFieldEnabled(field.id, nextEnabled, account);
61
+ if (result.status === "ok") {
62
+ queryClient.invalidateQueries({ queryKey: ["pagerduty", "customFields", account ?? ""] });
63
+ } else {
64
+ setToggleError(result.error);
65
+ }
66
+ }, [pagerDutyApi, account, queryClient]);
67
+ const columnConfig = useMemo(() => [
68
+ { id: "name", label: "Custom Field", isRowHeader: true, isSortable: false, cell: (item) => /* @__PURE__ */ jsx(CellText, { title: item.pagerdutyCustomFieldDisplayName }) },
69
+ { id: "entityPath", label: "Entity Path", isRowHeader: false, isSortable: false, cell: (item) => /* @__PURE__ */ jsx(CellText, { title: item.backstageEntityMappingPath }) },
70
+ { id: "description", label: "Description", isRowHeader: false, isSortable: false, cell: (item) => /* @__PURE__ */ jsx(CellText, { title: item.description ?? "" }) },
71
+ {
72
+ id: "actions",
73
+ label: "",
74
+ isRowHeader: false,
75
+ isSortable: false,
76
+ cell: (item) => /* @__PURE__ */ jsx(CellText, { title: "", leadingIcon: /* @__PURE__ */ jsxs(MenuTrigger, { children: [
77
+ /* @__PURE__ */ jsx(ButtonIcon, { icon: /* @__PURE__ */ jsx(MoreVert, { fontSize: "small" }), "aria-label": "actions", variant: "tertiary", size: "small" }),
78
+ /* @__PURE__ */ jsxs(Menu, { children: [
79
+ /* @__PURE__ */ jsx(MenuItem, { iconStart: /* @__PURE__ */ jsx(Edit, { fontSize: "small" }), onAction: () => handleOpenEditModal(item), children: "Edit" }),
80
+ /* @__PURE__ */ jsx(
81
+ MenuItem,
82
+ {
83
+ iconStart: item.pagerdutyCustomFieldEnabled ? /* @__PURE__ */ jsx(ToggleOn, { fontSize: "small" }) : /* @__PURE__ */ jsx(ToggleOff, { fontSize: "small" }),
84
+ onAction: () => handleToggleEnabled(item),
85
+ children: item.pagerdutyCustomFieldEnabled ? "Disable" : "Enable"
86
+ }
87
+ ),
88
+ /* @__PURE__ */ jsx(MenuItem, { iconStart: /* @__PURE__ */ jsx(Delete, { fontSize: "small" }), onAction: () => setFieldToDelete(item), children: "Delete" })
89
+ ] })
90
+ ] }) })
91
+ }
92
+ ], [handleOpenEditModal, handleToggleEnabled]);
93
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
94
+ isLoading ? /* @__PURE__ */ jsx(
95
+ TableSkeleton,
96
+ {
97
+ columns: [
98
+ { label: "Custom Field", width: "30%" },
99
+ { label: "Entity Path", width: "25%" },
100
+ { label: "Description", width: "35%" },
101
+ { label: "", width: "10%" }
102
+ ]
103
+ }
104
+ ) : /* @__PURE__ */ jsx(
105
+ Table,
106
+ {
107
+ columnConfig,
108
+ data: customFields,
109
+ pagination: { type: "none" },
110
+ rowConfig: {
111
+ getIsDisabled: (item) => !item.pagerdutyCustomFieldEnabled
112
+ },
113
+ emptyState: /* @__PURE__ */ jsx(CustomFieldsEmptyState, { message: "No custom fields have been added" })
114
+ }
115
+ ),
116
+ /* @__PURE__ */ jsx(
117
+ CustomFieldModal,
118
+ {
119
+ open: isEditModalOpen,
120
+ saving: editSaving,
121
+ error: editError,
122
+ onClose: handleCloseEditModal,
123
+ onSave: handleUpdateCustomField,
124
+ mode: "edit",
125
+ initialValues: selectedCustomField ? {
126
+ name: selectedCustomField.pagerdutyCustomFieldDisplayName,
127
+ entityPath: selectedCustomField.backstageEntityMappingPath,
128
+ description: selectedCustomField.description ?? ""
129
+ } : void 0
130
+ }
131
+ ),
132
+ /* @__PURE__ */ jsx(
133
+ DeleteCustomFieldDialog,
134
+ {
135
+ field: fieldToDelete,
136
+ onClose: () => setFieldToDelete(null),
137
+ onSuccess: () => setFieldToDelete(null)
138
+ }
139
+ ),
140
+ /* @__PURE__ */ jsx(
141
+ Snackbar,
142
+ {
143
+ open: toggleError !== null,
144
+ autoHideDuration: 5e3,
145
+ onClose: () => setToggleError(null),
146
+ anchorOrigin: { vertical: "bottom", horizontal: "right" },
147
+ children: /* @__PURE__ */ jsx(Alert, { severity: "error", onClose: () => setToggleError(null), children: toggleError })
148
+ }
149
+ )
150
+ ] });
151
+ };
152
+
153
+ export { CustomFieldsTabPanel };
154
+ //# sourceMappingURL=CustomFieldsTabPanel.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CustomFieldsTabPanel.esm.js","sources":["../../../../src/components/PagerDutyPage/CustomFields/CustomFieldsTabPanel.tsx"],"sourcesContent":["import { useState, useMemo, useCallback } from 'react';\nimport { useQuery, useQueryClient } from '@tanstack/react-query';\nimport {\n ButtonIcon,\n CellText,\n Menu,\n MenuItem,\n MenuTrigger,\n Table,\n type ColumnConfig,\n} from '@backstage/ui';\nimport { Delete, Edit, MoreVert, ToggleOff, ToggleOn } from '@mui/icons-material';\nimport Snackbar from '@mui/material/Snackbar';\nimport { Alert } from '@material-ui/lab';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { pagerDutyApiRef } from '../../../api';\nimport { BackstageCustomField } from '@pagerduty/backstage-plugin-common';\nimport { CustomFieldModal, FieldErrors } from '../CustomFieldModal';\nimport { TableSkeleton } from '../MappingsTable/TableSkeleton';\nimport { useAccountContext } from '../AccountContext';\nimport { toFieldErrors } from './customFieldErrors';\nimport { CustomFieldsEmptyState } from './CustomFieldsEmptyState';\nimport { DeleteCustomFieldDialog } from './DeleteCustomFieldDialog';\n\nexport const CustomFieldsTabPanel = () => {\n const pagerDutyApi = useApi(pagerDutyApiRef);\n const queryClient = useQueryClient();\n const { selectedAccount } = useAccountContext();\n const account = selectedAccount || undefined;\n const [selectedCustomField, setSelectedCustomField] = useState<BackstageCustomField | null>(null);\n const [isEditModalOpen, setIsEditModalOpen] = useState(false);\n const [editSaving, setEditSaving] = useState(false);\n const [editError, setEditError] = useState<FieldErrors | null>(null);\n const [toggleError, setToggleError] = useState<string | null>(null);\n const [fieldToDelete, setFieldToDelete] = useState<BackstageCustomField | null>(null);\n\n const { data: customFieldsData, isLoading } = useQuery({\n queryKey: ['pagerduty', 'customFields', account ?? ''],\n queryFn: () => pagerDutyApi.getCustomFields(account),\n });\n const customFields = customFieldsData?.customFields ?? [];\n\n const handleOpenEditModal = useCallback((field: BackstageCustomField) => {\n setSelectedCustomField(field);\n setEditError(null);\n setIsEditModalOpen(true);\n }, []);\n\n const handleCloseEditModal = () => {\n setIsEditModalOpen(false);\n setSelectedCustomField(null);\n setEditError(null);\n };\n\n const handleUpdateCustomField = async (formData: { name: string; entityPath: string; description: string }) => {\n if (!selectedCustomField) return;\n const fieldId = selectedCustomField.id;\n setEditSaving(true);\n setEditError(null);\n const result = await pagerDutyApi.updateCustomField(fieldId, formData, account);\n if (result.status === 'ok') {\n queryClient.invalidateQueries({ queryKey: ['pagerduty', 'customFields', account ?? ''] });\n setIsEditModalOpen(false);\n setSelectedCustomField(null);\n } else {\n setEditError(toFieldErrors(result.error));\n }\n setEditSaving(false);\n };\n\n const handleToggleEnabled = useCallback(async (field: BackstageCustomField) => {\n const nextEnabled = !field.pagerdutyCustomFieldEnabled;\n const result = await pagerDutyApi.setCustomFieldEnabled(field.id, nextEnabled, account);\n if (result.status === 'ok') {\n queryClient.invalidateQueries({ queryKey: ['pagerduty', 'customFields', account ?? ''] });\n } else {\n setToggleError(result.error);\n }\n }, [pagerDutyApi, account, queryClient]);\n\n const columnConfig: ColumnConfig<BackstageCustomField>[] = useMemo(() => [\n { id: 'name', label: 'Custom Field', isRowHeader: true, isSortable: false, cell: item => <CellText title={item.pagerdutyCustomFieldDisplayName} /> },\n { id: 'entityPath', label: 'Entity Path', isRowHeader: false, isSortable: false, cell: item => <CellText title={item.backstageEntityMappingPath} /> },\n { id: 'description', label: 'Description', isRowHeader: false, isSortable: false, cell: item => <CellText title={item.description ?? ''} /> },\n {\n id: 'actions', label: '', isRowHeader: false, isSortable: false,\n cell: item => (\n <CellText title=\"\" leadingIcon={\n <MenuTrigger>\n <ButtonIcon icon={<MoreVert fontSize=\"small\" />} aria-label=\"actions\" variant=\"tertiary\" size=\"small\" />\n <Menu>\n <MenuItem iconStart={<Edit fontSize=\"small\" />} onAction={() => handleOpenEditModal(item)}>Edit</MenuItem>\n <MenuItem\n iconStart={\n item.pagerdutyCustomFieldEnabled ? (\n <ToggleOn fontSize=\"small\" />\n ) : (\n <ToggleOff fontSize=\"small\" />\n )\n }\n onAction={() => handleToggleEnabled(item)}\n >\n {item.pagerdutyCustomFieldEnabled ? 'Disable' : 'Enable'}\n </MenuItem>\n <MenuItem iconStart={<Delete fontSize=\"small\" />} onAction={() => setFieldToDelete(item)}>Delete</MenuItem>\n </Menu>\n </MenuTrigger>\n } />\n ),\n },\n ], [handleOpenEditModal, handleToggleEnabled]);\n\n return (\n <>\n {isLoading ? (\n <TableSkeleton\n columns={[\n { label: 'Custom Field', width: '30%' },\n { label: 'Entity Path', width: '25%' },\n { label: 'Description', width: '35%' },\n { label: '', width: '10%' },\n ]}\n />\n ) : (\n <Table\n columnConfig={columnConfig}\n data={customFields}\n pagination={{ type: 'none' }}\n rowConfig={{\n getIsDisabled: item => !item.pagerdutyCustomFieldEnabled,\n }}\n emptyState={\n <CustomFieldsEmptyState message='No custom fields have been added' />\n }\n />\n )}\n\n <CustomFieldModal\n open={isEditModalOpen}\n saving={editSaving}\n error={editError}\n onClose={handleCloseEditModal}\n onSave={handleUpdateCustomField}\n mode=\"edit\"\n initialValues={selectedCustomField ? {\n name: selectedCustomField.pagerdutyCustomFieldDisplayName,\n entityPath: selectedCustomField.backstageEntityMappingPath,\n description: selectedCustomField.description ?? '',\n } : undefined}\n />\n\n <DeleteCustomFieldDialog\n field={fieldToDelete}\n onClose={() => setFieldToDelete(null)}\n onSuccess={() => setFieldToDelete(null)}\n />\n\n <Snackbar\n open={toggleError !== null}\n autoHideDuration={5000}\n onClose={() => setToggleError(null)}\n anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}\n >\n <Alert severity=\"error\" onClose={() => setToggleError(null)}>\n {toggleError}\n </Alert>\n </Snackbar>\n </>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { useState } from 'react';
3
+ import { useQueryClient } from '@tanstack/react-query';
4
+ import { Dialog, DialogHeader, DialogBody, Box, Text, DialogFooter, Flex, Button } from '@backstage/ui';
5
+ import { useApi } from '@backstage/core-plugin-api';
6
+ import { pagerDutyApiRef } from '../../../api/client.esm.js';
7
+ import { useAccountContext } from '../AccountContext.esm.js';
8
+
9
+ const DeleteCustomFieldDialog = ({
10
+ field,
11
+ onClose,
12
+ onSuccess
13
+ }) => {
14
+ const pagerDutyApi = useApi(pagerDutyApiRef);
15
+ const queryClient = useQueryClient();
16
+ const { selectedAccount } = useAccountContext();
17
+ const account = selectedAccount || void 0;
18
+ const [deleting, setDeleting] = useState(false);
19
+ const [error, setError] = useState(null);
20
+ const handleClose = () => {
21
+ setError(null);
22
+ onClose();
23
+ };
24
+ const handleConfirm = async () => {
25
+ if (!field) return;
26
+ setDeleting(true);
27
+ setError(null);
28
+ const result = await pagerDutyApi.deleteCustomField(field.id, account);
29
+ if (result.status === "ok") {
30
+ queryClient.invalidateQueries({ queryKey: ["pagerduty", "customFields", account ?? ""] });
31
+ onSuccess();
32
+ } else {
33
+ setError(result.error);
34
+ }
35
+ setDeleting(false);
36
+ };
37
+ return /* @__PURE__ */ jsxs(
38
+ Dialog,
39
+ {
40
+ isOpen: field !== null,
41
+ onOpenChange: (isOpen) => !isOpen && handleClose(),
42
+ width: 440,
43
+ children: [
44
+ /* @__PURE__ */ jsx(DialogHeader, { children: "Delete Custom Field" }),
45
+ /* @__PURE__ */ jsxs(DialogBody, { children: [
46
+ error && /* @__PURE__ */ jsx(Box, { style: { marginBottom: 16 }, children: /* @__PURE__ */ jsx(Text, { variant: "body-small", color: "danger", children: error }) }),
47
+ /* @__PURE__ */ jsxs(Text, { children: [
48
+ "Are you sure you want to delete ",
49
+ /* @__PURE__ */ jsx("strong", { children: field?.pagerdutyCustomFieldDisplayName }),
50
+ "? This will remove the custom field from PagerDuty and reclaim its slot."
51
+ ] })
52
+ ] }),
53
+ /* @__PURE__ */ jsx(DialogFooter, { children: /* @__PURE__ */ jsxs(Flex, { gap: "2", justify: "end", children: [
54
+ /* @__PURE__ */ jsx(Button, { variant: "secondary", isDisabled: deleting, onClick: handleClose, children: "Cancel" }),
55
+ /* @__PURE__ */ jsx(Button, { variant: "primary", isDisabled: deleting, onClick: handleConfirm, children: deleting ? "Deleting\u2026" : "Delete" })
56
+ ] }) })
57
+ ]
58
+ }
59
+ );
60
+ };
61
+
62
+ export { DeleteCustomFieldDialog };
63
+ //# sourceMappingURL=DeleteCustomFieldDialog.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DeleteCustomFieldDialog.esm.js","sources":["../../../../src/components/PagerDutyPage/CustomFields/DeleteCustomFieldDialog.tsx"],"sourcesContent":["import { useState } from 'react';\nimport { useQueryClient } from '@tanstack/react-query';\nimport {\n Box,\n Button,\n Dialog,\n DialogBody,\n DialogFooter,\n DialogHeader,\n Flex,\n Text,\n} from '@backstage/ui';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { BackstageCustomField } from '@pagerduty/backstage-plugin-common';\nimport { pagerDutyApiRef } from '../../../api';\nimport { useAccountContext } from '../AccountContext';\n\ninterface DeleteCustomFieldDialogProps {\n field: BackstageCustomField | null;\n onClose: () => void;\n onSuccess: () => void;\n}\n\nexport const DeleteCustomFieldDialog = ({\n field,\n onClose,\n onSuccess,\n}: DeleteCustomFieldDialogProps) => {\n const pagerDutyApi = useApi(pagerDutyApiRef);\n const queryClient = useQueryClient();\n const { selectedAccount } = useAccountContext();\n const account = selectedAccount || undefined;\n\n const [deleting, setDeleting] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const handleClose = () => {\n setError(null);\n onClose();\n };\n\n const handleConfirm = async () => {\n if (!field) return;\n setDeleting(true);\n setError(null);\n const result = await pagerDutyApi.deleteCustomField(field.id, account);\n if (result.status === 'ok') {\n queryClient.invalidateQueries({ queryKey: ['pagerduty', 'customFields', account ?? ''] });\n onSuccess();\n } else {\n setError(result.error);\n }\n setDeleting(false);\n };\n\n return (\n <Dialog\n isOpen={field !== null}\n onOpenChange={isOpen => !isOpen && handleClose()}\n width={440}\n >\n <DialogHeader>Delete Custom Field</DialogHeader>\n <DialogBody>\n {error && (\n <Box style={{ marginBottom: 16 }}>\n <Text variant=\"body-small\" color=\"danger\">{error}</Text>\n </Box>\n )}\n <Text>\n Are you sure you want to delete <strong>{field?.pagerdutyCustomFieldDisplayName}</strong>? This will remove the custom field from PagerDuty and reclaim its slot.\n </Text>\n </DialogBody>\n <DialogFooter>\n <Flex gap=\"2\" justify=\"end\">\n <Button variant=\"secondary\" isDisabled={deleting} onClick={handleClose}>\n Cancel\n </Button>\n <Button variant=\"primary\" isDisabled={deleting} onClick={handleConfirm}>\n {deleting ? 'Deleting…' : 'Delete'}\n </Button>\n </Flex>\n </DialogFooter>\n </Dialog>\n );\n};\n"],"names":[],"mappings":";;;;;;;;AAuBO,MAAM,0BAA0B,CAAC;AAAA,EACtC,KAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF,CAAA,KAAoC;AAClC,EAAA,MAAM,YAAA,GAAe,OAAO,eAAe,CAAA;AAC3C,EAAA,MAAM,cAAc,cAAA,EAAe;AACnC,EAAA,MAAM,EAAE,eAAA,EAAgB,GAAI,iBAAA,EAAkB;AAC9C,EAAA,MAAM,UAAU,eAAA,IAAmB,MAAA;AAEnC,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,CAAA,GAAI,SAAS,KAAK,CAAA;AAC9C,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAAwB,IAAI,CAAA;AAEtD,EAAA,MAAM,cAAc,MAAM;AACxB,IAAA,QAAA,CAAS,IAAI,CAAA;AACb,IAAA,OAAA,EAAQ;AAAA,EACV,CAAA;AAEA,EAAA,MAAM,gBAAgB,YAAY;AAChC,IAAA,IAAI,CAAC,KAAA,EAAO;AACZ,IAAA,WAAA,CAAY,IAAI,CAAA;AAChB,IAAA,QAAA,CAAS,IAAI,CAAA;AACb,IAAA,MAAM,SAAS,MAAM,YAAA,CAAa,iBAAA,CAAkB,KAAA,CAAM,IAAI,OAAO,CAAA;AACrE,IAAA,IAAI,MAAA,CAAO,WAAW,IAAA,EAAM;AAC1B,MAAA,WAAA,CAAY,iBAAA,CAAkB,EAAE,QAAA,EAAU,CAAC,aAAa,cAAA,EAAgB,OAAA,IAAW,EAAE,CAAA,EAAG,CAAA;AACxF,MAAA,SAAA,EAAU;AAAA,IACZ,CAAA,MAAO;AACL,MAAA,QAAA,CAAS,OAAO,KAAK,CAAA;AAAA,IACvB;AACA,IAAA,WAAA,CAAY,KAAK,CAAA;AAAA,EACnB,CAAA;AAEA,EAAA,uBACE,IAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,QAAQ,KAAA,KAAU,IAAA;AAAA,MAClB,YAAA,EAAc,CAAA,MAAA,KAAU,CAAC,MAAA,IAAU,WAAA,EAAY;AAAA,MAC/C,KAAA,EAAO,GAAA;AAAA,MAEP,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAC,gBAAa,QAAA,EAAA,qBAAA,EAAmB,CAAA;AAAA,6BAChC,UAAA,EAAA,EACE,QAAA,EAAA;AAAA,UAAA,KAAA,oBACC,GAAA,CAAC,GAAA,EAAA,EAAI,KAAA,EAAO,EAAE,cAAc,EAAA,EAAG,EAC7B,QAAA,kBAAA,GAAA,CAAC,IAAA,EAAA,EAAK,OAAA,EAAQ,YAAA,EAAa,KAAA,EAAM,QAAA,EAAU,iBAAM,CAAA,EACnD,CAAA;AAAA,+BAED,IAAA,EAAA,EAAK,QAAA,EAAA;AAAA,YAAA,kCAAA;AAAA,4BAC4B,GAAA,CAAC,QAAA,EAAA,EAAQ,QAAA,EAAA,KAAA,EAAO,+BAAA,EAAgC,CAAA;AAAA,YAAS;AAAA,WAAA,EAC3F;AAAA,SAAA,EACF,CAAA;AAAA,4BACC,YAAA,EAAA,EACC,QAAA,kBAAA,IAAA,CAAC,QAAK,GAAA,EAAI,GAAA,EAAI,SAAQ,KAAA,EACpB,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,UAAO,OAAA,EAAQ,WAAA,EAAY,YAAY,QAAA,EAAU,OAAA,EAAS,aAAa,QAAA,EAAA,QAAA,EAExE,CAAA;AAAA,0BACA,GAAA,CAAC,MAAA,EAAA,EAAO,OAAA,EAAQ,SAAA,EAAU,UAAA,EAAY,UAAU,OAAA,EAAS,aAAA,EACtD,QAAA,EAAA,QAAA,GAAW,gBAAA,GAAc,QAAA,EAC5B;AAAA,SAAA,EACF,CAAA,EACF;AAAA;AAAA;AAAA,GACF;AAEJ;;;;"}