slice-machine-ui 1.23.1-beta.2 → 1.23.1-beta.4

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 (52) hide show
  1. package/components/CustomTypeTable/changesPage.tsx +1 -0
  2. package/components/DeleteDocumentsDrawer/HardDeleteDocumentsDrawer.tsx +11 -23
  3. package/components/DeleteDocumentsDrawer/SoftDeleteDocumentsDrawer.tsx +11 -23
  4. package/components/DeleteDocumentsDrawer/index.tsx +0 -1
  5. package/components/SliceMachineDrawer/index.tsx +4 -6
  6. package/out/404.html +1 -1
  7. package/out/_next/static/{8aiH3LjdI_Vj38RRmPnNx → N2MQkjqkeMvE9gtxiUiFA}/_buildManifest.js +1 -1
  8. package/out/_next/static/chunks/25-37d6fa7f064be04b.js +1 -0
  9. package/out/_next/static/chunks/{727-15cf3f2fea9a37e5.js → 727-2016e98f80ea6a62.js} +1 -1
  10. package/out/_next/static/chunks/{904-ccd8ca3368ce29fc.js → 904-4c4d0a2183ae9a27.js} +1 -1
  11. package/out/_next/static/chunks/pages/{_app-46cdcb7304fa805f.js → _app-6fc45ce12a6c566a.js} +2 -2
  12. package/out/_next/static/chunks/pages/{changelog-68d115a14f1423d7.js → changelog-afd18276fe018b24.js} +1 -1
  13. package/out/_next/static/chunks/pages/changes-898f58035cfafe03.js +1 -0
  14. package/out/_next/static/chunks/pages/{labs-526bb7d60a1b90f4.js → labs-ee206005948f8e87.js} +1 -1
  15. package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/{[variation]-73dd999915509965.js → [variation]-b2a9d773ce5d7739.js} +1 -1
  16. package/out/_next/static/chunks/pages/{slices-7b09cb5130c63bb3.js → slices-e9c70c082ca3e3f9.js} +1 -1
  17. package/out/changelog.html +1 -1
  18. package/out/changes.html +1 -1
  19. package/out/custom-types/[customTypeId].html +1 -1
  20. package/out/custom-types.html +1 -1
  21. package/out/index.html +1 -1
  22. package/out/labs.html +1 -1
  23. package/out/page-types/[pageTypeId].html +1 -1
  24. package/out/slices/[lib]/[sliceName]/[variation]/simulator.html +1 -1
  25. package/out/slices/[lib]/[sliceName]/[variation].html +1 -1
  26. package/out/slices.html +1 -1
  27. package/package.json +3 -3
  28. package/pages/changes.tsx +67 -28
  29. package/src/components/FieldSet/FieldSet.module.css +92 -0
  30. package/src/components/FieldSet/FieldSet.module.css.d.ts +18 -0
  31. package/src/components/FieldSet/FieldSet.stories.tsx +208 -0
  32. package/src/components/FieldSet/FieldSet.tsx +72 -0
  33. package/src/components/FieldSet/index.ts +9 -0
  34. package/src/features/changes/actions/pushChanges.ts +66 -0
  35. package/src/{modules/pushChangesSaga → features/changes/actions}/trackPushChangesSuccess.ts +16 -12
  36. package/src/icons/BitbucketIcon.tsx +19 -0
  37. package/src/icons/GitHubIcon.tsx +17 -0
  38. package/src/icons/GitLabIcon.tsx +19 -0
  39. package/src/modules/loading/types.ts +0 -1
  40. package/src/modules/modal/types.ts +0 -3
  41. package/src/modules/useSliceMachineActions.ts +3 -18
  42. package/src/modules/userContext/index.ts +6 -3
  43. package/src/redux/reducer.ts +0 -2
  44. package/src/redux/saga.ts +0 -2
  45. package/src/redux/type.ts +0 -2
  46. package/components/DeleteDocumentsDrawer/ReferencesErrorDrawer.tsx +0 -92
  47. package/lib/models/common/TransactionalPush.ts +0 -10
  48. package/out/_next/static/chunks/25-8fedd33ad9b6de5b.js +0 -1
  49. package/out/_next/static/chunks/pages/changes-6a24f50da1a00688.js +0 -1
  50. package/src/modules/pushChangesSaga/index.ts +0 -191
  51. package/test/src/modules/pushChangesSaga.test.ts +0 -261
  52. /package/out/_next/static/{8aiH3LjdI_Vj38RRmPnNx → N2MQkjqkeMvE9gtxiUiFA}/_ssgManifest.js +0 -0
