@postgres.ai/shared 3.5.0-pr-1027.1 → 4.0.0-pr-1028.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. package/components/DestroyCloneModal/index.js +3 -3
  2. package/components/DestroyCloneRestrictionModal/index.js +1 -1
  3. package/components/MenuButton/index.d.ts +2 -0
  4. package/components/MenuButton/index.js +1 -1
  5. package/components/ResetCloneModal/index.js +5 -3
  6. package/icons/ArrowDropDown/index.d.ts +1 -0
  7. package/icons/ArrowDropDown/index.js +1 -1
  8. package/icons/PostgresSQL/index.d.ts +2 -0
  9. package/icons/PostgresSQL/index.js +40 -0
  10. package/package.json +1 -1
  11. package/pages/Branches/Branch/context.d.ts +22 -0
  12. package/pages/Branches/Branch/context.js +3 -0
  13. package/pages/Branches/Branch/index.d.ts +9 -0
  14. package/pages/Branches/Branch/index.js +172 -0
  15. package/pages/Branches/Branch/stores/Main.d.ts +37 -0
  16. package/pages/Branches/Branch/stores/Main.js +90 -0
  17. package/pages/Branches/Branch/useCreatedStores.d.ts +6 -0
  18. package/pages/Branches/Branch/useCreatedStores.js +5 -0
  19. package/pages/Branches/components/BranchesTable/index.d.ts +10 -0
  20. package/pages/Branches/components/BranchesTable/index.js +107 -0
  21. package/pages/Branches/components/Modals/DeleteBranchModal/index.d.ts +11 -0
  22. package/pages/Branches/components/Modals/DeleteBranchModal/index.js +49 -0
  23. package/pages/Branches/components/Modals/types.d.ts +4 -0
  24. package/pages/Branches/components/Modals/types.js +1 -0
  25. package/pages/Branches/index.d.ts +6 -0
  26. package/pages/Branches/index.js +60 -0
  27. package/pages/Clone/context.d.ts +2 -0
  28. package/pages/Clone/index.d.ts +3 -1
  29. package/pages/Clone/index.js +54 -23
  30. package/pages/Clone/stores/Main.d.ts +4 -2
  31. package/pages/Clone/utils/index.d.ts +4 -0
  32. package/pages/Clone/utils/index.js +12 -0
  33. package/pages/CreateBranch/index.d.ts +17 -0
  34. package/pages/CreateBranch/index.js +135 -0
  35. package/pages/CreateBranch/stores/Main.d.ts +43 -0
  36. package/pages/CreateBranch/stores/Main.js +59 -0
  37. package/pages/CreateBranch/useCreatedStores.d.ts +6 -0
  38. package/pages/CreateBranch/useCreatedStores.js +5 -0
  39. package/pages/CreateBranch/useForm.d.ts +51 -0
  40. package/pages/CreateBranch/useForm.js +30 -0
  41. package/pages/CreateBranch/utils/index.d.ts +2 -0
  42. package/pages/CreateBranch/utils/index.js +10 -0
  43. package/pages/CreateClone/index.d.ts +4 -2
  44. package/pages/CreateClone/index.js +92 -40
  45. package/pages/CreateClone/stores/Main.d.ts +25 -2
  46. package/pages/CreateClone/stores/Main.js +26 -2
  47. package/pages/CreateClone/styles.module.scss +47 -4
  48. package/pages/CreateClone/useForm.d.ts +1 -0
  49. package/pages/CreateClone/useForm.js +1 -0
  50. package/pages/CreateClone/utils/index.d.ts +3 -0
  51. package/pages/CreateClone/utils/index.js +17 -0
  52. package/pages/CreateSnapshot/index.d.ts +17 -0
  53. package/pages/CreateSnapshot/index.js +117 -0
  54. package/pages/CreateSnapshot/stores/Main.d.ts +21 -0
  55. package/pages/CreateSnapshot/stores/Main.js +31 -0
  56. package/pages/CreateSnapshot/useCreatedStores.d.ts +6 -0
  57. package/pages/CreateSnapshot/useCreatedStores.js +5 -0
  58. package/pages/CreateSnapshot/useForm.d.ts +53 -0
  59. package/pages/CreateSnapshot/useForm.js +25 -0
  60. package/pages/CreateSnapshot/utils/index.d.ts +1 -0
  61. package/pages/CreateSnapshot/utils/index.js +3 -0
  62. package/pages/Instance/{components → Clones}/ClonesList/MenuCell/index.js +1 -1
  63. package/pages/Instance/{components → Clones}/ClonesList/MenuCell/utils.js +2 -2
  64. package/pages/Instance/Clones/ClonesList/index.js +96 -0
  65. package/pages/Instance/{components → Clones}/ClonesList/styles.module.scss +10 -0
  66. package/pages/Instance/{ClonesModal → Clones/ClonesModal}/index.js +5 -5
  67. package/pages/Instance/Clones/Header/styles.module.scss +4 -1
  68. package/pages/Instance/Clones/index.d.ts +5 -1
  69. package/pages/Instance/Clones/index.js +6 -8
  70. package/pages/{Configuration → Instance/Configuration}/InputWithTooltip/index.js +15 -11
  71. package/pages/{Configuration → Instance/Configuration}/index.d.ts +2 -1
  72. package/pages/{Configuration → Instance/Configuration}/index.js +9 -6
  73. package/pages/{Configuration → Instance/Configuration}/tooltipText.js +1 -1
  74. package/pages/Instance/Info/Disks/Disk/index.js +6 -4
  75. package/pages/Instance/Info/Retrieval/RetrievalModal/index.js +0 -4
  76. package/pages/Instance/Info/Retrieval/index.js +1 -3
  77. package/pages/Instance/Info/Snapshots/Calendar/utils.d.ts +4 -0
  78. package/pages/Instance/Info/Snapshots/index.js +10 -5
  79. package/pages/Instance/Info/Snapshots/utils.d.ts +13 -2
  80. package/pages/Instance/Info/Snapshots/utils.js +16 -6
  81. package/pages/Instance/Info/Status/index.js +2 -2
  82. package/pages/Instance/Info/index.js +2 -1
  83. package/pages/Instance/Snapshots/components/SnapshotHeader/index.d.ts +11 -0
  84. package/pages/Instance/Snapshots/components/SnapshotHeader/index.js +36 -0
  85. package/pages/Instance/Snapshots/components/SnapshotsList/index.d.ts +11 -0
  86. package/pages/Instance/Snapshots/components/SnapshotsList/index.js +157 -0
  87. package/pages/Instance/Snapshots/components/SnapshotsTable/index.d.ts +6 -0
  88. package/pages/Instance/Snapshots/components/SnapshotsTable/index.js +125 -0
  89. package/pages/Instance/Snapshots/index.d.ts +6 -0
  90. package/pages/Instance/Snapshots/index.js +92 -0
  91. package/pages/Instance/Snapshots/utils/index.d.ts +16 -0
  92. package/pages/Instance/Snapshots/utils/index.js +30 -0
  93. package/pages/Instance/SnapshotsModal/index.js +1 -1
  94. package/pages/Instance/Tabs/PlatformTabs.d.ts +10 -0
  95. package/pages/Instance/Tabs/PlatformTabs.js +51 -0
  96. package/pages/Instance/Tabs/index.d.ts +19 -2
  97. package/pages/Instance/Tabs/index.js +71 -36
  98. package/pages/Instance/Tabs/styles.d.ts +1 -0
  99. package/pages/Instance/Tabs/styles.js +62 -0
  100. package/pages/Instance/components/ModalReloadButton/index.js +1 -1
  101. package/pages/Instance/context.d.ts +7 -0
  102. package/pages/Instance/index.js +14 -13
  103. package/pages/Instance/stores/Main.d.ts +36 -10
  104. package/pages/Instance/stores/Main.js +83 -24
  105. package/pages/Instance/styles.scss +1 -4
  106. package/pages/Logs/hooks/useWsScroll.js +6 -8
  107. package/pages/Logs/index.d.ts +2 -1
  108. package/pages/Logs/index.js +42 -31
  109. package/pages/Logs/wsLogs.d.ts +3 -2
  110. package/pages/Logs/wsLogs.js +24 -8
  111. package/pages/Logs/wsSnackbar.js +7 -7
  112. package/pages/Snapshots/Snapshot/DestorySnapshotModal/index.d.ts +12 -0
  113. package/pages/Snapshots/Snapshot/DestorySnapshotModal/index.js +69 -0
  114. package/pages/Snapshots/Snapshot/context.d.ts +23 -0
  115. package/pages/Snapshots/Snapshot/context.js +3 -0
  116. package/pages/Snapshots/Snapshot/index.d.ts +9 -0
  117. package/pages/Snapshots/Snapshot/index.js +171 -0
  118. package/pages/Snapshots/Snapshot/stores/Main.d.ts +33 -0
  119. package/pages/Snapshots/Snapshot/stores/Main.js +71 -0
  120. package/pages/Snapshots/Snapshot/useCreatedStores.d.ts +6 -0
  121. package/pages/Snapshots/Snapshot/useCreatedStores.js +5 -0
  122. package/stores/Snapshots.d.ts +12 -3
  123. package/stores/Snapshots.js +27 -3
  124. package/types/api/endpoints/createBranch.d.ts +12 -0
  125. package/types/api/endpoints/createBranch.js +1 -0
  126. package/types/api/endpoints/createClone.d.ts +1 -0
  127. package/types/api/endpoints/createSnapshot.d.ts +5 -0
  128. package/types/api/endpoints/createSnapshot.js +1 -0
  129. package/types/api/endpoints/deleteBranch.d.ts +4 -0
  130. package/types/api/endpoints/deleteBranch.js +1 -0
  131. package/types/api/endpoints/destroySnapshot.d.ts +4 -0
  132. package/types/api/endpoints/destroySnapshot.js +1 -0
  133. package/types/api/endpoints/getBranchSnapshot.d.ts +5 -0
  134. package/types/api/endpoints/getBranchSnapshot.js +1 -0
  135. package/types/api/endpoints/getBranches.d.ts +18 -0
  136. package/types/api/endpoints/getBranches.js +5 -0
  137. package/types/api/endpoints/getConfig.d.ts +2 -2
  138. package/types/api/endpoints/getEngine.d.ts +1 -1
  139. package/types/api/endpoints/getFullConfig.d.ts +1 -1
  140. package/types/api/endpoints/getSnapshotList.d.ts +10 -0
  141. package/types/api/endpoints/getSnapshotList.js +1 -0
  142. package/types/api/endpoints/getSnapshots.d.ts +1 -0
  143. package/types/api/endpoints/updateConfig.d.ts +1 -1
  144. package/types/api/entities/branchSnapshot.d.ts +6 -0
  145. package/types/api/entities/branchSnapshot.js +1 -0
  146. package/types/api/entities/branchSnapshots.d.ts +15 -0
  147. package/types/api/entities/branchSnapshots.js +7 -0
  148. package/types/api/entities/clone.d.ts +6 -0
  149. package/types/api/entities/config.js +1 -1
  150. package/types/api/entities/createBranch.d.ts +5 -0
  151. package/types/api/entities/createBranch.js +1 -0
  152. package/types/api/entities/createSnapshot.d.ts +5 -0
  153. package/types/api/entities/createSnapshot.js +1 -0
  154. package/types/api/entities/dbSource.d.ts +1 -0
  155. package/types/api/entities/instance.d.ts +5 -0
  156. package/types/api/entities/instanceState.d.ts +5 -0
  157. package/types/api/entities/snapshot.d.ts +8 -0
  158. package/types/api/entities/snapshot.js +1 -1
  159. package/utils/date.d.ts +2 -0
  160. package/utils/date.js +7 -0
  161. package/utils/snapshot.d.ts +5 -2
  162. package/utils/snapshot.js +6 -1
  163. package/pages/Instance/components/ClonesList/index.js +0 -52
  164. /package/pages/Instance/{components → Clones}/ClonesList/ConnectionModal/index.d.ts +0 -0
  165. /package/pages/Instance/{components → Clones}/ClonesList/ConnectionModal/index.js +0 -0
  166. /package/pages/Instance/{components → Clones}/ClonesList/MenuCell/index.d.ts +0 -0
  167. /package/pages/Instance/{components → Clones}/ClonesList/MenuCell/utils.d.ts +0 -0
  168. /package/pages/Instance/{components → Clones}/ClonesList/index.d.ts +0 -0
  169. /package/pages/Instance/{ClonesModal → Clones/ClonesModal}/index.d.ts +0 -0
  170. /package/pages/Instance/{ClonesModal → Clones/ClonesModal}/utils.d.ts +0 -0
  171. /package/pages/Instance/{ClonesModal → Clones/ClonesModal}/utils.js +0 -0
  172. /package/pages/{Configuration → Instance/Configuration}/Header/index.d.ts +0 -0
  173. /package/pages/{Configuration → Instance/Configuration}/Header/index.js +0 -0
  174. /package/pages/{Configuration → Instance/Configuration}/InputWithTooltip/index.d.ts +0 -0
  175. /package/pages/{Configuration → Instance/Configuration}/ResponseMessage/index.d.ts +0 -0
  176. /package/pages/{Configuration → Instance/Configuration}/ResponseMessage/index.js +0 -0
  177. /package/pages/{Configuration → Instance/Configuration}/configOptions.d.ts +0 -0
  178. /package/pages/{Configuration → Instance/Configuration}/configOptions.js +0 -0
  179. /package/pages/{Configuration → Instance/Configuration}/styles.module.scss +0 -0
  180. /package/pages/{Configuration → Instance/Configuration}/tooltipText.d.ts +0 -0
  181. /package/pages/{Configuration → Instance/Configuration}/useForm.d.ts +0 -0
  182. /package/pages/{Configuration → Instance/Configuration}/useForm.js +0 -0
  183. /package/pages/{Configuration → Instance/Configuration}/utils/index.d.ts +0 -0
  184. /package/pages/{Configuration → Instance/Configuration}/utils/index.js +0 -0
  185. /package/pages/Instance/{SnapshotsModal → Snapshots/components/SnapshotsModal}/utils.d.ts +0 -0
  186. /package/pages/Instance/{SnapshotsModal → Snapshots/components/SnapshotsModal}/utils.js +0 -0
