sanity-plugin-dashboard-widget-netlify 2.0.1 → 2.0.3

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2022 Sanity.io
3
+ Copyright (c) 2025 Sanity.io
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/lib/index.d.ts ADDED
@@ -0,0 +1,45 @@
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 CHANGED
@@ -1,2 +1,172 @@
1
- "use strict";var e;function t(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function r(e){for(var r=1;r<arguments.length;r++){var i=null!=arguments[r]?arguments[r]:{};r%2?t(Object(i),!0).forEach((function(t){n(e,t,i[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(i)):t(Object(i)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(i,t))}))}return e}function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}Object.defineProperty(exports,"__esModule",{value:!0});var i=require("react/jsx-runtime"),s=require("react-props-stream"),o=require("rxjs/operators"),a=require("rxjs"),c=require("abort-controller"),l=require("react"),d=require("@sanity/ui"),p=require("@sanity/dashboard"),u=require("styled-components");function h(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var m=h(c),f=h(u);const x=(e,t)=>new a.Observable((n=>{const i="AbortController"in window?new AbortController:new m.default;return fetch(e,r(r({},t),{},{signal:i.signal})).then((e=>{if(e.status<200||e.status>299)throw new Error("HTTP Error ".concat(e.status,": ").concat(e.statusText));return e.status})).then((e=>{n.next(e),n.complete()}),(e=>{"AbortError"===e.name?n.complete():n.error(e)})),()=>{i.abort()}}));const j=o.scan(((e,t)=>{switch(t.type){case"setSites":return r(r({},e),{},{sites:t.sites||[]});case"deploy/started":return r(r({},e),{},{sites:e.sites.map((e=>t.site&&e.id===t.site.id?r({},e):e))});case"deploy/failed":return r(r({},e),{},{error:t.error});case"deploy/completed":return r(r({},e),{},{sites:e.sites.map((e=>t.site&&e.id===t.site.id?r(r({},e),{},{error:t.error}):e))});default:return e}})),b={title:"Netlify sites",sites:[],isLoading:!0,onDeploy:()=>{}},y=e=>{const t=(e.sites||[]).map((e=>({id:e.apiId,name:e.name,title:e.title,buildHookId:e.buildHookId,url:e.url||e.branch&&"https://".concat(e.branch,"--").concat(e.name,".netlify.app/")||e.name&&"https://".concat(e.name,".netlify.app/"),adminUrl:e.name&&"https://app.netlify.com/sites/".concat(e.name),branch:e.branch}))),[n,i]=s.createEventHandler(),c=a.of(t).pipe(o.map((e=>({type:"setSites",sites:e})))),l=n.pipe(o.map((e=>({type:"deploy/started",site:e})))),d=n.pipe(o.switchMap((e=>function(e){return e.buildHookId?x("https://api.netlify.com/build_hooks/".concat(e.buildHookId),{method:"POST"}).pipe(o.map((t=>({result:t,site:e})))):a.of(new Error("Site missing buildHookId"))}(e)))).pipe(o.map((e=>r({type:"deploy/completed"},e)),o.catchError((e=>a.of({type:"deploy/failed",error:e})))));return a.merge(c,l,d).pipe(j).subscribe(),a.of(t).pipe(o.map((t=>({sites:t,title:e.title||b.title,description:e.description,isLoading:!1,onDeploy:i}))),o.startWith(b))},g=e=>{const{url:t,children:r}=e;return i.jsx("span",{children:i.jsx("a",{href:t,target:"_blank",rel:"noreferrer",children:r})})},w=e=>{const{url:t,adminUrl:r}=e;return t&&r?i.jsxs("span",{children:["(",i.jsx(g,{url:t,children:"view"}),", ",i.jsx(g,{url:r,children:"admin"}),")"]}):t?i.jsx(g,{url:t,children:"(view)"}):r?i.jsx(g,{url:r,children:"(admin)"}):null},O=(e,t)=>{const r="https://api.netlify.com/api/v1/badges/".concat(e,"/deploy-status"),n=(new Date).getTime(),i="branch=".concat(t);return t?"".concat(r,"?").concat(n,"&").concat(i):"".concat(r,"?").concat(n)},v=e=>{const[t,r]=l.useState(!1),{site:n,onDeploy:s}=e,{id:o,name:a,title:c,url:p,adminUrl:u,buildHookId:h,branch:m}=n,[f,x]=((e,t)=>{const[r,n]=l.useState((()=>O(e,t))),i=l.useCallback((()=>n(O(e,t))),[e]);return l.useEffect((()=>{const e=window.setInterval(i,1e4);return()=>window.clearInterval(e)}),[i]),[r,i]})(o,m),j=((e,t,r)=>{const n=l.useRef(-1);return l.useEffect((()=>()=>window.clearTimeout(n.current)),[]),l.useCallback((()=>{t(e),n.current=window.setTimeout(r,1e3)}),[e,t,r])})(n,s,x);return i.jsxs(d.Flex,{as:"li",children:[i.jsx(d.Box,{flex:1,paddingY:2,paddingX:3,children:i.jsxs(d.Stack,{space:2,children:[i.jsxs(d.Text,{as:"h4",children:[c||a,i.jsx(w,{url:p,adminUrl:u})]}),i.jsxs(d.Flex,{justify:"flex-start",children:[!t&&i.jsx("img",{src:f,onError:()=>{r(!0)},alt:"Badge"}),t&&i.jsx(d.Card,{tone:"critical",radius:2,padding:2,children:i.jsx(d.Label,{size:0,muted:!0,children:"Failed to load badge"})})]})]})}),h?i.jsx(d.Box,{paddingY:2,paddingX:3,children:i.jsx(d.Button,{mode:"ghost",onClick:j,text:"Deploy"})}):null]})};function k(e){const{isLoading:t,onDeploy:r,sites:n}=e;return t?i.jsx(d.Card,{padding:4,children:i.jsxs(d.Flex,{direction:"column",justify:"center",align:"center",children:[i.jsx(d.Spinner,{muted:!0}),i.jsx(d.Box,{marginTop:3,children:i.jsx(d.Text,{muted:!0,children:"Loading sites…"})})]})}):!n||n&&0===n.length?i.jsx(d.Card,{tone:"critical",padding:3,children:i.jsx(d.Text,{children:"No sites are defined in the widget options. Please check your config."})}):i.jsx(d.Box,{paddingY:2,children:i.jsx(d.Stack,{as:"ul",space:2,children:n.map(((e,t)=>i.jsx(v,{onDeploy:r,site:e},"site-".concat(t))))})})}const D=f.default(d.Card)(e||(P=["\n min-height: 66px;\n"],T||(T=P.slice(0)),e=Object.freeze(Object.defineProperties(P,{raw:{value:Object.freeze(T)}}))));var P,T;function S(e){const{title:t,description:r,isLoading:n,sites:s,onDeploy:o}=e,a=i.jsx(d.Flex,{direction:"column",align:"stretch",children:i.jsx(d.Button,{as:"a",href:n?void 0:"https://app.netlify.com/account/sites",disabled:n,paddingX:2,paddingY:4,mode:"bleed",tone:"primary",text:"Manage sites at Netlify",loading:n,target:"_blank"})});return i.jsx(p.DashboardWidgetContainer,{header:t,footer:a,children:i.jsxs(D,{paddingY:1,children:[r&&i.jsx(d.Box,{paddingY:3,paddingX:3,children:i.jsx(d.Text,{as:"p",size:1,muted:!0,children:i.jsx("span",{dangerouslySetInnerHTML:{__html:r}})})}),i.jsx(k,{isLoading:n,onDeploy:o,sites:s})]})})}var C=s.streamingComponent((e=>e.pipe(o.switchMap((e=>y(e).pipe(o.map((e=>i.jsx(S,r({},e))))))))));exports.netlifyWidget=function(e){var t;return{name:"netlify-widget",component:()=>i.jsx(C,r({},e)),layout:null!=(t=e.layout)?t:{width:"medium"}}};
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;
2
172
  //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/http/utils/createAbortController.ts","../src/http/statusCodeRequest.ts","../src/reducers.ts","../src/props.ts","../src/datastores/deploy.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 {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 {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 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":["statusCodeRequest","input","init","Observable","subscriber","controller","window","AbortController","AbortControllerPolyfill","fetch","_objectSpread","signal","then","res","status","Error","concat","statusText","next","complete","err","name","error","abort","stateReducer$","scan","state","action","type","sites","map","site","id","INITIAL_PROPS","title","isLoading","onDeploy","props$","options","configuredSites","apiId","buildHookId","url","branch","adminUrl","onDeploy$","createEventHandler","setSitesAction$","of","pipe","deployAction$","deployCompletedAction$","switchMap","method","result","deploy","catchError","merge","subscribe","description","startWith","Link","props","children","jsx","href","target","rel","Links","jsxs","getImageUrl","siteId","branchName","baseUrl","time","Date","getTime","SiteItem","hasBadgeError","setHasBadgeError","useState","badge","updateBadge","src","setSrc","update","useCallback","useEffect","interval","setInterval","clearInterval","useBadgeImage","handleDeploy","timeoutRef","useRef","clearTimeout","current","setTimeout","useDeploy","Flex","as","Box","flex","paddingY","paddingX","Stack","space","Text","justify","onError","alt","Card","tone","radius","padding","Label","size","muted","Button","mode","onClick","text","SiteList","direction","align","Spinner","marginTop","length","index","ContentCard","styled","_templateObject","NetlifyWidget","footer","disabled","loading","DashboardWidgetContainer","header","dangerouslySetInnerHTML","__html","Widget","streamingComponent","options$","config","_a","component","layout","width"],"mappings":"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"}
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 ADDED
@@ -0,0 +1,176 @@
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
@@ -0,0 +1 @@
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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sanity-plugin-dashboard-widget-netlify",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
4
4
  "description": "Sanity Studio Dashboard Widget for triggering Netlify builds",
5
5
  "keywords": [
6
6
  "sanity",
@@ -19,20 +19,19 @@
19
19
  },
20
20
  "license": "MIT",
21
21
  "author": "Sanity.io <hello@sanity.io>",
22
+ "type": "commonjs",
22
23
  "exports": {
23
24
  ".": {
24
- "types": "./lib/src/index.d.ts",
25
25
  "source": "./src/index.ts",
26
- "import": "./lib/index.esm.js",
26
+ "import": "./lib/index.mjs",
27
27
  "require": "./lib/index.js",
28
- "default": "./lib/index.esm.js"
28
+ "default": "./lib/index.js"
29
29
  },
30
30
  "./package.json": "./package.json"
31
31
  },
32
32
  "main": "./lib/index.js",
33
- "module": "./lib/index.esm.js",
34
- "source": "./src/index.ts",
35
- "types": "./lib/src/index.d.ts",
33
+ "module": "./lib/index.mjs",
34
+ "types": "./lib/index.d.ts",
36
35
  "files": [
37
36
  "src",
38
37
  "lib",
@@ -41,18 +40,16 @@
41
40
  ],
42
41
  "scripts": {
43
42
  "__test": "jest --coverage",
44
- "prebuild": "npm run clean && plugin-kit verify-package --silent && pkg-utils",
45
- "build": "pkg-utils build --strict",
43
+ "build": "plugin-kit verify-package --silent && pkg-utils build --strict --check --clean",
46
44
  "clean": "rimraf lib",
47
45
  "compile": "tsc --noEmit",
48
46
  "link-watch": "plugin-kit link-watch",
49
47
  "lint": "eslint .",
50
48
  "prepare": "husky install",
51
49
  "prepublishOnly": "npm run compile && npm run build",
52
- "test": "echo 'tests disabled for now'",
53
50
  "test:prod": "npm run lint && npm run test -- --no-cache",
54
51
  "test:watch": "jest --coverage --watch",
55
- "watch": "pkg-utils watch"
52
+ "watch": "pkg-utils watch --strict"
56
53
  },
57
54
  "prettier": {
58
55
  "bracketSpacing": false,
@@ -61,8 +58,8 @@
61
58
  "singleQuote": true
62
59
  },
63
60
  "dependencies": {
64
- "@sanity/incompatible-plugin": "^1.0.4",
65
- "@sanity/ui": "^1.0.0",
61
+ "@sanity/incompatible-plugin": "^1.0.5",
62
+ "@sanity/ui": "^2.16.4",
66
63
  "abort-controller": "^2.0.3",
67
64
  "react-props-stream": "^1.0.1",
68
65
  "rxjs": "^6.6.7"
@@ -72,9 +69,9 @@
72
69
  "@babel/preset-react": "^7.18.6",
73
70
  "@commitlint/cli": "^17.2.0",
74
71
  "@commitlint/config-conventional": "^17.2.0",
75
- "@sanity/dashboard": "^3.0.0",
76
- "@sanity/pkg-utils": "^1.17.2",
77
- "@sanity/plugin-kit": "^2.1.5",
72
+ "@sanity/dashboard": "^4.1.4",
73
+ "@sanity/pkg-utils": "^7.9.3",
74
+ "@sanity/plugin-kit": "^4.0.19",
78
75
  "@sanity/semantic-release-preset": "^2.0.2",
79
76
  "@testing-library/jest-dom": "^5.16.5",
80
77
  "@testing-library/react": "^13.4.0",
@@ -82,7 +79,6 @@
82
79
  "@types/node": "^18.11.9",
83
80
  "@types/react": "^18",
84
81
  "@types/react-dom": "^18",
85
- "@types/styled-components": "^5.1.26",
86
82
  "@typescript-eslint/eslint-plugin": "^5.42.0",
87
83
  "@typescript-eslint/parser": "^5.42.0",
88
84
  "eslint": "^8.26.0",
@@ -102,19 +98,19 @@
102
98
  "react-dom": "^18",
103
99
  "rimraf": "^3.0.2",
104
100
  "sanity": "^3.0.0",
105
- "styled-components": "^5.3.6",
101
+ "styled-components": "^6.1.19",
106
102
  "ts-jest": "^29.0.3",
107
- "typescript": "^4.8.4"
103
+ "typescript": "5.8.3"
108
104
  },
109
105
  "peerDependencies": {
110
- "@sanity/dashboard": "^3.0.0",
111
- "react": "^18",
112
- "react-dom": "^18",
113
- "sanity": "^3.0.0",
114
- "styled-components": "^5.2"
106
+ "@sanity/dashboard": "^4.1.4",
107
+ "react": "^18.3 || ^19",
108
+ "react-dom": "^18.3 || ^19",
109
+ "sanity": "^3 || ^4.0.0-0 || ^5.0.0",
110
+ "styled-components": "^6.1"
115
111
  },
116
112
  "engines": {
117
- "node": ">=14"
113
+ "node": ">=18"
118
114
  },
119
115
  "publishConfig": {
120
116
  "access": "public"
@@ -2,7 +2,7 @@ import React from 'react'
2
2
  import {NetlifyWidgetProps} from '../types'
3
3
  import SiteList from './SiteList'
4
4
  import {DashboardWidgetContainer} from '@sanity/dashboard'
5
- import styled from 'styled-components'
5
+ import {styled} from 'styled-components'
6
6
  import {Button, Flex, Card, Text, Box} from '@sanity/ui'
7
7
 
8
8
  const ContentCard = styled(Card)`
package/lib/index.esm.js DELETED
@@ -1,2 +0,0 @@
1
- var e;function t(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function r(e){for(var r=1;r<arguments.length;r++){var i=null!=arguments[r]?arguments[r]:{};r%2?t(Object(i),!0).forEach((function(t){n(e,t,i[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(i)):t(Object(i)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(i,t))}))}return e}function n(e,t,r){return t in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}import{jsxs as i,jsx as o}from"react/jsx-runtime";import{createEventHandler as a,streamingComponent as c}from"react-props-stream";import{map as s,scan as l,switchMap as d,catchError as p,startWith as u}from"rxjs/operators";import{Observable as m,of as h,merge as f}from"rxjs";import y from"abort-controller";import{useState as g,useCallback as b,useEffect as w,useRef as O}from"react";import{Flex as j,Box as v,Stack as D,Text as P,Card as k,Label as x,Button as I,Spinner as T}from"@sanity/ui";import{DashboardWidgetContainer as H}from"@sanity/dashboard";import E from"styled-components";const L=(e,t)=>new m((n=>{const i="AbortController"in window?new AbortController:new y;return fetch(e,r(r({},t),{},{signal:i.signal})).then((e=>{if(e.status<200||e.status>299)throw new Error("HTTP Error ".concat(e.status,": ").concat(e.statusText));return e.status})).then((e=>{n.next(e),n.complete()}),(e=>{"AbortError"===e.name?n.complete():n.error(e)})),()=>{i.abort()}}));const S=l(((e,t)=>{switch(t.type){case"setSites":return r(r({},e),{},{sites:t.sites||[]});case"deploy/started":return r(r({},e),{},{sites:e.sites.map((e=>t.site&&e.id===t.site.id?r({},e):e))});case"deploy/failed":return r(r({},e),{},{error:t.error});case"deploy/completed":return r(r({},e),{},{sites:e.sites.map((e=>t.site&&e.id===t.site.id?r(r({},e),{},{error:t.error}):e))});default:return e}})),Y={title:"Netlify sites",sites:[],isLoading:!0,onDeploy:()=>{}},_=e=>{const t=(e.sites||[]).map((e=>({id:e.apiId,name:e.name,title:e.title,buildHookId:e.buildHookId,url:e.url||e.branch&&"https://".concat(e.branch,"--").concat(e.name,".netlify.app/")||e.name&&"https://".concat(e.name,".netlify.app/"),adminUrl:e.name&&"https://app.netlify.com/sites/".concat(e.name),branch:e.branch}))),[n,i]=a(),o=h(t).pipe(s((e=>({type:"setSites",sites:e})))),c=n.pipe(s((e=>({type:"deploy/started",site:e})))),l=n.pipe(d((e=>function(e){return e.buildHookId?L("https://api.netlify.com/build_hooks/".concat(e.buildHookId),{method:"POST"}).pipe(s((t=>({result:t,site:e})))):h(new Error("Site missing buildHookId"))}(e)))).pipe(s((e=>r({type:"deploy/completed"},e)),p((e=>h({type:"deploy/failed",error:e})))));return f(o,c,l).pipe(S).subscribe(),h(t).pipe(s((t=>({sites:t,title:e.title||Y.title,description:e.description,isLoading:!1,onDeploy:i}))),u(Y))},z=e=>{const{url:t,children:r}=e;return o("span",{children:o("a",{href:t,target:"_blank",rel:"noreferrer",children:r})})},U=e=>{const{url:t,adminUrl:r}=e;return t&&r?i("span",{children:["(",o(z,{url:t,children:"view"}),", ",o(z,{url:r,children:"admin"}),")"]}):t?o(z,{url:t,children:"(view)"}):r?o(z,{url:r,children:"(admin)"}):null},X=(e,t)=>{const r="https://api.netlify.com/api/v1/badges/".concat(e,"/deploy-status"),n=(new Date).getTime(),i="branch=".concat(t);return t?"".concat(r,"?").concat(n,"&").concat(i):"".concat(r,"?").concat(n)},A=e=>{const[t,r]=g(!1),{site:n,onDeploy:a}=e,{id:c,name:s,title:l,url:d,adminUrl:p,buildHookId:u,branch:m}=n,[h,f]=((e,t)=>{const[r,n]=g((()=>X(e,t))),i=b((()=>n(X(e,t))),[e]);return w((()=>{const e=window.setInterval(i,1e4);return()=>window.clearInterval(e)}),[i]),[r,i]})(c,m),y=((e,t,r)=>{const n=O(-1);return w((()=>()=>window.clearTimeout(n.current)),[]),b((()=>{t(e),n.current=window.setTimeout(r,1e3)}),[e,t,r])})(n,a,f);return i(j,{as:"li",children:[o(v,{flex:1,paddingY:2,paddingX:3,children:i(D,{space:2,children:[i(P,{as:"h4",children:[l||s,o(U,{url:d,adminUrl:p})]}),i(j,{justify:"flex-start",children:[!t&&o("img",{src:h,onError:()=>{r(!0)},alt:"Badge"}),t&&o(k,{tone:"critical",radius:2,padding:2,children:o(x,{size:0,muted:!0,children:"Failed to load badge"})})]})]})}),u?o(v,{paddingY:2,paddingX:3,children:o(I,{mode:"ghost",onClick:y,text:"Deploy"})}):null]})};function C(e){const{isLoading:t,onDeploy:r,sites:n}=e;return t?o(k,{padding:4,children:i(j,{direction:"column",justify:"center",align:"center",children:[o(T,{muted:!0}),o(v,{marginTop:3,children:o(P,{muted:!0,children:"Loading sites…"})})]})}):!n||n&&0===n.length?o(k,{tone:"critical",padding:3,children:o(P,{children:"No sites are defined in the widget options. Please check your config."})}):o(v,{paddingY:2,children:o(D,{as:"ul",space:2,children:n.map(((e,t)=>o(A,{onDeploy:r,site:e},"site-".concat(t))))})})}const N=E(k)(e||(M=["\n min-height: 66px;\n"],B||(B=M.slice(0)),e=Object.freeze(Object.defineProperties(M,{raw:{value:Object.freeze(B)}}))));var M,B;function F(e){const{title:t,description:r,isLoading:n,sites:a,onDeploy:c}=e;return o(H,{header:t,footer:o(j,{direction:"column",align:"stretch",children:o(I,{as:"a",href:n?void 0:"https://app.netlify.com/account/sites",disabled:n,paddingX:2,paddingY:4,mode:"bleed",tone:"primary",text:"Manage sites at Netlify",loading:n,target:"_blank"})}),children:i(N,{paddingY:1,children:[r&&o(v,{paddingY:3,paddingX:3,children:o(P,{as:"p",size:1,muted:!0,children:o("span",{dangerouslySetInnerHTML:{__html:r}})})}),o(C,{isLoading:n,onDeploy:c,sites:a})]})})}var q=c((e=>e.pipe(d((e=>_(e).pipe(s((e=>o(F,r({},e))))))))));function G(e){var t;return{name:"netlify-widget",component:()=>o(q,r({},e)),layout:null!=(t=e.layout)?t:{width:"medium"}}}export{G as netlifyWidget};
2
- //# sourceMappingURL=index.esm.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.esm.js","sources":["../src/http/utils/createAbortController.ts","../src/http/statusCodeRequest.ts","../src/reducers.ts","../src/props.ts","../src/datastores/deploy.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 {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 {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 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":["statusCodeRequest","input","init","Observable","subscriber","controller","window","AbortController","AbortControllerPolyfill","fetch","_objectSpread","signal","then","res","status","Error","concat","statusText","next","complete","err","name","error","abort","stateReducer$","scan","state","action","type","sites","map","site","id","INITIAL_PROPS","title","isLoading","onDeploy","props$","options","configuredSites","apiId","buildHookId","url","branch","adminUrl","onDeploy$","createEventHandler","setSitesAction$","of","pipe","deployAction$","deployCompletedAction$","switchMap","method","result","deploy","catchError","merge","subscribe","description","startWith","Link","props","children","jsx","href","target","rel","Links","jsxs","getImageUrl","siteId","branchName","baseUrl","time","Date","getTime","SiteItem","hasBadgeError","setHasBadgeError","useState","badge","updateBadge","src","setSrc","update","useCallback","useEffect","interval","setInterval","clearInterval","useBadgeImage","handleDeploy","timeoutRef","useRef","clearTimeout","current","setTimeout","useDeploy","Flex","as","Box","flex","paddingY","paddingX","Stack","space","Text","justify","onError","alt","Card","tone","radius","padding","Label","size","muted","Button","mode","onClick","text","SiteList","direction","align","Spinner","marginTop","length","index","ContentCard","styled","_templateObject","NetlifyWidget","DashboardWidgetContainer","header","footer","disabled","loading","dangerouslySetInnerHTML","__html","Widget","streamingComponent","options$","netlifyWidget","config","_a","component","layout","width"],"mappings":"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"}
File without changes