@@ -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=""/><link rel="preload" href="/_next/static/css/b22c0750c14cc089.css" as="style"/><link rel="stylesheet" href="/_next/static/css/b22c0750c14cc089.css" data-n-p=""/><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-46cdcb7304fa805f.js" defer=""></script><script src="/_next/static/chunks/59b4e022-7a3b5554b806349f.js" defer=""></script><script src="/_next/static/chunks/c8eae200-966ce352f7b5d2b9.js" defer=""></script><script src="/_next/static/chunks/f36c6662-03bb5e9d9aa0b0aa.js" defer=""></script><script src="/_next/static/chunks/4c744e84-e3161d754618373f.js" defer=""></script><script src="/_next/static/chunks/065a3ddb-9a38ca0d60f0bf2f.js" defer=""></script><script src="/_next/static/chunks/1cc2734a-2c5b6c0367fcde86.js" defer=""></script><script src="/_next/static/chunks/183-4feb6bb3eddbc768.js" defer=""></script><script src="/_next/static/chunks/50-cfc2514205b86001.js" defer=""></script><script src="/_next/static/chunks/543-f8766685f7f451e2.js" defer=""></script><script src="/_next/static/chunks/696-b12edad30a3617e5.js" defer=""></script><script src="/_next/static/chunks/25-8fedd33ad9b6de5b.js" defer=""></script><script src="/_next/static/chunks/318-541db69860d31138.js" defer=""></script><script src="/_next/static/chunks/286-ed90373e9a469944.js" defer=""></script><script src="/_next/static/chunks/pages/slices/%5Blib%5D/%5BsliceName%5D/%5Bvariation%5D-73dd999915509965.js" defer=""></script><script src="/_next/static/8aiH3LjdI_Vj38RRmPnNx/_buildManifest.js" defer=""></script><script src="/_next/static/8aiH3LjdI_Vj38RRmPnNx/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/slices/[lib]/[sliceName]/[variation]","query":{},"buildId":"8aiH3LjdI_Vj38RRmPnNx","runtimeConfig":{"sentryEnvironment":"beta"},"nextExport":true,"autoExport":true,"isFallback":false,"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/200244e3e0463c39.css" as="style"/><link rel="stylesheet" href="/_next/static/css/200244e3e0463c39.css" data-n-g=""/><link rel="preload" href="/_next/static/css/b22c0750c14cc089.css" as="style"/><link rel="stylesheet" href="/_next/static/css/b22c0750c14cc089.css" data-n-p=""/><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-6fc45ce12a6c566a.js" defer=""></script><script src="/_next/static/chunks/59b4e022-7a3b5554b806349f.js" defer=""></script><script src="/_next/static/chunks/c8eae200-966ce352f7b5d2b9.js" defer=""></script><script src="/_next/static/chunks/f36c6662-03bb5e9d9aa0b0aa.js" defer=""></script><script src="/_next/static/chunks/4c744e84-e3161d754618373f.js" defer=""></script><script src="/_next/static/chunks/065a3ddb-9a38ca0d60f0bf2f.js" defer=""></script><script src="/_next/static/chunks/1cc2734a-2c5b6c0367fcde86.js" defer=""></script><script src="/_next/static/chunks/183-4feb6bb3eddbc768.js" defer=""></script><script src="/_next/static/chunks/50-cfc2514205b86001.js" defer=""></script><script src="/_next/static/chunks/543-f8766685f7f451e2.js" defer=""></script><script src="/_next/static/chunks/696-b12edad30a3617e5.js" defer=""></script><script src="/_next/static/chunks/25-37d6fa7f064be04b.js" defer=""></script><script src="/_next/static/chunks/318-541db69860d31138.js" defer=""></script><script src="/_next/static/chunks/286-ed90373e9a469944.js" defer=""></script><script src="/_next/static/chunks/pages/slices/%5Blib%5D/%5BsliceName%5D/%5Bvariation%5D-b2a9d773ce5d7739.js" defer=""></script><script src="/_next/static/N2MQkjqkeMvE9gtxiUiFA/_buildManifest.js" defer=""></script><script src="/_next/static/N2MQkjqkeMvE9gtxiUiFA/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/slices/[lib]/[sliceName]/[variation]","query":{},"buildId":"N2MQkjqkeMvE9gtxiUiFA","runtimeConfig":{"sentryEnvironment":"beta"},"nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
package/out/slices.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=""/><link rel="preload" href="/_next/static/css/f8eb526e10bc2441.css" as="style"/><link rel="stylesheet" href="/_next/static/css/f8eb526e10bc2441.css" data-n-p=""/><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-46cdcb7304fa805f.js" defer=""></script><script src="/_next/static/chunks/59b4e022-7a3b5554b806349f.js" defer=""></script><script src="/_next/static/chunks/c8eae200-966ce352f7b5d2b9.js" defer=""></script><script src="/_next/static/chunks/50-cfc2514205b86001.js" defer=""></script><script src="/_next/static/chunks/25-8fedd33ad9b6de5b.js" defer=""></script><script src="/_next/static/chunks/286-ed90373e9a469944.js" defer=""></script><script src="/_next/static/chunks/pages/slices-7b09cb5130c63bb3.js" defer=""></script><script src="/_next/static/8aiH3LjdI_Vj38RRmPnNx/_buildManifest.js" defer=""></script><script src="/_next/static/8aiH3LjdI_Vj38RRmPnNx/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/slices","query":{},"buildId":"8aiH3LjdI_Vj38RRmPnNx","runtimeConfig":{"sentryEnvironment":"beta"},"nextExport":true,"autoExport":true,"isFallback":false,"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/200244e3e0463c39.css" as="style"/><link rel="stylesheet" href="/_next/static/css/200244e3e0463c39.css" data-n-g=""/><link rel="preload" href="/_next/static/css/f8eb526e10bc2441.css" as="style"/><link rel="stylesheet" href="/_next/static/css/f8eb526e10bc2441.css" data-n-p=""/><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-6fc45ce12a6c566a.js" defer=""></script><script src="/_next/static/chunks/59b4e022-7a3b5554b806349f.js" defer=""></script><script src="/_next/static/chunks/c8eae200-966ce352f7b5d2b9.js" defer=""></script><script src="/_next/static/chunks/50-cfc2514205b86001.js" defer=""></script><script src="/_next/static/chunks/25-37d6fa7f064be04b.js" defer=""></script><script src="/_next/static/chunks/286-ed90373e9a469944.js" defer=""></script><script src="/_next/static/chunks/pages/slices-e9c70c082ca3e3f9.js" defer=""></script><script src="/_next/static/N2MQkjqkeMvE9gtxiUiFA/_buildManifest.js" defer=""></script><script src="/_next/static/N2MQkjqkeMvE9gtxiUiFA/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/slices","query":{},"buildId":"N2MQkjqkeMvE9gtxiUiFA","runtimeConfig":{"sentryEnvironment":"beta"},"nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slice-machine-ui",
3
- "version": "1.23.1-beta.2",
3
+ "version": "1.23.1-beta.4",
4
4
  "license": "MIT",