@@ -35,7 +35,7 @@ const useStyles = makeStyles({
35
35
  fontSize: '12px',
36
36
  },
37
37
  }, { index: 1 });
38
- export const Configuration = observer(({ switchActiveTab, reload, isConfigurationActive, disableConfigModification, }) => {
38
+ export const Configuration = observer(({ instanceId, switchActiveTab, reload, isConfigurationActive, disableConfigModification, }) => {
39
39
  const classes = useStyles();
40
40
  const stores = useStores();
41
41
  const { config, isConfigurationLoading, updateConfig, getSeImages, fullConfig, testDbSource, configError, getFullConfig, getFullConfigError, getEngine, } = stores.main;
@@ -98,7 +98,7 @@ export const Configuration = observer(({ switchActiveTab, reload, isConfiguratio
98
98
  await updateConfig({
99
99
  ...values,
100
100
  tuningParams: formatTuningParamsToObj(values.tuningParams),
101
- }).then((response) => {
101
+ }, instanceId).then((response) => {
102
102
  if (response === null || response === void 0 ? void 0 : response.ok) {
103
103
  setSubmitState({
104
104
  status: 'success',
@@ -141,7 +141,10 @@ export const Configuration = observer(({ switchActiveTab, reload, isConfiguratio
141
141
  },
142
142
  },
143
143
  });
144
- testDbSource(connectionData)
144
+ testDbSource({
145
+ ...connectionData,
146
+ instanceId,
147
+ })
145
148
  .then((res) => {
146
149
  var _a;
147
150
  if (res === null || res === void 0 ? void 0 : res.response) {
@@ -202,7 +205,7 @@ export const Configuration = observer(({ switchActiveTab, reload, isConfiguratio
202
205
  }
203
206
  };
204
207
  const handleModalClick = async () => {
205
- await getFullConfig();
208
+ await getFullConfig(instanceId);
206
209
  setIsModalOpen(true);
207
210
  };
208
211
  const handleDeleteChip = (_, uniqueValue, id) => {
@@ -417,7 +420,7 @@ export const Configuration = observer(({ switchActiveTab, reload, isConfiguratio
417
420
  }
418
421
  }, [config]);
419
422
  useEffect(() => {
420
- getEngine().then((res) => {
423
+ getEngine(instanceId).then((res) => {
421
424
  setDledition(String(res === null || res === void 0 ? void 0 : res.edition));
422
425
  });
423
426
  }, []);
@@ -426,7 +429,7 @@ export const Configuration = observer(({ switchActiveTab, reload, isConfiguratio
426
429
  if (formik.dirty &&
427
430
  !isCeEdition &&
428
431
  !customOrGenericImage(configData === null || configData === void 0 ? void 0 : configData.dockerImageType)) {
429
- await getFullConfig().then(async (data) => {
432
+ await getFullConfig(instanceId).then(async (data) => {
430
433
  if (data) {
431
434
  await fetchSeImages({
432
435
  packageGroup: configData === null || configData === void 0 ? void 0 : configData.dockerImageType,
@@ -17,5 +17,5 @@ export const tooltipText = {
17
17
  restoreParallelJobs: () => (_jsx("div", { children: "Number of parallel workers used to restore databases from dump to Postgres managed by DBLab. For initial data retrieval (very first data refresh), it is recommended to use the number of vCPUs available on machine running DBLab. With this approach, we have faster restore time, but we need to keep in mind that we can also have higher usage of CPU and disk IO on this machine (up to temporary saturation of resources). For subsequent refreshes, if DBLab is constantly used, it is recommended to reduce this value by 50% to keep some room for normal use of DBLab (such as work with clones)." })),
18
18
  pgRestoreCustomOptions: () => (_jsx("div", { children: "pg_restore options to be used to restore from a database dump, for example: '--exclude-schema=repack --exclude-schema=\"camelStyleSchemaName\"'. Note that due to security reasons, the current implementation supports only letters, numbers, hyphen, underscore, equal sign, and double quotes." })),
19
19
  timetable: () => (_jsxs("div", { children: ["Schedule for full data refreshes, in", ' ', _jsx("a", { target: '_blank', href: 'https://en.wikipedia.org/wiki/Cron#Overview', className: styles.externalLink, children: "crontab format" }), "."] })),
20
- tuningParams: () => _jsx("div", { children: "Test" }),
20
+ tuningParams: () => (_jsxs("div", { children: ["Query tuning parameters. This is essential to ensure that cloned PostgreSQL most likely generates the same plans as on the source (specifically, it is crutial for query performance troubleshooting and optimization, including working with EXPLAIN plans). For details, see the", ' ', _jsx("a", { target: '_blank', href: 'https://postgres.ai/docs/how-to-guides/administration/postgresql-configuration#postgresql-configuration-in-clones', className: styles.externalLink, children: "docs" }), "."] })),
21
21
  };
@@ -4,7 +4,7 @@ import { formatDistanceToNowStrict } from 'date-fns';
4
4
  import { colors } from '@postgres.ai/shared/styles/colors';
5
5
  import { formatBytesIEC } from '@postgres.ai/shared/utils/units';
6
6
  import { Status as PerformanceStatus } from '@postgres.ai/shared/components/Status';
7
- import { formatUTC } from '@postgres.ai/shared/utils/date';
7
+ import { formatUTC, isValidDate } from '@postgres.ai/shared/utils/date';
8
8
  import { Property } from '../../components/Property';
9
9
  import { ActionsMenu } from './ActionsMenu';
10
10
  import { Status } from './Status';
@@ -63,7 +63,9 @@ export const Disk = (props) => {
63
63
  const shouldShowWarning = props.status === 'active' &&
64
64
  getPercent(props.usedDataSize, props.totalDataSize) >
65
65
  WARNING_THRESHOLD_PERCENT;
66
- return (_jsxs("div", { className: classes.root, children: [_jsxs("div", { className: classes.header, children: [_jsxs("div", { className: classes.titleWrapper, children: [_jsx("h6", { title: props.name, className: classes.title, children: props.name }), _jsx(ActionsMenu, { poolId: props.id, poolName: props.name, isActive: props.status === 'active' })] }), _jsx(Status, { value: props.status, hasWarning: shouldShowWarning })] }), _jsx(Property, { name: "Mode", classes: { content: classes.uppercaseContent }, children: props.mode }), props.status === 'refreshing' && props.refreshingStartDate && (_jsx("div", { className: classes.content, children: _jsxs(Property, { name: "Refreshing started at", children: [formatUTC(props.refreshingStartDate, 'yyyy-MM-dd HH:mm:ss'), " UTC (", formatDistanceToNowStrict(props.refreshingStartDate, {
67
- addSuffix: true,
68
- }), ")"] }) })), _jsxs("div", { className: classes.content, children: [_jsx(Property, { name: "Clones", children: props.clonesCount }), _jsx(Property, { name: "Snapshots", children: props.snapshotsCount })] }), _jsxs("div", { className: classes.content, children: [_jsx(Property, { name: "Size", children: formatBytesIEC(props.totalDataSize) }), _jsxs(Property, { name: _jsxs(_Fragment, { children: ["Used\u00A0", _jsx(Marker, { className: classes.markerUsed })] }), children: [formatBytesIEC(props.usedDataSize), " /", ' ', getPercent(props.usedDataSize, props.totalDataSize), " %"] }), _jsxs(Property, { name: _jsxs(_Fragment, { children: ["Free\u00A0", _jsx(Marker, { className: classes.markerFree })] }), children: [formatBytesIEC(props.freeDataSize), " /", ' ', getPercent(props.freeDataSize, props.totalDataSize), " %"] })] }), _jsx(ProgressBar, { value: props.usedDataSize, total: props.totalDataSize, thresholdPercent: WARNING_THRESHOLD_PERCENT }), shouldShowWarning && (_jsxs(PerformanceStatus, { type: "warning", className: classes.warningMessage, children: ["+", WARNING_THRESHOLD_PERCENT, "% disk usage may result in performance degradation"] }))] }));
66
+ return (_jsxs("div", { className: classes.root, children: [_jsxs("div", { className: classes.header, children: [_jsxs("div", { className: classes.titleWrapper, children: [_jsx("h6", { title: props.name, className: classes.title, children: props.name }), _jsx(ActionsMenu, { poolId: props.id, poolName: props.name, isActive: props.status === 'active' })] }), _jsx(Status, { value: props.status, hasWarning: shouldShowWarning })] }), _jsx(Property, { name: "Mode", classes: { content: classes.uppercaseContent }, children: props.mode }), props.status === 'refreshing' && props.refreshingStartDate && (_jsx("div", { className: classes.content, children: _jsxs(Property, { name: "Refreshing started at", children: [formatUTC(props.refreshingStartDate, 'yyyy-MM-dd HH:mm:ss'), " UTC (", isValidDate(props.refreshingStartDate)
67
+ ? formatDistanceToNowStrict(props.refreshingStartDate, {
68
+ addSuffix: true,
69
+ })
70
+ : '-', ")"] }) })), _jsxs("div", { className: classes.content, children: [_jsx(Property, { name: "Clones", children: props.clonesCount }), _jsx(Property, { name: "Snapshots", children: props.snapshotsCount })] }), _jsxs("div", { className: classes.content, children: [_jsx(Property, { name: "Size", children: formatBytesIEC(props.totalDataSize) }), _jsxs(Property, { name: _jsxs(_Fragment, { children: ["Used\u00A0", _jsx(Marker, { className: classes.markerUsed })] }), children: [formatBytesIEC(props.usedDataSize), " /", ' ', getPercent(props.usedDataSize, props.totalDataSize), " %"] }), _jsxs(Property, { name: _jsxs(_Fragment, { children: ["Free\u00A0", _jsx(Marker, { className: classes.markerFree })] }), children: [formatBytesIEC(props.freeDataSize), " /", ' ', getPercent(props.freeDataSize, props.totalDataSize), " %"] })] }), _jsx(ProgressBar, { value: props.usedDataSize, total: props.totalDataSize, thresholdPercent: WARNING_THRESHOLD_PERCENT }), shouldShowWarning && (_jsxs(PerformanceStatus, { type: "warning", className: classes.warningMessage, children: ["+", WARNING_THRESHOLD_PERCENT, "% disk usage may result in performance degradation"] }))] }));
69
71
  };
@@ -1,5 +1,4 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useEffect } from 'react';
3
2
  import { Modal } from '@postgres.ai/shared/components/Modal';
4
3
  import { useStores } from '@postgres.ai/shared/pages/Instance/context';
5
4
  import { ModalReloadButton } from '@postgres.ai/shared/pages/Instance/components/ModalReloadButton';
@@ -8,8 +7,5 @@ import styles from './styles.module.scss';
8
7
  export const RetrievalModal = ({ isOpen, onClose, data, }) => {
9
8
  const stores = useStores();
10
9
  const { isReloadingInstanceRetrieval, reloadInstanceRetrieval } = stores.main;
11
- useEffect(() => {
12
- reloadInstanceRetrieval();
13
- }, []);
14
10
  return (_jsx(Modal, { title: "Retrieval activity details", isOpen: isOpen, onClose: onClose, size: "md", titleRightContent: _jsx(ModalReloadButton, { isReloading: isReloadingInstanceRetrieval, onReload: reloadInstanceRetrieval }), children: _jsxs("div", { className: styles.tableContainer, children: [_jsx(RetrievalTable, { data: data === null || data === void 0 ? void 0 : data.source, activity: "source" }), _jsx(RetrievalTable, { data: data === null || data === void 0 ? void 0 : data.target, activity: "target" })] }) }));
15
11
  };
@@ -7,8 +7,6 @@ import { Status } from '@postgres.ai/shared/components/Status';
7
7
  import { capitalize } from '@postgres.ai/shared/utils/strings';
8
8
  import { formatDateStd } from '@postgres.ai/shared/utils/date';
9
9
  import { Button } from '@postgres.ai/shared/components/Button2';
10
- import { Tooltip } from '@postgres.ai/shared/components/Tooltip';
11
- import { InfoIcon } from '@postgres.ai/shared/icons/Info';
12
10
  import { Section } from '../components/Section';
13
11
  import { Property } from '../components/Property';
14
12
  import { RefreshFailedAlert } from './RefreshFailedAlert';
@@ -41,7 +39,7 @@ export const Retrieval = observer(() => {
41
39
  const { mode, status, activity } = instanceRetrieval;
42
40
  const isVisible = mode !== 'physical' && !isRetrievalUnknown(mode);
43
41
  const isActive = mode === 'logical' && status === 'refreshing';
44
- return (_jsxs(Section, { title: "Retrieval", children: [_jsx(Property, { name: "Status", children: _jsxs(Status, { type: getTypeByStatus(retrieving.status), children: [capitalize(retrieving.status), isVisible && (_jsxs(_Fragment, { children: [_jsx(Button, { theme: "primary", onClick: () => setIsModalOpen(true), isDisabled: !isActive, className: classes.detailsButton, children: "Show details" }), !isActive && (_jsx(Tooltip, { content: "No retrieval activity details", children: _jsx(InfoIcon, { className: classes.infoIcon }) }))] }))] }) }), _jsx(Property, { name: "Mode", children: retrieving.mode }), _jsx(Property, { name: "Last refresh", children: retrieving.lastRefresh
42
+ return (_jsxs(Section, { title: "Retrieval", children: [_jsx(Property, { name: "Status", children: _jsxs(Status, { type: getTypeByStatus(retrieving.status), children: [capitalize(retrieving.status), isVisible && (_jsx(_Fragment, { children: _jsx(Button, { theme: "primary", onClick: () => setIsModalOpen(true), isDisabled: !isActive, className: classes.detailsButton, children: "Show details" }) }))] }) }), _jsx(Property, { name: "Mode", children: retrieving.mode }), _jsx(Property, { name: "Last refresh", children: retrieving.lastRefresh
45
43
  ? formatDateStd(retrieving.lastRefresh, { withDistance: true })
46
44
  : '-' }), _jsx(Property, { name: "Next refresh", children: retrieving.nextRefresh
47
45
  ? formatDateStd(retrieving.nextRefresh, { withDistance: true })
@@ -7,12 +7,16 @@ export declare const getCalendar: (monthStartDate: Date, snapshots: Snapshot[])
7
7
  snapshots: {
8
8
  createdAtDate: Date;
9
9
  dataStateAtDate: Date;
10
+ numClones: string | number;
11
+ clones: string[];
10
12
  createdAt: string;
11
13
  dataStateAt: string;
12
14
  id: string;
13
15
  pool: string;
14
16
  physicalSize: number;
15
17
  logicalSize: number;
18
+ message: string;
19
+ branch: string;
16
20
  }[];
17
21
  isBreak: boolean;
18
22
  isDisabled: boolean;
@@ -12,6 +12,7 @@ import { Button } from '@postgres.ai/shared/components/Button2';
12
12
  import { Spinner } from '@postgres.ai/shared/components/Spinner';
13
13
  import { ErrorStub } from '@postgres.ai/shared/components/ErrorStub';
14
14
  import { useStores } from '@postgres.ai/shared/pages/Instance/context';
15
+ import { isValidDate } from '@postgres.ai/shared/utils/date';
15
16
  import { Section } from '../components/Section';
16
17
  import { Property } from '../components/Property';
17
18
  import { getEdgeSnapshots } from './utils';
@@ -27,9 +28,13 @@ export const Snapshots = observer(() => {
27
28
  const { snapshots } = stores.main;
28
29
  const classes = useStyles();
29
30
  const { firstSnapshot, lastSnapshot } = getEdgeSnapshots((_a = snapshots.data) !== null && _a !== void 0 ? _a : []);
30
- return (_jsxs(Section, { title: "Snapshots", rightContent: !snapshots.data && !snapshots.error && _jsx(Spinner, { size: "sm" }), children: [snapshots.error && _jsx(ErrorStub, { message: snapshots.error, size: "normal" }), snapshots.data && !snapshots.error && (_jsxs(_Fragment, { children: [_jsx(Property, { name: "Number of snapshots", children: snapshots.data.length }), _jsxs(Property, { name: "Oldest data state time", children: [lastSnapshot && (_jsxs(_Fragment, { children: [lastSnapshot.dataStateAt, " (", formatDistanceToNowStrict(lastSnapshot.dataStateAtDate, {
31
- addSuffix: true,
32
- }), ")"] })), !lastSnapshot && '-'] }), _jsxs(Property, { name: "Newest data state time", children: [firstSnapshot && (_jsxs(_Fragment, { children: [firstSnapshot.dataStateAt, " (", formatDistanceToNowStrict(firstSnapshot.dataStateAtDate, {
33
- addSuffix: true,
34
- }), ")"] })), !firstSnapshot && '-'] }), _jsx(Calendar, { snapshots: snapshots.data, onSelectDate: (date) => stores.snapshotsModal.openModal({ date }) }), _jsx(Button, { className: classes.button, onClick: () => stores.snapshotsModal.openModal(), children: "Show all snapshots" })] }))] }));
31
+ return (_jsxs(Section, { title: "Snapshots", rightContent: !snapshots.data && !snapshots.error && _jsx(Spinner, { size: "sm" }), children: [snapshots.error && _jsx(ErrorStub, { message: snapshots.error, size: "normal" }), snapshots.data && !snapshots.error && (_jsxs(_Fragment, { children: [_jsx(Property, { name: "Number of snapshots", children: snapshots.data.length }), _jsxs(Property, { name: "Oldest data state time", children: [lastSnapshot && (_jsxs(_Fragment, { children: [lastSnapshot.dataStateAt, " (", isValidDate(lastSnapshot.dataStateAtDate)
32
+ ? formatDistanceToNowStrict(lastSnapshot.dataStateAtDate, {
33
+ addSuffix: true,
34
+ })
35
+ : '-', ")"] })), !lastSnapshot && '-'] }), _jsxs(Property, { name: "Newest data state time", children: [firstSnapshot && (_jsxs(_Fragment, { children: [firstSnapshot.dataStateAt, " (", isValidDate(firstSnapshot.dataStateAtDate)
36
+ ? formatDistanceToNowStrict(firstSnapshot.dataStateAtDate, {
37
+ addSuffix: true,
38
+ })
39
+ : '-', ")"] })), !firstSnapshot && '-'] }), _jsx(Calendar, { snapshots: snapshots.data, onSelectDate: (date) => stores.snapshotsModal.openModal({ date }) }), _jsx(Button, { className: classes.button, onClick: () => stores.snapshotsModal.openModal(), children: "Show all snapshots" })] }))] }));
35
40
  });
@@ -1,23 +1,34 @@
1
1
  import { Snapshot } from '@postgres.ai/shared/types/api/entities/snapshot';
2
2
  export declare const getEdgeSnapshots: (snapshots: Snapshot[]) => {
3
+ firstSnapshot: null;
4
+ lastSnapshot: null;
5
+ } | {
3
6
  firstSnapshot: {
4
7
  createdAtDate: Date;
5
8
  dataStateAtDate: Date;
9
+ numClones: string | number;
10
+ clones: string[];
6
11
  createdAt: string;
7
12
  dataStateAt: string;
8
13
  id: string;
9
14
  pool: string;
10
15
  physicalSize: number;
11
16
  logicalSize: number;
12
- } | null;
17
+ message: string;
18
+ branch: string;
19
+ };
13
20
  lastSnapshot: {
14
21
  createdAtDate: Date;
15
22
  dataStateAtDate: Date;
23
+ numClones: string | number;
24
+ clones: string[];
16
25
  createdAt: string;
17
26
  dataStateAt: string;
18
27
  id: string;
19
28
  pool: string;
20
29
  physicalSize: number;
21
30
  logicalSize: number;
22
- } | null;
31
+ message: string;
32
+ branch: string;
33
+ };
23
34
  };
@@ -5,12 +5,22 @@
5
5
  *--------------------------------------------------------------------------
6
6
  */
7
7
  export const getEdgeSnapshots = (snapshots) => {
8
- var _a, _b;
9
- const list = [...snapshots];
10
- const [first] = list;
11
- const [last] = list.reverse();
8
+ if (!snapshots.length) {
9
+ return {
10
+ firstSnapshot: null,
11
+ lastSnapshot: null
12
+ };
13
+ }
14
+ const sortedList = [...snapshots].sort((a, b) => {
15
+ var _a, _b, _c, _d;
16
+ const aTime = (_b = (_a = a.dataStateAtDate) === null || _a === void 0 ? void 0 : _a.getTime()) !== null && _b !== void 0 ? _b : 0;
17
+ const bTime = (_d = (_c = b.dataStateAtDate) === null || _c === void 0 ? void 0 : _c.getTime()) !== null && _d !== void 0 ? _d : 0;
18
+ return bTime - aTime;
19
+ });
20
+ const [first] = sortedList;
21
+ const [last] = sortedList.slice(-1);
12
22
  return {
13
- firstSnapshot: (_a = first) !== null && _a !== void 0 ? _a : null,
14
- lastSnapshot: (_b = last) !== null && _b !== void 0 ? _b : null
23
+ firstSnapshot: first !== null && first !== void 0 ? first : null,
24
+ lastSnapshot: last !== null && last !== void 0 ? last : null // oldest
15
25
  };
16
26
  };
@@ -21,11 +21,11 @@ import styles from './styles.module.scss';
21
21
  export const Status = observer(() => {
22
22
  const [isOpenInstanceResponseModal, setIsOpenInstanceResponseModal] = useState(false);
23
23
  const stores = useStores();
24
- const { instance } = stores.main;
24
+ const { instance, uiVersion, config } = stores.main;
25
25
  if (!instance || !instance.state)
26
26
  return null;
27
27
  const { code, message } = instance.state.status;
28
28
  const { version, startedAt } = instance.state.engine;
29
29
  const isStatusOk = code === 'OK';
30
- return (_jsxs(Section, { title: "Status", children: [_jsx(Property, { name: "Status", children: _jsxs(StatusIndicator, { type: getType(code), children: [getText(code), !isStatusOk && (_jsxs(_Fragment, { children: [_jsx("br", {}), message] }))] }) }), startedAt && (_jsx(Property, { name: "Started", children: formatDateStd(startedAt, { withDistance: true }) })), instance.createdAt && (_jsx(Property, { name: "Registered", children: formatDateStd(instance.createdAt, { withDistance: true }) })), version && _jsx(Property, { name: "Version", children: version }), !isStatusOk && (_jsxs("div", { className: styles.controls, children: [_jsx(Button, { onClick: () => setIsOpenInstanceResponseModal(true), className: styles.button, children: "Show full response" }), _jsx(GatewayLink, { className: styles.button, href: linksConfig.support, children: _jsx(Button, { theme: "accent", children: "Ask support" }) })] })), _jsx(InstanceResponseModal, { isOpen: isOpenInstanceResponseModal, onClose: () => setIsOpenInstanceResponseModal(false) })] }));
30
+ return (_jsxs(Section, { title: "Status", children: [_jsx(Property, { name: "Status", children: _jsxs(StatusIndicator, { type: getType(code), children: [getText(code), !isStatusOk && (_jsxs(_Fragment, { children: [_jsx("br", {}), message] }))] }) }), startedAt && (_jsx(Property, { name: "Started", children: formatDateStd(startedAt, { withDistance: true }) })), instance.createdAt && (_jsx(Property, { name: "Registered", children: formatDateStd(instance.createdAt, { withDistance: true }) })), uiVersion && _jsx(Property, { name: "UI version", children: `v${uiVersion}` }), version && _jsx(Property, { name: "Engine version", children: version }), (config === null || config === void 0 ? void 0 : config.dockerPath) && (_jsx(Property, { name: "Docker image", children: config === null || config === void 0 ? void 0 : config.dockerPath })), !isStatusOk && (_jsxs("div", { className: styles.controls, children: [_jsx(Button, { onClick: () => setIsOpenInstanceResponseModal(true), className: styles.button, children: "Show full response" }), _jsx(GatewayLink, { className: styles.button, href: linksConfig.support, children: _jsx(Button, { theme: "accent", children: "Ask support" }) })] })), _jsx(InstanceResponseModal, { isOpen: isOpenInstanceResponseModal, onClose: () => setIsOpenInstanceResponseModal(false) })] }));
31
31
  });
@@ -65,11 +65,12 @@ const useStyles = makeStyles((theme) => ({
65
65
  export const Info = () => {
66
66
  const classes = useStyles();
67
67
  const width = useWindowDimensions();
68
+ const [onHover, setOnHover] = useState(false);
68
69
  const isMobileScreen = width <= SMALL_BREAKPOINT_PX;
69
70
  const [isCollapsed, setIsCollapsed] = useState(() => localStorage.getItem(SIDEBAR_COLLAPSED_PARAM) === '1' && !isMobileScreen);
70
71
  const handleClick = () => {
71
72
  setIsCollapsed(!isCollapsed);
72
73
  localStorage.setItem(SIDEBAR_COLLAPSED_PARAM, isCollapsed ? '0' : '1');
73
74
  };
74
- return (_jsxs("div", { className: cn(classes.container, !isCollapsed ? classes.root : classes.collapsed), children: [!isMobileScreen && (_jsx(Button, { className: classes.collapseBtn, onClick: handleClick, isCollapsed: isCollapsed, icon: isCollapsed ? (_jsx(ArrowLeft, { className: classes.arrowImage })) : (_jsx(ArrowRight, { className: classes.arrowImage })), children: "Collapse" })), !isCollapsed && (_jsxs("div", { children: [_jsx(Status, {}), _jsx(Retrieval, {}), _jsx(Connection, {}), _jsx(Disks, {}), _jsx(Snapshots, {})] }))] }));
75
+ return (_jsxs("div", { className: cn(classes.container, !isCollapsed ? classes.root : classes.collapsed), children: [!isMobileScreen && (_jsx(Button, { onMouseEnter: () => setOnHover(true), onMouseLeave: () => setOnHover(false), className: classes.collapseBtn, onClick: handleClick, isCollapsed: isCollapsed, type: "button", icon: isCollapsed ? (_jsx(ArrowLeft, { className: classes.arrowImage })) : (_jsx(ArrowRight, { className: classes.arrowImage })), children: onHover && 'Collapse' })), !isCollapsed && (_jsxs("div", { children: [_jsx(Status, {}), _jsx(Retrieval, {}), _jsx(Connection, {}), _jsx(Disks, {}), _jsx(Snapshots, {})] }))] }));
75
76
  };
@@ -0,0 +1,11 @@
1
+ /// <reference types="react" />
2
+ interface SnapshotHeaderProps {
3
+ branches: string[] | null;
4
+ selectedBranch: string;
5
+ setMessageFilter: (value: string) => void;
6
+ setSelectedBranch: (value: string) => void;
7
+ }
8
+ export declare const SnapshotHeader: (({ branches, selectedBranch, setMessageFilter, setSelectedBranch, }: SnapshotHeaderProps) => JSX.Element) & {
9
+ displayName: string;
10
+ };
11
+ export {};
@@ -0,0 +1,36 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { observer } from 'mobx-react-lite';
3
+ import { makeStyles, TextField } from '@material-ui/core';
4
+ import { Select } from '@postgres.ai/shared/components/Select';
5
+ const useStyles = makeStyles({
6
+ outerContainer: {
7
+ display: 'flex',
8
+ justifyContent: 'space-between',
9
+ alignItems: 'center',
10
+ paddingBottom: '6px',
11
+ },
12
+ select: {
13
+ width: '200px',
14
+ },
15
+ inputContainer: {
16
+ width: '300px',
17
+ '& input': {
18
+ padding: '8px',
19
+ },
20
+ },
21
+ }, { index: 1 });
22
+ export const SnapshotHeader = observer(({ branches, selectedBranch, setMessageFilter, setSelectedBranch, }) => {
23
+ const classes = useStyles();
24
+ return (_jsxs("div", { className: classes.outerContainer, children: [_jsx(Select, { fullWidth: true, label: "Branch", className: classes.select, value: selectedBranch, disabled: !branches, onChange: (e) => {
25
+ setSelectedBranch(e.target.value);
26
+ }, items: branches
27
+ ? branches.map((branch) => {
28
+ return {
29
+ value: branch,
30
+ children: _jsx("div", { children: branch }),
31
+ };
32
+ })
33
+ : [] }), _jsx(TextField, { variant: "outlined", className: classes.inputContainer, onChange: (e) => setMessageFilter(e.target.value), label: 'Filter by message', InputLabelProps: {
34
+ shrink: true,
35
+ } })] }));
36
+ });
@@ -0,0 +1,11 @@
1
+ /// <reference types="react" />
2
+ import { Snapshot } from '@postgres.ai/shared/types/api/entities/snapshot';
3
+ export declare const SnapshotsList: (({ routes, filteredSnapshots, instanceId, }: {
4
+ routes: {
5
+ snapshot: (snapshotId: string) => string;
6
+ };
7
+ filteredSnapshots: Snapshot[];
8
+ instanceId: string;
9
+ }) => JSX.Element) & {
10
+ displayName: string;
11
+ };
@@ -0,0 +1,157 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React from 'react';
3
+ import { observer } from 'mobx-react-lite';
4
+ import { makeStyles } from '@material-ui/core';
5
+ import copy from 'copy-to-clipboard';
6
+ import { HorizontalScrollContainer } from '@postgres.ai/shared/components/HorizontalScrollContainer';
7
+ import { DestroySnapshotModal } from '@postgres.ai/shared/pages/Snapshots/Snapshot/DestorySnapshotModal';
8
+ import { useHost, useStores } from '@postgres.ai/shared/pages/Instance/context';
9
+ import { IconButton } from '@mui/material';
10
+ import { icons } from '@postgres.ai/shared/styles/icons';
11
+ import { RowMenu } from '@postgres.ai/shared/components/Table/RowMenu';
12
+ import { generateSnapshotPageId, groupSnapshotsByCreatedAtDate, } from '@postgres.ai/shared/pages/Instance/Snapshots/utils';
13
+ import { format, formatDistanceToNowStrict } from 'date-fns';
14
+ import { formatBytesIEC } from '@postgres.ai/shared/utils/units';
15
+ import { useHistory } from 'react-router';
16
+ const useStyles = makeStyles({
17
+ pointerCursor: {
18
+ cursor: 'pointer',
19
+ padding: '0 8px',
20
+ '&:hover': {
21
+ backgroundColor: '#f9f9f9',
22
+ },
23
+ },
24
+ commitItem: {
25
+ display: 'flex',
26
+ justifyContent: 'space-between',
27
+ padding: '14px 0',
28
+ borderBottom: '1px solid #ddd',
29
+ '&:last-child': {
30
+ borderBottom: 'none',
31
+ marginBottom: '12px',
32
+ },
33
+ },
34
+ infoBlock: {
35
+ display: 'flex',
36
+ flexDirection: 'column',
37
+ justifyContent: 'center',
38
+ overflow: 'hidden',
39
+ },
40
+ header: {
41
+ fontWeight: 500,
42
+ },
43
+ infoContent: {
44
+ fontSize: '12px',
45
+ color: '#808080',
46
+ display: 'flex',
47
+ alignItems: 'center',
48
+ gap: '5px',
49
+ },
50
+ snapshotId: {
51
+ fontSize: '12px',
52
+ overflow: 'hidden',
53
+ textOverflow: 'ellipsis',
54
+ whiteSpace: 'nowrap',
55
+ padding: '0 10px',
56
+ },
57
+ actionsContainer: {
58
+ overflow: 'hidden',
59
+ display: 'flex',
60
+ height: 'max-content',
61
+ alignItems: 'center',
62
+ justifyContent: 'flex-end',
63
+ border: '1px solid #ddd',
64
+ borderRadius: '5px',
65
+ padding: '0 14px',
66
+ justifySelf: 'end',
67
+ maxWidth: '100%',
68
+ '& .MuiButtonBase-root, .MuiTableCell-root': {
69
+ padding: '0!important',
70
+ borderBottom: 'none',
71
+ },
72
+ },
73
+ dateGroup: {
74
+ fontSize: '14px',
75
+ fontWeight: 'bold',
76
+ padding: '14px 0 5px 0',
77
+ borderBottom: '1px solid #ddd',
78
+ },
79
+ rowMenuContainer: {
80
+ paddingLeft: '10px',
81
+ '& .MuiButtonBase-root': {
82
+ width: '20px',
83
+ height: '20px',
84
+ padding: '8px',
85
+ },
86
+ },
87
+ copyButtonContainer: {
88
+ '& .MuiButtonBase-root': {
89
+ borderLeft: '1px solid #ddd',
90
+ borderRadius: '0',
91
+ borderRight: '1px solid #ddd',
92
+ },
93
+ },
94
+ copyButton: {
95
+ width: '32px',
96
+ height: '32px',
97
+ padding: '8px',
98
+ },
99
+ tooltipInfo: {
100
+ fontSize: '12px',
101
+ },
102
+ gridContainer: {
103
+ width: '100%',
104
+ display: 'grid',
105
+ columnGap: '20px',
106
+ gridTemplateColumns: 'repeat(5, 0.75fr) 1fr',
107
+ },
108
+ }, { index: 1 });
109
+ const SnapshotListItem = ({ snapshot, setSnapshotModal, openClonesModal, }) => {
110
+ var _a, _b;
111
+ const classes = useStyles();
112
+ const timeAgo = formatDistanceToNowStrict(snapshot.createdAtDate);
113
+ const history = useHistory();
114
+ const host = useHost();
115
+ return (_jsx("div", { className: classes.commitItem, children: _jsxs("div", { className: classes.gridContainer, children: [_jsxs("div", { className: classes.infoBlock, children: [_jsx("div", { className: classes.header, children: snapshot.message || '-' }), _jsxs("div", { className: classes.infoContent, title: snapshot.dataStateAt, children: [timeAgo, " ago"] })] }), _jsxs("div", { className: classes.infoBlock, children: [_jsx("div", { className: classes.header, children: "Pool" }), _jsx("div", { className: classes.infoContent, children: (_a = snapshot.pool) !== null && _a !== void 0 ? _a : '-' })] }), _jsxs("div", { className: classes.infoBlock, children: [_jsx("div", { className: classes.header, children: "Number of clones" }), _jsx("div", { className: classes.infoContent, children: (_b = snapshot.numClones) !== null && _b !== void 0 ? _b : '-' })] }), _jsxs("div", { className: classes.infoBlock, children: [_jsx("div", { className: classes.header, children: "Logical Size" }), _jsx("div", { className: classes.infoContent, children: snapshot.logicalSize ? formatBytesIEC(snapshot.logicalSize) : '-' })] }), _jsxs("div", { className: classes.infoBlock, children: [_jsx("div", { className: classes.header, children: "Physical Size" }), _jsx("div", { className: classes.infoContent, children: snapshot.physicalSize
116
+ ? formatBytesIEC(snapshot.physicalSize)
117
+ : '-' })] }), _jsxs("div", { className: classes.actionsContainer, onClick: (e) => e.stopPropagation(), children: [_jsx("div", { className: classes.snapshotId, children: snapshot.id }), _jsx("div", { className: classes.copyButtonContainer, title: "Copy snapshot ID", children: _jsx(IconButton, { className: classes.copyButton, onClick: (e) => {
118
+ e.stopPropagation();
119
+ copy(snapshot.id);
120
+ }, children: icons.copyIcon }) }), _jsx("div", { className: classes.rowMenuContainer, title: "Actions", children: _jsx(RowMenu, { actions: [
121
+ {
122
+ name: 'Show related clones',
123
+ onClick: () => openClonesModal(),
124
+ },
125
+ {
126
+ name: 'Create new clone',
127
+ onClick: () => history.push(host.routes.createClone()),
128
+ },
129
+ {
130
+ name: 'Delete snapshot',
131
+ onClick: () => setSnapshotModal({
132
+ isOpen: true,
133
+ snapshotId: snapshot.id,
134
+ }),
135
+ }
136
+ ] }) })] })] }) }));
137
+ };
138
+ export const SnapshotsList = observer(({ routes, filteredSnapshots, instanceId, }) => {
139
+ const classes = useStyles();
140
+ const stores = useStores();
141
+ const history = useHistory();
142
+ const groupedSnapshots = groupSnapshotsByCreatedAtDate(filteredSnapshots);
143
+ const [snapshotModal, setSnapshotModal] = React.useState({
144
+ isOpen: false,
145
+ snapshotId: '',
146
+ });
147
+ return (_jsxs(HorizontalScrollContainer, { children: [groupedSnapshots.map((group, index) => {
148
+ const groupDateFormatted = format(group[0].createdAtDate, 'MMM dd, yyyy');
149
+ return (_jsxs("div", { children: [_jsx("div", { className: classes.dateGroup, children: groupDateFormatted }), group.map((snapshot) => {
150
+ const snapshotPageId = generateSnapshotPageId(snapshot.id);
151
+ return (_jsx("div", { className: classes.pointerCursor, onClick: () => snapshotPageId &&
152
+ history.push(routes.snapshot(snapshotPageId)), children: _jsx(SnapshotListItem, { snapshot: snapshot, setSnapshotModal: setSnapshotModal, openClonesModal: () => stores.clonesModal.openModal({
153
+ snapshotId: snapshot.id,
154
+ }) }) }, snapshot.id));
155
+ })] }, index));
156
+ }), snapshotModal.isOpen && snapshotModal.snapshotId && (_jsx(DestroySnapshotModal, { isOpen: snapshotModal.isOpen, onClose: () => setSnapshotModal({ isOpen: false, snapshotId: '' }), snapshotId: snapshotModal.snapshotId, instanceId: instanceId, afterSubmitClick: () => stores.main.load(instanceId), destroySnapshot: stores.main.destroySnapshot }))] }));
157
+ });
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ interface SnapshotsTableProps {
3
+ instanceId: string;
4
+ }
5
+ export declare const SnapshotsTable: React.FC<SnapshotsTableProps>;
6
+ export {};