@evenicanpm/admin-integrate 1.1.0 → 1.2.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 (101) hide show
  1. package/documents/ProcessSchedule/fragments.ts +24 -0
  2. package/documents/ProcessSchedule/read.ts +12 -0
  3. package/documents/ProcessScheduleGroup/fragments.ts +29 -0
  4. package/documents/ProcessScheduleGroup/read.ts +12 -0
  5. package/documents/ScheduledProcess/fragments.ts +24 -0
  6. package/documents/ScheduledProcess/list.ts +27 -0
  7. package/package.json +21 -17
  8. package/src/api/dashboard/queries/get-process-executions.query.ts +33 -36
  9. package/src/api/dashboard/queries/get-process-executions.server.ts +4 -4
  10. package/src/api/scheduler/queries/get-process-schedule-group-details.query.ts +45 -0
  11. package/src/api/scheduler/queries/get-process-schedule-group-details.server.ts +14 -0
  12. package/src/api/scheduler/queries/get-process-schedule.query.ts +45 -0
  13. package/src/api/scheduler/queries/get-process-schedule.server.ts +14 -0
  14. package/src/api/scheduler/queries/get-scheduled-processes.query.ts +45 -0
  15. package/src/api/scheduler/queries/get-scheduled-processes.server.ts +11 -0
  16. package/src/api/scheduler/queries/index.ts +3 -0
  17. package/src/components/breadcrumbs/breadcrumbs.tsx +23 -26
  18. package/src/components/breadcrumbs/index.ts +1 -1
  19. package/src/components/breadcrumbs/types.tsx +4 -0
  20. package/src/components/button/outlined-icon-button.tsx +26 -38
  21. package/src/components/core/date-time-popover.tsx +32 -0
  22. package/src/components/core/edited-typography.tsx +20 -0
  23. package/src/components/core/index.ts +3 -0
  24. package/src/components/core/loading.tsx +6 -6
  25. package/src/components/core/title-edit.tsx +122 -0
  26. package/src/components/dashboard-list/dashboard-list-row.tsx +114 -115
  27. package/src/components/dashboard-list/dashboard-list.tsx +119 -119
  28. package/src/components/data-table/table-header.tsx +85 -81
  29. package/src/components/data-table/table-pagination.tsx +27 -27
  30. package/src/components/data-table/table-row.tsx +14 -14
  31. package/src/components/data-table/table-skeleton.tsx +34 -34
  32. package/src/components/execution/execution-filter.ts +22 -22
  33. package/src/components/execution/execution-status-icon.tsx +16 -17
  34. package/src/components/execution/execution-tag.tsx +81 -80
  35. package/src/components/footer/footer.tsx +34 -34
  36. package/src/components/header/dashboard-list-header.tsx +64 -63
  37. package/src/components/header/execution-details-header.tsx +102 -129
  38. package/src/components/header/header.tsx +27 -27
  39. package/src/components/header/index.ts +1 -0
  40. package/src/components/header/integration-details-header.tsx +99 -0
  41. package/src/components/icons/up-down.tsx +15 -15
  42. package/src/components/integration-view/edges/default-edge.tsx +18 -17
  43. package/src/components/integration-view/elk-layout-options.ts +26 -26
  44. package/src/components/integration-view/elk-types.ts +16 -12
  45. package/src/components/integration-view/flow-types.tsx +5 -5
  46. package/src/components/integration-view/integration-view.tsx +132 -130
  47. package/src/components/integration-view/nodes/base-node.tsx +50 -0
  48. package/src/components/integration-view/nodes/connection-node.tsx +8 -8
  49. package/src/components/integration-view/nodes/entry-node.tsx +8 -8
  50. package/src/components/integration-view/nodes/group-node.tsx +47 -6
  51. package/src/components/integration-view/nodes/task-node.tsx +58 -13
  52. package/src/components/integration-view/temp-data/initialElements.tsx +224 -0
  53. package/src/components/integration-view/types.ts +6 -6
  54. package/src/components/layouts/main-layout.tsx +13 -13
  55. package/src/components/layouts/root-container.tsx +25 -25
  56. package/src/components/link-cards/link-card.tsx +23 -23
  57. package/src/components/link-cards/styles.ts +15 -15
  58. package/src/components/list-filter/date-filter.tsx +41 -45
  59. package/src/components/list-filter/date-range-filter.tsx +78 -77
  60. package/src/components/list-filter/list-filter-types.ts +38 -38
  61. package/src/components/list-filter/list-filter.tsx +363 -354
  62. package/src/components/list-filter/multi-select-filter.tsx +94 -95
  63. package/src/components/list-filter/select-filter.tsx +67 -64
  64. package/src/components/scheduler/day-selector.tsx +174 -0
  65. package/src/components/scheduler/day-tag.tsx +73 -0
  66. package/src/components/scheduler/index.ts +4 -0
  67. package/src/components/scheduler/schedule-filter.ts +25 -0
  68. package/src/components/scheduler/schedule-icon.tsx +87 -0
  69. package/src/components/scheduler/scheduler-types.ts +40 -0
  70. package/src/hooks/use-breadcrumbs.ts +31 -31
  71. package/src/hooks/use-recurrence.tsx +13 -0
  72. package/src/hooks/use-timestamp.tsx +21 -21
  73. package/src/pages/dashboard/dashboard-link-cards.tsx +99 -99
  74. package/src/pages/dashboard/dashboard-list-sections.tsx +130 -125
  75. package/src/pages/dashboard/dashboard.tsx +6 -6
  76. package/src/pages/execution-details/execution-details.tsx +23 -29
  77. package/src/pages/executions/executions-list/executions-list-row.tsx +101 -104
  78. package/src/pages/executions/executions-list/executions-list-table.tsx +45 -53
  79. package/src/pages/executions/executions-list/executions-list.tsx +219 -212
  80. package/src/pages/executions/executions.tsx +67 -72
  81. package/src/pages/integrations/integrations.tsx +17 -25
  82. package/src/pages/scheduler/schedule-drawer/edited/edited-types.ts +17 -0
  83. package/src/pages/scheduler/schedule-drawer/edited/index.ts +1 -0
  84. package/src/pages/scheduler/schedule-drawer/index.ts +1 -0
  85. package/src/pages/scheduler/schedule-drawer/schedule-details-integrations.tsx +227 -0
  86. package/src/pages/scheduler/schedule-drawer/schedule-details-main.tsx +292 -0
  87. package/src/pages/scheduler/schedule-drawer/schedule-details-name.tsx +77 -0
  88. package/src/pages/scheduler/schedule-drawer/schedule-details-skeleton.tsx +64 -0
  89. package/src/pages/scheduler/schedule-drawer/schedule-details.tsx +42 -0
  90. package/src/pages/scheduler/schedule-drawer/schedule-drawer-buttons.tsx +72 -0
  91. package/src/pages/scheduler/schedule-drawer/schedule-drawer-group.tsx +103 -0
  92. package/src/pages/scheduler/schedule-drawer/schedule-drawer-legacy.tsx +94 -0
  93. package/src/pages/scheduler/schedule-drawer/schedule-drawer.tsx +101 -0
  94. package/src/pages/scheduler/schedule-drawer/sortable-integration-row.tsx +93 -0
  95. package/src/pages/scheduler/scheduler.tsx +106 -30
  96. package/src/pages/scheduler/schedules-list/index.ts +1 -0
  97. package/src/pages/scheduler/schedules-list/schedules-list-row.tsx +235 -0
  98. package/src/pages/scheduler/schedules-list/schedules-list-table.tsx +74 -0
  99. package/src/pages/scheduler/schedules-list/schedules-list.tsx +280 -0
  100. package/tsconfig.json +29 -26
  101. package/src/components/integration-view/temp-data/initialElements.ts +0 -238