5
5
  "description": "A visual builder for your Slice Models with all the tools you need to generate data models and mock CMS content locally.",
6
6
  "repository": {
@@ -36,8 +36,8 @@
36
36
  },
37
37
  "dependencies": {
38
38
  "@radix-ui/react-visually-hidden": "1.0.3",
39
- "@slicemachine/manager": "0.17.8-beta.2",
40
- "start-slicemachine": "0.12.14-beta.2"
39
+ "@slicemachine/manager": "0.17.8-beta.4",
40
+ "start-slicemachine": "0.12.14-beta.4"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@emotion/react": "11.11.1",
package/pages/changes.tsx CHANGED
@@ -1,9 +1,8 @@
1
1
  import { Button } from "@prismicio/editor-ui";
2
- import React, { useEffect, useMemo } from "react";
2
+ import React, { useMemo, useState } from "react";
3
+ import { toast } from "react-toastify";
3
4
  import Head from "next/head";
4
5
  import { BaseStyles } from "theme-ui";
5
- import { useSelector } from "react-redux";
6
- import { SliceMachineStoreType } from "../src/redux/type";
7
6
  import {
8
7
  AppLayout,
9
8
  AppLayoutActions,
@@ -18,19 +17,19 @@ import { NoChangesBlankSlate } from "@src/features/changes/BlankSlates";
18
17
 
19
18
  import { AuthStatus } from "@src/modules/userContext/types";
20
19
  import { unSyncStatuses, useUnSyncChanges } from "@src/hooks/useUnSyncChanges";
21
- import { isLoading } from "@src/modules/loading";
22
- import { LoadingKeysEnum } from "@src/modules/loading/types";
23
20
  import useSliceMachineActions from "@src/modules/useSliceMachineActions";
24
21
  import {
25
22
  SoftDeleteDocumentsDrawer,
26
23
  HardDeleteDocumentsDrawer,
27
- ReferencesErrorDrawer,
28
24
  } from "@components/DeleteDocumentsDrawer";
29
25
  import { hasLocal } from "@lib/models/common/ModelData";
30
26
  import {
31
27
  ChangedCustomType,
32
28
  ChangedSlice,
33
29
  } from "@lib/models/common/ModelStatus";
30
+ import { PushChangesLimit } from "@slicemachine/manager";
31
+ import { pushChanges } from "@src/features/changes/actions/pushChanges";
32
+ import { getState } from "@src/apiClient";
34
33
 
35
34
  const Changes: React.FunctionComponent = () => {
36
35
  const {
@@ -59,28 +58,57 @@ const Changes: React.FunctionComponent = () => {
59
58
  return { changedSlices, changedCustomTypes };
60
59
  }, [unSyncedSlices, unSyncedCustomTypes, modelsStatuses]);
61
60
 
62
- const { pushChanges, closeModals } = useSliceMachineActions();
61
+ const { pushChangesSuccess, refreshState } = useSliceMachineActions();
62
+ const [isSyncing, setIsSyncing] = useState(false);
63
+ const [openModalData, setOpenModalData] = useState<
64
+ PushChangesLimit | undefined
65
+ >(undefined);
63
66
 
64
- const { isSyncing } = useSelector((store: SliceMachineStoreType) => ({
65
- isSyncing: isLoading(store, LoadingKeysEnum.CHANGES_PUSH),
66
- }));
67
+ const numberOfChanges = unSyncedSlices.length + unSyncedCustomTypes.length;
67
68
 
68
- useEffect(() => {
69
- return () => {
70
- closeModals();
71
- };
72
- // Do not remote the eslint disable, fixing the eslint warning creates a bug that prevent from opening all modals
73
- // eslint-disable-next-line react-hooks/exhaustive-deps
74
- }, []);
69
+ const onPush = async (confirmDeleteDocuments: boolean) => {
70
+ try {
71
+ setIsSyncing(true);
72
+ setOpenModalData(undefined);
75
73
 
76
- const numberOfChanges = unSyncedSlices.length + unSyncedCustomTypes.length;
74
+ const limit = await pushChanges({
75
+ confirmDeleteDocuments,
76
+ changedSlices,
77
+ changedCustomTypes,
78
+ });
79
+
80
+ if (limit !== undefined) {
81
+ setOpenModalData(limit);
82
+ } else {
83
+ // TODO(DT-1737): Remove the use of global getState
84
+ const serverState = await getState();
85
+ refreshState({
86
+ env: serverState.env,
87
+ remoteCustomTypes: serverState.remoteCustomTypes,
88
+ customTypes: serverState.customTypes,
89
+ libraries: serverState.libraries,
90
+ remoteSlices: serverState.remoteSlices,
91
+ clientError: serverState.clientError,
92
+ });
77
93
 
78
- const onPush = (confirmDeleteDocuments: boolean) =>
79
- pushChanges({
80
- confirmDeleteDocuments: confirmDeleteDocuments,
81
- changedSlices,
82
- changedCustomTypes,
83
- });
94
+ // Update last sync value in local storage
95
+ pushChangesSuccess();
96
+
97
+ toast.success("All slices and types have been pushed");
98
+ }
99
+ } catch (error) {
100
+ console.error(
101
+ "Something went wrong when manually pushing your changes",
102
+ error,
103
+ );
104
+
105
+ toast.error(
106
+ "Something went wrong when pushing your changes. Check your terminal logs.",
107
+ );
108
+ }
109
+
110
+ setIsSyncing(false);
111
+ };
84
112
 
85
113
  const PageContent = useMemo(() => {
86
114
  if (!isOnline) {
@@ -123,7 +151,7 @@ const Changes: React.FunctionComponent = () => {
123
151
  <AppLayoutBreadcrumb folder="Changes" />
124
152
  <AppLayoutActions>
125
153
  <Button
126
- onClick={() => onPush(false)} // not deleting documents by default
154
+ onClick={() => void onPush(false)} // not deleting documents by default
127
155
  loading={isSyncing}
128
156
  disabled={
129
157
  numberOfChanges === 0 ||
@@ -141,9 +169,20 @@ const Changes: React.FunctionComponent = () => {
141
169
  <AppLayoutContent>
142
170
  <BaseStyles sx={{ display: "flex", flexDirection: "column" }}>
143
171
  {PageContent}
144
- <SoftDeleteDocumentsDrawer pushChanges={onPush} />
145
- <HardDeleteDocumentsDrawer pushChanges={onPush} />
146
- <ReferencesErrorDrawer pushChanges={onPush} />
172
+ <SoftDeleteDocumentsDrawer
173
+ pushChanges={(confirmDeleteDocuments) =>
174
+ void onPush(confirmDeleteDocuments)
175
+ }
176
+ modalData={openModalData}
177
+ onClose={() => setOpenModalData(undefined)}
178
+ />
179
+ <HardDeleteDocumentsDrawer
180
+ pushChanges={(confirmDeleteDocuments) =>
181
+ void onPush(confirmDeleteDocuments)
182
+ }
183
+ modalData={openModalData}
184
+ onClose={() => setOpenModalData(undefined)}
185
+ />
147
186
  </BaseStyles>
148
187
  </AppLayoutContent>
149
188
  </AppLayout>
@@ -0,0 +1,92 @@
1
+ .flex {
2
+ all: unset;
3
+ display: flex;
4
+ }
5
+
6
+ .column {
7
+ composes: flex;
8
+ flex-direction: column;
9
+ }
10
+
11
+ .root {
12
+ composes: column;
13
+ border-color: var(--grey6);
14
+ border-radius: 6px;
15
+ border-style: solid;
16
+ border-width: 1px;
17
+ box-shadow: var(--box-shadow-1);
18
+ overflow-x: hidden;
19
+ }
20
+
21
+ .row {
22
+ composes: flex;
23
+ align-items: center;
24
+ flex-direction: row;
25
+ gap: 8px;
26
+ padding-inline: 16px;
27
+ }
28
+
29
+ .borderBottom {
30
+ box-sizing: border-box;
31
+ &:not(:last-child) {
32
+ border-bottom-color: var(--grey6);
33
+ border-bottom-style: solid;
34
+ border-bottom-width: 1px;
35
+ }
36
+ }
37
+
38
+ .legend {
39
+ composes: row borderBottom;
40
+ background-color: var(--grey2);
41
+ height: 48px;
42
+ order: 0;
43
+ }
44
+
45
+ .header {
46
+ composes: row borderBottom;
47
+ background-color: var(--grey2);
48
+ height: 72px;
49
+ order: 1;
50
+ }
51
+
52
+ .content {
53
+ composes: column;
54
+ background-color: var(--grey1);
55
+ order: 2;
56
+ padding: 16px;
57
+ }
58
+
59
+ .list {
60
+ composes: column;
61
+ max-height: 256px;
62
+ order: 2;
63
+ overflow-y: auto;
64
+ }
65
+
66
+ .listItem {
67
+ composes: row borderBottom;
68
+ background-color: var(--grey1);
69
+ flex-shrink: 0;
70
+ height: 64px;
71
+ }
72
+
73
+ .listItemText {
74
+ flex-grow: 1;
75
+ }
76
+
77
+ .borderTop:not(:first-child) {
78
+ /* stylelint-disable-next-line declaration-property-value-allowed-list -- Displays a 1 px top border outside the element. */
79
+ box-shadow: 0 -1px 0 0 var(--grey6);
80
+ }
81
+
82
+ .footer {
83
+ composes: row borderTop;
84
+ background-color: var(--grey1);
85
+ height: 48px;
86
+ order: 3;
87
+ padding-right: 8px;
88
+ }
89
+
90
+ .footerText {
91
+ flex-grow: 1;
92
+ }
@@ -0,0 +1,18 @@
1
+ declare const styles: {
2
+ readonly "borderBottom": string;
3
+ readonly "borderTop": string;
4
+ readonly "column": string;
5
+ readonly "content": string;
6
+ readonly "flex": string;
7
+ readonly "footer": string;
8
+ readonly "footerText": string;
9
+ readonly "header": string;
10
+ readonly "legend": string;
11
+ readonly "list": string;
12
+ readonly "listItem": string;
13
+ readonly "listItemText": string;
14
+ readonly "root": string;
15
+ readonly "row": string;
16
+ };
17
+ export = styles;
18
+
@@ -0,0 +1,208 @@
1
+ import {
2
+ Box,
3
+ Button,
4
+ ButtonGroup,
5
+ IconButton,
6
+ Skeleton,
7
+ Text,
8
+ tokens,
9
+ } from "@prismicio/editor-ui";
10
+ import type { Meta, StoryObj } from "@storybook/react";
11
+
12
+ import { BitbucketIcon } from "../../icons/BitbucketIcon";
13
+ import { GitHubIcon } from "../../icons/GitHubIcon";
14
+ import { GitLabIcon } from "../../icons/GitLabIcon";
15
+ import {
16
+ FieldSet,
17
+ FieldSetContent,
18
+ FieldSetFooter,
19
+ FieldSetHeader,
20
+ FieldSetLegend,
21
+ FieldSetList,
22
+ FieldSetListItem,
23
+ } from "./FieldSet";
24
+
25
+ type Story = StoryObj<typeof meta>;
26
+
27
+ const meta = {
28
+ component: FieldSet,
29
+ argTypes: {
30
+ children: { control: { disable: true } },
31
+ },
32
+ } satisfies Meta<typeof FieldSet>;
33
+
34
+ export default meta;
35
+
36
+ export const Default = {
37
+ args: {
38
+ children: (
39
+ <>
40
+ <FieldSetLegend />
41
+ <FieldSetHeader />
42
+ <FieldSetList>
43
+ <FieldSetListItem action={<Button color="grey">Action</Button>} />
44
+ </FieldSetList>
45
+ <FieldSetFooter action={<IconButton icon="openInNew" />} />
46
+ </>
47
+ ),
48
+ },
49
+ } satisfies Story;
50
+
51
+ export const WithButtonGroupContent = {
52
+ args: {
53
+ ...Default.args,
54
+ children: (
55
+ <>
56
+ <FieldSetLegend>Connected Git Repository</FieldSetLegend>
57
+ <FieldSetContent>
58
+ <ButtonGroup color="grey">
59
+ <Button
60
+ renderStartIcon={() => (
61
+ <GitHubIcon color={tokens.color.greyLight11} />
62
+ )}
63
+ sx={{ flexBasis: 0, flexGrow: 1 }}
64
+ >
65
+ GitHub
66
+ </Button>
67
+ <Button
68
+ disabled
69
+ renderStartIcon={() => (
70
+ <BitbucketIcon color={tokens.color.greyLight11} />
71
+ )}
72
+ sx={{ flexBasis: 0, flexGrow: 1 }}
73
+ >
74
+ Bitbucket{" "}
75
+ <Text color="inherit" variant="small">
76
+ (soon)
77
+ </Text>
78
+ </Button>
79
+ <Button
80
+ disabled
81
+ renderStartIcon={() => (
82
+ <GitLabIcon color={tokens.color.greyLight11} />
83
+ )}
84
+ sx={{ flexBasis: 0, flexGrow: 1 }}
85
+ >
86
+ GitLab{" "}
87
+ <Text color="inherit" variant="small">
88
+ (soon)
89
+ </Text>
90
+ </Button>
91
+ </ButtonGroup>
92
+ </FieldSetContent>
93
+ <FieldSetFooter action={<IconButton icon="openInNew" />}>
94
+ Learn more about Prismic for Git
95
+ </FieldSetFooter>
96
+ </>
97
+ ),
98
+ },
99
+ parameters: { controls: { hideNoControlsWarning: true, include: [] } },
100
+ } satisfies Story;
101
+
102
+ export const LoadingWithHeaderAndList = {
103
+ args: {
104
+ ...Default.args,
105
+ children: (
106
+ <>
107
+ <FieldSetLegend>Connected Git Repository</FieldSetLegend>
108
+ <FieldSetHeader />
109
+ <FieldSetList>
110
+ {[...Array(4).keys()].map((index) => (
111
+ <FieldSetListItem
112
+ action={<Skeleton height={32} width={67.59} />}
113
+ key={index}
114
+ >
115
+ <Skeleton
116
+ height={24}
117
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
118
+ // @ts-ignore TODO(DT-1918): add `verticalAlign: "middle"` to the `sx` prop.
119
+ sx={{ verticalAlign: "middle" }}
120
+ width={129.92}
121
+ />
122
+ </FieldSetListItem>
123
+ ))}
124
+ </FieldSetList>
125
+ <FieldSetFooter action={<IconButton icon="openInNew" />}>
126
+ Learn more about Prismic for Git
127
+ </FieldSetFooter>
128
+ </>
129
+ ),
130
+ },
131
+ parameters: { controls: { hideNoControlsWarning: true, include: [] } },
132
+ };
133
+
134
+ export const WithHeaderAndListOverflow = {
135
+ args: {
136
+ ...Default.args,
137
+ children: (
138
+ <>
139
+ <FieldSetLegend>Connected Git Repository</FieldSetLegend>
140
+ <FieldSetHeader />
141
+ <FieldSetList>
142
+ {[...Array(100).keys()].map((index) => (
143
+ <FieldSetListItem
144
+ action={<Button color="grey">Connect</Button>}
145
+ key={index}
146
+ >
147
+ Repository <Text color="grey11">• xd ago</Text>
148
+ </FieldSetListItem>
149
+ ))}
150
+ </FieldSetList>
151
+ <FieldSetFooter action={<IconButton icon="openInNew" />}>
152
+ Learn more about Prismic for Git
153
+ </FieldSetFooter>
154
+ </>
155
+ ),
156
+ },
157
+ parameters: { controls: { hideNoControlsWarning: true, include: [] } },
158
+ };
159
+
160
+ export const WithSingleListItem = {
161
+ args: {
162
+ ...Default.args,
163
+ children: (
164
+ <>
165
+ <FieldSetLegend>Connected Git Repository</FieldSetLegend>
166
+ <FieldSetList>
167
+ <FieldSetListItem action={<Button color="grey">Disconnect</Button>}>
168
+ Repository <Text color="grey11">• xd ago</Text>
169
+ </FieldSetListItem>
170
+ </FieldSetList>
171
+ <FieldSetFooter action={<IconButton icon="openInNew" />}>
172
+ Learn more about Prismic for Git
173
+ </FieldSetFooter>
174
+ </>
175
+ ),
176
+ },
177
+ parameters: { controls: { hideNoControlsWarning: true, include: [] } },
178
+ };
179
+
180
+ export const WithBoxContent = {
181
+ args: {
182
+ ...Default.args,
183
+ children: (
184
+ <>
185
+ <FieldSetLegend>Connected Git Repository</FieldSetLegend>
186
+ <FieldSetContent>
187
+ {/*
188
+ * TODO: these `padding` values actually don't match Figma, but they
189
+ * are the closest allowed by the `Box` component.
190
+ */}
191
+ <Box flexDirection="column" padding={{ block: 72, inline: 100 }}>
192
+ <Text align="center" variant="emphasized">
193
+ No Results Found
194
+ </Text>
195
+ <Text align="center" color="grey11">
196
+ Try selecting a different Git account or organization on the top
197
+ left.
198
+ </Text>
199
+ </Box>
200
+ </FieldSetContent>
201
+ <FieldSetFooter action={<IconButton icon="openInNew" />}>
202
+ Learn more about Prismic for Git
203
+ </FieldSetFooter>
204
+ </>
205
+ ),
206
+ },
207
+ parameters: { controls: { hideNoControlsWarning: true, include: [] } },
208
+ };
@@ -0,0 +1,72 @@
1
+ import { Text } from "@prismicio/editor-ui";
2
+ import type { FC, PropsWithChildren, ReactNode } from "react";
3
+
4
+ import styles from "./FieldSet.module.css";
5
+
6
+ export const FieldSet: FC<PropsWithChildren> = (props) => (
7
+ <div {...props} className={styles.root} />
8
+ );
9
+
10
+ export const FieldSetLegend: FC<PropsWithChildren> = ({
11
+ children,
12
+ ...otherProps
13
+ }) => (
14
+ <div {...otherProps} className={styles.legend}>
15
+ <Text color="grey11" component="span" noWrap variant="smallBold">
16
+ {children}
17
+ </Text>
18
+ </div>
19
+ );
20
+
21
+ export const FieldSetHeader: FC<PropsWithChildren> = (props) => (
22
+ <div {...props} className={styles.header} />
23
+ );
24
+
25
+ export const FieldSetContent: FC<PropsWithChildren> = (props) => (
26
+ <div {...props} className={styles.content} />
27
+ );
28
+
29
+ export const FieldSetList: FC<PropsWithChildren> = (props) => (
30
+ <div {...props} className={styles.list} />
31
+ );
32
+
33
+ type FieldSetListItemProps = PropsWithChildren<{ action?: ReactNode }>;
34
+
35
+ export const FieldSetListItem: FC<FieldSetListItemProps> = ({
36
+ action,
37
+ children,
38
+ ...otherProps
39
+ }) => (
40
+ <div {...otherProps} className={styles.listItem}>
41
+ <Text
42
+ className={styles.listItemText}
43
+ component="span"
44
+ noWrap
45
+ variant="bold"
46
+ >
47
+ {children}
48
+ </Text>
49
+ {action}
50
+ </div>
51
+ );
52
+
53
+ type FieldSetFooterProps = PropsWithChildren<{ action?: ReactNode }>;
54
+
55
+ export const FieldSetFooter: FC<FieldSetFooterProps> = ({
56
+ action,
57
+ children,
58
+ ...otherProps
59
+ }) => (
60
+ <div {...otherProps} className={styles.footer}>
61
+ <Text
62
+ className={styles.footerText}
63
+ color="grey11"
64
+ component="span"
65
+ noWrap
66
+ variant="small"
67
+ >
68
+ {children}
69
+ </Text>
70
+ {action}
71
+ </div>
72
+ );
@@ -0,0 +1,9 @@
1
+ export {
2
+ FieldSet,
3
+ FieldSetContent,
4
+ FieldSetFooter,
5
+ FieldSetHeader,
6
+ FieldSetLegend,
7
+ FieldSetList,
8
+ FieldSetListItem,
9
+ } from "./FieldSet";
@@ -0,0 +1,66 @@
1
+ import { pushChanges as pushChangesCall, telemetry } from "@src/apiClient";
2
+ import {
3
+ ChangedCustomType,
4
+ ChangedSlice,
5
+ } from "@lib/models/common/ModelStatus";
6
+ import { PushChangesLimit } from "@slicemachine/manager";
7
+
8
+ import { trackPushChangesSuccess } from "./trackPushChangesSuccess";
9
+
10
+ type PushChangesArgs = {
11
+ changedSlices: ReadonlyArray<ChangedSlice>;
12
+ changedCustomTypes: ReadonlyArray<ChangedCustomType>;
13
+ confirmDeleteDocuments?: boolean;
14
+ };
15
+
16
+ export async function pushChanges(
17
+ args: PushChangesArgs,
18
+ ): Promise<PushChangesLimit | undefined> {
19
+ const {
20
+ changedSlices,
21
+ changedCustomTypes,
22
+ confirmDeleteDocuments = false,
23
+ } = args;
24
+
25
+ const startTime = Date.now();
26
+ const sliceChanges = changedSlices.map((sliceChange) => ({
27
+ id: sliceChange.slice.model.id,
28
+ type: "Slice" as const,
29
+ libraryID: sliceChange.slice.from,
30
+ status: sliceChange.status,
31
+ }));
32
+ const customTypeChanges = changedCustomTypes.map((customTypeChange) => ({
33
+ id: customTypeChange.customType.id,
34
+ type: "CustomType" as const,
35
+ status: customTypeChange.status,
36
+ }));
37
+
38
+ // Creating a new payload with the correct format
39
+ const pushPayload = {
40
+ confirmDeleteDocuments,
41
+ changes: [...sliceChanges, ...customTypeChanges],
42
+ };
43
+
44
+ const response = await pushChangesCall(pushPayload);
45
+
46
+ if (response) {
47
+ // Tracking when a limit has been reached
48
+ void telemetry.track({
49
+ event: "changes:limit-reach",
50
+ limitType: response.type,
51
+ });
52
+
53
+ return response;
54
+ }
55
+
56
+ trackPushChangesSuccess({
57
+ changedCustomTypes,
58
+ changedSlices,
59
+ // Currently, we only pass confirmDeleteDocuments when the user
60
+ // has confirmed the deletion of documents
61
+ hasDeletedDocuments: confirmDeleteDocuments,
62
+ startTime,
63
+ });
64
+
65
+ return undefined;
66
+ }