├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .github ├── renovate.json └── workflows │ └── main.yml ├── .gitignore ├── .husky ├── commit-msg └── pre-commit ├── .npmignore ├── .releaserc.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── __mocks__ └── use-hot-module-reload.js ├── babel.config.js ├── commitlint.config.js ├── jest.config.js ├── lint-staged.config.js ├── package-lock.json ├── package.config.ts ├── package.json ├── sanity.json ├── src ├── components │ ├── NetlifyWidget.tsx │ ├── SiteItem │ │ ├── Links.tsx │ │ └── index.tsx │ └── SiteList.tsx ├── datastores │ └── deploy.ts ├── http │ ├── jsonRequest.ts │ ├── statusCodeRequest.ts │ └── utils │ │ └── createAbortController.ts ├── index.ts ├── plugin.tsx ├── props.ts ├── reducers.ts ├── types.ts └── widget.tsx ├── test ├── NetlifyWidget.test.tsx ├── SiteItem.test.tsx ├── Widget.test.tsx ├── __mocks__ │ ├── Anchor.tsx │ ├── DefaultButton.tsx │ ├── Spinner.tsx │ ├── WidgetContainer.tsx │ ├── styleMock.js │ └── undefinedObjectMock.tsx ├── index.test.ts └── setupTests.ts ├── tsconfig.dist.json ├── tsconfig.json ├── tsconfig.settings.json └── v2-incompatible.js /.editorconfig: -------------------------------------------------------------------------------- 1 | ; editorconfig.org 2 | root = true 3 | charset= utf8 4 | 5 | [*] 6 | end_of_line = lf 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | indent_style = space 10 | indent_size = 2 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | .eslintrc.js 2 | commitlint.config.js 3 | lib 4 | lint-staged.config.js 5 | package.config.ts 6 | *.js 7 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "env": { 4 | "node": true, 5 | "browser": true, 6 | "jest": true 7 | }, 8 | "extends": [ 9 | "sanity", 10 | "sanity/typescript", 11 | "sanity/react", 12 | "plugin:react-hooks/recommended", 13 | "plugin:prettier/recommended" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": ["github>sanity-io/renovate-config", "github>sanity-io/renovate-config:studio-v3"] 4 | } 5 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: CI & Release 3 | 4 | # Workflow name based on selected inputs. Fallback to default Github naming when expression evaluates to empty string 5 | run-name: >- 6 | ${{ 7 | inputs.release && inputs.test && 'Build ➤ Test ➤ Publish to NPM' || 8 | inputs.release && !inputs.test && 'Build ➤ Skip Tests ➤ Publish to NPM' || 9 | github.event_name == 'workflow_dispatch' && inputs.test && 'Build ➤ Test' || 10 | github.event_name == 'workflow_dispatch' && !inputs.test && 'Build ➤ Skip Tests' || 11 | '' 12 | }} 13 | 14 | on: 15 | # Build on pushes branches that have a PR (including drafts) 16 | pull_request: 17 | # Build on commits pushed to branches without a PR if it's in the allowlist 18 | push: 19 | branches: [main, studio-v2] 20 | # https://docs.github.com/en/actions/managing-workflow-runs/manually-running-a-workflow 21 | workflow_dispatch: 22 | inputs: 23 | test: 24 | description: Run tests 25 | required: true 26 | default: true 27 | type: boolean 28 | release: 29 | description: Release new version 30 | required: true 31 | default: false 32 | type: boolean 33 | 34 | concurrency: 35 | # On PRs builds will cancel if new pushes happen before the CI completes, as it defines `github.head_ref` and gives it the name of the branch the PR wants to merge into 36 | # Otherwise `github.run_id` ensures that you can quickly merge a queue of PRs without causing tests to auto cancel on any of the commits pushed to main. 37 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} 38 | cancel-in-progress: true 39 | 40 | jobs: 41 | build: 42 | runs-on: ubuntu-latest 43 | name: Lint & Build 44 | steps: 45 | - uses: actions/checkout@v4 46 | - uses: actions/setup-node@v4 47 | with: 48 | cache: npm 49 | node-version: lts/* 50 | - run: npm ci 51 | # Linting can be skipped 52 | - run: npm run lint --if-present 53 | if: github.event.inputs.test != 'false' 54 | # But not the build script, as semantic-release will crash if this command fails so it makes sense to test it early 55 | - run: npm run prepublishOnly --if-present 56 | 57 | test: 58 | needs: build 59 | # The test matrix can be skipped, in case a new release needs to be fast-tracked and tests are already passing on main 60 | if: github.event.inputs.test != 'false' 61 | runs-on: ${{ matrix.os }} 62 | name: Node.js ${{ matrix.node }} / ${{ matrix.os }} 63 | strategy: 64 | # A test failing on windows doesn't mean it'll fail on macos. It's useful to let all tests run to its completion to get the full picture 65 | fail-fast: false 66 | matrix: 67 | # Run the testing suite on each major OS with the latest LTS release of Node.js 68 | os: [macos-latest, ubuntu-latest, windows-latest] 69 | node: [lts/*] 70 | # It makes sense to also test the oldest, and latest, versions of Node.js, on ubuntu-only since it's the fastest CI runner 71 | include: 72 | - os: ubuntu-latest 73 | # Test the oldest LTS release of Node that's still receiving bugfixes and security patches, versions older than that have reached End-of-Life 74 | node: lts/-2 75 | - os: ubuntu-latest 76 | # Test the actively developed version that will become the latest LTS release next October 77 | node: current 78 | steps: 79 | # It's only necessary to do this for windows, as mac and ubuntu are sane OS's that already use LF 80 | - name: Set git to use LF 81 | if: matrix.os == 'windows-latest' 82 | run: | 83 | git config --global core.autocrlf false 84 | git config --global core.eol lf 85 | - uses: actions/checkout@v4 86 | - uses: actions/setup-node@v4 87 | with: 88 | cache: npm 89 | node-version: ${{ matrix.node }} 90 | - run: npm i 91 | - run: npm test --if-present 92 | 93 | release: 94 | needs: [build, test] 95 | # only run if opt-in during workflow_dispatch 96 | if: always() && github.event.inputs.release == 'true' && needs.build.result != 'failure' && needs.test.result != 'failure' && needs.test.result != 'cancelled' 97 | runs-on: ubuntu-latest 98 | name: Semantic release 99 | steps: 100 | - uses: actions/create-github-app-token@v2 101 | id: app-token 102 | with: 103 | app-id: ${{ secrets.ECOSPARK_APP_ID }} 104 | private-key: ${{ secrets.ECOSPARK_APP_PRIVATE_KEY }} 105 | - uses: actions/checkout@v4 106 | with: 107 | # Need to fetch entire commit history to 108 | # analyze every commit since last release 109 | fetch-depth: 0 110 | # Uses generated token to allow pushing commits back 111 | token: ${{ steps.app-token.outputs.token }} 112 | # Make sure the value of GITHUB_TOKEN will not be persisted in repo's config 113 | persist-credentials: false 114 | - uses: actions/setup-node@v4 115 | with: 116 | cache: npm 117 | node-version: lts/* 118 | - run: npm ci 119 | # Branches that will release new versions are defined in .releaserc.json 120 | - run: npx semantic-release 121 | env: 122 | GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} 123 | NPM_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }} 124 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | 39 | # macOS finder cache file 40 | .DS_Store 41 | 42 | # VS Code settings 43 | .vscode 44 | 45 | # IntelliJ 46 | .idea 47 | *.iml 48 | 49 | # Cache 50 | .cache 51 | 52 | # Yalc 53 | .yalc 54 | yalc.lock 55 | 56 | ##npm package zips 57 | *.tgz 58 | 59 | # Compiled plugin 60 | lib 61 | 62 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx --no -- commitlint --edit "" 5 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx lint-staged 5 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /test 2 | /coverage 3 | .editorconfig 4 | .eslintrc 5 | .gitignore 6 | .github 7 | .prettierrc 8 | .travis.yml 9 | .nyc_output 10 | -------------------------------------------------------------------------------- /.releaserc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@sanity/semantic-release-preset", 3 | "branches": ["main", {"name": "v3", "channel": "studio-v3", "prerelease": "v3-studio"}] 4 | } 5 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 📓 Changelog 4 | 5 | All notable changes to this project will be documented in this file. See 6 | [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 7 | 8 | ## [2.0.2](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/compare/v2.0.1...v2.0.2) (2025-07-10) 9 | 10 | ### Bug Fixes 11 | 12 | - **deps:** allow studio v4 peer dep ranges ([c27d307](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/commit/c27d3070aa798b6b9ae491cdc878d5cf59618b2d)) 13 | - **deps:** update peer dependencies to include styled components v6 and @sanity/dashboard v4 ([#87](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/issues/87)) ([b83e1af](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/commit/b83e1afd8f0e536eb847a2daa363ef45e0e995d9)) 14 | 15 | ## [2.0.1](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/compare/v2.0.0...v2.0.1) (2022-11-25) 16 | 17 | ### Bug Fixes 18 | 19 | - **deps:** sanity ^3.0.0 (works with rc.3) ([e1c00cd](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/commit/e1c00cd161a42184480c34a9a4aa5f1e949d9edf)) 20 | 21 | ## [2.0.0](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/compare/v1.3.1...v2.0.0) (2022-11-17) 22 | 23 | ### ⚠ BREAKING CHANGES 24 | 25 | - this version does not work in Sanity Studio v2 26 | - initial V3 version 27 | 28 | ### Features 29 | 30 | - initial Sanity Studio v3 release ([5f515bb](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/commit/5f515bbb29beda3bef75ab599fcc73a51d0d447b)) 31 | - initial V3 version ([9b6dd57](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/commit/9b6dd57bafecc4e0fae2cfeb6ec2f042b21226d8)) 32 | 33 | ### Bug Fixes 34 | 35 | - compiled for sanity 3.0.0-rc.0 ([5cdbed7](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/commit/5cdbed7784fbbc40baf535aa06dbe10d08755838)) 36 | - **deps:** dev-preview.21 ([13bcbd5](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/commit/13bcbd5f5580704fb6fd1efb9e492bc518c86c53)) 37 | - **deps:** dev-preview.22 ([91ba4ea](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/commit/91ba4eaf77c537b715d1e52ed1d17d1f3322c546)) 38 | - **deps:** pkg-utils & @sanity/plugin-kit ([5395a97](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/commit/5395a975aa527079110525d85484c86159bc2cd4)) 39 | - **deps:** sanity 3.0.0-dev-preview.17 and sanity/ui 0.38 ([eb19284](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/commit/eb192845f14ba8b8953e154596422cca0c8a3c4c)) 40 | - **deps:** update dependencies (non-major) ([#41](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/issues/41)) ([8e1b4fc](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/commit/8e1b4fcd2cc0ac925148a1351adc34821346c871)) 41 | - use correct `peerDependencies` semver on prereleases ([7b81060](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/commit/7b810606a547e5612bb33c09f957a7e5dc8c3142)) 42 | 43 | ## [2.0.0-v3-studio.7](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/compare/v2.0.0-v3-studio.6...v2.0.0-v3-studio.7) (2022-11-04) 44 | 45 | ### Bug Fixes 46 | 47 | - **deps:** pkg-utils & @sanity/plugin-kit ([5395a97](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/commit/5395a975aa527079110525d85484c86159bc2cd4)) 48 | 49 | ## [2.0.0-v3-studio.6](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/compare/v2.0.0-v3-studio.5...v2.0.0-v3-studio.6) (2022-11-04) 50 | 51 | ### Bug Fixes 52 | 53 | - **deps:** update dependencies (non-major) ([#41](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/issues/41)) ([8e1b4fc](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/commit/8e1b4fcd2cc0ac925148a1351adc34821346c871)) 54 | - use correct `peerDependencies` semver on prereleases ([7b81060](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/commit/7b810606a547e5612bb33c09f957a7e5dc8c3142)) 55 | 56 | ## [2.0.0-v3-studio.5](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/compare/v2.0.0-v3-studio.4...v2.0.0-v3-studio.5) (2022-11-03) 57 | 58 | ### Bug Fixes 59 | 60 | - compiled for sanity 3.0.0-rc.0 ([5cdbed7](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/commit/5cdbed7784fbbc40baf535aa06dbe10d08755838)) 61 | 62 | ## [2.0.0-v3-studio.4](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/compare/v2.0.0-v3-studio.3...v2.0.0-v3-studio.4) (2022-10-27) 63 | 64 | ### Bug Fixes 65 | 66 | - **deps:** dev-preview.22 ([91ba4ea](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/commit/91ba4eaf77c537b715d1e52ed1d17d1f3322c546)) 67 | 68 | ## [2.0.0-v3-studio.3](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/compare/v2.0.0-v3-studio.2...v2.0.0-v3-studio.3) (2022-10-07) 69 | 70 | ### Bug Fixes 71 | 72 | - **deps:** dev-preview.21 ([13bcbd5](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/commit/13bcbd5f5580704fb6fd1efb9e492bc518c86c53)) 73 | 74 | ## [2.0.0-v3-studio.2](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/compare/v2.0.0-v3-studio.1...v2.0.0-v3-studio.2) (2022-09-15) 75 | 76 | ### Bug Fixes 77 | 78 | - **deps:** sanity 3.0.0-dev-preview.17 and sanity/ui 0.38 ([eb19284](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/commit/eb192845f14ba8b8953e154596422cca0c8a3c4c)) 79 | 80 | ## [2.0.0-v3-studio.1](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/compare/v1.3.0...v2.0.0-v3-studio.1) (2022-09-02) 81 | 82 | ### ⚠ BREAKING CHANGES 83 | 84 | - initial V3 version 85 | 86 | ### Features 87 | 88 | - initial V3 version ([9b6dd57](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/commit/9b6dd57bafecc4e0fae2cfeb6ec2f042b21226d8)) 89 | 90 | ### Bug Fixes 91 | 92 | - **ci:** semver automation ([a474e7f](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/commit/a474e7f9ba0e7ea005fa53dd8b2c8e674dc03a39)) 93 | - compile errors ([32b4546](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/commit/32b45460d1f71c74dc4a40ed6af1d8a839b5423f)) 94 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Sanity.io 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sanity Dashboard Widget: Netlify 2 | 3 | >This is a **Sanity Studio v3** plugin. 4 | > For the v2 version, please refer to the [v2-branch](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/tree/studio-v2). 5 | 6 | Sanity Studio Dashboard Widget for triggering Netlify builds. 7 | 8 | ## Install 9 | 10 | ``` 11 | npm install --save sanity-plugin-dashboard-widget-netlify 12 | ``` 13 | 14 | or 15 | 16 | ``` 17 | yarn add sanity-plugin-dashboard-widget-netlify 18 | ``` 19 | 20 | Ensure that you have followed install and usage instructions for [@sanity/dashboard](https://github.com/sanity-io/dashboard). 21 | 22 | ## Usage 23 | 24 | Add it as a widget to @sanity/dashboard plugin in sanity.config.ts (or .js): 25 | 26 | ```js 27 | import { dashboardTool } from "@sanity/dashboard"; 28 | import { netlifyWidget } from "sanity-plugin-dashboard-widget-netlify"; 29 | 30 | export default defineConfig({ 31 | // ... 32 | plugins: [ 33 | dashboardTool({ 34 | widgets: [ 35 | netlifyWidget({ 36 | title: 'My Netlify deploys', 37 | sites: [ 38 | { 39 | title: 'Sanity Studio', 40 | apiId: 'xxxxx-yyyy-zzzz-xxxx-yyyyyyyy', 41 | buildHookId: 'xxxyyyxxxyyyyxxxyyy', 42 | name: 'sanity-gatsby-blog-20-studio', 43 | }, 44 | { 45 | title: 'Website', 46 | apiId: 'yyyyy-xxxxx-zzzz-xxxx-yyyyyyyy', 47 | buildHookId: 'yyyyxxxxxyyyxxdxxx', 48 | name: 'sanity-gatsby-blog-20-web', 49 | url: 'https://my-sanity-deployment.com', 50 | } 51 | ] 52 | }) 53 | ] 54 | }) 55 | ] 56 | }) 57 | ``` 58 | 59 | ### Widget options 60 | `title` - Override the widget default title 61 | 62 | `sites[]` - Your Netlify sites to show deploys for 63 | - `apiId`- The Netfliy API ID of your site (see *Site Settings > General > Site Details > Site Information -> API ID*). 64 | - `buildHookId` - The id of a build hook you have created for your site within the Netlify administration panel (see *Site Settings > Build & Deploy > Continuous Deployment -> Build Hooks*). 65 | - `name` - The Netlify site name 66 | - `title` - Override the site name with a custom title 67 | - `url` - Optionally override site deployment url. By default it is inferred to be `https://netlify-site-name.netlify.app`. 68 | - `branch` - Optionally pass the name of a branch to deploy 69 | 70 | ## License 71 | 72 | MIT-licensed. See LICENSE. 73 | 74 | ## Develop & test 75 | 76 | This plugin uses [@sanity/plugin-kit](https://github.com/sanity-io/plugin-kit) 77 | with default configuration for build & watch scripts. 78 | 79 | See [Testing a plugin in Sanity Studio](https://github.com/sanity-io/plugin-kit#testing-a-plugin-in-sanity-studio) 80 | on how to run this plugin with hotreload in the studio. 81 | 82 | ### Release new version 83 | 84 | Run ["CI & Release" workflow](https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/actions/workflows/main.yml). 85 | Make sure to select the main branch and check "Release new version". 86 | 87 | Semantic release will only release on configured branches, so it is safe to run release on any branch. 88 | -------------------------------------------------------------------------------- /__mocks__/use-hot-module-reload.js: -------------------------------------------------------------------------------- 1 | export {} 2 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | // used only by jest, .parcelrc configured to ignore this file 2 | module.exports = { 3 | presets: [ 4 | '@babel/preset-env', 5 | [ 6 | '@babel/preset-react', 7 | { 8 | runtime: 'automatic', 9 | }, 10 | ], 11 | ], 12 | } 13 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@commitlint/config-conventional'], 3 | } 4 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | testEnvironment: 'jsdom', 4 | testRegex: '(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$', 5 | coveragePathIgnorePatterns: ['/node_modules/', '/test/'], 6 | testPathIgnorePatterns: ['.yalc', 'node_modules', '.idea', 'lib', '.parcel-cache'], 7 | collectCoverageFrom: ['src/*.{js,ts}'], 8 | transformIgnorePatterns: ['node_modules/(?!(nanoid|uuid|get-random-values-esm))'], 9 | moduleDirectories: ['node_modules', 'node_modules/sanity/node_modules', 'src'], 10 | setupFilesAfterEnv: ['/test/setupTests.ts'], 11 | transform: { 12 | '^.+\\.(ts|tsx)?$': 'ts-jest', 13 | '^.+\\.(mjs|js|jsx)$': 'babel-jest', 14 | }, 15 | globals: { 16 | 'ts-jest': { 17 | babelConfig: true, 18 | }, 19 | }, 20 | } 21 | -------------------------------------------------------------------------------- /lint-staged.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | '**/*.{js,jsx}': ['eslint'], 3 | '**/*.{ts,tsx}': ['eslint', () => 'tsc --noEmit'], 4 | } 5 | -------------------------------------------------------------------------------- /package.config.ts: -------------------------------------------------------------------------------- 1 | import {defineConfig} from '@sanity/pkg-utils' 2 | 3 | export default defineConfig({ 4 | extract: { 5 | rules: { 6 | 'ae-incompatible-release-tags': 'off', 7 | 'ae-internal-missing-underscore': 'off', 8 | 'ae-missing-release-tag': 'off', 9 | }, 10 | }, 11 | tsconfig: 'tsconfig.dist.json', 12 | }) 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sanity-plugin-dashboard-widget-netlify", 3 | "version": "2.0.2", 4 | "description": "Sanity Studio Dashboard Widget for triggering Netlify builds", 5 | "keywords": [ 6 | "sanity", 7 | "plugin", 8 | "dashboard", 9 | "widget", 10 | "netlify" 11 | ], 12 | "homepage": "https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify#readme", 13 | "bugs": { 14 | "url": "https://github.com/sanity-io/sanity-plugin-dashboard-widget-netlify/issues" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "git@github.com:sanity-io/sanity-plugin-dashboard-widget-netlify.git" 19 | }, 20 | "license": "MIT", 21 | "author": "Sanity.io ", 22 | "type": "commonjs", 23 | "exports": { 24 | ".": { 25 | "source": "./src/index.ts", 26 | "import": "./lib/index.mjs", 27 | "require": "./lib/index.js", 28 | "default": "./lib/index.js" 29 | }, 30 | "./package.json": "./package.json" 31 | }, 32 | "main": "./lib/index.js", 33 | "module": "./lib/index.mjs", 34 | "types": "./lib/index.d.ts", 35 | "files": [ 36 | "src", 37 | "lib", 38 | "v2-incompatible.js", 39 | "sanity.json" 40 | ], 41 | "scripts": { 42 | "__test": "jest --coverage", 43 | "build": "plugin-kit verify-package --silent && pkg-utils build --strict --check --clean", 44 | "clean": "rimraf lib", 45 | "compile": "tsc --noEmit", 46 | "link-watch": "plugin-kit link-watch", 47 | "lint": "eslint .", 48 | "prepare": "husky install", 49 | "prepublishOnly": "npm run compile && npm run build", 50 | "test:prod": "npm run lint && npm run test -- --no-cache", 51 | "test:watch": "jest --coverage --watch", 52 | "watch": "pkg-utils watch --strict" 53 | }, 54 | "prettier": { 55 | "bracketSpacing": false, 56 | "printWidth": 100, 57 | "semi": false, 58 | "singleQuote": true 59 | }, 60 | "dependencies": { 61 | "@sanity/incompatible-plugin": "^1.0.5", 62 | "@sanity/ui": "^2.16.4", 63 | "abort-controller": "^2.0.3", 64 | "react-props-stream": "^1.0.1", 65 | "rxjs": "^6.6.7" 66 | }, 67 | "devDependencies": { 68 | "@babel/preset-env": "^7.19.4", 69 | "@babel/preset-react": "^7.18.6", 70 | "@commitlint/cli": "^17.2.0", 71 | "@commitlint/config-conventional": "^17.2.0", 72 | "@sanity/dashboard": "^4.1.4", 73 | "@sanity/pkg-utils": "^7.9.3", 74 | "@sanity/plugin-kit": "^4.0.19", 75 | "@sanity/semantic-release-preset": "^2.0.2", 76 | "@testing-library/jest-dom": "^5.16.5", 77 | "@testing-library/react": "^13.4.0", 78 | "@types/jest": "^29.2.1", 79 | "@types/node": "^18.11.9", 80 | "@types/react": "^18", 81 | "@types/react-dom": "^18", 82 | "@typescript-eslint/eslint-plugin": "^5.42.0", 83 | "@typescript-eslint/parser": "^5.42.0", 84 | "eslint": "^8.26.0", 85 | "eslint-config-prettier": "^8.5.0", 86 | "eslint-config-sanity": "^6.0.0", 87 | "eslint-plugin-prettier": "^4.2.1", 88 | "eslint-plugin-react": "^7.31.10", 89 | "eslint-plugin-react-hooks": "^4.6.0", 90 | "husky": "^8.0.1", 91 | "jest": "^29.2.2", 92 | "jest-date-mock": "^1.0.8", 93 | "jest-environment-jsdom": "^29.2.2", 94 | "lint-staged": "^13.0.3", 95 | "prettier": "^2.7.1", 96 | "prettier-plugin-packagejson": "^2.3.0", 97 | "react": "^18", 98 | "react-dom": "^18", 99 | "rimraf": "^3.0.2", 100 | "sanity": "^3.0.0", 101 | "styled-components": "^6.1.19", 102 | "ts-jest": "^29.0.3", 103 | "typescript": "5.8.3" 104 | }, 105 | "peerDependencies": { 106 | "@sanity/dashboard": "^4.1.4", 107 | "react": "^18.3 || ^19", 108 | "react-dom": "^18.3 || ^19", 109 | "sanity": "^3 || ^4.0.0-0", 110 | "styled-components": "^6.1" 111 | }, 112 | "engines": { 113 | "node": ">=18" 114 | }, 115 | "publishConfig": { 116 | "access": "public" 117 | }, 118 | "sanityPlugin": { 119 | "verifyPackage": { 120 | "babelConfig": false 121 | } 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /sanity.json: -------------------------------------------------------------------------------- 1 | { 2 | "parts": [ 3 | { 4 | "implements": "part:@sanity/base/sanity-root", 5 | "path": "./v2-incompatible.js" 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /src/components/NetlifyWidget.tsx: -------------------------------------------------------------------------------- 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 | 18 | 8 | ) 9 | } 10 | -------------------------------------------------------------------------------- /test/__mocks__/Spinner.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export default function Spinner() { 4 | return
Spinner...
5 | } 6 | -------------------------------------------------------------------------------- /test/__mocks__/WidgetContainer.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export default function WidgetContainer() { 4 | return
WidgetContainer
5 | } 6 | -------------------------------------------------------------------------------- /test/__mocks__/styleMock.js: -------------------------------------------------------------------------------- 1 | module.exports = {} 2 | -------------------------------------------------------------------------------- /test/__mocks__/undefinedObjectMock.tsx: -------------------------------------------------------------------------------- 1 | export default undefined 2 | -------------------------------------------------------------------------------- /test/index.test.ts: -------------------------------------------------------------------------------- 1 | import {netlifyWidget} from '../src' 2 | const instance = netlifyWidget({ 3 | sites: [], 4 | }) 5 | 6 | describe('index', () => { 7 | it('has a name', () => { 8 | expect(instance.name).toBe('netlify-widget') 9 | }) 10 | it('has a component', () => { 11 | expect(instance.component).toBeTruthy() 12 | }) 13 | it('has a layout', () => { 14 | expect(instance.layout).toEqual({width: 'medium'}) 15 | }) 16 | }) 17 | -------------------------------------------------------------------------------- /test/setupTests.ts: -------------------------------------------------------------------------------- 1 | // @ts-expect-error workaround for nanoid 2 | window.crypto = { 3 | getRandomValues(buffer) { 4 | // eslint-disable-next-line no-sync 5 | return require('crypto').randomFillSync(buffer) 6 | }, 7 | } 8 | 9 | export {} 10 | -------------------------------------------------------------------------------- /tsconfig.dist.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.settings", 3 | "include": ["./src"], 4 | "exclude": [ 5 | "./src/**/__fixtures__", 6 | "./src/**/__mocks__", 7 | "./src/**/__workshop__", 8 | "./src/**/*.test.ts", 9 | "./src/**/*.test.tsx" 10 | ], 11 | "compilerOptions": { 12 | "rootDir": ".", 13 | "outDir": "./dist", 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.settings", 3 | "include": [ 4 | "./package.config.ts", 5 | "./src", 6 | ], 7 | "compilerOptions": { 8 | "rootDir": ".", 9 | "noEmit": true 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /tsconfig.settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "Preserve", 5 | "moduleDetection": "force", 6 | "allowSyntheticDefaultImports": true, 7 | "jsx": "preserve", 8 | "outDir": "./lib", 9 | "noEmit": true, 10 | 11 | // Strict type-checking 12 | "strict": true, 13 | "noImplicitAny": true, 14 | "strictNullChecks": true, 15 | "strictFunctionTypes": true, 16 | "strictPropertyInitialization": true, 17 | "noImplicitThis": true, 18 | "alwaysStrict": true, 19 | 20 | // Additional checks 21 | "noUnusedLocals": true, 22 | "noUnusedParameters": true, 23 | "noImplicitReturns": true, 24 | "noFallthroughCasesInSwitch": true, 25 | "skipLibCheck": true 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /v2-incompatible.js: -------------------------------------------------------------------------------- 1 | const {showIncompatiblePluginDialog} = require('@sanity/incompatible-plugin') 2 | const {name, version, sanityExchangeUrl} = require('./package.json') 3 | 4 | export default showIncompatiblePluginDialog({ 5 | name: name, 6 | versions: { 7 | v3: version, 8 | v2: '^1.3.1', 9 | }, 10 | sanityExchangeUrl, 11 | }) 12 | --------------------------------------------------------------------------------