@@ -0,0 +1,94 @@
1
+ import { useEffect } from "react";
2
+
3
+ // Api
4
+ import { getProcessScheduleById } from "@evenicanpm/admin-integrate/api/scheduler/queries";
5
+ import { GetProcessScheduleByIdQuery } from "@evenicanpm/admin-core/api/e4/graphqlRequestSdk";
6
+
7
+ // Mui
8
+ import { Divider } from "@mui/material";
9
+
10
+ // Local components
11
+ import ScheduleDrawerButtons from "./schedule-drawer-buttons";
12
+ import ScheduleDetails from "./schedule-details";
13
+ import ScheduleDetailsIntegrations from "./schedule-details-integrations";
14
+ import ScheduleDetailsSkeleton from "./schedule-details-skeleton";
15
+
16
+ // Types
17
+ import { DrawerOpen } from "../scheduler";
18
+ import { Edited } from "./edited";
19
+ import { ProcessScheduleById } from "./schedule-drawer";
20
+
21
+ interface Props {
22
+ drawerOpen: DrawerOpen;
23
+ details: ProcessScheduleById | null;
24
+ setDetails: (newDetails: ProcessScheduleById | null) => void;
25
+ edited: Edited;
26
+ setEdited: (newEdited: Edited) => void;
27
+ handleClose: () => void;
28
+ }
29
+
30
+ export default function ScheduleDrawerLegacy(props: Props) {
31
+ const styles = getStyles();
32
+
33
+ const { data } = getProcessScheduleById.useData({
34
+ id: props.drawerOpen.id,
35
+ });
36
+
37
+ useEffect(() => {
38
+ if (data) {
39
+ const typedData = data as GetProcessScheduleByIdQuery;
40
+ if (typedData.processScheduleById) {
41
+ const fetchedDetails = typedData.processScheduleById;
42
+
43
+ props.setDetails(fetchedDetails as ProcessScheduleById);
44
+ } else {
45
+ props.setDetails(null);
46
+ }
47
+ }
48
+ }, [data]);
49
+
50
+ const handleSave = () => {};
51
+
52
+ return (
53
+ <>
54
+ <ScheduleDrawerButtons
55
+ handleClose={props.handleClose}
56
+ handleSave={handleSave}
57
+ edited={props.edited}
58
+ readOnly
59
+ />
60
+ <Divider sx={styles.divider} />
61
+ {props.details ? (
62
+ <>
63
+ <ScheduleDetails
64
+ id={props.drawerOpen.id}
65
+ details={props.details}
66
+ setDetails={props.setDetails}
67
+ edited={props.edited}
68
+ setEdited={props.setEdited}
69
+ readOnly
70
+ />
71
+ <Divider sx={styles.divider} />
72
+ <ScheduleDetailsIntegrations
73
+ data={data as GetProcessScheduleByIdQuery}
74
+ details={props.details}
75
+ setDetails={props.setDetails}
76
+ edited={props.edited}
77
+ setEdited={props.setEdited}
78
+ readOnly
79
+ />
80
+ </>
81
+ ) : (
82
+ <ScheduleDetailsSkeleton />
83
+ )}
84
+ </>
85
+ );
86
+ }
87
+
88
+ const getStyles = () => {
89
+ return {
90
+ divider: {
91
+ borderColor: "grey.400",
92
+ },
93
+ };
94
+ };
@@ -0,0 +1,101 @@
1
+ import { useTranslations } from "next-intl";
2
+ import React, { useState } from "react";
3
+
4
+ // API
5
+ import {
6
+ ProcessScheduleGroupDetailsUpdate,
7
+ GetProcessScheduleByIdQuery,
8
+ } from "@evenicanpm/admin-core/api/e4/graphqlRequestSdk";
9
+
10
+ // MUI
11
+ import { Theme, useTheme } from "@mui/material";
12
+ import { Drawer, Box } from "@mui/material";
13
+
14
+ // Local components
15
+ import ScheduleDrawerGroup from "./schedule-drawer-group";
16
+ import ScheduleDrawerLegacy from "./schedule-drawer-legacy";
17
+
18
+ // Types
19
+ import { Edited, initialEdited } from "./edited";
20
+ import { DrawerOpen } from "../scheduler";
21
+
22
+ export type ProcessScheduleById =
23
+ GetProcessScheduleByIdQuery["processScheduleById"];
24
+
25
+ interface Props {
26
+ drawerOpen: DrawerOpen | null;
27
+ setDrawerOpen: (drawerOpen: DrawerOpen | null) => void;
28
+ }
29
+
30
+ export default function ScheduleDrawer(props: Props) {
31
+ const t = useTranslations("Integrate.Scheduler");
32
+
33
+ const theme = useTheme();
34
+ const styles = getStyles(theme);
35
+
36
+ const [edited, setEdited] = useState<Edited>(initialEdited);
37
+
38
+ const [detailsGroup, setDetailsGroup] =
39
+ useState<ProcessScheduleGroupDetailsUpdate | null>(null);
40
+ const [detailsLegacy, setDetailsLegacy] =
41
+ useState<ProcessScheduleById | null>(null);
42
+
43
+ const handleClose = () => {
44
+ const isEdited = Object.values(edited).some((value) => value);
45
+ if (isEdited) {
46
+ const confirmClose = confirm(t("unsavedChanges"));
47
+ if (!confirmClose) return;
48
+ }
49
+ setDetailsGroup(null);
50
+ setDetailsLegacy(null);
51
+ setEdited(initialEdited);
52
+ props.setDrawerOpen(null);
53
+ };
54
+
55
+ return (
56
+ <Drawer
57
+ open={props.drawerOpen !== null}
58
+ onClose={handleClose}
59
+ anchor="right"
60
+ >
61
+ <Box sx={styles.main}>
62
+ {props.drawerOpen && props.drawerOpen.group && (
63
+ <ScheduleDrawerGroup
64
+ drawerOpen={props.drawerOpen}
65
+ details={detailsGroup}
66
+ setDetails={setDetailsGroup}
67
+ edited={edited}
68
+ setEdited={setEdited}
69
+ handleClose={handleClose}
70
+ />
71
+ )}
72
+ {props.drawerOpen && !props.drawerOpen.group && (
73
+ <ScheduleDrawerLegacy
74
+ drawerOpen={props.drawerOpen}
75
+ details={detailsLegacy}
76
+ setDetails={setDetailsLegacy}
77
+ edited={edited}
78
+ setEdited={setEdited}
79
+ handleClose={handleClose}
80
+ />
81
+ )}
82
+ </Box>
83
+ </Drawer>
84
+ );
85
+ }
86
+
87
+ const getStyles = (theme: Theme) => {
88
+ return {
89
+ main: {
90
+ [theme.breakpoints.down("sm")]: {
91
+ width: theme.spacing(35),
92
+ },
93
+ [theme.breakpoints.up("sm")]: {
94
+ width: theme.spacing(55),
95
+ },
96
+ [theme.breakpoints.up("xl")]: {
97
+ width: theme.spacing(75),
98
+ },
99
+ },
100
+ };
101
+ };
@@ -0,0 +1,93 @@
1
+ import React from "react";
2
+ import { useSortable } from "@dnd-kit/sortable";
3
+ import { CSS } from "@dnd-kit/utilities";
4
+
5
+ // Mui
6
+ import { Box, Stack, IconButton, Typography } from "@mui/material";
7
+ import { DragIndicator, DeleteOutline } from "@mui/icons-material";
8
+
9
+ // Custom components
10
+ import {
11
+ StyledTableCell,
12
+ StyledTableRow,
13
+ StyledIconButton,
14
+ } from "@evenicanpm/admin-integrate/components/data-table/table-row";
15
+
16
+ // Types
17
+ import { Process } from "./schedule-details-integrations";
18
+ import { Head } from "@evenicanpm/admin-integrate/components/data-table/table-header";
19
+ import { TableCellProps } from "@mui/material";
20
+
21
+ interface Props {
22
+ item: Process;
23
+ heading: Head[];
24
+ handleDeleteIntegration: (item: Process) => void;
25
+ readOnly?: boolean;
26
+ }
27
+
28
+ export default function SortableIntegrationRow(props: Props) {
29
+ const styles = getStyles();
30
+
31
+ const { attributes, listeners, setNodeRef, transform, transition } =
32
+ useSortable({ id: props.item.id });
33
+
34
+ const transformStyles = {
35
+ transform: CSS.Transform.toString(transform),
36
+ transition,
37
+ };
38
+
39
+ const handleClickDelete = () => {
40
+ if (!props.readOnly) {
41
+ props.handleDeleteIntegration(props.item);
42
+ }
43
+ };
44
+
45
+ const listenersProps = props.readOnly ? {} : listeners;
46
+
47
+ return (
48
+ <StyledTableRow
49
+ ref={setNodeRef}
50
+ sx={{ ...transformStyles, ...styles.row }}
51
+ {...attributes}
52
+ >
53
+ <StyledTableCell
54
+ align={props.heading[0].align as TableCellProps["align"]}
55
+ width={props.heading[0].width}
56
+ sx={{ padding: 0 }}
57
+ >
58
+ <IconButton {...listenersProps} disableRipple>
59
+ <DragIndicator />
60
+ </IconButton>
61
+ </StyledTableCell>
62
+ <StyledTableCell
63
+ align={props.heading[1].align as TableCellProps["align"]}
64
+ width={props.heading[1].width}
65
+ >
66
+ <Stack spacing={1} direction="row">
67
+ <Box display="flex" justifyContent="flex-end" alignItems="center">
68
+ {/* process icon */}
69
+ </Box>
70
+ <Box display="flex" justifyContent="flex-end" alignItems="center">
71
+ <Typography variant="caption">{props.item.name}</Typography>
72
+ </Box>
73
+ </Stack>
74
+ </StyledTableCell>
75
+ <StyledTableCell
76
+ align={props.heading[2].align as TableCellProps["align"]}
77
+ width={props.heading[2].width}
78
+ >
79
+ <StyledIconButton onClick={handleClickDelete} disabled={props.readOnly}>
80
+ <DeleteOutline color={props.readOnly ? "disabled" : "error"} />
81
+ </StyledIconButton>
82
+ </StyledTableCell>
83
+ </StyledTableRow>
84
+ );
85
+ }
86
+
87
+ const getStyles = () => {
88
+ return {
89
+ row: {
90
+ backgroundColor: "white",
91
+ },
92
+ };
93
+ };
@@ -1,39 +1,115 @@
1
- import React from "react";
1
+ import React, { useState } from "react";
2
2
  import { useTranslations } from "next-intl";
