slice-machine-ui 1.23.2-beta.1 → 1.23.2-beta.11

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 (164) hide show
  1. package/.depcheckrc +3 -0
  2. package/components/ChangesEmptyState/OfflinePage.tsx +1 -1
  3. package/components/ChangesItems/ChangesItems.tsx +6 -2
  4. package/components/CustomTypeTable/changesPage.tsx +12 -7
  5. package/components/DeleteSliceModal/index.tsx +37 -24
  6. package/components/DeleteVariationModal/index.tsx +1 -0
  7. package/components/Forms/CreateCustomTypeModal/CreateCustomTypeModal.tsx +65 -38
  8. package/components/Forms/CreateSliceModal/CreateSliceModal.tsx +3 -1
  9. package/components/Forms/RenameCustomTypeModal/RenameCustomTypeModal.tsx +7 -2
  10. package/components/Forms/RenameSliceModal/RenameSliceModal.tsx +36 -21
  11. package/components/Forms/RenameVariationModal/RenameVariationModal.tsx +0 -1
  12. package/components/LoginModal/index.tsx +40 -2
  13. package/components/ModalFormCard/index.tsx +0 -1
  14. package/components/Navigation/ChangesItem.tsx +117 -0
  15. package/components/Navigation/Environment.tsx +51 -4
  16. package/components/Navigation/index.css.ts +1 -2
  17. package/components/Navigation/index.test.tsx +5 -85
  18. package/components/Navigation/index.tsx +32 -20
  19. package/components/ReviewModal/ReviewForm.tsx +0 -1
  20. package/lib/builders/SliceBuilder/index.tsx +3 -3
  21. package/lib/builders/common/EditModal/Form.jsx +0 -1
  22. package/lib/builders/common/Zone/Card/components/NewField.tsx +0 -1
  23. package/lib/models/common/ModelStatus/index.ts +25 -0
  24. package/lib/models/common/widgets/StructuredText/index.ts +1 -1
  25. package/out/404.html +1 -1
  26. package/out/_next/static/chunks/18539003-5f78714a35fde4a1.js +97 -0
  27. package/out/_next/static/chunks/25-3aa4d4b24167d340.js +1 -0
  28. package/out/_next/static/chunks/318-19dbcae10cdb6408.js +1 -0
  29. package/out/_next/static/chunks/727-de03055e40815a3a.js +1 -0
  30. package/out/_next/static/chunks/777-8c5507e3b119b5dc.js +8 -0
  31. package/out/_next/static/chunks/799-0af1215eb2b3c17e.js +1 -0
  32. package/out/_next/static/chunks/904-40686b0426716111.js +1 -0
  33. package/out/_next/static/chunks/pages/_app-bca191df4ac7078e.js +434 -0
  34. package/out/_next/static/chunks/pages/{changelog-afd18276fe018b24.js → changelog-cb1df3a70b20f1b8.js} +1 -1
  35. package/out/_next/static/chunks/pages/changes-ccfd715c2bdc4f83.js +1 -0
  36. package/out/_next/static/chunks/pages/custom-types/{[customTypeId]-3f862ad6111a1fc0.js → [customTypeId]-97ab3b90b85d645d.js} +1 -1
  37. package/out/_next/static/chunks/pages/{custom-types-94b8f8dbf7727412.js → custom-types-3c8e721ec6802127.js} +1 -1
  38. package/out/_next/static/chunks/pages/index-cf93d16e9c63b6db.js +1 -0
  39. package/out/_next/static/chunks/pages/{labs-ee206005948f8e87.js → labs-2adfb5127f9c4081.js} +1 -1
  40. package/out/_next/static/chunks/pages/page-types/{[pageTypeId]-d1ffca11c42f2603.js → [pageTypeId]-84a22c5e480d3fa9.js} +1 -1
  41. package/out/_next/static/chunks/pages/settings-94bcd7422e8b237d.js +1 -0
  42. package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]/{simulator-897ca93c114a1435.js → simulator-aaf65fbec8f5839c.js} +1 -1
  43. package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]-90bb2ea76d2abf42.js +1 -0
  44. package/out/_next/static/chunks/pages/slices-e0ce615c38e8338d.js +1 -0
  45. package/out/_next/static/css/39e089aad1742a3a.css +1 -0
  46. package/out/_next/static/css/{37153180c3b0dd66.css → 838fd8bb5a7c32b0.css} +1 -1
  47. package/out/_next/static/css/ca32882a5d2d8d88.css +1 -0
  48. package/out/_next/static/dS_xZnzzna6Y6uwcTgf90/_buildManifest.js +1 -0
  49. package/out/changelog.html +1 -1
  50. package/out/changes.html +1 -1
  51. package/out/custom-types/[customTypeId].html +1 -1
  52. package/out/custom-types.html +1 -1
  53. package/out/index.html +1 -1
  54. package/out/labs.html +1 -1
  55. package/out/page-types/[pageTypeId].html +1 -1
  56. package/out/settings.html +1 -0
  57. package/out/slices/[lib]/[sliceName]/[variation]/simulator.html +1 -1
  58. package/out/slices/[lib]/[sliceName]/[variation].html +1 -1
  59. package/out/slices.html +1 -1
  60. package/package.json +9 -6
  61. package/pages/_app.tsx +34 -32
  62. package/pages/changes.tsx +27 -41
  63. package/pages/settings.tsx +1 -0
  64. package/pages/slices.tsx +20 -8
  65. package/postcss.config.js +10 -0
  66. package/src/apiClient.ts +1 -22
  67. package/src/components/FieldSet/FieldSet.stories.tsx +20 -11
  68. package/src/components/RelativeTime/RelativeTime.stories.tsx +25 -0
  69. package/src/components/RelativeTime/RelativeTime.tsx +40 -0
  70. package/src/components/RelativeTime/index.ts +1 -0
  71. package/src/components/SideNav/SideNav.css.ts +1 -1
  72. package/src/components/SideNav/SideNav.tsx +9 -5
  73. package/src/components/SideNav/SideNavEnvironmentSelector.tsx +31 -11
  74. package/src/domain/__tests__/customType.test.ts +205 -19
  75. package/src/domain/customType.ts +132 -7
  76. package/src/domain/slice.ts +38 -0
  77. package/src/features/autoSave/AutoSaveStatusIndicator.tsx +4 -4
  78. package/src/features/customTypes/PageTypeOnboarding.tsx +21 -26
  79. package/src/features/customTypes/actions/convertCustomToPageType.ts +14 -10
  80. package/src/features/customTypes/actions/createCustomType.ts +69 -0
  81. package/src/features/customTypes/actions/deleteCustomType.ts +13 -3
  82. package/src/features/customTypes/actions/renameCustomType.ts +10 -4
  83. package/src/features/customTypes/customTypesBuilder/CustomTypeProvider.tsx +11 -10
  84. package/src/features/customTypes/customTypesBuilder/CustomTypesBuilderPage.tsx +5 -3
  85. package/src/features/customTypes/customTypesTable/CustomTypesTable.tsx +8 -8
  86. package/src/features/customTypes/customTypesTable/CustomTypesTablePage.tsx +18 -17
  87. package/src/features/environments/actions/setEnvironment.ts +4 -4
  88. package/src/features/settings/SettingsPage.tsx +47 -0
  89. package/src/features/settings/git/ConnectGitRepository.tsx +126 -0
  90. package/src/features/settings/git/ConnectGitRepositoryBlankSlate.tsx +33 -0
  91. package/src/features/settings/git/GitOwnerSelect.tsx +71 -0
  92. package/src/features/settings/git/GitProvider.ts +40 -0
  93. package/src/features/settings/git/GitProviderConnectButtons.tsx +63 -0
  94. package/src/features/settings/git/GitRepositoriesList.tsx +76 -0
  95. package/src/features/settings/git/GitRepositoriesSearch.tsx +69 -0
  96. package/src/features/settings/git/GitRepositoryConnectDialog.tsx +85 -0
  97. package/src/features/settings/git/GitRepositoryDisconnectDialog.tsx +60 -0
  98. package/src/features/settings/git/useGitIntegrationExperiment.ts +8 -0
  99. package/src/features/settings/git/useGitOwners.ts +12 -0
  100. package/src/features/settings/git/useGitRepos.ts +24 -0
  101. package/src/features/settings/git/useLinkedGitRepos.ts +41 -0
  102. package/src/features/settings/git/useWriteAPIToken.ts +23 -0
  103. package/src/features/slices/actions/createSlice.ts +5 -29
  104. package/src/features/slices/actions/deleteSlice.ts +33 -0
  105. package/src/features/slices/actions/renameSlice.ts +37 -0
  106. package/src/features/slices/convertLegacySlice/ConvertLegacySliceAsNewSliceDialog.tsx +0 -1
  107. package/src/features/slices/convertLegacySlice/ConvertLegacySliceAsNewVariationDialog.tsx +0 -1
  108. package/src/features/slices/convertLegacySlice/ConvertLegacySliceMergeWithIdenticalDialog.tsx +0 -1
  109. package/src/features/slices/sliceBuilder/SliceBuilderProvider.tsx +12 -10
  110. package/src/features/sync/AutoSyncProvider.tsx +252 -0
  111. package/src/features/sync/components/AutoSyncStatusIndicator.module.css +17 -0
  112. package/src/features/sync/components/AutoSyncStatusIndicator.module.css.d.ts +5 -0
  113. package/src/features/sync/components/AutoSyncStatusIndicator.tsx +58 -0
  114. package/src/features/sync/fetchUnSyncChanges.ts +40 -0
  115. package/src/features/sync/getUnSyncChanges.ts +144 -0
  116. package/src/features/sync/useUnSyncChanges.ts +32 -0
  117. package/src/hooks/useActionQueue.tsx +177 -0
  118. package/src/hooks/useAuthStatus.ts +12 -0
  119. package/src/hooks/useUser.ts +14 -0
  120. package/src/icons/SettingsIcon.tsx +19 -0
  121. package/src/icons/SyncFailed.tsx +30 -0
  122. package/src/icons/Synced.tsx +19 -0
  123. package/src/icons/Syncing.tsx +23 -0
  124. package/src/modules/availableCustomTypes/index.ts +29 -135
  125. package/src/modules/loading/types.ts +0 -5
  126. package/src/modules/modal/types.ts +0 -3
  127. package/src/modules/slices/index.ts +27 -193
  128. package/src/modules/slices/selector.ts +0 -14
  129. package/src/modules/useSliceMachineActions.ts +70 -89
  130. package/src/modules/userContext/index.ts +3 -3
  131. package/src/redux/saga.ts +0 -4
  132. package/test/__testutils__/index.tsx +8 -5
  133. package/test/src/modules/__fixtures__/serverState.ts +1 -2
  134. package/test/src/modules/availableCustomTypes/index.test.ts +2 -243
  135. package/test/src/modules/slices.test.ts +1 -267
  136. package/components/Navigation/ChangesListItem.tsx +0 -92
  137. package/components/Navigation/ChangesRightElement.tsx +0 -33
  138. package/out/_next/static/chunks/18539003-5cc559566b738915.js +0 -97
  139. package/out/_next/static/chunks/25-37d6fa7f064be04b.js +0 -1
  140. package/out/_next/static/chunks/318-ce7e74f18f2d5b22.js +0 -1
  141. package/out/_next/static/chunks/376-7e784d6069e01654.js +0 -8
  142. package/out/_next/static/chunks/727-3a3bc32518778317.js +0 -1
  143. package/out/_next/static/chunks/731-501990ebe6a71b32.js +0 -1
  144. package/out/_next/static/chunks/904-9a4c1264727ae89a.js +0 -1
  145. package/out/_next/static/chunks/pages/_app-cd9d4c76a4abc11a.js +0 -432
  146. package/out/_next/static/chunks/pages/changes-2a976f9efeb719aa.js +0 -1
  147. package/out/_next/static/chunks/pages/index-64cfb8b0948ba8ef.js +0 -1
  148. package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]-b2a9d773ce5d7739.js +0 -1
  149. package/out/_next/static/chunks/pages/slices-e9c70c082ca3e3f9.js +0 -1
  150. package/out/_next/static/css/200244e3e0463c39.css +0 -1
  151. package/out/_next/static/m6psnC5u1xT7Y6osWHKjp/_buildManifest.js +0 -1
  152. package/src/features/autoSave/useAutoSave.tsx +0 -177
  153. package/src/features/customTypes/__tests__/createCustomType.test.ts +0 -159
  154. package/src/features/customTypes/customTypesTable/createCustomType.ts +0 -107
  155. package/src/features/legacyState/actions/getLegacySliceMachineState.ts +0 -53
  156. package/src/features/legacyState/useLegacySliceMachineState.ts +0 -7
  157. package/src/hooks/useModelStatus.ts +0 -78
  158. package/src/hooks/useUnSyncChanges.ts +0 -88
  159. package/test/components/CreateCustomTypeModal.test.tsx +0 -73
  160. package/test/components/LoginModal.test.tsx +0 -67
  161. package/test/src/hooks/useModelStatus.test.ts +0 -115
  162. /package/out/_next/static/{m6psnC5u1xT7Y6osWHKjp → dS_xZnzzna6Y6uwcTgf90}/_ssgManifest.js +0 -0
  163. /package/src/features/{changes → sync}/actions/pushChanges.ts +0 -0
  164. /package/src/features/{changes → sync}/actions/trackPushChangesSuccess.ts +0 -0
