sanity-plugin-dashboard-widget-netlify 2.0.4 → 3.0.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/README.md +30 -46
- package/dist/index.d.ts +37 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +220 -0
- package/dist/index.js.map +1 -0
- package/package.json +39 -100
- package/lib/index.d.mts +0 -45
- package/lib/index.d.ts +0 -45
- package/lib/index.js +0 -172
- package/lib/index.js.map +0 -1
- package/lib/index.mjs +0 -176
- package/lib/index.mjs.map +0 -1
- package/sanity.json +0 -8
- package/src/components/NetlifyWidget.tsx +0 -47
- package/src/components/SiteItem/Links.tsx +0 -40
- package/src/components/SiteItem/index.tsx +0 -79
- package/src/components/SiteList.tsx +0 -42
- package/src/datastores/deploy.ts +0 -14
- package/src/http/jsonRequest.ts +0 -33
- package/src/http/statusCodeRequest.ts +0 -33
- package/src/http/utils/createAbortController.ts +0 -8
- package/src/index.ts +0 -7
- package/src/plugin.tsx +0 -16
- package/src/props.ts +0 -55
- package/src/reducers.ts +0 -53
- package/src/types.ts +0 -33
- package/src/widget.tsx +0 -18
- package/v2-incompatible.js +0 -11
package/lib/index.d.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
import {DashboardWidget} from '@sanity/dashboard'
|
|
2
|
-
import {LayoutConfig} from '@sanity/dashboard'
|
|
3
|
-
|
|
4
|
-
export declare type DeployAction = (site: Site) => void
|
|
5
|
-
|
|
6
|
-
export declare function netlifyWidget(config: NetlifyWidgetConfig): DashboardWidget
|
|
7
|
-
|
|
8
|
-
export declare type NetlifyWidgetConfig = WidgetOptions & {
|
|
9
|
-
layout?: LayoutConfig
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export declare interface NetlifyWidgetProps {
|
|
13
|
-
title?: string
|
|
14
|
-
description?: string
|
|
15
|
-
sites?: Site[]
|
|
16
|
-
isLoading: boolean
|
|
17
|
-
onDeploy: DeployAction
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export declare interface Site {
|
|
21
|
-
title: string
|
|
22
|
-
name?: string
|
|
23
|
-
id: string
|
|
24
|
-
url?: string
|
|
25
|
-
adminUrl?: string
|
|
26
|
-
buildHookId: string
|
|
27
|
-
branch?: string
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export declare interface SiteWidgetOption {
|
|
31
|
-
apiId: string
|
|
32
|
-
name?: string
|
|
33
|
-
title: string
|
|
34
|
-
buildHookId: string
|
|
35
|
-
url?: string
|
|
36
|
-
branch?: string
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export declare interface WidgetOptions {
|
|
40
|
-
title?: string
|
|
41
|
-
description?: string
|
|
42
|
-
sites: SiteWidgetOption[]
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export {}
|
package/lib/index.js
DELETED
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: !0 });
|
|
3
|
-
var jsxRuntime = require("react/jsx-runtime"), reactPropsStream = require("react-props-stream"), operators = require("rxjs/operators"), rxjs = require("rxjs"), AbortControllerPolyfill = require("abort-controller"), react = require("react"), ui = require("@sanity/ui"), dashboard = require("@sanity/dashboard"), styledComponents = require("styled-components");
|
|
4
|
-
function _interopDefaultCompat(e) {
|
|
5
|
-
return e && typeof e == "object" && "default" in e ? e : { default: e };
|
|
6
|
-
}
|
|
7
|
-
var AbortControllerPolyfill__default = /* @__PURE__ */ _interopDefaultCompat(AbortControllerPolyfill);
|
|
8
|
-
const createAbortController = () => "AbortController" in window ? new AbortController() : new AbortControllerPolyfill__default.default(), statusCodeRequest = (input, init) => new rxjs.Observable((subscriber) => {
|
|
9
|
-
const controller = createAbortController(), onResponse = (res) => {
|
|
10
|
-
subscriber.next(res), subscriber.complete();
|
|
11
|
-
}, onError = (err) => {
|
|
12
|
-
err.name === "AbortError" ? subscriber.complete() : subscriber.error(err);
|
|
13
|
-
};
|
|
14
|
-
return fetch(input, { ...init, signal: controller.signal }).then((res) => {
|
|
15
|
-
if (res.status < 200 || res.status > 299)
|
|
16
|
-
throw new Error(`HTTP Error ${res.status}: ${res.statusText}`);
|
|
17
|
-
return res.status;
|
|
18
|
-
}).then(onResponse, onError), () => {
|
|
19
|
-
controller.abort();
|
|
20
|
-
};
|
|
21
|
-
});
|
|
22
|
-
function deploy(site) {
|
|
23
|
-
return site.buildHookId ? statusCodeRequest(`https://api.netlify.com/build_hooks/${site.buildHookId}`, {
|
|
24
|
-
method: "POST"
|
|
25
|
-
}).pipe(operators.map((result) => ({ result, site }))) : rxjs.of(new Error("Site missing buildHookId"));
|
|
26
|
-
}
|
|
27
|
-
const stateReducer$ = operators.scan((state, action) => {
|
|
28
|
-
switch (action.type) {
|
|
29
|
-
case "setSites":
|
|
30
|
-
return { ...state, sites: action.sites || [] };
|
|
31
|
-
case "deploy/started":
|
|
32
|
-
return {
|
|
33
|
-
...state,
|
|
34
|
-
sites: state.sites.map((site) => action.site && site.id === action.site.id ? { ...site } : site)
|
|
35
|
-
};
|
|
36
|
-
case "deploy/failed":
|
|
37
|
-
return {
|
|
38
|
-
...state,
|
|
39
|
-
error: action.error
|
|
40
|
-
};
|
|
41
|
-
case "deploy/completed":
|
|
42
|
-
return {
|
|
43
|
-
...state,
|
|
44
|
-
sites: state.sites.map((site) => action.site && site.id === action.site.id ? { ...site, error: action.error } : site)
|
|
45
|
-
};
|
|
46
|
-
default:
|
|
47
|
-
return state;
|
|
48
|
-
}
|
|
49
|
-
}), noop = () => {
|
|
50
|
-
}, INITIAL_PROPS = {
|
|
51
|
-
title: "Netlify sites",
|
|
52
|
-
sites: [],
|
|
53
|
-
isLoading: !0,
|
|
54
|
-
onDeploy: noop
|
|
55
|
-
}, props$ = (options) => {
|
|
56
|
-
const configuredSites = (options.sites || []).map((site) => ({
|
|
57
|
-
id: site.apiId,
|
|
58
|
-
name: site.name,
|
|
59
|
-
title: site.title,
|
|
60
|
-
buildHookId: site.buildHookId,
|
|
61
|
-
url: site.url || site.branch && `https://${site.branch}--${site.name}.netlify.app/` || site.name && `https://${site.name}.netlify.app/`,
|
|
62
|
-
adminUrl: site.name && `https://app.netlify.com/sites/${site.name}`,
|
|
63
|
-
branch: site.branch
|
|
64
|
-
})), [onDeploy$, onDeploy] = reactPropsStream.createEventHandler(), setSitesAction$ = rxjs.of(configuredSites).pipe(operators.map((sites) => ({ type: "setSites", sites }))), deployAction$ = onDeploy$.pipe(operators.map((site) => ({ type: "deploy/started", site }))), deployCompletedAction$ = onDeploy$.pipe(operators.switchMap((site) => deploy(site))).pipe(
|
|
65
|
-
operators.map(
|
|
66
|
-
(result) => ({ type: "deploy/completed", ...result }),
|
|
67
|
-
operators.catchError((error) => rxjs.of({ type: "deploy/failed", error }))
|
|
68
|
-
)
|
|
69
|
-
);
|
|
70
|
-
return rxjs.merge(setSitesAction$, deployAction$, deployCompletedAction$).pipe(stateReducer$).subscribe(), rxjs.of(configuredSites).pipe(
|
|
71
|
-
operators.map((sites) => ({
|
|
72
|
-
sites,
|
|
73
|
-
title: options.title || INITIAL_PROPS.title,
|
|
74
|
-
description: options.description,
|
|
75
|
-
isLoading: !1,
|
|
76
|
-
onDeploy
|
|
77
|
-
})),
|
|
78
|
-
operators.startWith(INITIAL_PROPS)
|
|
79
|
-
);
|
|
80
|
-
}, Link = (props) => {
|
|
81
|
-
const { url, children } = props;
|
|
82
|
-
return /* @__PURE__ */ jsxRuntime.jsx("span", { children: /* @__PURE__ */ jsxRuntime.jsx("a", { href: url, target: "_blank", rel: "noreferrer", children }) });
|
|
83
|
-
}, Links = (props) => {
|
|
84
|
-
const { url, adminUrl } = props;
|
|
85
|
-
return url && adminUrl ? /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
86
|
-
"(",
|
|
87
|
-
/* @__PURE__ */ jsxRuntime.jsx(Link, { url, children: "view" }),
|
|
88
|
-
", ",
|
|
89
|
-
/* @__PURE__ */ jsxRuntime.jsx(Link, { url: adminUrl, children: "admin" }),
|
|
90
|
-
")"
|
|
91
|
-
] }) : url ? /* @__PURE__ */ jsxRuntime.jsx(Link, { url, children: "(view)" }) : adminUrl ? /* @__PURE__ */ jsxRuntime.jsx(Link, { url: adminUrl, children: "(admin)" }) : null;
|
|
92
|
-
}, IMAGE_PULL_INTERVAL = 1e4, getImageUrl = (siteId, branchName) => {
|
|
93
|
-
const baseUrl = `https://api.netlify.com/api/v1/badges/${siteId}/deploy-status`, time = (/* @__PURE__ */ new Date()).getTime(), branch = `branch=${branchName}`;
|
|
94
|
-
return branchName ? `${baseUrl}?${time}&${branch}` : `${baseUrl}?${time}`;
|
|
95
|
-
}, useBadgeImage = (siteId, branchName) => {
|
|
96
|
-
const [src, setSrc] = react.useState(() => getImageUrl(siteId, branchName)), update = react.useCallback(() => setSrc(getImageUrl(siteId, branchName)), [siteId]);
|
|
97
|
-
return react.useEffect(() => {
|
|
98
|
-
const interval = window.setInterval(update, IMAGE_PULL_INTERVAL);
|
|
99
|
-
return () => window.clearInterval(interval);
|
|
100
|
-
}, [update]), [src, update];
|
|
101
|
-
}, useDeploy = (site, onDeploy, updateBadge) => {
|
|
102
|
-
const timeoutRef = react.useRef(-1);
|
|
103
|
-
return react.useEffect(() => () => window.clearTimeout(timeoutRef.current), []), react.useCallback(() => {
|
|
104
|
-
onDeploy(site), timeoutRef.current = window.setTimeout(updateBadge, 1e3);
|
|
105
|
-
}, [site, onDeploy, updateBadge]);
|
|
106
|
-
}, SiteItem = (props) => {
|
|
107
|
-
const [hasBadgeError, setHasBadgeError] = react.useState(!1), { site, onDeploy } = props, { id, name, title, url, adminUrl, buildHookId, branch } = site, [badge, updateBadge] = useBadgeImage(id, branch), handleDeploy = useDeploy(site, onDeploy, updateBadge);
|
|
108
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { as: "li", children: [
|
|
109
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Box, { flex: 1, paddingY: 2, paddingX: 3, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Stack, { space: 2, children: [
|
|
110
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { as: "h4", children: [
|
|
111
|
-
title || name,
|
|
112
|
-
/* @__PURE__ */ jsxRuntime.jsx(Links, { url, adminUrl })
|
|
113
|
-
] }),
|
|
114
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { justify: "flex-start", children: [
|
|
115
|
-
!hasBadgeError && /* @__PURE__ */ jsxRuntime.jsx("img", { src: badge, onError: () => {
|
|
116
|
-
setHasBadgeError(!0);
|
|
117
|
-
}, alt: "Badge" }),
|
|
118
|
-
hasBadgeError && /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { tone: "critical", radius: 2, padding: 2, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: 0, muted: !0, children: "Failed to load badge" }) })
|
|
119
|
-
] })
|
|
120
|
-
] }) }),
|
|
121
|
-
buildHookId ? /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { paddingY: 2, paddingX: 3, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { mode: "ghost", onClick: handleDeploy, text: "Deploy" }) }) : null
|
|
122
|
-
] });
|
|
123
|
-
};
|
|
124
|
-
function SiteList(props) {
|
|
125
|
-
const { isLoading, onDeploy, sites } = props;
|
|
126
|
-
return isLoading ? /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { padding: 4, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Flex, { direction: "column", justify: "center", align: "center", children: [
|
|
127
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Spinner, { muted: !0 }),
|
|
128
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Box, { marginTop: 3, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { muted: !0, children: "Loading sites\u2026" }) })
|
|
129
|
-
] }) }) : !sites || sites && sites.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Card, { tone: "critical", padding: 3, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { children: "No sites are defined in the widget options. Please check your config." }) }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { paddingY: 2, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Stack, { as: "ul", space: 2, children: sites.map((site, index) => /* @__PURE__ */ jsxRuntime.jsx(SiteItem, { onDeploy, site }, `site-${index}`)) }) });
|
|
130
|
-
}
|
|
131
|
-
const ContentCard = styledComponents.styled(ui.Card)`
|
|
132
|
-
min-height: 66px;
|
|
133
|
-
`;
|
|
134
|
-
function NetlifyWidget(props) {
|
|
135
|
-
const netlifySitesUrl = "https://app.netlify.com/account/sites", { title, description, isLoading, sites, onDeploy } = props;
|
|
136
|
-
return /* @__PURE__ */ jsxRuntime.jsx(dashboard.DashboardWidgetContainer, { header: title, footer: /* @__PURE__ */ jsxRuntime.jsx(ui.Flex, { direction: "column", align: "stretch", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
137
|
-
ui.Button,
|
|
138
|
-
{
|
|
139
|
-
as: "a",
|
|
140
|
-
href: isLoading ? void 0 : netlifySitesUrl,
|
|
141
|
-
disabled: isLoading,
|
|
142
|
-
paddingX: 2,
|
|
143
|
-
paddingY: 4,
|
|
144
|
-
mode: "bleed",
|
|
145
|
-
tone: "primary",
|
|
146
|
-
text: "Manage sites at Netlify",
|
|
147
|
-
loading: isLoading,
|
|
148
|
-
target: "_blank"
|
|
149
|
-
}
|
|
150
|
-
) }), children: /* @__PURE__ */ jsxRuntime.jsxs(ContentCard, { paddingY: 1, children: [
|
|
151
|
-
description && /* @__PURE__ */ jsxRuntime.jsx(ui.Box, { paddingY: 3, paddingX: 3, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { as: "p", size: 1, muted: !0, children: /* @__PURE__ */ jsxRuntime.jsx("span", { dangerouslySetInnerHTML: { __html: description } }) }) }),
|
|
152
|
-
/* @__PURE__ */ jsxRuntime.jsx(SiteList, { isLoading, onDeploy, sites })
|
|
153
|
-
] }) });
|
|
154
|
-
}
|
|
155
|
-
var Widget = reactPropsStream.streamingComponent(
|
|
156
|
-
(options$) => options$.pipe(
|
|
157
|
-
operators.switchMap(
|
|
158
|
-
(options) => props$(options).pipe(
|
|
159
|
-
operators.map((props) => /* @__PURE__ */ jsxRuntime.jsx(NetlifyWidget, { ...props }))
|
|
160
|
-
)
|
|
161
|
-
)
|
|
162
|
-
)
|
|
163
|
-
);
|
|
164
|
-
function netlifyWidget(config) {
|
|
165
|
-
return {
|
|
166
|
-
name: "netlify-widget",
|
|
167
|
-
component: () => /* @__PURE__ */ jsxRuntime.jsx(Widget, { ...config }),
|
|
168
|
-
layout: config.layout ?? { width: "medium" }
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
exports.netlifyWidget = netlifyWidget;
|
|
172
|
-
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/http/utils/createAbortController.ts","../src/http/statusCodeRequest.ts","../src/datastores/deploy.ts","../src/reducers.ts","../src/props.ts","../src/components/SiteItem/Links.tsx","../src/components/SiteItem/index.tsx","../src/components/SiteList.tsx","../src/components/NetlifyWidget.tsx","../src/widget.tsx","../src/plugin.tsx"],"sourcesContent":["import AbortControllerPolyfill from 'abort-controller'\n\nexport const createAbortController = (): AbortController => {\n if (!('AbortController' in window)) {\n return new AbortControllerPolyfill() as AbortController\n }\n return new AbortController()\n}\n","import {Observable} from 'rxjs'\nimport {createAbortController} from './utils/createAbortController'\n\n// eslint-disable-next-line no-undef\nexport const statusCodeRequest = (input: RequestInfo, init?: RequestInit): Observable<number> => {\n return new Observable((subscriber) => {\n const controller = createAbortController()\n const onResponse = (res: number) => {\n subscriber.next(res)\n subscriber.complete()\n }\n const onError = (err: Error) => {\n if (err.name === 'AbortError') {\n subscriber.complete()\n } else {\n subscriber.error(err)\n }\n }\n\n fetch(input, {...init, signal: controller.signal})\n .then((res: Response) => {\n if (res.status < 200 || res.status > 299) {\n throw new Error(`HTTP Error ${res.status}: ${res.statusText}`)\n }\n return res.status\n })\n .then(onResponse, onError)\n\n return () => {\n controller.abort()\n }\n })\n}\n","import {Observable, of} from 'rxjs'\nimport {map} from 'rxjs/operators'\nimport {statusCodeRequest} from '../http/statusCodeRequest'\nimport {Site} from '../types'\n\nexport function deploy(site: Site): Observable<{result: number; site: Site} | Error> {\n if (!site.buildHookId) {\n return of(new Error('Site missing buildHookId'))\n }\n\n return statusCodeRequest(`https://api.netlify.com/build_hooks/${site.buildHookId}`, {\n method: 'POST',\n }).pipe(map((result) => ({result, site})))\n}\n","import {scan} from 'rxjs/operators'\nimport {Site} from './types'\n\ninterface Deployment {\n id: string\n}\n\ninterface Action {\n type: string\n sites?: Site[]\n site?: Site\n error?: Error\n deployments?: Deployment[]\n}\n\ninterface State {\n sites: Site[]\n action: Action\n}\n\nexport const stateReducer$ = scan((state: State, action: Action) => {\n switch (action.type) {\n case 'setSites':\n return {...state, sites: action.sites || []}\n case 'deploy/started':\n return {\n ...state,\n sites: state.sites.map((site: Site) => {\n if (action.site && site.id === action.site.id) {\n return {...site}\n }\n return site\n }),\n }\n case 'deploy/failed':\n return {\n ...state,\n error: action.error,\n }\n case 'deploy/completed':\n return {\n ...state,\n sites: state.sites.map((site: Site) => {\n if (action.site && site.id === action.site.id) {\n return {...site, error: action.error}\n }\n return site\n }),\n }\n default:\n return state\n }\n})\n","import {merge, of} from 'rxjs'\nimport {createEventHandler} from 'react-props-stream'\nimport {catchError, map, startWith, switchMap} from 'rxjs/operators'\nimport {deploy} from './datastores/deploy'\nimport {Site, WidgetOptions} from './types'\nimport {stateReducer$} from './reducers'\n\nconst noop = () => undefined\n\nconst INITIAL_PROPS = {\n title: 'Netlify sites',\n sites: [],\n isLoading: true,\n onDeploy: noop,\n}\n\n// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\nexport const props$ = (options: WidgetOptions) => {\n const configuredSites = (options.sites || []).map((site) => ({\n id: site.apiId,\n name: site.name,\n title: site.title,\n buildHookId: site.buildHookId,\n url:\n site.url ||\n (site.branch && `https://${site.branch}--${site.name}.netlify.app/`) ||\n (site.name && `https://${site.name}.netlify.app/`),\n adminUrl: site.name && `https://app.netlify.com/sites/${site.name}`,\n branch: site.branch,\n }))\n\n const [onDeploy$, onDeploy] = createEventHandler<Site>()\n const setSitesAction$ = of(configuredSites).pipe(map((sites) => ({type: 'setSites', sites})))\n const deployAction$ = onDeploy$.pipe(map((site) => ({type: 'deploy/started', site})))\n const deployResult$ = onDeploy$.pipe(switchMap((site) => deploy(site)))\n const deployCompletedAction$ = deployResult$.pipe(\n map(\n (result) => ({type: 'deploy/completed', ...result}),\n catchError((error) => of({type: 'deploy/failed', error}))\n )\n )\n\n merge(setSitesAction$, deployAction$, deployCompletedAction$).pipe(stateReducer$).subscribe()\n\n return of(configuredSites).pipe(\n map((sites) => ({\n sites,\n title: options.title || INITIAL_PROPS.title,\n description: options.description,\n isLoading: false,\n onDeploy,\n })),\n startWith(INITIAL_PROPS)\n )\n}\n","import React, {FunctionComponent, PropsWithChildren} from 'react'\n\nconst Link = (props: PropsWithChildren<{url: string}>) => {\n const {url, children} = props\n\n return (\n <span>\n <a href={url} target=\"_blank\" rel=\"noreferrer\">\n {children}\n </a>\n </span>\n )\n}\n\ntype Props = {\n url?: string\n adminUrl?: string\n}\n\nconst Links: FunctionComponent<Props> = (props) => {\n const {url, adminUrl} = props\n\n if (url && adminUrl) {\n return (\n <span>\n (<Link url={url}>view</Link>, <Link url={adminUrl}>admin</Link>)\n </span>\n )\n }\n\n if (url) {\n return <Link url={url}>(view)</Link>\n }\n if (adminUrl) {\n return <Link url={adminUrl}>(admin)</Link>\n }\n return null\n}\n\nexport default Links\n","import React, {FunctionComponent, useCallback, useEffect, useRef, useState} from 'react'\nimport {Button, Flex, Box, Card, Text, Stack, Label} from '@sanity/ui'\nimport {DeployAction, Site} from '../../types'\nimport Links from './Links'\n\ninterface Props {\n site: Site\n onDeploy: DeployAction\n}\n\nexport const IMAGE_PULL_INTERVAL = 10000\n\nconst getImageUrl = (siteId: string, branchName?: string) => {\n const baseUrl = `https://api.netlify.com/api/v1/badges/${siteId}/deploy-status`\n const time = new Date().getTime()\n const branch = `branch=${branchName}`\n\n return branchName ? `${baseUrl}?${time}&${branch}` : `${baseUrl}?${time}`\n}\n\nconst useBadgeImage = (siteId: string, branchName?: string ) => {\n const [src, setSrc] = useState(() => getImageUrl(siteId, branchName))\n const update = useCallback(() => setSrc(getImageUrl(siteId, branchName)), [siteId])\n\n useEffect(() => {\n const interval = window.setInterval(update, IMAGE_PULL_INTERVAL)\n return () => window.clearInterval(interval)\n }, [update])\n\n return [src, update] as const\n}\n\nconst useDeploy = (site: Site, onDeploy: DeployAction, updateBadge: () => void) => {\n const timeoutRef = useRef(-1)\n useEffect(() => () => window.clearTimeout(timeoutRef.current), [])\n\n return useCallback(() => {\n onDeploy(site)\n timeoutRef.current = window.setTimeout(updateBadge, 1000)\n }, [site, onDeploy, updateBadge])\n}\n\nconst SiteItem: FunctionComponent<Props> = (props) => {\n const [hasBadgeError, setHasBadgeError] = useState(false)\n const {site, onDeploy} = props\n const {id, name, title, url, adminUrl, buildHookId, branch} = site\n\n const [badge, updateBadge] = useBadgeImage(id, branch)\n const handleDeploy = useDeploy(site, onDeploy, updateBadge)\n const handleBadgeError = () => {\n setHasBadgeError(true)\n }\n\n return (\n <Flex as=\"li\">\n <Box flex={1} paddingY={2} paddingX={3}>\n <Stack space={2}>\n <Text as=\"h4\">\n {title || name}\n <Links url={url} adminUrl={adminUrl} />\n </Text>\n\n <Flex justify=\"flex-start\">\n {!hasBadgeError && <img src={badge} onError={handleBadgeError} alt=\"Badge\" />}\n {hasBadgeError && <Card tone=\"critical\" radius={2} padding={2}><Label size={0} muted>Failed to load badge</Label></Card>}\n </Flex>\n </Stack>\n </Box>\n\n {buildHookId ? (\n <Box paddingY={2} paddingX={3}>\n <Button mode=\"ghost\" onClick={handleDeploy} text=\"Deploy\" />\n </Box>\n ) : null}\n </Flex>\n )\n}\n\nexport default SiteItem\n","import React from 'react'\nimport {DeployAction, Site} from '../types'\nimport SiteItem from './SiteItem'\nimport {Flex, Box, Card, Text, Spinner, Stack} from '@sanity/ui'\n\ninterface Props {\n isLoading: boolean\n sites?: Site[]\n onDeploy: DeployAction\n}\n\nexport default function SiteList(props: Props) {\n const {isLoading, onDeploy, sites} = props\n if (isLoading) {\n return (\n <Card padding={4}>\n <Flex direction=\"column\" justify=\"center\" align=\"center\">\n <Spinner muted />\n <Box marginTop={3}>\n <Text muted>Loading sites…</Text>\n </Box>\n </Flex>\n </Card>\n )\n }\n if (!sites || (sites && sites.length === 0)) {\n return (\n <Card tone=\"critical\" padding={3}>\n <Text>No sites are defined in the widget options. Please check your config.</Text>\n </Card>\n )\n }\n return (\n <Box paddingY={2}>\n <Stack as=\"ul\" space={2}>\n {sites.map((site, index) => {\n return <SiteItem onDeploy={onDeploy} site={site} key={`site-${index}`} />\n })}\n </Stack>\n </Box>\n )\n}\n","import React from 'react'\nimport {NetlifyWidgetProps} from '../types'\nimport SiteList from './SiteList'\nimport {DashboardWidgetContainer} from '@sanity/dashboard'\nimport {styled} from 'styled-components'\nimport {Button, Flex, Card, Text, Box} from '@sanity/ui'\n\nconst ContentCard = styled(Card)`\n min-height: 66px;\n`\n\nexport default function NetlifyWidget(props: NetlifyWidgetProps) {\n const netlifySitesUrl = 'https://app.netlify.com/account/sites'\n const {title, description, isLoading, sites, onDeploy} = props\n\n const footer = (\n <Flex direction=\"column\" align=\"stretch\">\n <Button\n as=\"a\"\n href={isLoading ? undefined : netlifySitesUrl}\n disabled={isLoading}\n paddingX={2}\n paddingY={4}\n mode=\"bleed\"\n tone=\"primary\"\n text=\"Manage sites at Netlify\"\n loading={isLoading}\n target=\"_blank\"\n />\n </Flex>\n )\n\n return (\n <DashboardWidgetContainer header={title} footer={footer}>\n <ContentCard paddingY={1}>\n {description && (\n <Box paddingY={3} paddingX={3}>\n <Text as=\"p\" size={1} muted>\n <span dangerouslySetInnerHTML={{__html: description}} />\n </Text>\n </Box>\n )}\n <SiteList isLoading={isLoading} onDeploy={onDeploy} sites={sites} />\n </ContentCard>\n </DashboardWidgetContainer>\n )\n}\n","import React from 'react'\nimport {streamingComponent} from 'react-props-stream'\nimport {map, switchMap} from 'rxjs/operators'\nimport {WidgetOptions} from './types'\nimport {props$} from './props'\nimport NetlifyWidget from './components/NetlifyWidget'\n\nexport default streamingComponent<WidgetOptions>((options$) =>\n options$.pipe(\n switchMap((options) =>\n props$(options).pipe(\n map((props) => {\n return <NetlifyWidget {...props} />\n })\n )\n )\n )\n)\n","import React from 'react'\nimport Widget from './widget'\nimport {WidgetOptions} from './types'\nimport {DashboardWidget, LayoutConfig} from '@sanity/dashboard'\n\nexport type NetlifyWidgetConfig = WidgetOptions & {layout?: LayoutConfig}\n\nexport function netlifyWidget(config: NetlifyWidgetConfig): DashboardWidget {\n return {\n name: 'netlify-widget',\n component: () => {\n return <Widget {...config} />\n },\n layout: config.layout ?? {width: 'medium'},\n }\n}\n"],"names":["AbortControllerPolyfill","Observable","map","of","scan","createEventHandler","switchMap","catchError","merge","startWith","jsx","jsxs","useState","useCallback","useEffect","useRef","Flex","Box","Stack","Text","Card","Label","Button","Spinner","styled","DashboardWidgetContainer","streamingComponent"],"mappings":"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"}
|
package/lib/index.mjs
DELETED
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
|
-
import { createEventHandler, streamingComponent } from "react-props-stream";
|
|
3
|
-
import { map, scan, switchMap, catchError, startWith } from "rxjs/operators";
|
|
4
|
-
import { Observable, of, merge } from "rxjs";
|
|
5
|
-
import AbortControllerPolyfill from "abort-controller";
|
|
6
|
-
import { useState, useCallback, useEffect, useRef } from "react";
|
|
7
|
-
import { Flex, Box, Stack, Text, Card, Label, Button, Spinner } from "@sanity/ui";
|
|
8
|
-
import { DashboardWidgetContainer } from "@sanity/dashboard";
|
|
9
|
-
import { styled } from "styled-components";
|
|
10
|
-
const createAbortController = () => "AbortController" in window ? new AbortController() : new AbortControllerPolyfill(), statusCodeRequest = (input, init) => new Observable((subscriber) => {
|
|
11
|
-
const controller = createAbortController(), onResponse = (res) => {
|
|
12
|
-
subscriber.next(res), subscriber.complete();
|
|
13
|
-
}, onError = (err) => {
|
|
14
|
-
err.name === "AbortError" ? subscriber.complete() : subscriber.error(err);
|
|
15
|
-
};
|
|
16
|
-
return fetch(input, { ...init, signal: controller.signal }).then((res) => {
|
|
17
|
-
if (res.status < 200 || res.status > 299)
|
|
18
|
-
throw new Error(`HTTP Error ${res.status}: ${res.statusText}`);
|
|
19
|
-
return res.status;
|
|
20
|
-
}).then(onResponse, onError), () => {
|
|
21
|
-
controller.abort();
|
|
22
|
-
};
|
|
23
|
-
});
|
|
24
|
-
function deploy(site) {
|
|
25
|
-
return site.buildHookId ? statusCodeRequest(`https://api.netlify.com/build_hooks/${site.buildHookId}`, {
|
|
26
|
-
method: "POST"
|
|
27
|
-
}).pipe(map((result) => ({ result, site }))) : of(new Error("Site missing buildHookId"));
|
|
28
|
-
}
|
|
29
|
-
const stateReducer$ = scan((state, action) => {
|
|
30
|
-
switch (action.type) {
|
|
31
|
-
case "setSites":
|
|
32
|
-
return { ...state, sites: action.sites || [] };
|
|
33
|
-
case "deploy/started":
|
|
34
|
-
return {
|
|
35
|
-
...state,
|
|
36
|
-
sites: state.sites.map((site) => action.site && site.id === action.site.id ? { ...site } : site)
|
|
37
|
-
};
|
|
38
|
-
case "deploy/failed":
|
|
39
|
-
return {
|
|
40
|
-
...state,
|
|
41
|
-
error: action.error
|
|
42
|
-
};
|
|
43
|
-
case "deploy/completed":
|
|
44
|
-
return {
|
|
45
|
-
...state,
|
|
46
|
-
sites: state.sites.map((site) => action.site && site.id === action.site.id ? { ...site, error: action.error } : site)
|
|
47
|
-
};
|
|
48
|
-
default:
|
|
49
|
-
return state;
|
|
50
|
-
}
|
|
51
|
-
}), noop = () => {
|
|
52
|
-
}, INITIAL_PROPS = {
|
|
53
|
-
title: "Netlify sites",
|
|
54
|
-
sites: [],
|
|
55
|
-
isLoading: !0,
|
|
56
|
-
onDeploy: noop
|
|
57
|
-
}, props$ = (options) => {
|
|
58
|
-
const configuredSites = (options.sites || []).map((site) => ({
|
|
59
|
-
id: site.apiId,
|
|
60
|
-
name: site.name,
|
|
61
|
-
title: site.title,
|
|
62
|
-
buildHookId: site.buildHookId,
|
|
63
|
-
url: site.url || site.branch && `https://${site.branch}--${site.name}.netlify.app/` || site.name && `https://${site.name}.netlify.app/`,
|
|
64
|
-
adminUrl: site.name && `https://app.netlify.com/sites/${site.name}`,
|
|
65
|
-
branch: site.branch
|
|
66
|
-
})), [onDeploy$, onDeploy] = createEventHandler(), setSitesAction$ = of(configuredSites).pipe(map((sites) => ({ type: "setSites", sites }))), deployAction$ = onDeploy$.pipe(map((site) => ({ type: "deploy/started", site }))), deployCompletedAction$ = onDeploy$.pipe(switchMap((site) => deploy(site))).pipe(
|
|
67
|
-
map(
|
|
68
|
-
(result) => ({ type: "deploy/completed", ...result }),
|
|
69
|
-
catchError((error) => of({ type: "deploy/failed", error }))
|
|
70
|
-
)
|
|
71
|
-
);
|
|
72
|
-
return merge(setSitesAction$, deployAction$, deployCompletedAction$).pipe(stateReducer$).subscribe(), of(configuredSites).pipe(
|
|
73
|
-
map((sites) => ({
|
|
74
|
-
sites,
|
|
75
|
-
title: options.title || INITIAL_PROPS.title,
|
|
76
|
-
description: options.description,
|
|
77
|
-
isLoading: !1,
|
|
78
|
-
onDeploy
|
|
79
|
-
})),
|
|
80
|
-
startWith(INITIAL_PROPS)
|
|
81
|
-
);
|
|
82
|
-
}, Link = (props) => {
|
|
83
|
-
const { url, children } = props;
|
|
84
|
-
return /* @__PURE__ */ jsx("span", { children: /* @__PURE__ */ jsx("a", { href: url, target: "_blank", rel: "noreferrer", children }) });
|
|
85
|
-
}, Links = (props) => {
|
|
86
|
-
const { url, adminUrl } = props;
|
|
87
|
-
return url && adminUrl ? /* @__PURE__ */ jsxs("span", { children: [
|
|
88
|
-
"(",
|
|
89
|
-
/* @__PURE__ */ jsx(Link, { url, children: "view" }),
|
|
90
|
-
", ",
|
|
91
|
-
/* @__PURE__ */ jsx(Link, { url: adminUrl, children: "admin" }),
|
|
92
|
-
")"
|
|
93
|
-
] }) : url ? /* @__PURE__ */ jsx(Link, { url, children: "(view)" }) : adminUrl ? /* @__PURE__ */ jsx(Link, { url: adminUrl, children: "(admin)" }) : null;
|
|
94
|
-
}, IMAGE_PULL_INTERVAL = 1e4, getImageUrl = (siteId, branchName) => {
|
|
95
|
-
const baseUrl = `https://api.netlify.com/api/v1/badges/${siteId}/deploy-status`, time = (/* @__PURE__ */ new Date()).getTime(), branch = `branch=${branchName}`;
|
|
96
|
-
return branchName ? `${baseUrl}?${time}&${branch}` : `${baseUrl}?${time}`;
|
|
97
|
-
}, useBadgeImage = (siteId, branchName) => {
|
|
98
|
-
const [src, setSrc] = useState(() => getImageUrl(siteId, branchName)), update = useCallback(() => setSrc(getImageUrl(siteId, branchName)), [siteId]);
|
|
99
|
-
return useEffect(() => {
|
|
100
|
-
const interval = window.setInterval(update, IMAGE_PULL_INTERVAL);
|
|
101
|
-
return () => window.clearInterval(interval);
|
|
102
|
-
}, [update]), [src, update];
|
|
103
|
-
}, useDeploy = (site, onDeploy, updateBadge) => {
|
|
104
|
-
const timeoutRef = useRef(-1);
|
|
105
|
-
return useEffect(() => () => window.clearTimeout(timeoutRef.current), []), useCallback(() => {
|
|
106
|
-
onDeploy(site), timeoutRef.current = window.setTimeout(updateBadge, 1e3);
|
|
107
|
-
}, [site, onDeploy, updateBadge]);
|
|
108
|
-
}, SiteItem = (props) => {
|
|
109
|
-
const [hasBadgeError, setHasBadgeError] = useState(!1), { site, onDeploy } = props, { id, name, title, url, adminUrl, buildHookId, branch } = site, [badge, updateBadge] = useBadgeImage(id, branch), handleDeploy = useDeploy(site, onDeploy, updateBadge);
|
|
110
|
-
return /* @__PURE__ */ jsxs(Flex, { as: "li", children: [
|
|
111
|
-
/* @__PURE__ */ jsx(Box, { flex: 1, paddingY: 2, paddingX: 3, children: /* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
112
|
-
/* @__PURE__ */ jsxs(Text, { as: "h4", children: [
|
|
113
|
-
title || name,
|
|
114
|
-
/* @__PURE__ */ jsx(Links, { url, adminUrl })
|
|
115
|
-
] }),
|
|
116
|
-
/* @__PURE__ */ jsxs(Flex, { justify: "flex-start", children: [
|
|
117
|
-
!hasBadgeError && /* @__PURE__ */ jsx("img", { src: badge, onError: () => {
|
|
118
|
-
setHasBadgeError(!0);
|
|
119
|
-
}, alt: "Badge" }),
|
|
120
|
-
hasBadgeError && /* @__PURE__ */ jsx(Card, { tone: "critical", radius: 2, padding: 2, children: /* @__PURE__ */ jsx(Label, { size: 0, muted: !0, children: "Failed to load badge" }) })
|
|
121
|
-
] })
|
|
122
|
-
] }) }),
|
|
123
|
-
buildHookId ? /* @__PURE__ */ jsx(Box, { paddingY: 2, paddingX: 3, children: /* @__PURE__ */ jsx(Button, { mode: "ghost", onClick: handleDeploy, text: "Deploy" }) }) : null
|
|
124
|
-
] });
|
|
125
|
-
};
|
|
126
|
-
function SiteList(props) {
|
|
127
|
-
const { isLoading, onDeploy, sites } = props;
|
|
128
|
-
return isLoading ? /* @__PURE__ */ jsx(Card, { padding: 4, children: /* @__PURE__ */ jsxs(Flex, { direction: "column", justify: "center", align: "center", children: [
|
|
129
|
-
/* @__PURE__ */ jsx(Spinner, { muted: !0 }),
|
|
130
|
-
/* @__PURE__ */ jsx(Box, { marginTop: 3, children: /* @__PURE__ */ jsx(Text, { muted: !0, children: "Loading sites\u2026" }) })
|
|
131
|
-
] }) }) : !sites || sites && sites.length === 0 ? /* @__PURE__ */ jsx(Card, { tone: "critical", padding: 3, children: /* @__PURE__ */ jsx(Text, { children: "No sites are defined in the widget options. Please check your config." }) }) : /* @__PURE__ */ jsx(Box, { paddingY: 2, children: /* @__PURE__ */ jsx(Stack, { as: "ul", space: 2, children: sites.map((site, index) => /* @__PURE__ */ jsx(SiteItem, { onDeploy, site }, `site-${index}`)) }) });
|
|
132
|
-
}
|
|
133
|
-
const ContentCard = styled(Card)`
|
|
134
|
-
min-height: 66px;
|
|
135
|
-
`;
|
|
136
|
-
function NetlifyWidget(props) {
|
|
137
|
-
const netlifySitesUrl = "https://app.netlify.com/account/sites", { title, description, isLoading, sites, onDeploy } = props;
|
|
138
|
-
return /* @__PURE__ */ jsx(DashboardWidgetContainer, { header: title, footer: /* @__PURE__ */ jsx(Flex, { direction: "column", align: "stretch", children: /* @__PURE__ */ jsx(
|
|
139
|
-
Button,
|
|
140
|
-
{
|
|
141
|
-
as: "a",
|
|
142
|
-
href: isLoading ? void 0 : netlifySitesUrl,
|
|
143
|
-
disabled: isLoading,
|
|
144
|
-
paddingX: 2,
|
|
145
|
-
paddingY: 4,
|
|
146
|
-
mode: "bleed",
|
|
147
|
-
tone: "primary",
|
|
148
|
-
text: "Manage sites at Netlify",
|
|
149
|
-
loading: isLoading,
|
|
150
|
-
target: "_blank"
|
|
151
|
-
}
|
|
152
|
-
) }), children: /* @__PURE__ */ jsxs(ContentCard, { paddingY: 1, children: [
|
|
153
|
-
description && /* @__PURE__ */ jsx(Box, { paddingY: 3, paddingX: 3, children: /* @__PURE__ */ jsx(Text, { as: "p", size: 1, muted: !0, children: /* @__PURE__ */ jsx("span", { dangerouslySetInnerHTML: { __html: description } }) }) }),
|
|
154
|
-
/* @__PURE__ */ jsx(SiteList, { isLoading, onDeploy, sites })
|
|
155
|
-
] }) });
|
|
156
|
-
}
|
|
157
|
-
var Widget = streamingComponent(
|
|
158
|
-
(options$) => options$.pipe(
|
|
159
|
-
switchMap(
|
|
160
|
-
(options) => props$(options).pipe(
|
|
161
|
-
map((props) => /* @__PURE__ */ jsx(NetlifyWidget, { ...props }))
|
|
162
|
-
)
|
|
163
|
-
)
|
|
164
|
-
)
|
|
165
|
-
);
|
|
166
|
-
function netlifyWidget(config) {
|
|
167
|
-
return {
|
|
168
|
-
name: "netlify-widget",
|
|
169
|
-
component: () => /* @__PURE__ */ jsx(Widget, { ...config }),
|
|
170
|
-
layout: config.layout ?? { width: "medium" }
|
|
171
|
-
};
|
|
172
|
-
}
|
|
173
|
-
export {
|
|
174
|
-
netlifyWidget
|
|
175
|
-
};
|
|
176
|
-
//# sourceMappingURL=index.mjs.map
|
package/lib/index.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":["../src/http/utils/createAbortController.ts","../src/http/statusCodeRequest.ts","../src/datastores/deploy.ts","../src/reducers.ts","../src/props.ts","../src/components/SiteItem/Links.tsx","../src/components/SiteItem/index.tsx","../src/components/SiteList.tsx","../src/components/NetlifyWidget.tsx","../src/widget.tsx","../src/plugin.tsx"],"sourcesContent":["import AbortControllerPolyfill from 'abort-controller'\n\nexport const createAbortController = (): AbortController => {\n if (!('AbortController' in window)) {\n return new AbortControllerPolyfill() as AbortController\n }\n return new AbortController()\n}\n","import {Observable} from 'rxjs'\nimport {createAbortController} from './utils/createAbortController'\n\n// eslint-disable-next-line no-undef\nexport const statusCodeRequest = (input: RequestInfo, init?: RequestInit): Observable<number> => {\n return new Observable((subscriber) => {\n const controller = createAbortController()\n const onResponse = (res: number) => {\n subscriber.next(res)\n subscriber.complete()\n }\n const onError = (err: Error) => {\n if (err.name === 'AbortError') {\n subscriber.complete()\n } else {\n subscriber.error(err)\n }\n }\n\n fetch(input, {...init, signal: controller.signal})\n .then((res: Response) => {\n if (res.status < 200 || res.status > 299) {\n throw new Error(`HTTP Error ${res.status}: ${res.statusText}`)\n }\n return res.status\n })\n .then(onResponse, onError)\n\n return () => {\n controller.abort()\n }\n })\n}\n","import {Observable, of} from 'rxjs'\nimport {map} from 'rxjs/operators'\nimport {statusCodeRequest} from '../http/statusCodeRequest'\nimport {Site} from '../types'\n\nexport function deploy(site: Site): Observable<{result: number; site: Site} | Error> {\n if (!site.buildHookId) {\n return of(new Error('Site missing buildHookId'))\n }\n\n return statusCodeRequest(`https://api.netlify.com/build_hooks/${site.buildHookId}`, {\n method: 'POST',\n }).pipe(map((result) => ({result, site})))\n}\n","import {scan} from 'rxjs/operators'\nimport {Site} from './types'\n\ninterface Deployment {\n id: string\n}\n\ninterface Action {\n type: string\n sites?: Site[]\n site?: Site\n error?: Error\n deployments?: Deployment[]\n}\n\ninterface State {\n sites: Site[]\n action: Action\n}\n\nexport const stateReducer$ = scan((state: State, action: Action) => {\n switch (action.type) {\n case 'setSites':\n return {...state, sites: action.sites || []}\n case 'deploy/started':\n return {\n ...state,\n sites: state.sites.map((site: Site) => {\n if (action.site && site.id === action.site.id) {\n return {...site}\n }\n return site\n }),\n }\n case 'deploy/failed':\n return {\n ...state,\n error: action.error,\n }\n case 'deploy/completed':\n return {\n ...state,\n sites: state.sites.map((site: Site) => {\n if (action.site && site.id === action.site.id) {\n return {...site, error: action.error}\n }\n return site\n }),\n }\n default:\n return state\n }\n})\n","import {merge, of} from 'rxjs'\nimport {createEventHandler} from 'react-props-stream'\nimport {catchError, map, startWith, switchMap} from 'rxjs/operators'\nimport {deploy} from './datastores/deploy'\nimport {Site, WidgetOptions} from './types'\nimport {stateReducer$} from './reducers'\n\nconst noop = () => undefined\n\nconst INITIAL_PROPS = {\n title: 'Netlify sites',\n sites: [],\n isLoading: true,\n onDeploy: noop,\n}\n\n// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types\nexport const props$ = (options: WidgetOptions) => {\n const configuredSites = (options.sites || []).map((site) => ({\n id: site.apiId,\n name: site.name,\n title: site.title,\n buildHookId: site.buildHookId,\n url:\n site.url ||\n (site.branch && `https://${site.branch}--${site.name}.netlify.app/`) ||\n (site.name && `https://${site.name}.netlify.app/`),\n adminUrl: site.name && `https://app.netlify.com/sites/${site.name}`,\n branch: site.branch,\n }))\n\n const [onDeploy$, onDeploy] = createEventHandler<Site>()\n const setSitesAction$ = of(configuredSites).pipe(map((sites) => ({type: 'setSites', sites})))\n const deployAction$ = onDeploy$.pipe(map((site) => ({type: 'deploy/started', site})))\n const deployResult$ = onDeploy$.pipe(switchMap((site) => deploy(site)))\n const deployCompletedAction$ = deployResult$.pipe(\n map(\n (result) => ({type: 'deploy/completed', ...result}),\n catchError((error) => of({type: 'deploy/failed', error}))\n )\n )\n\n merge(setSitesAction$, deployAction$, deployCompletedAction$).pipe(stateReducer$).subscribe()\n\n return of(configuredSites).pipe(\n map((sites) => ({\n sites,\n title: options.title || INITIAL_PROPS.title,\n description: options.description,\n isLoading: false,\n onDeploy,\n })),\n startWith(INITIAL_PROPS)\n )\n}\n","import React, {FunctionComponent, PropsWithChildren} from 'react'\n\nconst Link = (props: PropsWithChildren<{url: string}>) => {\n const {url, children} = props\n\n return (\n <span>\n <a href={url} target=\"_blank\" rel=\"noreferrer\">\n {children}\n </a>\n </span>\n )\n}\n\ntype Props = {\n url?: string\n adminUrl?: string\n}\n\nconst Links: FunctionComponent<Props> = (props) => {\n const {url, adminUrl} = props\n\n if (url && adminUrl) {\n return (\n <span>\n (<Link url={url}>view</Link>, <Link url={adminUrl}>admin</Link>)\n </span>\n )\n }\n\n if (url) {\n return <Link url={url}>(view)</Link>\n }\n if (adminUrl) {\n return <Link url={adminUrl}>(admin)</Link>\n }\n return null\n}\n\nexport default Links\n","import React, {FunctionComponent, useCallback, useEffect, useRef, useState} from 'react'\nimport {Button, Flex, Box, Card, Text, Stack, Label} from '@sanity/ui'\nimport {DeployAction, Site} from '../../types'\nimport Links from './Links'\n\ninterface Props {\n site: Site\n onDeploy: DeployAction\n}\n\nexport const IMAGE_PULL_INTERVAL = 10000\n\nconst getImageUrl = (siteId: string, branchName?: string) => {\n const baseUrl = `https://api.netlify.com/api/v1/badges/${siteId}/deploy-status`\n const time = new Date().getTime()\n const branch = `branch=${branchName}`\n\n return branchName ? `${baseUrl}?${time}&${branch}` : `${baseUrl}?${time}`\n}\n\nconst useBadgeImage = (siteId: string, branchName?: string ) => {\n const [src, setSrc] = useState(() => getImageUrl(siteId, branchName))\n const update = useCallback(() => setSrc(getImageUrl(siteId, branchName)), [siteId])\n\n useEffect(() => {\n const interval = window.setInterval(update, IMAGE_PULL_INTERVAL)\n return () => window.clearInterval(interval)\n }, [update])\n\n return [src, update] as const\n}\n\nconst useDeploy = (site: Site, onDeploy: DeployAction, updateBadge: () => void) => {\n const timeoutRef = useRef(-1)\n useEffect(() => () => window.clearTimeout(timeoutRef.current), [])\n\n return useCallback(() => {\n onDeploy(site)\n timeoutRef.current = window.setTimeout(updateBadge, 1000)\n }, [site, onDeploy, updateBadge])\n}\n\nconst SiteItem: FunctionComponent<Props> = (props) => {\n const [hasBadgeError, setHasBadgeError] = useState(false)\n const {site, onDeploy} = props\n const {id, name, title, url, adminUrl, buildHookId, branch} = site\n\n const [badge, updateBadge] = useBadgeImage(id, branch)\n const handleDeploy = useDeploy(site, onDeploy, updateBadge)\n const handleBadgeError = () => {\n setHasBadgeError(true)\n }\n\n return (\n <Flex as=\"li\">\n <Box flex={1} paddingY={2} paddingX={3}>\n <Stack space={2}>\n <Text as=\"h4\">\n {title || name}\n <Links url={url} adminUrl={adminUrl} />\n </Text>\n\n <Flex justify=\"flex-start\">\n {!hasBadgeError && <img src={badge} onError={handleBadgeError} alt=\"Badge\" />}\n {hasBadgeError && <Card tone=\"critical\" radius={2} padding={2}><Label size={0} muted>Failed to load badge</Label></Card>}\n </Flex>\n </Stack>\n </Box>\n\n {buildHookId ? (\n <Box paddingY={2} paddingX={3}>\n <Button mode=\"ghost\" onClick={handleDeploy} text=\"Deploy\" />\n </Box>\n ) : null}\n </Flex>\n )\n}\n\nexport default SiteItem\n","import React from 'react'\nimport {DeployAction, Site} from '../types'\nimport SiteItem from './SiteItem'\nimport {Flex, Box, Card, Text, Spinner, Stack} from '@sanity/ui'\n\ninterface Props {\n isLoading: boolean\n sites?: Site[]\n onDeploy: DeployAction\n}\n\nexport default function SiteList(props: Props) {\n const {isLoading, onDeploy, sites} = props\n if (isLoading) {\n return (\n <Card padding={4}>\n <Flex direction=\"column\" justify=\"center\" align=\"center\">\n <Spinner muted />\n <Box marginTop={3}>\n <Text muted>Loading sites…</Text>\n </Box>\n </Flex>\n </Card>\n )\n }\n if (!sites || (sites && sites.length === 0)) {\n return (\n <Card tone=\"critical\" padding={3}>\n <Text>No sites are defined in the widget options. Please check your config.</Text>\n </Card>\n )\n }\n return (\n <Box paddingY={2}>\n <Stack as=\"ul\" space={2}>\n {sites.map((site, index) => {\n return <SiteItem onDeploy={onDeploy} site={site} key={`site-${index}`} />\n })}\n </Stack>\n </Box>\n )\n}\n","import React from 'react'\nimport {NetlifyWidgetProps} from '../types'\nimport SiteList from './SiteList'\nimport {DashboardWidgetContainer} from '@sanity/dashboard'\nimport {styled} from 'styled-components'\nimport {Button, Flex, Card, Text, Box} from '@sanity/ui'\n\nconst ContentCard = styled(Card)`\n min-height: 66px;\n`\n\nexport default function NetlifyWidget(props: NetlifyWidgetProps) {\n const netlifySitesUrl = 'https://app.netlify.com/account/sites'\n const {title, description, isLoading, sites, onDeploy} = props\n\n const footer = (\n <Flex direction=\"column\" align=\"stretch\">\n <Button\n as=\"a\"\n href={isLoading ? undefined : netlifySitesUrl}\n disabled={isLoading}\n paddingX={2}\n paddingY={4}\n mode=\"bleed\"\n tone=\"primary\"\n text=\"Manage sites at Netlify\"\n loading={isLoading}\n target=\"_blank\"\n />\n </Flex>\n )\n\n return (\n <DashboardWidgetContainer header={title} footer={footer}>\n <ContentCard paddingY={1}>\n {description && (\n <Box paddingY={3} paddingX={3}>\n <Text as=\"p\" size={1} muted>\n <span dangerouslySetInnerHTML={{__html: description}} />\n </Text>\n </Box>\n )}\n <SiteList isLoading={isLoading} onDeploy={onDeploy} sites={sites} />\n </ContentCard>\n </DashboardWidgetContainer>\n )\n}\n","import React from 'react'\nimport {streamingComponent} from 'react-props-stream'\nimport {map, switchMap} from 'rxjs/operators'\nimport {WidgetOptions} from './types'\nimport {props$} from './props'\nimport NetlifyWidget from './components/NetlifyWidget'\n\nexport default streamingComponent<WidgetOptions>((options$) =>\n options$.pipe(\n switchMap((options) =>\n props$(options).pipe(\n map((props) => {\n return <NetlifyWidget {...props} />\n })\n )\n )\n )\n)\n","import React from 'react'\nimport Widget from './widget'\nimport {WidgetOptions} from './types'\nimport {DashboardWidget, LayoutConfig} from '@sanity/dashboard'\n\nexport type NetlifyWidgetConfig = WidgetOptions & {layout?: LayoutConfig}\n\nexport function netlifyWidget(config: NetlifyWidgetConfig): DashboardWidget {\n return {\n name: 'netlify-widget',\n component: () => {\n return <Widget {...config} />\n },\n layout: config.layout ?? {width: 'medium'},\n }\n}\n"],"names":[],"mappings":"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"}
|
package/sanity.json
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import {NetlifyWidgetProps} from '../types'
|
|
3
|
-
import SiteList from './SiteList'
|
|
4
|
-
import {DashboardWidgetContainer} from '@sanity/dashboard'
|
|
5
|
-
import {styled} from 'styled-components'
|
|
6
|
-
import {Button, Flex, Card, Text, Box} from '@sanity/ui'
|
|
7
|
-
|
|
8
|
-
const ContentCard = styled(Card)`
|
|
9
|
-
min-height: 66px;
|
|
10
|
-
`
|
|
11
|
-
|
|
12
|
-
export default function NetlifyWidget(props: NetlifyWidgetProps) {
|
|
13
|
-
const netlifySitesUrl = 'https://app.netlify.com/account/sites'
|
|
14
|
-
const {title, description, isLoading, sites, onDeploy} = props
|
|
15
|
-
|
|
16
|
-
const footer = (
|
|
17
|
-
<Flex direction="column" align="stretch">
|
|
18
|
-
<Button
|
|
19
|
-
as="a"
|
|
20
|
-
href={isLoading ? undefined : netlifySitesUrl}
|
|
21
|
-
disabled={isLoading}
|
|
22
|
-
paddingX={2}
|
|
23
|
-
paddingY={4}
|
|
24
|
-
mode="bleed"
|
|
25
|
-
tone="primary"
|
|
26
|
-
text="Manage sites at Netlify"
|
|
27
|
-
loading={isLoading}
|
|
28
|
-
target="_blank"
|
|
29
|
-
/>
|
|
30
|
-
</Flex>
|
|
31
|
-
)
|
|
32
|
-
|
|
33
|
-
return (
|
|
34
|
-
<DashboardWidgetContainer header={title} footer={footer}>
|
|
35
|
-
<ContentCard paddingY={1}>
|
|
36
|
-
{description && (
|
|
37
|
-
<Box paddingY={3} paddingX={3}>
|
|
38
|
-
<Text as="p" size={1} muted>
|
|
39
|
-
<span dangerouslySetInnerHTML={{__html: description}} />
|
|
40
|
-
</Text>
|
|
41
|
-
</Box>
|
|
42
|
-
)}
|
|
43
|
-
<SiteList isLoading={isLoading} onDeploy={onDeploy} sites={sites} />
|
|
44
|
-
</ContentCard>
|
|
45
|
-
</DashboardWidgetContainer>
|
|
46
|
-
)
|
|
47
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import React, {FunctionComponent, PropsWithChildren} from 'react'
|
|
2
|
-
|
|
3
|
-
const Link = (props: PropsWithChildren<{url: string}>) => {
|
|
4
|
-
const {url, children} = props
|
|
5
|
-
|
|
6
|
-
return (
|
|
7
|
-
<span>
|
|
8
|
-
<a href={url} target="_blank" rel="noreferrer">
|
|
9
|
-
{children}
|
|
10
|
-
</a>
|
|
11
|
-
</span>
|
|
12
|
-
)
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
type Props = {
|
|
16
|
-
url?: string
|
|
17
|
-
adminUrl?: string
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const Links: FunctionComponent<Props> = (props) => {
|
|
21
|
-
const {url, adminUrl} = props
|
|
22
|
-
|
|
23
|
-
if (url && adminUrl) {
|
|
24
|
-
return (
|
|
25
|
-
<span>
|
|
26
|
-
(<Link url={url}>view</Link>, <Link url={adminUrl}>admin</Link>)
|
|
27
|
-
</span>
|
|
28
|
-
)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if (url) {
|
|
32
|
-
return <Link url={url}>(view)</Link>
|
|
33
|
-
}
|
|
34
|
-
if (adminUrl) {
|
|
35
|
-
return <Link url={adminUrl}>(admin)</Link>
|
|
36
|
-
}
|
|
37
|
-
return null
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export default Links
|