3
3
 
4
+ // API
5
+ import { getScheduledProcesses } from "@evenicanpm/admin-integrate/api/scheduler/queries";
6
+ import {
7
+ ScheduledProcessInput,
8
+ GetScheduledProcessesQuery,
9
+ } from "@evenicanpm/admin-core/api/e4/graphqlRequestSdk";
10
+
4
11
  // MUI
5
- import { Theme, useTheme } from "@mui/material";
6
12
  import { Box } from "@mui/material";
7
13
 
8
14
  // Custom components
9
- import {
10
- IntegrateBreadcrumbs,
11
- Crumb,
12
- } from "@evenicanpm/admin-integrate/components/breadcrumbs";
15
+ import { IntegrateBreadcrumbs } from "@evenicanpm/admin-integrate/components/breadcrumbs";
13
16
 
14
- export default function Scheduler() {
15
- const t = useTranslations("Integrate");
16
-
17
- const theme = useTheme();
18
- const styles = getStyles(theme);
19
-
20
- const breadcrumbs: Crumb[] = [
21
- {
22
- name: t("Header.dashboard"),
23
- url: "/e4integrate",
24
- },
25
- {
26
- name: t("Header.scheduler"),
27
- },
28
- ];
29
-
30
- return (
31
- <Box>
32
- <IntegrateBreadcrumbs breadcrumbs={breadcrumbs} />
33
- </Box>
34
- );
35
- }
17
+ // Local components
18
+ import SchedulesList from "./schedules-list";
19
+ import ScheduleDrawer from "./schedule-drawer";
20
+
21
+ // Types
22
+ import { Crumb } from "@evenicanpm/admin-integrate/components/breadcrumbs";
23
+ import { Head } from "@evenicanpm/admin-integrate/components/data-table/table-header";
36
24
 
