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
@@ -0,0 +1,117 @@
1
+ import { type FC } from "react";
2
+ import { useRouter } from "next/router";
3
+ import { Box, Button, Text } from "@prismicio/editor-ui";
4
+
5
+ import {
6
+ HoverCard,
7
+ HoverCardCloseButton,
8
+ HoverCardDescription,
9
+ HoverCardMedia,
10
+ HoverCardTitle,
11
+ } from "@src/components/HoverCard";
12
+ import useSliceMachineActions from "@src/modules/useSliceMachineActions";
13
+ import { useNetwork } from "@src/hooks/useNetwork";
14
+ import { useAuthStatus } from "@src/hooks/useAuthStatus";
15
+ import { useUnSyncChanges } from "@src/features/sync/useUnSyncChanges";
16
+ import { AuthStatus } from "@src/modules/userContext/types";
17
+ import { useAutoSync } from "@src/features/sync/AutoSyncProvider";
18
+ import { AutoSyncStatusIndicator } from "@src/features/sync/components/AutoSyncStatusIndicator";
19
+
20
+ export const ChangesItem: FC = () => {
21
+ const { setSeenChangesToolTip } = useSliceMachineActions();
22
+ const open = useOpenChangesHoverCard();
23
+ const router = useRouter();
24
+ const { autoSyncStatus } = useAutoSync();
25
+
26
+ const onClose = () => {
27
+ setSeenChangesToolTip();
28
+ };
29
+
30
+ return (
31
+ <HoverCard
32
+ open={open}
33
+ openDelay={3000}
34
+ onClose={onClose}
35
+ side="right"
36
+ sideOffset={24}
37
+ collisionPadding={280}
38
+ trigger={
39
+ <Box padding={{ bottom: 24 }}>
40
+ {autoSyncStatus === "failed" ||
41
+ autoSyncStatus === "synced" ||
42
+ autoSyncStatus === "syncing" ? (
43
+ <AutoSyncStatusIndicator autoSyncStatus={autoSyncStatus} />
44
+ ) : (
45
+ // TODO(DT-1942): This should be a Button with a link component for
46
+ // accessibility
47
+ <Button
48
+ color="grey"
49
+ onClick={() => {
50
+ void router.push("/changes");
51
+ }}
52
+ sx={{ width: "100%" }}
53
+ >
54
+ <Box alignItems="center" gap={4}>
55
+ <Text variant="bold">Review changes</Text> <ChangesCount />
56
+ </Box>
57
+ </Button>
58
+ )}
59
+ </Box>
60
+ }
61
+ >
62
+ <HoverCardTitle>Push your changes</HoverCardTitle>
63
+ <HoverCardMedia component="image" src="/push.png" />
64
+ <HoverCardDescription>
65
+ When you click Save, your changes are saved locally. Then, you can push
66
+ your models to Prismic from the Changes page.
67
+ </HoverCardDescription>
68
+ <HoverCardCloseButton>Got it</HoverCardCloseButton>
69
+ </HoverCard>
70
+ );
71
+ };
72
+
73
+ export const ChangesCount: FC = () => {
74
+ const isOnline = useNetwork();
75
+ const authStatus = useAuthStatus();
76
+ const { unSyncedSlices, unSyncedCustomTypes } = useUnSyncChanges();
77
+ const numberOfChanges = unSyncedSlices.length + unSyncedCustomTypes.length;
78
+
79
+ if (
80
+ !isOnline ||
81
+ authStatus === AuthStatus.UNAUTHORIZED ||
82
+ authStatus === AuthStatus.FORBIDDEN
83
+ ) {
84
+ return null;
85
+ }
86
+
87
+ if (numberOfChanges === 0) {
88
+ return null;
89
+ }
90
+
91
+ const formattedNumberOfChanges = numberOfChanges > 9 ? "+9" : numberOfChanges;
92
+
93
+ return (
94
+ <Box padding={{ inline: 6 }} borderRadius={10} backgroundColor="grey5">
95
+ <Text color="grey11" variant="small">
96
+ {formattedNumberOfChanges}
97
+ </Text>
98
+ </Box>
99
+ );
100
+ };
101
+
102
+ // TODO(DT-1925): Reactivate this feature
103
+ const useOpenChangesHoverCard = () => {
104
+ // const { hasSeenChangesToolTip, hasSeenSimulatorToolTip } = useSelector(
105
+ // (store: SliceMachineStoreType) => ({
106
+ // hasSeenChangesToolTip: userHasSeenChangesToolTip(store),
107
+ // hasSeenSimulatorToolTip: userHasSeenSimulatorToolTip(store),
108
+ // }),
109
+ // );
110
+
111
+ // return (
112
+ // !hasSeenChangesToolTip &&
113
+ // hasSeenSimulatorToolTip
114
+ // );
115
+
116
+ return false;
117
+ };
@@ -1,25 +1,40 @@
1
+ import { useState } from "react";
1
2
  import {
2
3
  Environment as EnvironmentType,
3
4
  isUnauthenticatedError,
4
5
  isUnauthorizedError,
5
6
  } from "@slicemachine/manager/client";
