slice-machine-ui 2.17.3-alpha.dani-git-integration.2 → 2.17.3-alpha.jp-revert-section-naming-experiment.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/404.html +1 -1
- package/out/_next/static/QRJGmIoJFXeQ96FN-TwH5/_buildManifest.js +1 -0
- package/out/_next/static/chunks/248-03446cd9e9f13730.js +1 -0
- package/out/_next/static/chunks/489-dd74b228384df643.js +1 -0
- package/out/_next/static/chunks/{630-29c729ad2a291ef6.js → 630-799c128fd87fa645.js} +1 -1
- package/out/_next/static/chunks/903-04bef419234ad926.js +1 -0
- package/out/_next/static/chunks/pages/{_app-8c46096695410bd2.js → _app-abfff64c4bacad47.js} +1 -1
- package/out/_next/static/chunks/pages/changelog-063c5e11dfc8fd55.js +1 -0
- package/out/_next/static/chunks/pages/changes-b4b7d3047cf012a0.js +1 -0
- package/out/_next/static/chunks/pages/custom-types/{[customTypeId]-041985d94bb9649f.js → [customTypeId]-1958f229bf899036.js} +1 -1
- package/out/_next/static/chunks/pages/labs-9630bfb1005be02b.js +1 -0
- package/out/_next/static/chunks/pages/page-types/{[pageTypeId]-338f685c0723043b.js → [pageTypeId]-1c048ceedced0df1.js} +1 -1
- package/out/_next/static/chunks/pages/settings-01f4aeb9112a1f87.js +1 -0
- package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]/simulator-0ecd552897e61e29.js +1 -0
- package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]-0a51da2e35d6e62f.js +1 -0
- package/out/_next/static/chunks/pages/slices-e057c5c9cb56b1ef.js +1 -0
- package/out/_next/static/css/e5f781f20e24a5ea.css +1 -0
- package/out/changelog.html +1 -1
- package/out/changes.html +1 -1
- package/out/custom-types/[customTypeId].html +1 -1
- package/out/custom-types.html +1 -1
- package/out/index.html +1 -1
- package/out/labs.html +1 -1
- package/out/page-types/[pageTypeId].html +1 -1
- package/out/settings.html +1 -0
- package/out/slices/[lib]/[sliceName]/[variation]/simulator.html +1 -1
- package/out/slices/[lib]/[sliceName]/[variation].html +1 -1
- package/out/slices.html +1 -1
- package/package.json +3 -3
- package/src/components/FieldSet/FieldSet.module.css +84 -0
- package/src/components/FieldSet/FieldSet.module.css.d.ts +16 -0
- package/src/components/FieldSet/FieldSet.stories.tsx +244 -0
- package/src/components/FieldSet/FieldSet.tsx +67 -0
- package/src/components/FieldSet/index.ts +9 -0
- package/src/features/changes/PushChangesButton.tsx +67 -4
- package/src/features/customTypes/customTypesBuilder/CreateSliceFromImageModal/CreateSliceFromImageModal.tsx +8 -21
- package/src/features/customTypes/customTypesBuilder/SliceZoneBlankSlate.tsx +52 -36
- package/src/features/navigation/Navigation.tsx +13 -7
- package/src/features/settings/SettingsPage.tsx +50 -0
- package/src/features/settings/git/ConnectGitRepository.tsx +112 -0
- package/src/features/settings/git/ConnectGitRepositoryBlankSlate.tsx +33 -0
- package/src/features/settings/git/GitOwnerSelect.tsx +71 -0
- package/src/features/settings/git/GitProvider.ts +40 -0
- package/src/features/settings/git/GitProviderConnectButtons.tsx +63 -0
- package/src/features/settings/git/GitRepositoriesList.tsx +76 -0
- package/src/features/settings/git/GitRepositoriesSearch.tsx +69 -0
- package/src/features/settings/git/GitRepositoryConnectDialog.tsx +97 -0
- package/src/features/settings/git/GitRepositoryDisconnectDialog.tsx +62 -0
- package/src/features/settings/git/useGitIntegrationExperiment.ts +8 -0
- package/src/features/settings/git/useGitOwners.ts +12 -0
- package/src/features/settings/git/useGitRepos.ts +24 -0
- package/src/features/settings/git/useLinkedGitRepos.ts +41 -0
- package/src/features/settings/git/useWriteAPIToken.ts +23 -0
- package/src/icons/BitbucketIcon.tsx +19 -0
- package/src/icons/GitHubIcon.tsx +17 -0
- package/src/icons/GitLabIcon.tsx +19 -0
- package/src/icons/SettingsIcon.tsx +19 -0
- package/src/legacy/components/ChangesItems/ChangesItems.tsx +1 -8
- package/src/legacy/components/Forms/CreateSliceModal/CreateSliceModal.tsx +3 -8
- package/src/legacy/components/Simulator/components/FailedConnect/index.tsx +51 -56
- package/src/legacy/components/ToasterContainer/index.tsx +3 -14
- package/src/legacy/lib/builders/CustomTypeBuilder/SliceZone/SlicesTemplatesModal.tsx +1 -4
- package/src/legacy/lib/builders/CustomTypeBuilder/SliceZone/UpdateSliceZoneModal.tsx +1 -5
- package/src/legacy/lib/builders/CustomTypeBuilder/SliceZone/index.tsx +53 -40
- package/src/legacy/lib/builders/SliceBuilder/index.tsx +1 -6
- package/src/legacy/lib/builders/common/Zone/components/ZoneEmptyState/ZoneEmptyState.tsx +5 -10
- package/src/pages/settings.tsx +1 -0
- package/src/pages/slices.tsx +36 -57
- package/out/_next/static/OERdRe23c5buVNy_8FtIU/_buildManifest.js +0 -1
- package/out/_next/static/chunks/248-6f20227ad4764216.js +0 -1
- package/out/_next/static/chunks/268-6a9214b97195af9c.js +0 -1
- package/out/_next/static/chunks/489-eaa4848c00e8986b.js +0 -1
- package/out/_next/static/chunks/pages/changelog-98836c22c6a40c5d.js +0 -1
- package/out/_next/static/chunks/pages/changes-db800bf4a08faa31.js +0 -1
- package/out/_next/static/chunks/pages/labs-ad7f36c6f544c1a8.js +0 -1
- package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]/simulator-5008e29008aa04f4.js +0 -1
- package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]-0bc862dd7bd99611.js +0 -1
- package/out/_next/static/chunks/pages/slices-6dbc3df2c4ef058a.js +0 -1
- package/src/features/builder/useSectionsNamingExperiment.ts +0 -15
- package/src/features/customTypes/customTypesBuilder/sliceCreationOptions.tsx +0 -74
- package/src/utils/textConversion.ts +0 -11
- /package/out/_next/static/{OERdRe23c5buVNy_8FtIU → QRJGmIoJFXeQ96FN-TwH5}/_ssgManifest.js +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ActionList,
|
|
3
3
|
ActionListItem,
|
|
4
|
+
BackgroundIcon,
|
|
4
5
|
BlankSlate,
|
|
5
6
|
BlankSlateActions,
|
|
6
7
|
BlankSlateDescription,
|
|
@@ -10,10 +11,6 @@ import {
|
|
|
10
11
|
import { FC } from "react";
|
|
11
12
|
|
|
12
13
|
import { useAiSliceGenerationExperiment } from "@/features/builder/useAiSliceGenerationExperiment";
|
|
13
|
-
import { useSectionsNamingExperiment } from "@/features/builder/useSectionsNamingExperiment";
|
|
14
|
-
import { capitalizeFirstLetter, pluralize } from "@/utils/textConversion";
|
|
15
|
-
|
|
16
|
-
import { getSliceCreationOptions } from "./sliceCreationOptions";
|
|
17
14
|
|
|
18
15
|
export type SliceZoneBlankSlateProps = {
|
|
19
16
|
openUpdateSliceZoneModal: () => void;
|
|
@@ -33,11 +30,6 @@ export const SliceZoneBlankSlate: FC<SliceZoneBlankSlateProps> = ({
|
|
|
33
30
|
isSlicesTemplatesSupported,
|
|
34
31
|
}) => {
|
|
35
32
|
const aiSliceGenerationExperiment = useAiSliceGenerationExperiment();
|
|
36
|
-
const sectionsNamingExperiment = useSectionsNamingExperiment();
|
|
37
|
-
const sliceCreationOptions = getSliceCreationOptions({
|
|
38
|
-
menuType: "ActionList",
|
|
39
|
-
sectionsNamingExperiment,
|
|
40
|
-
});
|
|
41
33
|
|
|
42
34
|
return (
|
|
43
35
|
<BlankSlate data-testid="slice-zone-blank-slate" sx={{ width: 648 }}>
|
|
@@ -47,57 +39,81 @@ export const SliceZoneBlankSlate: FC<SliceZoneBlankSlateProps> = ({
|
|
|
47
39
|
name="add"
|
|
48
40
|
size="large"
|
|
49
41
|
/>
|
|
50
|
-
<BlankSlateTitle size="big">
|
|
51
|
-
Add {pluralize(sectionsNamingExperiment.value)}
|
|
52
|
-
</BlankSlateTitle>
|
|
42
|
+
<BlankSlateTitle size="big">Add slices</BlankSlateTitle>
|
|
53
43
|
<BlankSlateDescription>
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
content. Each on different pages with different content. Each{" "}
|
|
57
|
-
{sectionsNamingExperiment.value} has its own component in your code.
|
|
44
|
+
Slices are website sections that you can reuse on different pages with
|
|
45
|
+
different content. Each slice has its own component in your code.
|
|
58
46
|
</BlankSlateDescription>
|
|
59
47
|
<BlankSlateActions>
|
|
60
48
|
<ActionList>
|
|
61
49
|
{aiSliceGenerationExperiment.eligible && (
|
|
62
50
|
<ActionListItem
|
|
63
|
-
renderStartIcon={() =>
|
|
64
|
-
|
|
65
|
-
|
|
51
|
+
renderStartIcon={() => (
|
|
52
|
+
<BackgroundIcon
|
|
53
|
+
name="autoFixHigh"
|
|
54
|
+
size="small"
|
|
55
|
+
iconSize="medium"
|
|
56
|
+
color="purple"
|
|
57
|
+
variant="solid"
|
|
58
|
+
radius={6}
|
|
59
|
+
/>
|
|
60
|
+
)}
|
|
66
61
|
onClick={openCreateSliceFromImageModal}
|
|
67
|
-
description=
|
|
62
|
+
description="Build a slice based on your design image."
|
|
68
63
|
>
|
|
69
|
-
|
|
64
|
+
Generate from image
|
|
70
65
|
</ActionListItem>
|
|
71
66
|
)}
|
|
72
67
|
<ActionListItem
|
|
73
|
-
renderStartIcon={() =>
|
|
74
|
-
|
|
75
|
-
|
|
68
|
+
renderStartIcon={() => (
|
|
69
|
+
<BackgroundIcon
|
|
70
|
+
name="add"
|
|
71
|
+
size="small"
|
|
72
|
+
iconSize="medium"
|
|
73
|
+
color="white"
|
|
74
|
+
variant="solid"
|
|
75
|
+
radius={6}
|
|
76
|
+
/>
|
|
77
|
+
)}
|
|
76
78
|
onClick={openCreateSliceModal}
|
|
77
|
-
description=
|
|
79
|
+
description="Build a custom slice your way."
|
|
78
80
|
>
|
|
79
|
-
|
|
81
|
+
Start from scratch
|
|
80
82
|
</ActionListItem>
|
|
81
83
|
{isSlicesTemplatesSupported && (
|
|
82
84
|
<ActionListItem
|
|
83
|
-
renderStartIcon={() =>
|
|
84
|
-
|
|
85
|
-
|
|
85
|
+
renderStartIcon={() => (
|
|
86
|
+
<BackgroundIcon
|
|
87
|
+
name="contentCopy"
|
|
88
|
+
size="small"
|
|
89
|
+
iconSize="medium"
|
|
90
|
+
color="white"
|
|
91
|
+
variant="solid"
|
|
92
|
+
radius={6}
|
|
93
|
+
/>
|
|
94
|
+
)}
|
|
86
95
|
onClick={openSlicesTemplatesModal}
|
|
87
|
-
description=
|
|
96
|
+
description="Choose from ready-made examples."
|
|
88
97
|
>
|
|
89
|
-
|
|
98
|
+
Use a template
|
|
90
99
|
</ActionListItem>
|
|
91
100
|
)}
|
|
92
101
|
{projectHasAvailableSlices && (
|
|
93
102
|
<ActionListItem
|
|
94
|
-
renderStartIcon={() =>
|
|
95
|
-
|
|
96
|
-
|
|
103
|
+
renderStartIcon={() => (
|
|
104
|
+
<BackgroundIcon
|
|
105
|
+
name="folder"
|
|
106
|
+
size="small"
|
|
107
|
+
iconSize="medium"
|
|
108
|
+
color="white"
|
|
109
|
+
variant="solid"
|
|
110
|
+
radius={6}
|
|
111
|
+
/>
|
|
112
|
+
)}
|
|
97
113
|
onClick={openUpdateSliceZoneModal}
|
|
98
|
-
description=
|
|
114
|
+
description="Select from your created slices."
|
|
99
115
|
>
|
|
100
|
-
|
|
116
|
+
Reuse an existing slice
|
|
101
117
|
</ActionListItem>
|
|
102
118
|
)}
|
|
103
119
|
</ActionList>
|
|
@@ -8,16 +8,16 @@ import { CUSTOM_TYPES_CONFIG } from "@/features/customTypes/customTypesConfig";
|
|
|
8
8
|
import { CUSTOM_TYPES_MESSAGES } from "@/features/customTypes/customTypesMessages";
|
|
9
9
|
import { RepositoryInfo } from "@/features/navigation/RepositoryInfo";
|
|
10
10
|
import { OnboardingGuide } from "@/features/onboarding";
|
|
11
|
+
import { useGitIntegrationExperiment } from "@/features/settings/git/useGitIntegrationExperiment";
|
|
11
12
|
import { useAdapterName } from "@/hooks/useAdapterName";
|
|
12
13
|
import { useMarketingContent } from "@/hooks/useMarketingContent";
|
|
13
14
|
import { FolderIcon } from "@/icons/FolderIcon";
|
|
14
15
|
import { LightningIcon } from "@/icons/Lightning";
|
|
15
16
|
import { MenuBookIcon } from "@/icons/MenuBookIcon";
|
|
16
|
-
import {
|
|
17
|
+
import { SettingsIcon } from "@/icons/SettingsIcon";
|
|
17
18
|
|
|
18
19
|
import { ChangesItem } from "../../legacy/components/Navigation/ChangesItem";
|
|
19
20
|
import { Environment } from "../../legacy/components/Navigation/Environment";
|
|
20
|
-
import { useSectionsNamingExperiment } from "../builder/useSectionsNamingExperiment";
|
|
21
21
|
import { NavigationItem } from "./NavigationItem";
|
|
22
22
|
import { SliceMachineVersion } from "./SliceMachineVersion";
|
|
23
23
|
import { UpdateInfo } from "./UpdateInfo";
|
|
@@ -25,8 +25,8 @@ import { UpdateInfo } from "./UpdateInfo";
|
|
|
25
25
|
export function Navigation() {
|
|
26
26
|
const router = useRouter();
|
|
27
27
|
|
|
28
|
+
const gitIntegrationExperiment = useGitIntegrationExperiment();
|
|
28
29
|
const { documentationLink } = useMarketingContent();
|
|
29
|
-
const sectionsNamingExperiment = useSectionsNamingExperiment();
|
|
30
30
|
const adapter = useAdapterName();
|
|
31
31
|
|
|
32
32
|
interface CustomTypeNavigationItemProps {
|
|
@@ -75,9 +75,7 @@ export function Navigation() {
|
|
|
75
75
|
<CustomTypeNavigationItem type="custom" />
|
|
76
76
|
|
|
77
77
|
<NavigationItem
|
|
78
|
-
title=
|
|
79
|
-
capitalizeFirstLetter(sectionsNamingExperiment.value),
|
|
80
|
-
)}
|
|
78
|
+
title="Slices"
|
|
81
79
|
href="/slices"
|
|
82
80
|
Icon={FolderIcon}
|
|
83
81
|
active={router.asPath.startsWith("/slices")}
|
|
@@ -98,7 +96,6 @@ export function Navigation() {
|
|
|
98
96
|
<OnboardingGuide />
|
|
99
97
|
</Suspense>
|
|
100
98
|
</ErrorBoundary>
|
|
101
|
-
|
|
102
99
|
<NavigationItem
|
|
103
100
|
title="Documentation"
|
|
104
101
|
href={documentationLink}
|
|
@@ -112,6 +109,15 @@ export function Navigation() {
|
|
|
112
109
|
}}
|
|
113
110
|
/>
|
|
114
111
|
|
|
112
|
+
{gitIntegrationExperiment.eligible && (
|
|
113
|
+
<NavigationItem
|
|
114
|
+
title="Settings"
|
|
115
|
+
href="/settings"
|
|
116
|
+
Icon={SettingsIcon}
|
|
117
|
+
active={router.asPath.startsWith("/settings")}
|
|
118
|
+
/>
|
|
119
|
+
)}
|
|
120
|
+
|
|
115
121
|
<NavigationItem
|
|
116
122
|
title="Changelog"
|
|
117
123
|
href="/changelog"
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Box } from "@prismicio/editor-ui";
|
|
2
|
+
import Head from "next/head";
|
|
3
|
+
import { useRouter } from "next/router";
|
|
4
|
+
import { type FC, useEffect } from "react";
|
|
5
|
+
|
|
6
|
+
import { BreadcrumbItem } from "@/components/Breadcrumb";
|
|
7
|
+
import { ConnectGitRepository } from "@/features/settings/git/ConnectGitRepository";
|
|
8
|
+
import { useGitIntegrationExperiment } from "@/features/settings/git/useGitIntegrationExperiment";
|
|
9
|
+
import {
|
|
10
|
+
AppLayout,
|
|
11
|
+
AppLayoutBreadcrumb,
|
|
12
|
+
AppLayoutContent,
|
|
13
|
+
AppLayoutHeader,
|
|
14
|
+
} from "@/legacy/components/AppLayout";
|
|
15
|
+
|
|
16
|
+
export const SettingsPage: FC = () => {
|
|
17
|
+
const gitIntegrationExperiment = useGitIntegrationExperiment();
|
|
18
|
+
const router = useRouter();
|
|
19
|
+
|
|
20
|
+
// TODO(DT-1801): implement a 404 page.
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
if (!gitIntegrationExperiment.eligible) {
|
|
23
|
+
void router.replace("/");
|
|
24
|
+
}
|
|
25
|
+
}, [gitIntegrationExperiment.eligible, router]);
|
|
26
|
+
|
|
27
|
+
if (!gitIntegrationExperiment.eligible) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<>
|
|
33
|
+
<Head>
|
|
34
|
+
<title>Settings - Slice Machine</title>
|
|
35
|
+
</Head>
|
|
36
|
+
<AppLayout>
|
|
37
|
+
<AppLayoutHeader>
|
|
38
|
+
<AppLayoutBreadcrumb>
|
|
39
|
+
<BreadcrumbItem>Settings</BreadcrumbItem>
|
|
40
|
+
</AppLayoutBreadcrumb>
|
|
41
|
+
</AppLayoutHeader>
|
|
42
|
+
<AppLayoutContent>
|
|
43
|
+
<Box flexDirection="column" maxWidth={600}>
|
|
44
|
+
<ConnectGitRepository />
|
|
45
|
+
</Box>
|
|
46
|
+
</AppLayoutContent>
|
|
47
|
+
</AppLayout>
|
|
48
|
+
</>
|
|
49
|
+
);
|
|
50
|
+
};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { Button, IconButton, Tooltip } from "@prismicio/editor-ui";
|
|
2
|
+
import {
|
|
3
|
+
isUnauthenticatedError,
|
|
4
|
+
isUnauthorizedError,
|
|
5
|
+
} from "@slicemachine/manager/client";
|
|
6
|
+
import { type FC, type ReactNode, Suspense } from "react";
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
FieldSet,
|
|
10
|
+
FieldSetContent,
|
|
11
|
+
FieldSetFooter,
|
|
12
|
+
FieldSetLegend,
|
|
13
|
+
} from "@/components/FieldSet";
|
|
14
|
+
import { ErrorBoundary } from "@/ErrorBoundary";
|
|
15
|
+
import { ConnectGitRepositoryBlankSlate } from "@/features/settings/git/ConnectGitRepositoryBlankSlate";
|
|
16
|
+
import { GitProviderConnectButtons } from "@/features/settings/git/GitProviderConnectButtons";
|
|
17
|
+
import { GitRepositoriesList } from "@/features/settings/git/GitRepositoriesList";
|
|
18
|
+
import {
|
|
19
|
+
GitRepositoriesSearch,
|
|
20
|
+
GitRepositoriesSearchSkeleton,
|
|
21
|
+
} from "@/features/settings/git/GitRepositoriesSearch";
|
|
22
|
+
import { useGitOwners } from "@/features/settings/git/useGitOwners";
|
|
23
|
+
import { useLinkedGitRepos } from "@/features/settings/git/useLinkedGitRepos";
|
|
24
|
+
import useSliceMachineActions from "@/modules/useSliceMachineActions";
|
|
25
|
+
|
|
26
|
+
export const ConnectGitRepository: FC = () => (
|
|
27
|
+
<FieldSet>
|
|
28
|
+
<FieldSetLegend>Connected Git Repository</FieldSetLegend>
|
|
29
|
+
<ErrorBoundary renderError={renderError}>
|
|
30
|
+
<Suspense fallback={<GitRepositoriesSearchSkeleton gitOwnerSelect />}>
|
|
31
|
+
<Content />
|
|
32
|
+
</Suspense>
|
|
33
|
+
</ErrorBoundary>
|
|
34
|
+
<FieldSetFooter
|
|
35
|
+
action={
|
|
36
|
+
<Tooltip content="Documentation is coming soon." side="bottom">
|
|
37
|
+
<IconButton disabled icon="openInNew" />
|
|
38
|
+
</Tooltip>
|
|
39
|
+
}
|
|
40
|
+
>
|
|
41
|
+
Learn more about Prismic for Git
|
|
42
|
+
</FieldSetFooter>
|
|
43
|
+
</FieldSet>
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
const Content: FC = () => {
|
|
47
|
+
const { linkedGitRepos } = useLinkedGitRepos();
|
|
48
|
+
return linkedGitRepos.length > 0 ? (
|
|
49
|
+
<GitRepositoriesList mode="unlink" repos={linkedGitRepos} />
|
|
50
|
+
) : (
|
|
51
|
+
<UnlinkedRepositoryContent />
|
|
52
|
+
);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const UnlinkedRepositoryContent: FC = () => {
|
|
56
|
+
const owners = useGitOwners();
|
|
57
|
+
return owners.length > 0 ? (
|
|
58
|
+
<GitRepositoriesSearch owners={owners} />
|
|
59
|
+
) : (
|
|
60
|
+
<FieldSetContent>
|
|
61
|
+
<GitProviderConnectButtons />
|
|
62
|
+
</FieldSetContent>
|
|
63
|
+
);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
function renderError(error: unknown, reset: () => void): ReactNode {
|
|
67
|
+
if (isUnauthenticatedError(error)) {
|
|
68
|
+
return <UnauthenticatedErrorContent />;
|
|
69
|
+
} else if (isUnauthorizedError(error)) {
|
|
70
|
+
return <UnauthorizedErrorContent />;
|
|
71
|
+
} else {
|
|
72
|
+
return <UnknownErrorContent reset={reset} />;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const UnauthenticatedErrorContent: FC = () => {
|
|
77
|
+
const { openLoginModal } = useSliceMachineActions();
|
|
78
|
+
return (
|
|
79
|
+
<FieldSetContent>
|
|
80
|
+
<ConnectGitRepositoryBlankSlate
|
|
81
|
+
title="It seems like you are logged out"
|
|
82
|
+
description="Log in to connect a Git repository."
|
|
83
|
+
action={<Button onClick={openLoginModal}>Log in to Prismic</Button>}
|
|
84
|
+
/>
|
|
85
|
+
</FieldSetContent>
|
|
86
|
+
);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const UnauthorizedErrorContent: FC = () => (
|
|
90
|
+
<FieldSetContent>
|
|
91
|
+
<ConnectGitRepositoryBlankSlate
|
|
92
|
+
title="It seems like you do not have permission"
|
|
93
|
+
description="An owner or admin is required to connect a Git repository."
|
|
94
|
+
/>
|
|
95
|
+
</FieldSetContent>
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
type UnknownErrorContentProps = { reset: () => void };
|
|
99
|
+
|
|
100
|
+
const UnknownErrorContent: FC<UnknownErrorContentProps> = ({ reset }) => (
|
|
101
|
+
<FieldSetContent>
|
|
102
|
+
<ConnectGitRepositoryBlankSlate
|
|
103
|
+
title="Unable to fetch data"
|
|
104
|
+
description="An error occurred while fetching the list of connected Git repositories."
|
|
105
|
+
action={
|
|
106
|
+
<Button color="grey" onClick={reset}>
|
|
107
|
+
Retry
|
|
108
|
+
</Button>
|
|
109
|
+
}
|
|
110
|
+
/>
|
|
111
|
+
</FieldSetContent>
|
|
112
|
+
);
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Box, ButtonGroup, Text } from "@prismicio/editor-ui";
|
|
2
|
+
import type { FC, ReactNode } from "react";
|
|
3
|
+
|
|
4
|
+
type ConnectGitRepositoryBlankSlateProps = {
|
|
5
|
+
title: string;
|
|
6
|
+
description: string;
|
|
7
|
+
action?: ReactNode;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const ConnectGitRepositoryBlankSlate: FC<
|
|
11
|
+
ConnectGitRepositoryBlankSlateProps
|
|
12
|
+
> = ({ title, description, action }) => (
|
|
13
|
+
<Box
|
|
14
|
+
flexDirection="column"
|
|
15
|
+
/*
|
|
16
|
+
* TODO: these `padding` values actually don't match Figma, but they are the
|
|
17
|
+
* closest allowed by the `Box` component.
|
|
18
|
+
*/
|
|
19
|
+
padding={{ block: 72, inline: 100 }}
|
|
20
|
+
>
|
|
21
|
+
<Text align="center" variant="emphasized">
|
|
22
|
+
{title}
|
|
23
|
+
</Text>
|
|
24
|
+
<Text align="center" color="grey11">
|
|
25
|
+
{description}
|
|
26
|
+
</Text>
|
|
27
|
+
{Boolean(action) ? (
|
|
28
|
+
<ButtonGroup sx={{ alignSelf: "center", marginTop: 8 }}>
|
|
29
|
+
{action}
|
|
30
|
+
</ButtonGroup>
|
|
31
|
+
) : undefined}
|
|
32
|
+
</Box>
|
|
33
|
+
);
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Select, SelectItem, theme } from "@prismicio/editor-ui";
|
|
2
|
+
import type { GitOwner } from "@slicemachine/manager";
|
|
3
|
+
import type { ComponentPropsWithoutRef, FC } from "react";
|
|
4
|
+
|
|
5
|
+
import { gitProviderToConfig } from "@/features/settings/git/GitProvider";
|
|
6
|
+
|
|
7
|
+
type GitOwnerSelectProps = {
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
owners?: GitOwner[];
|
|
10
|
+
selectedOwner?: GitOwner;
|
|
11
|
+
onSelectedOwnerChange?: (selectedOwner: GitOwner) => void;
|
|
12
|
+
sx?: SX;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const GitOwnerSelect: FC<GitOwnerSelectProps> = ({
|
|
16
|
+
disabled,
|
|
17
|
+
owners = [],
|
|
18
|
+
selectedOwner,
|
|
19
|
+
onSelectedOwnerChange,
|
|
20
|
+
sx,
|
|
21
|
+
}) => (
|
|
22
|
+
<Select
|
|
23
|
+
color="grey"
|
|
24
|
+
constrainContentWidth
|
|
25
|
+
disabled={disabled}
|
|
26
|
+
flexContent
|
|
27
|
+
onValueChange={(value) => {
|
|
28
|
+
const [provider, id] = parseGitOwnerKey(value);
|
|
29
|
+
const selectedOwner = owners.find(
|
|
30
|
+
(owner) => owner.provider === provider && owner.id === id,
|
|
31
|
+
);
|
|
32
|
+
if (selectedOwner) {
|
|
33
|
+
onSelectedOwnerChange?.(selectedOwner);
|
|
34
|
+
}
|
|
35
|
+
}}
|
|
36
|
+
placeholder="Owner"
|
|
37
|
+
renderStartIcon={() => <GitOwnerIcon owner={selectedOwner} />}
|
|
38
|
+
size="large"
|
|
39
|
+
sx={sx}
|
|
40
|
+
value={selectedOwner ? formatGitOwnerKey(selectedOwner) : undefined}
|
|
41
|
+
>
|
|
42
|
+
{owners.map((owner) => (
|
|
43
|
+
<SelectItem
|
|
44
|
+
key={formatGitOwnerKey(owner)}
|
|
45
|
+
renderStartIcon={() => <GitOwnerIcon owner={owner} />}
|
|
46
|
+
size="large"
|
|
47
|
+
value={formatGitOwnerKey(owner)}
|
|
48
|
+
>
|
|
49
|
+
{owner.name}
|
|
50
|
+
</SelectItem>
|
|
51
|
+
))}
|
|
52
|
+
</Select>
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
type GitOwnerIconProps = { owner: GitOwner | undefined };
|
|
56
|
+
|
|
57
|
+
const GitOwnerIcon: FC<GitOwnerIconProps> = ({ owner }) => {
|
|
58
|
+
const { Icon } = gitProviderToConfig[owner?.provider ?? "gitHub"];
|
|
59
|
+
return <Icon color={theme.color.grey11} />;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
function formatGitOwnerKey(owner: GitOwner): string {
|
|
63
|
+
return `${owner.provider}@${owner.id}`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function parseGitOwnerKey(key: string): string[] {
|
|
67
|
+
return key.split("@");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// TODO(DT-1928): export the `SX` type from `@prismicio/editor-ui`.
|
|
71
|
+
type SX = ComponentPropsWithoutRef<typeof Select>["sx"];
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { GIT_PROVIDER, GitProvider } from "@slicemachine/manager/client";
|
|
2
|
+
|
|
3
|
+
import { BitbucketIcon } from "@/icons/BitbucketIcon";
|
|
4
|
+
import { GitHubIcon } from "@/icons/GitHubIcon";
|
|
5
|
+
import { GitLabIcon } from "@/icons/GitLabIcon";
|
|
6
|
+
import { managerClient } from "@/managerClient";
|
|
7
|
+
|
|
8
|
+
export const gitProviderToConfig = {
|
|
9
|
+
gitHub: {
|
|
10
|
+
connect: async () => await openInstallationWindow("gitHub"),
|
|
11
|
+
Icon: GitHubIcon,
|
|
12
|
+
name: "GitHub",
|
|
13
|
+
supported: isSupported("gitHub"),
|
|
14
|
+
},
|
|
15
|
+
bitbucket: {
|
|
16
|
+
connect: async () => await openInstallationWindow("bitbucket"),
|
|
17
|
+
Icon: BitbucketIcon,
|
|
18
|
+
name: "Bitbucket",
|
|
19
|
+
supported: isSupported("bitbucket"),
|
|
20
|
+
},
|
|
21
|
+
gitLab: {
|
|
22
|
+
connect: async () => await openInstallationWindow("gitLab"),
|
|
23
|
+
Icon: GitLabIcon,
|
|
24
|
+
name: "GitLab",
|
|
25
|
+
supported: isSupported("gitLab"),
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
async function openInstallationWindow(provider: string) {
|
|
30
|
+
if (!isSupported(provider)) {
|
|
31
|
+
throw new Error("Not implemented.");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const url = await managerClient.git.getProviderAppInstallURL({ provider });
|
|
35
|
+
window.open(url, "git-provider-app-installation");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function isSupported(provider: string): provider is GitProvider {
|
|
39
|
+
return Boolean(Object.values<string>(GIT_PROVIDER).includes(provider));
|
|
40
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { keys } from "@prismicio/editor-support/Object";
|
|
2
|
+
import { Button, ButtonGroup, Text, theme } from "@prismicio/editor-ui";
|
|
3
|
+
import { type ComponentPropsWithoutRef, type FC, useState } from "react";
|
|
4
|
+
import { toast } from "react-toastify";
|
|
5
|
+
|
|
6
|
+
import { gitProviderToConfig } from "@/features/settings/git/GitProvider";
|
|
7
|
+
|
|
8
|
+
export const GitProviderConnectButtons: FC = () => (
|
|
9
|
+
<ButtonGroup>
|
|
10
|
+
{keys(gitProviderToConfig).map((provider) => (
|
|
11
|
+
<GitProviderConnectButton
|
|
12
|
+
key={provider}
|
|
13
|
+
provider={provider}
|
|
14
|
+
sx={{ flexBasis: 0, flexGrow: 1 }}
|
|
15
|
+
/>
|
|
16
|
+
))}
|
|
17
|
+
</ButtonGroup>
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
type GitProviderConnectButtonProps = {
|
|
21
|
+
provider: keyof typeof gitProviderToConfig;
|
|
22
|
+
sx?: SX;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const GitProviderConnectButton: FC<GitProviderConnectButtonProps> = ({
|
|
26
|
+
provider,
|
|
27
|
+
sx,
|
|
28
|
+
}) => {
|
|
29
|
+
const { connect, Icon, name, supported } = gitProviderToConfig[provider];
|
|
30
|
+
const [loading, setLoading] = useState(false);
|
|
31
|
+
return (
|
|
32
|
+
<Button
|
|
33
|
+
color="grey"
|
|
34
|
+
disabled={!supported}
|
|
35
|
+
loading={loading}
|
|
36
|
+
onClick={() => {
|
|
37
|
+
void (async () => {
|
|
38
|
+
setLoading(true);
|
|
39
|
+
try {
|
|
40
|
+
await connect();
|
|
41
|
+
} catch (error) {
|
|
42
|
+
const message = `Could not connect to ${name}`;
|
|
43
|
+
console.error(message, error);
|
|
44
|
+
toast.error(message);
|
|
45
|
+
setLoading(false);
|
|
46
|
+
}
|
|
47
|
+
})();
|
|
48
|
+
}}
|
|
49
|
+
renderStartIcon={() => <Icon color={theme.color.grey11} />}
|
|
50
|
+
sx={sx}
|
|
51
|
+
>
|
|
52
|
+
{name}
|
|
53
|
+
{supported ? undefined : (
|
|
54
|
+
<Text color="inherit" variant="small">
|
|
55
|
+
{" (soon)"}
|
|
56
|
+
</Text>
|
|
57
|
+
)}
|
|
58
|
+
</Button>
|
|
59
|
+
);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
// TODO(DT-1928): export the `SX` type from `@prismicio/editor-ui`.
|
|
63
|
+
type SX = ComponentPropsWithoutRef<typeof Button>["sx"];
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Button, Skeleton, Text } from "@prismicio/editor-ui";
|
|
2
|
+
import type { GitRepo, GitRepoSpecifier } from "@slicemachine/manager";
|
|
3
|
+
import type { FC } from "react";
|
|
4
|
+
|
|
5
|
+
import { FieldSetList, FieldSetListItem } from "@/components/FieldSet";
|
|
6
|
+
import { RelativeTime } from "@/components/RelativeTime";
|
|
7
|
+
import { GitRepositoryConnectDialog } from "@/features/settings/git/GitRepositoryConnectDialog";
|
|
8
|
+
import { GitRepositoryDisconnectDialog } from "@/features/settings/git/GitRepositoryDisconnectDialog";
|
|
9
|
+
import { useLinkedGitRepos } from "@/features/settings/git/useLinkedGitRepos";
|
|
10
|
+
|
|
11
|
+
type GitRepositoriesListProps =
|
|
12
|
+
| { mode: "link"; repos: GitRepo[] }
|
|
13
|
+
| { mode: "unlink"; repos: GitRepoSpecifier[] };
|
|
14
|
+
|
|
15
|
+
export const GitRepositoriesList: FC<GitRepositoriesListProps> = ({
|
|
16
|
+
mode,
|
|
17
|
+
repos,
|
|
18
|
+
}) => {
|
|
19
|
+
const { linkRepo, unlinkRepo } = useLinkedGitRepos();
|
|
20
|
+
return (
|
|
21
|
+
<FieldSetList>
|
|
22
|
+
{mode === "link"
|
|
23
|
+
? repos.map((repo) => (
|
|
24
|
+
<FieldSetListItem
|
|
25
|
+
action={
|
|
26
|
+
<GitRepositoryConnectDialog
|
|
27
|
+
linkRepo={linkRepo}
|
|
28
|
+
repo={repo}
|
|
29
|
+
trigger={<Button color="grey">Connect</Button>}
|
|
30
|
+
/>
|
|
31
|
+
}
|
|
32
|
+
key={`${repo.provider}@${repo.id}`}
|
|
33
|
+
>
|
|
34
|
+
{repo.name}
|
|
35
|
+
<Text color="grey11">
|
|
36
|
+
{" • "}
|
|
37
|
+
<RelativeTime date={repo.pushedAt} />
|
|
38
|
+
</Text>
|
|
39
|
+
</FieldSetListItem>
|
|
40
|
+
))
|
|
41
|
+
: repos.map((repo) => (
|
|
42
|
+
<FieldSetListItem
|
|
43
|
+
action={
|
|
44
|
+
<GitRepositoryDisconnectDialog
|
|
45
|
+
repo={repo}
|
|
46
|
+
trigger={<Button color="grey">Disconnect</Button>}
|
|
47
|
+
unlinkRepo={unlinkRepo}
|
|
48
|
+
/>
|
|
49
|
+
}
|
|
50
|
+
key={`${repo.provider}@${repo.owner}/${repo.name}`}
|
|
51
|
+
>
|
|
52
|
+
{repo.name}
|
|
53
|
+
</FieldSetListItem>
|
|
54
|
+
))}
|
|
55
|
+
</FieldSetList>
|
|
56
|
+
);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export const GitRepositoriesListSkeleton: FC = () => (
|
|
60
|
+
<FieldSetList>
|
|
61
|
+
{[...Array(4).keys()].map((index) => (
|
|
62
|
+
<FieldSetListItem
|
|
63
|
+
action={<Skeleton height={32} width={67.59} />}
|
|
64
|
+
key={index}
|
|
65
|
+
>
|
|
66
|
+
<Skeleton
|
|
67
|
+
height={24}
|
|
68
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
69
|
+
// @ts-ignore TODO(DT-1918): add `verticalAlign: "middle"` to the `sx` prop.
|
|
70
|
+
sx={{ verticalAlign: "middle" }}
|
|
71
|
+
width={129.92}
|
|
72
|
+
/>
|
|
73
|
+
</FieldSetListItem>
|
|
74
|
+
))}
|
|
75
|
+
</FieldSetList>
|
|
76
|
+
);
|