37
- const getStyles = (theme: Theme) => {
38
- return {};
25
+ export type DrawerOpen = {
26
+ id: string;
27
+ group?: boolean;
39
28
  };
29
+
30
+ export default function Scheduler() {
31
+ const t = useTranslations("Integrate");
32
+ const l = useTranslations("Integrate.Scheduler.ListHeader");
33
+
34
+ const breadcrumbs: Crumb[] = [
35
+ {
36
+ name: t("Header.dashboard"),
37
+ url: "/e4integrate",
38
+ },
39
+ {
40
+ name: t("Header.scheduler"),
41
+ },
42
+ ];
43
+
44
+ const heading: Head[] = [
45
+ {
46
+ id: "name",
47
+ label: l("schedule"),
48
+ align: "left",
49
+ width: "20%",
50
+ sortable: true,
51
+ },
52
+ {
53
+ id: "daysOfTheWeek",
54
+ label: l("daysOfTheWeek"),
55
+ align: "center",
56
+ width: "20%",
57
+ },
58
+ {
59
+ id: "interval",
60
+ label: l("recurrence"),
61
+ align: "center",
62
+ width: "20%",
63
+ },
64
+ {
65
+ id: "startDate",
66
+ label: l("start"),
67
+ align: "center",
68
+ width: "15%",
69
+ sortable: true,
70
+ },
71
+ {
72
+ id: "modified",
73
+ label: l("lastModified"),
74
+ align: "center",
75
+ width: "15%",
76
+ sortable: true,
77
+ },
78
+ {
79
+ id: "view",
80
+ label: l("actions"),
81
+ align: "right",
82
+ width: "5%",
83
+ },
84
+ ];
85
+
86
+ // id of clicked schedule if open OR null if closed
87
+ const [drawerOpen, setDrawerOpen] = useState<DrawerOpen | null>(null);
88
+
89
+ // TODO: initialize input based on url query params
90
+ const [input, setInput] = useState<ScheduledProcessInput>({
91
+ sort: "modified",
92
+ sortDesc: true,
93
+ top: 10,
94
+ skip: 0,
95
+ });
96
+
97
+ const { data, isLoading } = getScheduledProcesses.useData({
98
+ input: input,
99
+ });
100
+
101
+ return (
102
+ <Box>
103
+ <IntegrateBreadcrumbs breadcrumbs={breadcrumbs} />
104
+ <SchedulesList
105
+ heading={heading}
106
+ data={data as GetScheduledProcessesQuery}
107
+ loading={isLoading}
108
+ input={input}
109
+ setInput={setInput}
110
+ setDrawerOpen={setDrawerOpen}
111
+ />
112
+ <ScheduleDrawer drawerOpen={drawerOpen} setDrawerOpen={setDrawerOpen} />
113
+ </Box>
114
+ );
115
+ }
@@ -0,0 +1 @@
1
+ export { default } from "./schedules-list";
@@ -0,0 +1,235 @@
1
+ import React, { useState } from "react";
2
+
3
+ // MUI
4
+ import { Theme, useTheme } from "@mui/material";
5
+ import { Box, Stack, Typography } from "@mui/material";
6
+ import { RemoveRedEye } from "@mui/icons-material";
7
+ import { SxProps } from "@mui/material";
8
+
9
+ // Custom components
10
+ import {
11
+ StyledTableCell,
12
+ StyledTableRow,
13
+ StyledIconButton,
14
+ } from "@evenicanpm/admin-integrate/components/data-table/table-row";
15
+ import {
16
+ DayTag,
17
+ ScheduleIcon,
18
+ } from "@evenicanpm/admin-integrate/components/scheduler";
19
+ import { DateTimePopover } from "@evenicanpm/admin-integrate/components/core";
20
+
21
+ // Hooks
22
+ import useTimestamp from "@evenicanpm/admin-integrate/hooks/use-timestamp";
23
+ import useRecurrence from "@evenicanpm/admin-integrate/hooks/use-recurrence";
24
+
25
+ // Types
26
+ import { Item } from "./schedules-list";
27
+ import { Head } from "@evenicanpm/admin-integrate/components/data-table/table-header";
28
+ import { TableCellProps } from "@mui/material";
29
+ import {
30
+ DayString,
31
+ dayKeys,
32
+ isDayMap,
33
+ } from "@evenicanpm/admin-integrate/components/scheduler";
34
+ import { DrawerOpen } from "../scheduler";
35
+
36
+ interface Props {
37
+ item: Item;
38
+ heading: Head[]; // for alignment
39
+ sx?: SxProps;
40
+ setDrawerOpen: React.Dispatch<React.SetStateAction<DrawerOpen | null>>;
41
+ }
42
+
43
+ const SchedulesListRow: React.FC<Props> = (props: Props) => {
44
+ const theme = useTheme();
45
+ const styles = getStyles(theme);
46
+
47
+ // e.g. "xx days ago"
48
+ const modified = useTimestamp(props.item.modified);
49
+ const modifiedFull = new Date(props.item.modified).toString();
50
+
51
+ const recurrence = useRecurrence(
52
+ props.item.interval,
53
+ props.item.intervalUnitId,
54
+ );
55
+
56
+ const start = new Date(props.item.startDate);
57
+ const startDateLocale = start.toLocaleString().split(",")[0];
58
+ const startTimeLocale = start.toLocaleTimeString().slice(0, 5);
59
+ const startDateFull = start.toString();
60
+
61
+ const [modifiedAnchorEl, setModifiedAnchorEl] = useState<HTMLElement | null>(
62
+ null,
63
+ );
64
+ const modifiedOpen = Boolean(modifiedAnchorEl);
65
+ const [startDateAnchorEl, setStartDateAnchorlEl] =
66
+ useState<HTMLElement | null>(null);
67
+ const startDateOpen = Boolean(startDateAnchorEl);
68
+
69
+ const handlePopoverOpen = (event: React.MouseEvent<HTMLElement>) => {
70
+ const classList = event.currentTarget.classList;
71
+ if (classList.contains("scheduled-process-modified")) {
72
+ setModifiedAnchorEl(event.currentTarget);
73
+ } else if (classList.contains("scheduled-process-start-date")) {
74
+ setStartDateAnchorlEl(event.currentTarget);
75
+ }
76
+ };
77
+
78
+ const handlePopoverClose = () => {
79
+ setModifiedAnchorEl(null);
80
+ setStartDateAnchorlEl(null);
81
+ };
82
+
83
+ const handleMenuOpen = () => {
84
+ const newDrawerOpen: DrawerOpen = {
85
+ id: props.item.id,
86
+ };
87
+ if (props.item.processScheduleGroup) {
88
+ newDrawerOpen.group = true;
89
+ }
90
+ props.setDrawerOpen(newDrawerOpen);
91
+ };
92
+
93
+ const daysOfTheWeek = parseDaysOfTheWeek(props.item);
94
+
95
+ return (
96
+ <StyledTableRow sx={props.sx}>
97
+ <StyledTableCell
98
+ align={props.heading[0].align as TableCellProps["align"]}
99
+ width={props.heading[0].width}
100
+ >
101
+ <Stack spacing={1} direction="row">
102
+ <Box display="flex" justifyContent="flex-end" alignItems="center">
103
+ <ScheduleIcon
104
+ isDisabled={props.item.isDisabled}
105
+ isLegacy={!props.item.processScheduleGroup}
106
+ enablePopover
107
+ />
108
+ </Box>
109
+ <Box display="flex" justifyContent="flex-end" alignItems="center">
110
+ <Typography>{props.item.name}</Typography>
111
+ </Box>
112
+ </Stack>
113
+ </StyledTableCell>
114
+ <StyledTableCell
115
+ align={props.heading[1].align as TableCellProps["align"]}
116
+ width={props.heading[1].width}
117
+ >
118
+ <Box
119
+ display="flex"
120
+ flexWrap="wrap"
121
+ justifyContent={props.heading[1].align as TableCellProps["align"]}
122
+ minWidth={theme.spacing(25)}
123
+ >
124
+ {daysOfTheWeek.map((day) => (
125
+ <DayTag
126
+ key={`${props.item.id}_${day}`}
127
+ day={day}
128
+ sx={styles.dayTag}
129
+ />
130
+ ))}
131
+ </Box>
132
+ </StyledTableCell>
133
+ <StyledTableCell
134
+ align={props.heading[2].align as TableCellProps["align"]}
135
+ width={props.heading[2].width}
136
+ >
137
+ <Typography>{recurrence}</Typography>
138
+ </StyledTableCell>
139
+ <StyledTableCell
140
+ align={props.heading[3].align as TableCellProps["align"]}
141
+ width={props.heading[3].width}
142
+ sx={styles.timeCell}
143
+ >
144
+ <Typography
145
+ className="scheduled-process-start-date"
146
+ onMouseEnter={handlePopoverOpen}
147
+ onMouseLeave={handlePopoverClose}
148
+ >
149
+ {`${startDateLocale} ${startTimeLocale}`}
150
+ </Typography>
151
+ </StyledTableCell>
152
+ <StyledTableCell
153
+ align={props.heading[4].align as TableCellProps["align"]}
154
+ width={props.heading[4].width}
155
+ sx={styles.timeCell}
156
+ >
157
+ <Typography
158
+ className="scheduled-process-modified"
159
+ onMouseEnter={handlePopoverOpen}
160
+ onMouseLeave={handlePopoverClose}
161
+ >
162
+ {modified}
163
+ </Typography>
164
+ </StyledTableCell>
165
+ <StyledTableCell
166
+ align={props.heading[5].align as TableCellProps["align"]}
167
+ width={props.heading[5].width}
168
+ >
169
+ <StyledIconButton onClick={handleMenuOpen}>
170
+ <RemoveRedEye />
171
+ </StyledIconButton>
172
+ </StyledTableCell>
173
+
174
+ <DateTimePopover
175
+ dateIsoString={modifiedFull}
176
+ sx={{ pointerEvents: "none" }}
177
+ open={modifiedOpen}
178
+ anchorEl={modifiedAnchorEl}
179
+ anchorOrigin={{
180
+ vertical: "bottom",
181
+ horizontal: "center",
182
+ }}
183
+ transformOrigin={{
184
+ vertical: "top",
185
+ horizontal: "center",
186
+ }}
187
+ onClose={handlePopoverClose}
188
+ disableRestoreFocus
189
+ />
190
+ <DateTimePopover
191
+ dateIsoString={startDateFull}
192
+ sx={{ pointerEvents: "none" }}
193
+ open={startDateOpen}
194
+ anchorEl={startDateAnchorEl}
195
+ anchorOrigin={{
196
+ vertical: "bottom",
197
+ horizontal: "center",
198
+ }}
199
+ transformOrigin={{
200
+ vertical: "top",
201
+ horizontal: "center",
202
+ }}
203
+ onClose={handlePopoverClose}
204
+ disableRestoreFocus
205
+ />
206
+ </StyledTableRow>
207
+ );
208
+ };
209
+
210
+ const getStyles = (theme: Theme) => {
211
+ return {
212
+ timeCell: {
213
+ cursor: "default",
214
+ },
215
+ popover: {
216
+ padding: theme.spacing(1),
217
+ },
218
+ dayTag: {
219
+ margin: theme.spacing(0.5),
220
+ },
221
+ };
222
+ };
223
+
224
+ const parseDaysOfTheWeek = (item: Item): DayString[] => {
225
+ type Day = keyof typeof isDayMap;
226
+
227
+ const selectedDays = dayKeys.filter((day): day is Day => {
228
+ const key = isDayMap[day as Day];
229
+ return item[key];
230
+ });
231
+
232
+ return selectedDays.length === 7 ? ["everyday"] : selectedDays;
233
+ };
234
+
235
+ export default SchedulesListRow;