slice-machine-ui 1.19.3-dev-environments.0 → 1.19.3-dev-environments.2
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/components/AppLayout/index.tsx +17 -8
- package/components/Navigation/Environment.tsx +47 -0
- package/components/Navigation/index.css.ts +6 -0
- package/components/Navigation/index.tsx +15 -9
- package/out/404.html +1 -1
- package/out/_next/static/{-4lxvQeV2M40FkqjVjg5k → NqynY6jJvk8ZGc3GEM_3O}/_buildManifest.js +1 -1
- package/out/_next/static/chunks/840-5b485c737b24324b.js +1 -0
- package/out/_next/static/chunks/904-e290f0254cc4b5df.js +1 -0
- package/out/_next/static/chunks/pages/{_app-14f16e3f98ecaf00.js → _app-dabcd3e651f50e3f.js} +6 -6
- package/out/_next/static/chunks/pages/{changelog-e0f1e523388e0a82.js → changelog-4b8369d91d82b28b.js} +1 -1
- package/out/_next/static/chunks/pages/changes-db6e8c6be5ae076e.js +1 -0
- package/out/_next/static/chunks/pages/labs-2922105ab714d32a.js +1 -0
- package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/{[variation]-d4214dec78681387.js → [variation]-ca780766d02c801b.js} +1 -1
- package/out/_next/static/chunks/pages/slices-2811e0ce8aa23ac2.js +1 -0
- package/out/_next/static/css/{412af4286eb0b283.css → 009bd7f5ac85fc6a.css} +1 -1
- 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/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 +4 -4
- package/src/components/Divider/Divider.css.ts +31 -0
- package/src/components/Divider/Divider.stories.tsx +27 -0
- package/src/components/Divider/Divider.tsx +25 -0
- package/src/components/Divider/index.ts +1 -0
- package/src/components/PageLayout/PageLayout.css.ts +8 -3
- package/src/components/PageLayout/PageLayout.stories.tsx +10 -1
- package/src/components/PageLayout/PageLayout.tsx +7 -2
- package/src/components/SideNav/SideNav.css.ts +3 -10
- package/src/components/SideNav/SideNav.stories.tsx +29 -2
- package/src/components/SideNav/SideNav.tsx +5 -1
- package/src/components/SideNav/SideNavEnvironmentSelector.css.ts +69 -0
- package/src/components/SideNav/SideNavEnvironmentSelector.tsx +163 -0
- package/src/components/SideNav/index.ts +1 -0
- package/src/features/environments/actions/getActiveEnvironmentDomain.ts +11 -0
- package/src/features/environments/actions/getEnvironments.ts +12 -0
- package/src/features/environments/actions/setEnvironment.ts +18 -0
- package/src/features/environments/useActiveEnvironment.ts +38 -0
- package/src/features/environments/useEnvironments.ts +2 -18
- package/src/features/legacyState/actions/getLegacySliceMachineState.ts +53 -0
- package/src/features/legacyState/useLegacySliceMachineState.ts +7 -0
- package/test/src/modules/__fixtures__/serverState.ts +2 -1
- package/components/Navigation/Environments.tsx +0 -12
- package/out/_next/static/chunks/840-098331627449589b.js +0 -1
- package/out/_next/static/chunks/904-cbbad0444735951e.js +0 -1
- package/out/_next/static/chunks/pages/changes-4bd97248080247cd.js +0 -1
- package/out/_next/static/chunks/pages/labs-80726c793a41c3cb.js +0 -1
- package/out/_next/static/chunks/pages/slices-f4990186eff9faa8.js +0 -1
- /package/out/_next/static/{-4lxvQeV2M40FkqjVjg5k → NqynY6jJvk8ZGc3GEM_3O}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { colors, sprinkles } from "@prismicio/editor-ui";
|
|
2
|
+
import { style, styleVariants } from "@vanilla-extract/css";
|
|
3
|
+
|
|
4
|
+
const base = style([
|
|
5
|
+
sprinkles({
|
|
6
|
+
width: "100%",
|
|
7
|
+
borderStyle: "none",
|
|
8
|
+
margin: 0,
|
|
9
|
+
}),
|
|
10
|
+
]);
|
|
11
|
+
|
|
12
|
+
export const variants = styleVariants({
|
|
13
|
+
dashed: [
|
|
14
|
+
base,
|
|
15
|
+
sprinkles({
|
|
16
|
+
borderColor: colors.currentColor,
|
|
17
|
+
borderTopStyle: "dashed",
|
|
18
|
+
borderWidth: 1,
|
|
19
|
+
}),
|
|
20
|
+
],
|
|
21
|
+
edgeFaded: [
|
|
22
|
+
base,
|
|
23
|
+
sprinkles({
|
|
24
|
+
height: 1,
|
|
25
|
+
}),
|
|
26
|
+
{
|
|
27
|
+
backgroundImage:
|
|
28
|
+
"linear-gradient(to right, color-mix(in srgb, currentColor 0%, transparent), currentColor, color-mix(in srgb, currentColor 0%, transparent))",
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { colors } from "@prismicio/editor-ui";
|
|
3
|
+
|
|
4
|
+
import { Divider } from "./Divider";
|
|
5
|
+
import { variants } from "./Divider.css";
|
|
6
|
+
|
|
7
|
+
type Story = StoryObj<typeof meta>;
|
|
8
|
+
|
|
9
|
+
const meta = {
|
|
10
|
+
component: Divider,
|
|
11
|
+
argTypes: {
|
|
12
|
+
variant: {
|
|
13
|
+
control: { type: "select" },
|
|
14
|
+
options: Object.keys(variants),
|
|
15
|
+
},
|
|
16
|
+
color: {
|
|
17
|
+
control: { type: "select" },
|
|
18
|
+
options: Object.keys(colors),
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
} satisfies Meta<typeof Divider>;
|
|
22
|
+
|
|
23
|
+
export default meta;
|
|
24
|
+
|
|
25
|
+
export const Default = {
|
|
26
|
+
args: {},
|
|
27
|
+
} satisfies Story;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { FC } from "react";
|
|
2
|
+
import { colors, sprinkles } from "@prismicio/editor-ui";
|
|
3
|
+
import clsx from "clsx";
|
|
4
|
+
|
|
5
|
+
import * as styles from "./Divider.css";
|
|
6
|
+
|
|
7
|
+
type DividerProps = {
|
|
8
|
+
color?: keyof typeof colors;
|
|
9
|
+
variant?: "dashed" | "edgeFaded";
|
|
10
|
+
className?: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const Divider: FC<DividerProps> = (props) => {
|
|
14
|
+
const { variant = "dashed", color = "currentColor", className } = props;
|
|
15
|
+
|
|
16
|
+
return (
|
|
17
|
+
<hr
|
|
18
|
+
className={clsx(
|
|
19
|
+
styles.variants[variant],
|
|
20
|
+
sprinkles({ color: colors[color] }),
|
|
21
|
+
className,
|
|
22
|
+
)}
|
|
23
|
+
/>
|
|
24
|
+
);
|
|
25
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Divider } from "./Divider";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { colors, sprinkles, vars } from "@prismicio/editor-ui";
|
|
2
|
-
import { style } from "@vanilla-extract/css";
|
|
2
|
+
import { style, styleVariants } from "@vanilla-extract/css";
|
|
3
3
|
|
|
4
4
|
const grid = sprinkles({ all: "unset", display: "grid" });
|
|
5
5
|
|
|
@@ -23,10 +23,9 @@ export const root = style([
|
|
|
23
23
|
},
|
|
24
24
|
]);
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
const borderTopBase = style([
|
|
27
27
|
sprinkles({
|
|
28
28
|
all: "unset",
|
|
29
|
-
backgroundColor: colors.purple9,
|
|
30
29
|
display: "revert",
|
|
31
30
|
height: 2,
|
|
32
31
|
position: "fixed",
|
|
@@ -35,6 +34,12 @@ export const borderTop = style([
|
|
|
35
34
|
{ width: "inherit" },
|
|
36
35
|
]);
|
|
37
36
|
|
|
37
|
+
export const borderTop = styleVariants({
|
|
38
|
+
prod: [borderTopBase, sprinkles({ backgroundColor: colors.purple9 })],
|
|
39
|
+
stage: [borderTopBase, sprinkles({ backgroundColor: colors.indigo10 })],
|
|
40
|
+
dev: [borderTopBase, sprinkles({ backgroundColor: colors.amber10 })],
|
|
41
|
+
});
|
|
42
|
+
|
|
38
43
|
export const pane = style([
|
|
39
44
|
grid,
|
|
40
45
|
sprinkles({
|
|
@@ -6,12 +6,21 @@ import {
|
|
|
6
6
|
PageLayoutHeader,
|
|
7
7
|
PageLayoutPane,
|
|
8
8
|
} from "./PageLayout";
|
|
9
|
+
import { borderTop } from "./PageLayout.css";
|
|
9
10
|
|
|
10
11
|
type Story = StoryObj<typeof meta>;
|
|
11
12
|
|
|
12
13
|
const meta = {
|
|
13
14
|
component: PageLayout,
|
|
14
|
-
argTypes: {
|
|
15
|
+
argTypes: {
|
|
16
|
+
children: {
|
|
17
|
+
control: { disable: true },
|
|
18
|
+
},
|
|
19
|
+
activeEnvironmentKind: {
|
|
20
|
+
control: { type: "select" },
|
|
21
|
+
options: Object.keys(borderTop),
|
|
22
|
+
},
|
|
23
|
+
},
|
|
15
24
|
parameters: {
|
|
16
25
|
docs: { story: { height: 256, inline: false } },
|
|
17
26
|
layout: "fullscreen",
|
|
@@ -2,13 +2,18 @@ import type { FC, PropsWithChildren } from "react";
|
|
|
2
2
|
|
|
3
3
|
import * as styles from "./PageLayout.css";
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
type PageLayoutProps = PropsWithChildren<{
|
|
6
|
+
activeEnvironmentKind?: "prod" | "stage" | "dev";
|
|
7
|
+
}>;
|
|
8
|
+
|
|
9
|
+
export const PageLayout: FC<PageLayoutProps> = ({
|
|
10
|
+
activeEnvironmentKind = "prod",
|
|
6
11
|
children,
|
|
7
12
|
...otherProps
|
|
8
13
|
}) => (
|
|
9
14
|
<div {...otherProps} className={styles.root}>
|
|
10
15
|
{children}
|
|
11
|
-
<div className={styles.borderTop} />
|
|
16
|
+
<div className={styles.borderTop[activeEnvironmentKind]} />
|
|
12
17
|
</div>
|
|
13
18
|
);
|
|
14
19
|
|
|
@@ -101,7 +101,6 @@ export const repositoryLinkIcon = style([
|
|
|
101
101
|
borderWidth: 1,
|
|
102
102
|
cursor: "pointer",
|
|
103
103
|
height: 32,
|
|
104
|
-
marginRight: 8,
|
|
105
104
|
width: 32,
|
|
106
105
|
color: colors.grey12,
|
|
107
106
|
backgroundColor: {
|
|
@@ -163,15 +162,9 @@ export const listTitle = style([
|
|
|
163
162
|
},
|
|
164
163
|
]);
|
|
165
164
|
|
|
166
|
-
export const
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
borderColor: colors.grey6,
|
|
170
|
-
borderTopStyle: "dashed",
|
|
171
|
-
borderWidth: 1,
|
|
172
|
-
marginTop: 8,
|
|
173
|
-
}),
|
|
174
|
-
]);
|
|
165
|
+
export const separator = sprinkles({
|
|
166
|
+
marginTop: 8,
|
|
167
|
+
});
|
|
175
168
|
|
|
176
169
|
export const link = style([
|
|
177
170
|
block,
|
|
@@ -5,7 +5,6 @@ import { LightningIcon } from "@src/icons/Lightning";
|
|
|
5
5
|
|
|
6
6
|
import {
|
|
7
7
|
SideNav,
|
|
8
|
-
SideNavLogo,
|
|
9
8
|
SideNavList,
|
|
10
9
|
SideNavListItem,
|
|
11
10
|
SideNavLink,
|
|
@@ -15,6 +14,7 @@ import {
|
|
|
15
14
|
SideNavRepository,
|
|
16
15
|
RightElement,
|
|
17
16
|
} from "./SideNav";
|
|
17
|
+
import { SideNavEnvironmentSelector } from "./SideNavEnvironmentSelector";
|
|
18
18
|
|
|
19
19
|
type Story = StoryObj<typeof meta>;
|
|
20
20
|
|
|
@@ -33,7 +33,34 @@ export const Default = {
|
|
|
33
33
|
args: {
|
|
34
34
|
children: (
|
|
35
35
|
<>
|
|
36
|
-
<
|
|
36
|
+
<SideNavEnvironmentSelector
|
|
37
|
+
environments={[
|
|
38
|
+
{
|
|
39
|
+
name: "Production",
|
|
40
|
+
domain: "example-prismic-repo",
|
|
41
|
+
kind: "prod",
|
|
42
|
+
users: [{ id: "id" }],
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: "Staging",
|
|
46
|
+
domain: "example-prismic-repo-staging",
|
|
47
|
+
kind: "stage",
|
|
48
|
+
users: [{ id: "id" }],
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: "Development",
|
|
52
|
+
domain: "example-prismic-repo-development",
|
|
53
|
+
kind: "dev",
|
|
54
|
+
users: [{ id: "id" }],
|
|
55
|
+
},
|
|
56
|
+
]}
|
|
57
|
+
activeEnvironment={{
|
|
58
|
+
name: "Production",
|
|
59
|
+
domain: "example-prismic-repo",
|
|
60
|
+
kind: "prod",
|
|
61
|
+
users: [{ id: "id" }],
|
|
62
|
+
}}
|
|
63
|
+
/>
|
|
37
64
|
|
|
38
65
|
<SideNavRepository
|
|
39
66
|
repositoryName="really long repository name"
|
|
@@ -16,6 +16,8 @@ import type { UrlObject } from "node:url";
|
|
|
16
16
|
import LogoIcon from "@src/icons/LogoIcon";
|
|
17
17
|
import OpenIcon from "@src/icons/OpenIcon";
|
|
18
18
|
|
|
19
|
+
import { Divider } from "../Divider";
|
|
20
|
+
|
|
19
21
|
import * as styles from "./SideNav.css";
|
|
20
22
|
|
|
21
23
|
type SideNavProps = PropsWithChildren<{ style?: CSSProperties }>;
|
|
@@ -90,7 +92,9 @@ export const SideNavListTitle: FC<PropsWithChildren> = (props) => (
|
|
|
90
92
|
<h3 {...props} className={styles.listTitle} />
|
|
91
93
|
);
|
|
92
94
|
|
|
93
|
-
export const SideNavSeparator = () =>
|
|
95
|
+
export const SideNavSeparator = () => (
|
|
96
|
+
<Divider color="grey6" className={styles.separator} />
|
|
97
|
+
);
|
|
94
98
|
|
|
95
99
|
export type SideNavLinkProps = {
|
|
96
100
|
title: string;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { colors, sprinkles } from "@prismicio/editor-ui";
|
|
2
|
+
import { style, styleVariants } from "@vanilla-extract/css";
|
|
3
|
+
|
|
4
|
+
export const logo = style([
|
|
5
|
+
sprinkles({
|
|
6
|
+
height: 40,
|
|
7
|
+
width: 40,
|
|
8
|
+
}),
|
|
9
|
+
{
|
|
10
|
+
display: "block",
|
|
11
|
+
},
|
|
12
|
+
]);
|
|
13
|
+
|
|
14
|
+
const environmentDotBase = style([
|
|
15
|
+
sprinkles({
|
|
16
|
+
flexShrink: 0,
|
|
17
|
+
borderRadius: "50%",
|
|
18
|
+
}),
|
|
19
|
+
{
|
|
20
|
+
width: 10,
|
|
21
|
+
height: 10,
|
|
22
|
+
},
|
|
23
|
+
]);
|
|
24
|
+
|
|
25
|
+
export const environmentDot = styleVariants({
|
|
26
|
+
prod: [environmentDotBase, sprinkles({ backgroundColor: colors.purple10 })],
|
|
27
|
+
stage: [environmentDotBase, sprinkles({ backgroundColor: colors.indigo10 })],
|
|
28
|
+
dev: [environmentDotBase, sprinkles({ backgroundColor: colors.amber10 })],
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
export const menuItemEnvironmentDot = sprinkles({
|
|
32
|
+
marginRight: 2,
|
|
33
|
+
marginLeft: 2,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
export const activeEnvironmentDot = style([
|
|
37
|
+
sprinkles({
|
|
38
|
+
position: "absolute",
|
|
39
|
+
bottom: 0,
|
|
40
|
+
right: 0,
|
|
41
|
+
outlineWidth: 3,
|
|
42
|
+
outlineColor: colors.grey2,
|
|
43
|
+
outlineStyle: "solid",
|
|
44
|
+
}),
|
|
45
|
+
{
|
|
46
|
+
transform: "translate(50%, 50%)",
|
|
47
|
+
},
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
export const activeEnvironmentName = style([
|
|
51
|
+
sprinkles({
|
|
52
|
+
overflow: "hidden",
|
|
53
|
+
textOverflow: "ellipsis",
|
|
54
|
+
whiteSpace: "nowrap",
|
|
55
|
+
}),
|
|
56
|
+
{
|
|
57
|
+
fontWeight: 500,
|
|
58
|
+
lineHeight: "1.25rem",
|
|
59
|
+
},
|
|
60
|
+
]);
|
|
61
|
+
|
|
62
|
+
export const actionRequiredLabel = style([
|
|
63
|
+
sprinkles({
|
|
64
|
+
color: colors.purple10,
|
|
65
|
+
}),
|
|
66
|
+
{
|
|
67
|
+
fontWeight: 500,
|
|
68
|
+
},
|
|
69
|
+
]);
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Box,
|
|
3
|
+
DropdownMenu,
|
|
4
|
+
DropdownMenuContent,
|
|
5
|
+
DropdownMenuItem,
|
|
6
|
+
DropdownMenuLabel,
|
|
7
|
+
DropdownMenuTrigger,
|
|
8
|
+
Icon,
|
|
9
|
+
IconButton,
|
|
10
|
+
Text,
|
|
11
|
+
} from "@prismicio/editor-ui";
|
|
12
|
+
import { Environment } from "@slicemachine/manager/client";
|
|
13
|
+
import type { FC } from "react";
|
|
14
|
+
import clsx from "clsx";
|
|
15
|
+
|
|
16
|
+
import LogoIcon from "@src/icons/LogoIcon";
|
|
17
|
+
|
|
18
|
+
import * as styles from "./SideNavEnvironmentSelector.css";
|
|
19
|
+
|
|
20
|
+
type SideNavEnvironmentSelectorProps = {
|
|
21
|
+
variant?: "default" | "unauthorized";
|
|
22
|
+
environments?: Environment[];
|
|
23
|
+
activeEnvironment?: Environment;
|
|
24
|
+
onSelect?: (environment: Environment) => void | Promise<void>;
|
|
25
|
+
onLogInClick?: () => void;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const SideNavEnvironmentSelector: FC<SideNavEnvironmentSelectorProps> = (
|
|
29
|
+
props,
|
|
30
|
+
) => {
|
|
31
|
+
const {
|
|
32
|
+
variant = "default",
|
|
33
|
+
environments = [],
|
|
34
|
+
activeEnvironment,
|
|
35
|
+
onSelect,
|
|
36
|
+
onLogInClick,
|
|
37
|
+
} = props;
|
|
38
|
+
|
|
39
|
+
const isProductionEnvironmentActive = activeEnvironment?.kind === "prod";
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<Box alignItems="center" gap={16}>
|
|
43
|
+
<Box position="relative">
|
|
44
|
+
<LogoIcon className={styles.logo} />
|
|
45
|
+
{activeEnvironment !== undefined && (
|
|
46
|
+
<EnvironmentDot
|
|
47
|
+
kind={activeEnvironment.kind}
|
|
48
|
+
className={styles.activeEnvironmentDot}
|
|
49
|
+
/>
|
|
50
|
+
)}
|
|
51
|
+
</Box>
|
|
52
|
+
<Box flexGrow={1} flexDirection="column" overflow="hidden">
|
|
53
|
+
<Text component="span" variant="small" color="grey11">
|
|
54
|
+
Environment
|
|
55
|
+
</Text>
|
|
56
|
+
{variant === "unauthorized" ? (
|
|
57
|
+
<Text component="span" className={styles.actionRequiredLabel}>
|
|
58
|
+
Login required
|
|
59
|
+
</Text>
|
|
60
|
+
) : activeEnvironment === undefined ? (
|
|
61
|
+
<Text component="span" className={styles.actionRequiredLabel}>
|
|
62
|
+
Select environment
|
|
63
|
+
</Text>
|
|
64
|
+
) : (
|
|
65
|
+
<Text component="span" className={styles.activeEnvironmentName}>
|
|
66
|
+
{isProductionEnvironmentActive
|
|
67
|
+
? "Production"
|
|
68
|
+
: activeEnvironment?.name}
|
|
69
|
+
</Text>
|
|
70
|
+
)}
|
|
71
|
+
</Box>
|
|
72
|
+
<Box flexShrink={0}>
|
|
73
|
+
{variant === "unauthorized" ? (
|
|
74
|
+
<IconButton icon="arrowForward" onClick={onLogInClick} />
|
|
75
|
+
) : !activeEnvironment || environments.length > 1 ? (
|
|
76
|
+
<EnvironmentDropdownMenu
|
|
77
|
+
environments={environments}
|
|
78
|
+
activeEnvironment={activeEnvironment}
|
|
79
|
+
onSelect={onSelect}
|
|
80
|
+
/>
|
|
81
|
+
) : null}
|
|
82
|
+
</Box>
|
|
83
|
+
</Box>
|
|
84
|
+
);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
type EnvironmentDropdownMenuProps = Pick<
|
|
88
|
+
SideNavEnvironmentSelectorProps,
|
|
89
|
+
"environments" | "activeEnvironment" | "onSelect"
|
|
90
|
+
>;
|
|
91
|
+
|
|
92
|
+
const EnvironmentDropdownMenu: FC<EnvironmentDropdownMenuProps> = (props) => {
|
|
93
|
+
const { environments = [], activeEnvironment, onSelect } = props;
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<DropdownMenu modal>
|
|
97
|
+
<DropdownMenuTrigger>
|
|
98
|
+
<IconButton icon="unfoldMore" />
|
|
99
|
+
</DropdownMenuTrigger>
|
|
100
|
+
<DropdownMenuContent align="end">
|
|
101
|
+
<DropdownMenuLabel>Regular Environments</DropdownMenuLabel>
|
|
102
|
+
{environments.map((environment) =>
|
|
103
|
+
environment.kind !== "dev" ? (
|
|
104
|
+
<EnvironmentDropdownMenuItem
|
|
105
|
+
key={environment.domain}
|
|
106
|
+
environment={environment}
|
|
107
|
+
onSelect={onSelect}
|
|
108
|
+
isActive={environment.domain === activeEnvironment?.domain}
|
|
109
|
+
/>
|
|
110
|
+
) : (
|
|
111
|
+
<>
|
|
112
|
+
<DropdownMenuLabel>Personal Environment</DropdownMenuLabel>
|
|
113
|
+
<EnvironmentDropdownMenuItem
|
|
114
|
+
key={environment.domain}
|
|
115
|
+
environment={environment}
|
|
116
|
+
onSelect={onSelect}
|
|
117
|
+
isActive={environment.domain === activeEnvironment?.domain}
|
|
118
|
+
/>
|
|
119
|
+
</>
|
|
120
|
+
),
|
|
121
|
+
)}
|
|
122
|
+
</DropdownMenuContent>
|
|
123
|
+
</DropdownMenu>
|
|
124
|
+
);
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
type EnvironmentDropdownMenuItemProps = {
|
|
128
|
+
environment: Environment;
|
|
129
|
+
isActive?: boolean;
|
|
130
|
+
} & Pick<SideNavEnvironmentSelectorProps, "onSelect">;
|
|
131
|
+
|
|
132
|
+
const EnvironmentDropdownMenuItem: FC<EnvironmentDropdownMenuItemProps> = (
|
|
133
|
+
props,
|
|
134
|
+
) => {
|
|
135
|
+
const { environment, onSelect, isActive } = props;
|
|
136
|
+
const isProductionEnvironment = environment.kind === "prod";
|
|
137
|
+
|
|
138
|
+
return (
|
|
139
|
+
<DropdownMenuItem
|
|
140
|
+
startIcon={
|
|
141
|
+
<EnvironmentDot
|
|
142
|
+
kind={environment.kind}
|
|
143
|
+
className={styles.menuItemEnvironmentDot}
|
|
144
|
+
/>
|
|
145
|
+
}
|
|
146
|
+
endIcon={Boolean(isActive) ? <Icon name="check" /> : undefined}
|
|
147
|
+
onSelect={() => void onSelect?.(environment)}
|
|
148
|
+
>
|
|
149
|
+
{isProductionEnvironment ? "Production" : environment.name}
|
|
150
|
+
</DropdownMenuItem>
|
|
151
|
+
);
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
type EnvironmentDotProps = {
|
|
155
|
+
kind: Environment["kind"];
|
|
156
|
+
className?: string;
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const EnvironmentDot: FC<EnvironmentDotProps> = (props) => {
|
|
160
|
+
const { kind, className } = props;
|
|
161
|
+
|
|
162
|
+
return <div className={clsx(styles.environmentDot[kind], className)} />;
|
|
163
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { managerClient } from "@src/managerClient";
|
|
2
|
+
|
|
3
|
+
export async function getActiveEnvironmentDomain() {
|
|
4
|
+
try {
|
|
5
|
+
const { environment } = await managerClient.project.readEnvironment();
|
|
6
|
+
|
|
7
|
+
return { activeEnvironmentDomain: environment };
|
|
8
|
+
} catch (error) {
|
|
9
|
+
return { error };
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { managerClient } from "@src/managerClient";
|
|
2
|
+
|
|
3
|
+
export async function getEnvironments() {
|
|
4
|
+
try {
|
|
5
|
+
const environments =
|
|
6
|
+
await managerClient.prismicRepository.fetchEnvironments();
|
|
7
|
+
|
|
8
|
+
return { environments };
|
|
9
|
+
} catch (error) {
|
|
10
|
+
return { error };
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { revalidateData } from "@prismicio/editor-support/Suspense";
|
|
2
|
+
import { Environment } from "@slicemachine/manager/client";
|
|
3
|
+
|
|
4
|
+
import { getLegacySliceMachineState } from "@src/features/legacyState/actions/getLegacySliceMachineState";
|
|
5
|
+
import { managerClient } from "@src/managerClient";
|
|
6
|
+
|
|
7
|
+
import { getActiveEnvironmentDomain } from "./getActiveEnvironmentDomain";
|
|
8
|
+
|
|
9
|
+
export async function setEnvironment(
|
|
10
|
+
environment: Pick<Environment, "domain">,
|
|
11
|
+
): Promise<void> {
|
|
12
|
+
await managerClient.project.updateEnvironment({
|
|
13
|
+
environment: environment.domain,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
revalidateData(getActiveEnvironmentDomain, []);
|
|
17
|
+
revalidateData(getLegacySliceMachineState, []);
|
|
18
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { useRequest } from "@prismicio/editor-support/Suspense";
|
|
2
|
+
|
|
3
|
+
import { getActiveEnvironmentDomain } from "./actions/getActiveEnvironmentDomain";
|
|
4
|
+
import { useEnvironments } from "./useEnvironments";
|
|
5
|
+
|
|
6
|
+
export function useActiveEnvironment() {
|
|
7
|
+
const { environments, error: useEnvironmentsError } = useEnvironments();
|
|
8
|
+
const { activeEnvironmentDomain, error: getActiveEnvironmentError } =
|
|
9
|
+
useRequest(getActiveEnvironmentDomain, []);
|
|
10
|
+
|
|
11
|
+
if (useEnvironmentsError !== undefined) {
|
|
12
|
+
return { error: useEnvironmentsError };
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (getActiveEnvironmentError !== undefined) {
|
|
16
|
+
return { error: getActiveEnvironmentError };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const activeEnvironment = environments?.find((environment) => {
|
|
20
|
+
if (activeEnvironmentDomain === undefined) {
|
|
21
|
+
return environment.kind === "prod";
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return environment.domain === activeEnvironmentDomain;
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
if (!activeEnvironment) {
|
|
28
|
+
return {
|
|
29
|
+
error: new Error(
|
|
30
|
+
`The active environment (${
|
|
31
|
+
activeEnvironmentDomain ?? "Production"
|
|
32
|
+
}) does not match one of the repository's environments.`,
|
|
33
|
+
),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return { activeEnvironment };
|
|
38
|
+
}
|
|
@@ -1,23 +1,7 @@
|
|
|
1
1
|
import { useRequest } from "@prismicio/editor-support/Suspense";
|
|
2
|
-
import { isUnauthenticatedError } from "@slicemachine/manager/client";
|
|
3
|
-
import { managerClient } from "@src/managerClient";
|
|
4
2
|
|
|
5
|
-
|
|
6
|
-
Awaited<ReturnType<typeof managerClient.prismicRepository.fetchEnvironments>>
|
|
7
|
-
> {
|
|
8
|
-
try {
|
|
9
|
-
return await managerClient.prismicRepository.fetchEnvironments();
|
|
10
|
-
} catch (error) {
|
|
11
|
-
if (isUnauthenticatedError(error)) {
|
|
12
|
-
return [];
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
throw error;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
3
|
+
import { getEnvironments } from "./actions/getEnvironments";
|
|
18
4
|
|
|
19
5
|
export function useEnvironments() {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
return environments;
|
|
6
|
+
return useRequest(getEnvironments, []);
|
|
23
7
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import ServerState from "@models/server/ServerState";
|
|
2
|
+
import { Slices } from "@lib/models/common/Slice";
|
|
3
|
+
import { CustomTypes } from "@lib/models/common/CustomType";
|
|
4
|
+
import { managerClient } from "@src/managerClient";
|
|
5
|
+
|
|
6
|
+
export async function getLegacySliceMachineState() {
|
|
7
|
+
const rawState = await managerClient.getState();
|
|
8
|
+
|
|
9
|
+
// `rawState` from the client contains non-SM-specific models. We need to
|
|
10
|
+
// transform the data to something SM recognizes.
|
|
11
|
+
const state: ServerState = {
|
|
12
|
+
...rawState,
|
|
13
|
+
libraries: rawState.libraries.map((library) => {
|
|
14
|
+
return {
|
|
15
|
+
...library,
|
|
16
|
+
components: library.components.map((component) => {
|
|
17
|
+
return {
|
|
18
|
+
...component,
|
|
19
|
+
model: Slices.toSM(component.model),
|
|
20
|
+
|
|
21
|
+
// Replace screnshot Blobs with URLs.
|
|
22
|
+
screenshots: Object.fromEntries(
|
|
23
|
+
Object.entries(component.screenshots).map(
|
|
24
|
+
([variationID, screenshot]) => {
|
|
25
|
+
return [
|
|
26
|
+
variationID,
|
|
27
|
+
{
|
|
28
|
+
...screenshot,
|
|
29
|
+
url: URL.createObjectURL(screenshot.data),
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
},
|
|
33
|
+
),
|
|
34
|
+
),
|
|
35
|
+
};
|
|
36
|
+
}),
|
|
37
|
+
};
|
|
38
|
+
}),
|
|
39
|
+
customTypes: rawState.customTypes.map((customTypeModel) => {
|
|
40
|
+
return CustomTypes.toSM(customTypeModel);
|
|
41
|
+
}),
|
|
42
|
+
remoteCustomTypes: rawState.remoteCustomTypes.map(
|
|
43
|
+
(remoteCustomTypeModel) => {
|
|
44
|
+
return CustomTypes.toSM(remoteCustomTypeModel);
|
|
45
|
+
},
|
|
46
|
+
),
|
|
47
|
+
remoteSlices: rawState.remoteSlices.map((remoteSliceModel) => {
|
|
48
|
+
return Slices.toSM(remoteSliceModel);
|
|
49
|
+
}),
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
return state;
|
|
53
|
+
}
|
|
@@ -36,7 +36,8 @@ export const dummyServerState: Pick<
|
|
|
36
36
|
"https://0yyeb2g040.execute-api.us-east-1.amazonaws.com/prod/",
|
|
37
37
|
PrismicOembed: "https://oembed.prismic.io",
|
|
38
38
|
PrismicUnsplash: "https://unsplash.prismic.io",
|
|
39
|
-
|
|
39
|
+
SliceMachineV1:
|
|
40
|
+
"https://21vvgrh0s6.execute-api.us-east-1.amazonaws.com/v1/",
|
|
40
41
|
},
|
|
41
42
|
shortId: "shortId",
|
|
42
43
|
supportsSliceSimulator: true,
|