package/.depcheckrc CHANGED
@@ -6,6 +6,9 @@ ignores:
6
6
  "@vitest/coverage-v8",
7
7
  "monocle-ts",
8
8
  "newtype-ts",
9
+ "postcss",
10
+ "postcss-flexbugs-fixes",
11
+ "postcss-preset-env",
9
12
  "semver",
10
13
  "start-slicemachine",
11
14
  "stylelint-config-css-modules",
@@ -28,7 +28,7 @@ export const OfflinePage = () => {
28
28
  <Text
29
29
  sx={{ fontSize: "13px", lineHeight: "24px", textAlign: "center" }}
30
30
  >
31
- You need a stable internet connection to review and push changes
31
+ Connect to the internet to sync your changes.
32
32
  </Text>
33
33
  </Flex>
34
34
  </Flex>
@@ -6,19 +6,23 @@ import { ChangesSectionHeader } from "@components/ChangesSectionHeader";
6
6
  import { CustomTypeTable } from "@components/CustomTypeTable/changesPage";
7
7
  import Grid from "@components/Grid";
8
8
  import { ComponentUI } from "@lib/models/common/ComponentUI";
9
- import { ModelStatusInformation } from "@src/hooks/useModelStatus";
10
9
  import ScreenshotChangesModal from "@components/ScreenshotChangesModal";
11
10
  import { countMissingScreenshots } from "@src/domain/slice";
12
11
  import { useScreenshotChangesModal } from "@src/hooks/useScreenshotChangesModal";
13
12
  import { ModelStatus } from "@lib/models/common/ModelStatus";
14
13
  import { LocalOrRemoteCustomType } from "@lib/models/common/ModelData";
15
14
  import { SharedSliceCard } from "@src/features/slices/sliceCards/SharedSliceCard";
15
+ import { AuthStatus } from "@src/modules/userContext/types";
16
+ import { ModelsStatuses } from "@src/features/sync/getUnSyncChanges";
16
17
 
17
18
  import { DevCollaborationExperiment } from "./DevCollaborationExperiment";
18
19
 
19
- interface ChangesItemsProps extends ModelStatusInformation {
20
+ interface ChangesItemsProps {
20
21
  unSyncedCustomTypes: LocalOrRemoteCustomType[];
21
22
  unSyncedSlices: ComponentUI[];
23
+ modelsStatuses: ModelsStatuses;
24
+ authStatus: AuthStatus;
25
+ isOnline: boolean;
22
26
  }
23
27
 
24
28
  export const ChangesItems: React.FC<ChangesItemsProps> = ({
@@ -1,7 +1,6 @@
1
1
  import Link from "next/link";
2
2
  import React from "react";
3
3
  import { Box, Text } from "theme-ui";
4
- import { ModelStatusInformation } from "@src/hooks/useModelStatus";
5
4
  import { CustomTypeSM } from "@lib/models/common/CustomType";
6
5
  import { ModelStatus } from "@lib/models/common/ModelStatus";
7
6
  import {
@@ -10,18 +9,26 @@ import {
10
9
  } from "@lib/models/common/ModelData";
11
10
  import { StatusBadge } from "@src/features/changes/StatusBadge";
12
11
  import { CUSTOM_TYPES_CONFIG } from "@src/features/customTypes/customTypesConfig";
12
+ import { AuthStatus } from "@src/modules/userContext/types";
13
+ import { ModelsStatuses } from "@src/features/sync/getUnSyncChanges";
13
14
 
14
- interface CustomTypeTableProps extends ModelStatusInformation {
15
+ interface CustomTypeTableProps {
15
16
  customTypes: LocalOrRemoteCustomType[];
17
+ modelsStatuses: ModelsStatuses;
18
+ authStatus: AuthStatus;
19
+ isOnline: boolean;
16
20
  }
17
21
 
18
22
  const firstColumnWidth = "40%";
19
23
  const secondColumnWidth = "40%";
20
24
  const thirdColumnWidth = "20%";
21
25
 
22
- const CustomTypeChangeRow: React.FC<
23
- { ct: CustomTypeSM; status: ModelStatus } & ModelStatusInformation
24
- > = ({ ct, status, authStatus, isOnline }) => {
26
+ const CustomTypeChangeRow: React.FC<{
27
+ ct: CustomTypeSM;
28
+ status: ModelStatus;
29
+ authStatus: AuthStatus;
30
+ isOnline: boolean;
31
+ }> = ({ ct, status, authStatus, isOnline }) => {
25
32
  return (
26
33
  <>
27
34
  <Box as={"td"} style={{ width: firstColumnWidth }}>
@@ -80,7 +87,6 @@ export const CustomTypeTable: React.FC<CustomTypeTableProps> = ({
80
87
  status={modelsStatuses.customTypes[customType.local.id]}
81
88
  authStatus={authStatus}
82
89
  isOnline={isOnline}
83
- modelsStatuses={modelsStatuses}
84
90
  key={customType.local.id}
85
91
  />
86
92
  </tr>
@@ -97,7 +103,6 @@ export const CustomTypeTable: React.FC<CustomTypeTableProps> = ({
97
103
  status={modelsStatuses.customTypes[customType.remote.id]}
98
104
  authStatus={authStatus}
99
105
  isOnline={isOnline}
100
- modelsStatuses={modelsStatuses}
101
106
  key={customType.remote.id}
102
107
  />
103
108
  </tr>
@@ -1,46 +1,57 @@
1
+ import { useState } from "react";
2
+ import { MdOutlineDelete } from "react-icons/md";
3
+ import { Close, Flex, Heading, Paragraph, Text, useThemeUI } from "theme-ui";
4
+
1
5
  import SliceMachineModal from "@components/SliceMachineModal";
2
- import { useSelector } from "react-redux";
3
- import { SliceMachineStoreType } from "@src/redux/type";
4
- import { isModalOpen } from "@src/modules/modal";
5
- import { ModalKeysEnum } from "@src/modules/modal/types";
6
6
  import useSliceMachineActions from "@src/modules/useSliceMachineActions";
7
- import { Close, Flex, Heading, Paragraph, Text, useThemeUI } from "theme-ui";
8
7
  import Card from "@components/Card";
9
- import { MdOutlineDelete } from "react-icons/md";
10
8
  import { Button } from "@components/Button";
11
- import { LoadingKeysEnum } from "@src/modules/loading/types";
12
- import { isLoading } from "@src/modules/loading";
9
+ import { deleteSlice } from "@src/features/slices/actions/deleteSlice";
10
+ import { useAutoSync } from "@src/features/sync/AutoSyncProvider";
13
11
 
14
12
  type DeleteSliceModalProps = {
13
+ isOpen: boolean;
14
+ libName: string;
15
15
  sliceId: string;
16
16
  sliceName: string;
17
- libName: string;
17
+ onClose: () => void;
18
18
  };
19
19
 
20
20
  export const DeleteSliceModal: React.FunctionComponent<
21
21
  DeleteSliceModalProps
22
- > = ({ sliceId, sliceName, libName }) => {
23
- const { isSliceModalOpen, isDeletingSlice } = useSelector(
24
- (store: SliceMachineStoreType) => ({
25
- isSliceModalOpen: isModalOpen(store, ModalKeysEnum.DELETE_SLICE),
26
- isDeletingSlice: isLoading(store, LoadingKeysEnum.DELETE_SLICE),
27
- }),
28
- );
22
+ > = ({ sliceId, sliceName, libName, isOpen, onClose }) => {
23
+ const [isDeleting, setIsDeleting] = useState(false);
24
+ const { deleteSliceSuccess } = useSliceMachineActions();
25
+ const { syncChanges } = useAutoSync();
26
+ const { theme } = useThemeUI();
29
27
 
30
- const { closeModals, deleteSlice } = useSliceMachineActions();
28
+ const onDelete = async () => {
29
+ setIsDeleting(true);
31
30
 
32
- const { theme } = useThemeUI();
31
+ await deleteSlice({
32
+ sliceID: sliceId,
33
+ sliceName,
34
+ libraryID: libName,
35
+ onSuccess: () => {
36
+ deleteSliceSuccess(sliceId, libName);
37
+ syncChanges();
38
+ },
39
+ });
40
+
41
+ onClose();
42
+ setIsDeleting(false);
43
+ };
33
44
 
34
45
  return (
35
46
  <SliceMachineModal
36
- isOpen={isSliceModalOpen}
47
+ isOpen={isOpen}
37
48
  shouldCloseOnOverlayClick={true}
38
49
  style={{
39
50
  content: {
40
51
  maxWidth: 612,
41
52
  },
42
53
  }}
43
- onRequestClose={closeModals}
54
+ onRequestClose={onClose}
44
55
  >
45
56
  <Card
46
57
  bodySx={{
@@ -79,7 +90,7 @@ export const DeleteSliceModal: React.FunctionComponent<
79
90
  Delete Slice
80
91
  </Heading>
81
92
  </Flex>
82
- <Close type="button" onClick={closeModals} />
93
+ <Close type="button" onClick={onClose} />
83
94
  </Flex>
84
95
  )}
85
96
  Footer={() => (
@@ -96,7 +107,7 @@ export const DeleteSliceModal: React.FunctionComponent<
96
107
  <Button
97
108
  label="Cancel"
98
109
  variant="secondary"
99
- onClick={() => closeModals()}
110
+ onClick={onClose}
100
111
  sx={{
101
112
  mr: "10px",
102
113
  fontWeight: "bold",
@@ -107,9 +118,11 @@ export const DeleteSliceModal: React.FunctionComponent<
107
118
  <Button
108
119
  label="Delete"
109
120
  variant="danger"
110
- isLoading={isDeletingSlice}
121
+ isLoading={isDeleting}
111
122
  sx={{ minHeight: 39, minWidth: 78 }}
112
- onClick={() => deleteSlice(sliceId, sliceName, libName)}
123
+ onClick={() => {
124
+ void onDelete();
125
+ }}
113
126
  />
114
127
  </Flex>
115
128
  )}
@@ -52,6 +52,7 @@ export const DeleteVariationModal: FC<DeleteVariationModalProps> = ({
52
52
  <DialogActions
53
53
  ok={{
54
54
  text: "Delete",
55
+ color: "tomato",
55
56
  onClick: () => {
56
57
  if (!variation) return;
57
58
  void (async () => {
@@ -2,25 +2,29 @@ import { SetStateAction, useState } from "react";
2
2
  import { Box } from "theme-ui";
3
3
  import { FormikErrors } from "formik";
4
4
  import { useSelector } from "react-redux";
5
+ import { useRouter } from "next/router";
5
6
 
6
7
  import ModalFormCard from "@components/ModalFormCard";
7
- import { InputBox } from "../components/InputBox";
8
- import { SelectRepeatable } from "../components/SelectRepeatable";
9
8
  import useSliceMachineActions from "@src/modules/useSliceMachineActions";
10
9
  import { SliceMachineStoreType } from "@src/redux/type";
11
10
  import {
12
11
  selectAllCustomTypeIds,
13
12
  selectAllCustomTypeLabels,
14
13
  } from "@src/modules/availableCustomTypes";
15
- import { isModalOpen } from "@src/modules/modal";
16
- import { ModalKeysEnum } from "@src/modules/modal/types";
17
- import { isLoading } from "@src/modules/loading";
18
- import { LoadingKeysEnum } from "@src/modules/loading/types";
19
- import { telemetry } from "@src/apiClient";
20
14
  import { slugify } from "@lib/utils/str";
21
15
  import { API_ID_REGEX } from "@lib/consts";
22
16
  import type { CustomTypeFormat } from "@slicemachine/manager";
23
17
  import { CUSTOM_TYPES_MESSAGES } from "@src/features/customTypes/customTypesMessages";
18
+ import {
19
+ CustomTypeOrigin,
20
+ createCustomType,
21
+ } from "@src/features/customTypes/actions/createCustomType";
22
+ import { CUSTOM_TYPES_CONFIG } from "@src/features/customTypes/customTypesConfig";
23
+ import { getFormat } from "@src/domain/customType";
24
+ import { useAutoSync } from "@src/features/sync/AutoSyncProvider";
25
+
26
+ import { InputBox } from "../components/InputBox";
27
+ import { SelectRepeatable } from "../components/SelectRepeatable";
24
28
 
25
29
  interface FormValues {
26
30
  id: string;
@@ -30,46 +34,67 @@ interface FormValues {
30
34
 
31
35
  type CreateCustomTypeModalProps = {
32
36
  format: CustomTypeFormat;
33
- origin?: "onboarding" | "table";
37
+ isCreating: boolean;
38
+ isOpen: boolean;
39
+ origin?: CustomTypeOrigin;
40
+ onCreateChange: (isCreating: boolean) => void;
41
+ onOpenChange: (isOpen: boolean) => void;
34
42
  };
35
43
 
36
44
  export const CreateCustomTypeModal: React.FC<CreateCustomTypeModalProps> = ({
37
45
  format,
46
+ isCreating,
47
+ isOpen,
38
48
  origin = "table",
49
+ onCreateChange,
50
+ onOpenChange,
39
51
  }) => {
40
- const { createCustomType, closeModals } = useSliceMachineActions();
41
-
42
- const {
43
- customTypeIds,
44
- isCreateCustomTypeModalOpen,
45
- isCreatingCustomType,
46
- customTypeLabels,
47
- } = useSelector((store: SliceMachineStoreType) => ({
48
- customTypeIds: selectAllCustomTypeIds(store),
49
- customTypeLabels: selectAllCustomTypeLabels(store),
50
- isCreateCustomTypeModalOpen: isModalOpen(
51
- store,
52
- ModalKeysEnum.CREATE_CUSTOM_TYPE,
53
- ),
54
- isCreatingCustomType: isLoading(store, LoadingKeysEnum.CREATE_CUSTOM_TYPE),
55
- }));
52
+ const { createCustomTypeSuccess } = useSliceMachineActions();
53
+
54
+ const { customTypeIds, customTypeLabels } = useSelector(
55
+ (store: SliceMachineStoreType) => ({
56
+ customTypeIds: selectAllCustomTypeIds(store),
57
+ customTypeLabels: selectAllCustomTypeLabels(store),
58
+ }),
59
+ );
56
60
  const customTypesMessages = CUSTOM_TYPES_MESSAGES[format];
57
61
  const [isIdFieldPristine, setIsIdFieldPristine] = useState(true);
62
+ const { syncChanges } = useAutoSync();
63
+ const router = useRouter();
58
64
 
59
- const createCustomTypeAndTrack = ({ id, label, repeatable }: FormValues) => {
60
- const name = label || id;
65
+ const onSubmit = async ({ id, label, repeatable }: FormValues) => {
66
+ onCreateChange(true);
61
67
 
62
- void telemetry.track({
63
- event: "custom-type:created",
64
- id,
65
- name,
68
+ await createCustomType({
66
69
  format,
67
- type: repeatable ? "repeatable" : "single",
70
+ id,
71
+ label,
68
72
  origin,
73
+ repeatable,
74
+ onSuccess: async (newCustomType) => {
75
+ createCustomTypeSuccess(newCustomType);
76
+
77
+ const format = getFormat(newCustomType);
78
+ const customTypesConfig = CUSTOM_TYPES_CONFIG[format];
79
+
80
+ setIsIdFieldPristine(true);
81
+
82
+ await router.push({
83
+ pathname: customTypesConfig.getBuilderPagePathname(id),
84
+ query:
85
+ newCustomType.format === "page"
86
+ ? {
87
+ newPageType: true,
88
+ }
89
+ : undefined,
90
+ });
91
+
92
+ syncChanges();
93
+ },
69
94
  });
70
- createCustomType(id, name, repeatable, format);
71
- closeModals();
72
- setIsIdFieldPristine(true);
95
+
96
+ onCreateChange(false);
97
+ onOpenChange(false);
73
98
  };
74
99
 
75
100
  const handleLabelChange = (
@@ -106,16 +131,18 @@ export const CreateCustomTypeModal: React.FC<CreateCustomTypeModalProps> = ({
106
131
  return (
107
132
  <ModalFormCard
108
133
  dataCy="create-ct-modal"
109
- isOpen={isCreateCustomTypeModalOpen}
134
+ isOpen={isOpen}
110
135
  widthInPx="530px"
111
136
  formId="create-custom-type"
112
137
  buttonLabel={"Create"}
113
138
  close={() => {
114
- closeModals();
139
+ onOpenChange(false);
115
140
  setIsIdFieldPristine(true);
116
141
  }}
117
- onSubmit={createCustomTypeAndTrack}
118
- isLoading={isCreatingCustomType}
142
+ onSubmit={(values) => {
143
+ void onSubmit(values);
144
+ }}
145
+ isLoading={isCreating}
119
146
  initialValues={{
120
147
  repeatable: true,
121
148
  id: "",
@@ -9,6 +9,7 @@ import ModalFormCard from "@components/ModalFormCard";
9
9
  import { createSlice } from "@src/features/slices/actions/createSlice";
10
10
  import useSliceMachineActions from "@src/modules/useSliceMachineActions";
11
11
  import { getState } from "@src/apiClient";
12
+ import { useAutoSync } from "@src/features/sync/AutoSyncProvider";
12
13
 
13
14
  import { validateSliceModalValues } from "../formsValidator";
14
15
  import { InputBox } from "../components/InputBox";
@@ -30,6 +31,7 @@ export const CreateSliceModal: FC<CreateSliceModalProps> = ({
30
31
  }) => {
31
32
  const { createSliceSuccess } = useSliceMachineActions();
32
33
  const [isCreatingSlice, setIsCreatingSlice] = useState(false);
34
+ const { syncChanges } = useAutoSync();
33
35
 
34
36
  const onSubmit = async (values: FormValues) => {
35
37
  const sliceName = values.sliceName;
@@ -45,8 +47,8 @@ export const CreateSliceModal: FC<CreateSliceModalProps> = ({
45
47
  const serverState = await getState();
46
48
  // Update Redux store
47
49
  createSliceSuccess(serverState.libraries);
48
-
49
50
  onSuccess(newSlice, libraryName);
51
+ syncChanges();
50
52
  },
51
53
  });
52
54
  };
@@ -13,6 +13,7 @@ import { CustomTypeFormat } from "@slicemachine/manager";
13
13
  import { CUSTOM_TYPES_MESSAGES } from "@src/features/customTypes/customTypesMessages";
14
14
 
15
15
  import { renameCustomType } from "@src/features/customTypes/actions/renameCustomType";
16
+ import { useAutoSync } from "@src/features/sync/AutoSyncProvider";
16
17
 
17
18
  interface RenameCustomTypeModalProps {
18
19
  isChangesLocal: boolean;
@@ -31,7 +32,8 @@ export const RenameCustomTypeModal: React.FC<RenameCustomTypeModalProps> = ({
31
32
  }) => {
32
33
  const customTypeName = customType?.label ?? "";
33
34
  const customTypeId = customType?.id ?? "";
34
- const { renameAvailableCustomTypeSuccess } = useSliceMachineActions();
35
+ const { renameCustomTypeSuccess } = useSliceMachineActions();
36
+ const { syncChanges } = useAutoSync();
35
37
 
36
38
  const [isRenaming, setIsRenaming] = useState(false);
37
39
 
@@ -46,7 +48,10 @@ export const RenameCustomTypeModal: React.FC<RenameCustomTypeModalProps> = ({
46
48
  await renameCustomType({
47
49
  model: customType,
48
50
  newLabel: values.customTypeName,
49
- onSuccess: renameAvailableCustomTypeSuccess,
51
+ onSuccess: (renamedCustomType) => {
52
+ renameCustomTypeSuccess(renamedCustomType);
53
+ syncChanges();
54
+ },
50
55
  });
51
56
  }
52
57
  setIsRenaming(false);
@@ -1,50 +1,65 @@
1
1
  import { Box } from "theme-ui";
2
- import useSliceMachineActions from "@src/modules/useSliceMachineActions";
3
- import ModalFormCard from "../../ModalFormCard";
4
- import { InputBox } from "../components/InputBox";
5
2
  import { useSelector } from "react-redux";
3
+
4
+ import useSliceMachineActions from "@src/modules/useSliceMachineActions";
6
5
  import { SliceMachineStoreType } from "@src/redux/type";
7
- import { isModalOpen } from "@src/modules/modal";
8
- import { ModalKeysEnum } from "@src/modules/modal/types";
9
6
  import { getLibraries, getRemoteSlices } from "@src/modules/slices";
7
+ import { ComponentUI } from "@lib/models/common/ComponentUI";
8
+ import { renameSlice } from "@src/features/slices/actions/renameSlice";
9
+ import { useAutoSync } from "@src/features/sync/AutoSyncProvider";
10
+
11
+ import { InputBox } from "../components/InputBox";
12
+ import ModalFormCard from "../../ModalFormCard";
10
13
  import { SliceModalValues } from "../formsTypes";
11
14
  import { validateSliceModalValues } from "../formsValidator";
12
15
 
13
16
  interface RenameSliceModalProps {
14
- sliceName: string;
15
- sliceId: string;
16
- libName: string;
17
+ isOpen: boolean;
18
+ slice?: ComponentUI;
19
+ onClose: () => void;
17
20
  }
18
21
 
19
22
  export const RenameSliceModal: React.FC<RenameSliceModalProps> = ({
20
- sliceName,
21
- sliceId,
22
- libName,
23
+ slice,
24
+ isOpen,
25
+ onClose,
23
26
  }) => {
24
- const { renameSlice, closeModals } = useSliceMachineActions();
25
- const { isRenameSliceModalOpen, localLibs, remoteLibs } = useSelector(
27
+ const { renameSliceSuccess } = useSliceMachineActions();
28
+ const { syncChanges } = useAutoSync();
29
+ const { localLibs, remoteLibs } = useSelector(
26
30
  (store: SliceMachineStoreType) => ({
27
- isRenameSliceModalOpen: isModalOpen(store, ModalKeysEnum.RENAME_SLICE),
28
31
  localLibs: getLibraries(store),
29
32
  remoteLibs: getRemoteSlices(store),
30
33
  }),
31
34
  );
35
+ const initialSliceName = slice?.model.name ?? "";
36
+
37
+ const handleOnSubmit = async (values: SliceModalValues) => {
38
+ if (slice) {
39
+ await renameSlice({
40
+ slice,
41
+ newSliceName: values.sliceName,
42
+ onSuccess: (renamedSlice) => {
43
+ renameSliceSuccess(renamedSlice.from, renamedSlice.model);
44
+ syncChanges();
45
+ },
46
+ });
32
47
 
33
- const handleOnSubmit = (values: SliceModalValues) => {
34
- renameSlice(libName, sliceId, values.sliceName);
48
+ onClose();
49
+ }
35
50
  };
36
51
 
37
52
  return (
38
53
  <ModalFormCard<SliceModalValues>
39
54
  dataCy="rename-slice-modal"
40
- isOpen={isRenameSliceModalOpen}
55
+ isOpen={isOpen}
41
56
  widthInPx="530px"
42
- formId={`rename-slice-modal-${sliceId}`}
43
- close={closeModals}
57
+ formId={`rename-slice-modal-${slice?.model.id ?? ""}`}
58
+ close={onClose}
44
59
  buttonLabel="Rename"
45
- onSubmit={handleOnSubmit}
60
+ onSubmit={(values) => void handleOnSubmit(values)}
46
61
  initialValues={{
47
- sliceName: sliceName,
62
+ sliceName: initialSliceName,
48
63
  }}
49
64
  content={{
50
65
  title: "Rename a slice",
@@ -45,7 +45,6 @@ export const RenameVariationModal: FC<RenameVariationModalProps> = ({
45
45
  <DialogHeader icon="edit" title="Rename variation" />
46
46
  <DialogContent>
47
47
  <Formik
48
- validateOnChange
49
48
  validateOnMount
50
49
  initialValues={{ variationName: variation?.name ?? "" }}
51
50
  validate={(values) => {
@@ -11,7 +11,7 @@ import {
11
11
  Text,
12
12
  } from "theme-ui";
13
13
  import SliceMachineModal from "@components/SliceMachineModal";
14
- import { checkAuthStatus, startAuth } from "@src/apiClient";
14
+ import { checkAuthStatus, getState, startAuth } from "@src/apiClient";
15
15
  import { buildEndpoints } from "@lib/prismic/endpoints";
16
16
  import { startPolling } from "@lib/utils/poll";
17
17
  import { CheckAuthStatusResponse } from "@models/common/Auth";
@@ -25,6 +25,12 @@ import { getEnvironment } from "@src/modules/environment";
25
25
  import useSliceMachineActions from "@src/modules/useSliceMachineActions";
26
26
  import preferWroomBase from "@lib/utils/preferWroomBase";
27
27
  import { ToasterType } from "@src/modules/toaster";
28
+ import { getUnSyncedChanges } from "@src/features/sync/getUnSyncChanges";
29
+ import { normalizeFrontendCustomTypes } from "@lib/models/common/normalizers/customType";
30
+ import { normalizeFrontendSlices } from "@lib/models/common/normalizers/slices";
31
+ import { AuthStatus } from "@src/modules/userContext/types";
32
+ import { useAutoSync } from "@src/features/sync/AutoSyncProvider";
33
+ import { getActiveEnvironment } from "@src/features/environments/actions/getActiveEnvironment";
28
34
 
29
35
  interface ValidAuthStatus extends CheckAuthStatusResponse {
30
36
  status: "ok";
@@ -42,7 +48,7 @@ const LoginModal: React.FunctionComponent = () => {
42
48
  env: getEnvironment(store),
43
49
  }),
44
50
  );
45
-
51
+ const { syncChanges } = useAutoSync();
46
52
  const { closeModals, startLoadingLogin, stopLoadingLogin, openToaster } =
47
53
  useSliceMachineActions();
48
54
 
@@ -72,6 +78,38 @@ const LoginModal: React.FunctionComponent = () => {
72
78
  openToaster("Logged in", ToasterType.SUCCESS);
73
79
  stopLoadingLogin();
74
80
  closeModals();
81
+
82
+ const serverState = await getState();
83
+ const slices = normalizeFrontendSlices(
84
+ serverState.libraries,
85
+ serverState.remoteSlices,
86
+ );
87
+ const customTypes = Object.values(
88
+ normalizeFrontendCustomTypes(
89
+ serverState.customTypes,
90
+ serverState.remoteCustomTypes,
91
+ ),
92
+ );
93
+ const { changedCustomTypes, changedSlices } = getUnSyncedChanges({
94
+ authStatus: AuthStatus.AUTHORIZED,
95
+ customTypes,
96
+ isOnline: true,
97
+ libraries: serverState.libraries,
98
+ slices,
99
+ });
100
+ const { activeEnvironment } = await getActiveEnvironment();
101
+
102
+ if (
103
+ activeEnvironment?.kind === "dev" &&
104
+ (changedCustomTypes.length > 0 || changedSlices.length > 0)
105
+ ) {
106
+ syncChanges({
107
+ environment: activeEnvironment,
108
+ loggedIn: true,
109
+ changedCustomTypes,
110
+ changedSlices,
111
+ });
112
+ }
75
113
  } catch (e) {
76
114
  stopLoadingLogin();
77
115
  openToaster("Login failed", ToasterType.ERROR);
@@ -81,7 +81,6 @@ function ModalCard<Values extends FormikValues>({
81
81
  }}
82
82
  >
83
83
  <Formik
84
- validateOnChange
85
84
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
86
85
  initialValues={initialValues}
87
86
  // eslint-disable-next-line @typescript-eslint/no-unsafe-return