6
7
 
7
- import { telemetry } from "@src/apiClient";
8
+ import { getState, telemetry } from "@src/apiClient";
8
9
  import { useEnvironments } from "@src/features/environments/useEnvironments";
9
10
  import { setEnvironment } from "@src/features/environments/actions/setEnvironment";
10
11
  import { useActiveEnvironment } from "@src/features/environments/useActiveEnvironment";
11
- import { getLegacySliceMachineState } from "@src/features/legacyState/actions/getLegacySliceMachineState";
12
12
  import useSliceMachineActions from "@src/modules/useSliceMachineActions";
13
13
  import { SideNavEnvironmentSelector } from "@src/components/SideNav";
14
14
  import { useNetwork } from "@src/hooks/useNetwork";
15
+ import { useAutoSync } from "@src/features/sync/AutoSyncProvider";
16
+ import { normalizeFrontendSlices } from "@lib/models/common/normalizers/slices";
17
+ import { normalizeFrontendCustomTypes } from "@lib/models/common/normalizers/customType";
18
+ import { getUnSyncedChanges } from "@src/features/sync/getUnSyncChanges";
19
+ import { useAuthStatus } from "@src/hooks/useAuthStatus";
15
20
 
16
21
  export function Environment() {
17
22
  const { environments, error: useEnvironmentsError } = useEnvironments();
18
23
  const { activeEnvironment } = useActiveEnvironment();
19
24
  const { refreshState, openLoginModal } = useSliceMachineActions();
25
+ const { syncChanges } = useAutoSync();
20
26
  const isOnline = useNetwork();
27
+ const authStatus = useAuthStatus();
28
+ const [isSwitchingEnv, setIsSwitchingEnv] = useState(false);
29
+ const { autoSyncStatus } = useAutoSync();
21
30
 
22
31
  async function onSelect(environment: EnvironmentType) {
32
+ if (activeEnvironment?.name === environment.name) {
33
+ return;
34
+ }
35
+
36
+ setIsSwitchingEnv(true);
37
+
23
38
  void telemetry.track({
24
39
  event: "environment:switch",
25
40
  domain: environment.domain,
@@ -27,9 +42,39 @@ export function Environment() {
27
42
 
28
43
  await setEnvironment(environment);
29
44
 
30
- const legacySliceMachineState = await getLegacySliceMachineState();
45
+ const serverState = await getState();
46
+ refreshState(serverState);
47
+
48
+ const slices = normalizeFrontendSlices(
49
+ serverState.libraries,
50
+ serverState.remoteSlices,
51
+ );
52
+ const customTypes = Object.values(
53
+ normalizeFrontendCustomTypes(
54
+ serverState.customTypes,
55
+ serverState.remoteCustomTypes,
56
+ ),
57
+ );
58
+ const { changedCustomTypes, changedSlices } = getUnSyncedChanges({
59
+ authStatus,
60
+ customTypes,
61
+ isOnline,
62
+ libraries: serverState.libraries,
63
+ slices,
64
+ });
65
+
66
+ if (
67
+ environment.kind === "dev" &&
68
+ (changedCustomTypes.length > 0 || changedSlices.length > 0)
69
+ ) {
70
+ syncChanges({
71
+ environment,
72
+ changedCustomTypes,
73
+ changedSlices,
74
+ });
75
+ }
31
76
 
32
- refreshState(legacySliceMachineState);
77
+ setIsSwitchingEnv(false);
33
78
  }
34
79
 
35
80
  if (!isOnline) {
@@ -42,6 +87,8 @@ export function Environment() {
42
87
  environments={environments}
43
88
  activeEnvironment={activeEnvironment}
44
89
  onSelect={onSelect}
90
+ disabled={isSwitchingEnv || autoSyncStatus === "syncing"}
91
+ loading={isSwitchingEnv}
45
92
  />
46
93
  );
47
94
  }
@@ -1,6 +1,5 @@
1
1
  import { sprinkles } from "@prismicio/editor-ui";
2
2
 
3
3
  export const environmentDivider = sprinkles({
4
- marginTop: 16,
5
- marginBottom: 32,
4
+ marginBlock: 16,
6
5
  });
@@ -131,10 +131,8 @@ describe("Side Navigation", () => {
131
131
  test.skip.each([
132
132
  ["Page types", "/"],
133
133
  ["Custom types", "/custom-types"],
134
- ["Changes", "/changes"],
135
-
136
- ["Changelog", "/changelog"],
137
134
  ["Slices", "/slices"],
135
+ ["Changelog", "/changelog"],
138
136
  // TODO: once we have a plan fo how to display individual libraries change this
139
137
  // ["Slices/a", "/slices#slices/a"],
140
138
  // ["Slices/b", "/slices#slices/b"]
@@ -156,95 +154,17 @@ describe("Side Navigation", () => {
156
154
  },
157
155
  );
158
156
 
159
- test("should display the number of changes on the 'Changes' item", async () => {
157
+ test("should display the number of changes on the 'Review changes' item", async () => {
160
158
  renderSideNavigation({ canUpdate: true, hasChanges: true });
161
159
 
162
- expect(await screen.findByText("Changes")).toBeVisible();
160
+ expect(await screen.findByText("Review changes")).toBeVisible();
163
161
  const changesItem = screen
164
- .getByText("Changes")
165
- .closest("a") as HTMLAnchorElement;
162
+ .getByText("Review changes")
163
+ .closest("button") as HTMLButtonElement;
166
164
 
167
165
  expect(within(changesItem).getByText("1")).toBeVisible();
168
166
  });
169
167
 
170
- test("should not display the number of changes or 'Disconnect' on the 'Changes' item", async () => {
171
- renderSideNavigation({ canUpdate: true, hasChanges: false });
172
-
173
- expect(await screen.findByText("Changes")).toBeVisible();
174
- const changesItem = screen
175
- .getByText("Changes")
176
- .closest("a") as HTMLAnchorElement;
177
-
178
- expect(within(changesItem).queryByText("1")).not.toBeInTheDocument();
179
- expect(
180
- within(changesItem).queryByText("Logged out"),
181
- ).not.toBeInTheDocument();
182
- });
183
-
184
- test("should display the information that user is disconnected on the 'Changes' item when unauthorized", async () => {
185
- renderSideNavigation({
186
- canUpdate: true,
187
- hasChanges: true,
188
- authStatus: AuthStatus.UNAUTHORIZED,
189
- });
190
-
191
- expect(await screen.findByText("Changes")).toBeVisible();
192
- const changesItem = screen
193
- .getByText("Changes")
194
- .closest("a") as HTMLAnchorElement;
195
-
196
- expect(within(changesItem).getByText("Logged out")).toBeVisible();
197
- });
198
-
199
- test("should display the information that user is disconnected on the 'Changes' item when forbidden", async () => {
200
- renderSideNavigation({
201
- canUpdate: true,
202
- hasChanges: true,
203
- authStatus: AuthStatus.FORBIDDEN,
204
- });
205
-
206
- expect(await screen.findByText("Changes")).toBeVisible();
207
- const changesItem = screen
208
- .getByText("Changes")
209
- .closest("a") as HTMLAnchorElement;
210
-
211
- expect(within(changesItem).getByText("Logged out")).toBeVisible();
212
- });
213
-
214
- test("should display the information that user is disconnected on the 'Changes' item when offline", async () => {
215
- vi.spyOn(navigator, "onLine", "get").mockReturnValueOnce(false);
216
-
217
- renderSideNavigation({
218
- canUpdate: true,
219
- hasChanges: true,
220
- });
221
-
222
- expect(await screen.findByText("Changes")).toBeVisible();
223
- const changesItem = screen
224
- .getByText("Changes")
225
- .closest("a") as HTMLAnchorElement;
226
-
227
- expect(within(changesItem).getByText("Logged out")).toBeVisible();
228
- });
229
-
230
- test("should not display the information that user is disconnected when user is online", async () => {
231
- vi.spyOn(navigator, "onLine", "get").mockReturnValueOnce(true);
232
-
233
- renderSideNavigation({
234
- canUpdate: true,
235
- hasChanges: true,
236
- });
237
-
238
- expect(await screen.findByText("Changes")).toBeVisible();
239
- const changesItem = screen
240
- .getByText("Changes")
241
- .closest("a") as HTMLAnchorElement;
242
-
243
- expect(
244
- within(changesItem).queryByText("Logged out"),
245
- ).not.toBeInTheDocument();
246
- });
247
-
248
168
  test("Video Item with next", async (ctx) => {
249
169
  const adapter = createTestPlugin({
250
170
  meta: {
@@ -8,9 +8,9 @@ import { telemetry } from "@src/apiClient";
8
8
  import VideoItem from "@components/Navigation/VideoItem";
9
9
  import { LightningIcon } from "@src/icons/Lightning";
10
10
  import { MathPlusIcon } from "@src/icons/MathPlusIcon";
11
+ import { SettingsIcon } from "@src/icons/SettingsIcon";
11
12
  import { CUSTOM_TYPES_CONFIG } from "@src/features/customTypes/customTypesConfig";
12
13
  import {
13
- SideNavSeparator,
14
14
  SideNavLink,
15
15
  SideNavListItem,
16
16
  SideNavList,
@@ -26,9 +26,10 @@ import { SliceMachineStoreType } from "@src/redux/type";
26
26
  import useSliceMachineActions from "@src/modules/useSliceMachineActions";
27
27
  import { getChangelog } from "@src/modules/environment";
28
28
  import { CUSTOM_TYPES_MESSAGES } from "@src/features/customTypes/customTypesMessages";
29
+ import { useGitIntegrationExperiment } from "@src/features/settings/git/useGitIntegrationExperiment";
29
30
  import { useRepositoryInformation } from "@src/hooks/useRepositoryInformation";
30
31
 
31
- import { ChangesListItem } from "./ChangesListItem";
32
+ import { ChangesItem } from "./ChangesItem";
32
33
  import { Environment } from "./Environment";
33
34
 
34
35
  import * as styles from "./index.css";
@@ -45,6 +46,7 @@ const Navigation: FC = () => {
45
46
  useSliceMachineActions();
46
47
  const { repositoryName, repositoryDomain, repositoryUrl } =
47
48
  useRepositoryInformation();
49
+ const gitIntegrationExperiment = useGitIntegrationExperiment();
48
50
 
49
51
  return (
50
52
  <SideNav>
@@ -73,6 +75,8 @@ const Navigation: FC = () => {
73
75
  href={repositoryUrl}
74
76
  />
75
77
 
78
+ <ChangesItem />
79
+
76
80
  <SideNavList>
77
81
  <SideNavListItem>
78
82
  <SideNavLink
@@ -104,12 +108,6 @@ const Navigation: FC = () => {
104
108
  />
105
109
  </SideNavListItem>
106
110
 
107
- <SideNavSeparator />
108
-
109
- <ChangesListItem />
110
-
111
- <SideNavSeparator />
112
-
113
111
  <SideNavListItem>
114
112
  <SideNavLink
115
113
  title="Slices"
@@ -141,17 +139,19 @@ const Navigation: FC = () => {
141
139
  )}
142
140
 
143
141
  <SideNavList position="bottom">
144
- <SideNavLink
145
- title="Invite team"
146
- href={`${repositoryUrl}/settings/users`}
147
- Icon={(props) => <MathPlusIcon {...props} />}
148
- onClick={() => {
149
- void telemetry.track({
150
- event: "users-invite-button-clicked",
151
- });
152
- }}
153
- target="_blank"
154
- />
142
+ <SideNavListItem>
143
+ <SideNavLink
144
+ title="Invite team"
145
+ href={`${repositoryUrl}/settings/users`}
146
+ Icon={MathPlusIcon}
147
+ onClick={() => {
148
+ void telemetry.track({
149
+ event: "users-invite-button-clicked",
150
+ });
151
+ }}
152
+ target="_blank"
153
+ />
154
+ </SideNavListItem>
155
155
 
156
156
  <ErrorBoundary>
157
157
  <Suspense>
@@ -162,11 +162,23 @@ const Navigation: FC = () => {
162
162
  </Suspense>
163
163
  </ErrorBoundary>
164
164
 
165
+ {gitIntegrationExperiment.eligible ? (
166
+ <SideNavListItem>
167
+ <SideNavLink
168
+ title="Settings"
169
+ href="/settings"
170
+ Icon={SettingsIcon}
171
+ active={router.asPath.startsWith("/settings")}
172
+ component={Link}
173
+ />
174
+ </SideNavListItem>
175
+ ) : undefined}
176
+
165
177
  <SideNavListItem>
166
178
  <SideNavLink
167
179
  title="Changelog"
168
180
  href="/changelog"
169
- Icon={(props) => <LightningIcon {...props} />}
181
+ Icon={LightningIcon}
170
182
  active={router.asPath.startsWith("/changelog")}
171
183
  component={Link}
172
184
  RightElement={
@@ -94,7 +94,6 @@ export const ReviewForm: FC<ReviewFormProps> = (props) => {
94
94
  >
95
95
  <Formik
96
96
  validateOnMount
97
- validateOnChange
98
97
  initialValues={{
99
98
  rating: 0,
100
99
  comment: "",
@@ -21,7 +21,7 @@ import { useSliceState } from "@src/features/slices/sliceBuilder/SliceBuilderPro
21
21
  import { AutoSaveStatusIndicator } from "@src/features/autoSave/AutoSaveStatusIndicator";
22
22
 
23
23
  export const SliceBuilder: FC = () => {
24
- const { slice, autoSaveStatus } = useSliceState();
24
+ const { slice, actionQueueStatus } = useSliceState();
25
25
 
26
26
  const isSimulatorAvailableForFramework = useSelector(
27
27
  selectIsSimulatorAvailableForFramework,
@@ -33,10 +33,10 @@ export const SliceBuilder: FC = () => {
33
33
  <AppLayoutBackButton url="/slices" />
34
34
  <AppLayoutBreadcrumb folder="Slices" page={slice.model.name} />
35
35
  <AppLayoutActions>
36
- <AutoSaveStatusIndicator status={autoSaveStatus} />
36
+ <AutoSaveStatusIndicator status={actionQueueStatus} />
37
37
  <SimulatorButton
38
38
  isSimulatorAvailableForFramework={isSimulatorAvailableForFramework}
39
- disabled={autoSaveStatus !== "saved"}
39
+ disabled={actionQueueStatus !== "done"}
40
40
  />
41
41
  </AppLayoutActions>
42
42
  </AppLayoutHeader>
@@ -13,7 +13,6 @@ const WidgetForm = ({
13
13
  return (
14
14
  <Box>
15
15
  <Formik
16
- validateOnChange
17
16
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
18
17
  initialValues={initialValues}
19
18
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-assignment
@@ -114,7 +114,6 @@ const NewField: React.FC<NewField> = ({
114
114
 
115
115
  return (
116
116
  <Formik
117
- validateOnChange
118
117
  onSubmit={onSave}
119
118
  validationSchema={validationSchema}
120
119
  initialValues={initialValues}
@@ -117,3 +117,28 @@ export function computeModelStatus(
117
117
  : compareCustomTypeLocalToRemote(model);
118
118
  return { status, model };
119
119
  }
120
+
121
+ export function computeStatuses(
122
+ models: LocalOrRemoteCustomType[],
123
+ userHasAccessToModels: boolean,
124
+ ): { [sliceId: string]: ModelStatus };
125
+ export function computeStatuses(
126
+ models: LocalOrRemoteSlice[],
127
+ userHasAccessToModels: boolean,
128
+ ): { [sliceId: string]: ModelStatus };
129
+ export function computeStatuses(
130
+ models: LocalOrRemoteModel[],
131
+ userHasAccessToModels: boolean,
132
+ ) {
133
+ return models.reduce<{ [id: string]: ModelStatus }>(
134
+ (acc, model) => {
135
+ const { status } = computeModelStatus(model, userHasAccessToModels);
136
+
137
+ return {
138
+ ...acc,
139
+ [hasLocal(model) ? model.local.id : model.remote.id]: status,
140
+ };
141
+ },
142
+ {} as { [sliceId: string]: ModelStatus },
143
+ );
144
+ }
@@ -51,7 +51,7 @@ export const StructuredTextWidget: Widget<RichText, typeof schema> = {
51
51
  label,
52
52
  placeholder: "",
53
53
  allowTargetBlank: true,
54
- single: optionValues.join(","),
54
+ multi: optionValues.join(","),
55
55
  },
56
56
  }),
57
57
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
package/out/404.html CHANGED
@@ -1 +1 @@
1
- <!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/_next/static/css/200244e3e0463c39.css" as="style"/><link rel="stylesheet" href="/_next/static/css/200244e3e0463c39.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="/_next/static/chunks/webpack-2f903acb0cccbf9e.js" defer=""></script><script src="/_next/static/chunks/framework-cdccea7a52cc6e81.js" defer=""></script><script src="/_next/static/chunks/main-5e6780279ca21cb9.js" defer=""></script><script src="/_next/static/chunks/pages/_app-cd9d4c76a4abc11a.js" defer=""></script><script src="/_next/static/chunks/pages/_error-69b4f498bafdd188.js" defer=""></script><script src="/_next/static/m6psnC5u1xT7Y6osWHKjp/_buildManifest.js" defer=""></script><script src="/_next/static/m6psnC5u1xT7Y6osWHKjp/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"statusCode":404}},"page":"/_error","query":{},"buildId":"m6psnC5u1xT7Y6osWHKjp","runtimeConfig":{"sentryEnvironment":"beta"},"nextExport":true,"isFallback":false,"gip":true,"scriptLoader":[]}</script></body></html>
1
+ <!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/_next/static/css/39e089aad1742a3a.css" as="style"/><link rel="stylesheet" href="/_next/static/css/39e089aad1742a3a.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="/_next/static/chunks/webpack-2f903acb0cccbf9e.js" defer=""></script><script src="/_next/static/chunks/framework-cdccea7a52cc6e81.js" defer=""></script><script src="/_next/static/chunks/main-5e6780279ca21cb9.js" defer=""></script><script src="/_next/static/chunks/pages/_app-bca191df4ac7078e.js" defer=""></script><script src="/_next/static/chunks/pages/_error-69b4f498bafdd188.js" defer=""></script><script src="/_next/static/dS_xZnzzna6Y6uwcTgf90/_buildManifest.js" defer=""></script><script src="/_next/static/dS_xZnzzna6Y6uwcTgf90/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"statusCode":404}},"page":"/_error","query":{},"buildId":"dS_xZnzzna6Y6uwcTgf90","runtimeConfig":{"sentryEnvironment":"beta"},"nextExport":true,"isFallback":false,"gip":true,"scriptLoader":[]}</script></body></html>