├── .env.example ├── .gitignore ├── README.md ├── config.js ├── docker-compose.yaml ├── package-lock.json ├── package.json └── src ├── directus-extension-publish-netlify-endpoint └── index.js └── directus-extension-publish-netlify-module ├── api.js ├── components ├── deploys.vue ├── dialog.vue ├── error.vue ├── message.vue └── site.vue ├── index.js └── routes ├── build.vue └── settings.vue /.env.example: -------------------------------------------------------------------------------- 1 | NETLIFY_SITE=netlify_site_id 2 | NETLIFY_TOKEN=netlify_personal_access_token -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | .env 4 | .DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Directus Extension: directus-extension-publish-netlify 3 | 4 | A Directus v10+ Extension (including a frontend app module and backend API endpoints) for managing builds and deploys of a Netlify site. 5 | 6 | ![Main Module Interface](https://user-images.githubusercontent.com/7526014/137394029-05ac81cb-d985-4e47-8e8a-56a9e75dda6d.png) 7 | 8 | ## Use Case 9 | 10 | This was developed to make it easier for an admin user of the Directus app to start a build of a static site generator (such as gatsby, gridsome, etc) on Netlify after data in Directus has been updated. The extension will keep track of when the site was last updated and if there have been any data updates in Directus since the last update. The user can start a new Netlify build and manage the published deploy directly from within Directus. 11 | 12 | ## Installation 13 | 14 | View the [Directus Docs](https://docs.directus.io/extensions/installing-extensions.html) for the most up to date information on installing extensions. 15 | 16 | ## Configuration 17 | 18 | Some advanced configuration options can be set in the `config.js` file before the extension is built and deployed: 19 | 20 | ```js 21 | module.exports = { 22 | "extension": "dwaring87-publish-netlify", 23 | "activityFilter": { 24 | "action": { 25 | "_nin": ["login", "comment"] 26 | }, 27 | "collection": { 28 | "_nin": ["directus_dashboards", "directus_folders", "directus_migrations", "directus_panels", "directus_permissions", "directus_sessions", "directus_settings", "directus_webhooks"] 29 | } 30 | }, 31 | "additional_role_ids": ["bdc0ea73-1b18-4a2a-a2dd-dc5c6d139810"], 32 | "deploy_history_count": 25, 33 | "extension_path_env_var": "DIRECTUS_EXTENSIONS_PATH" 34 | } 35 | ``` 36 | 37 | ### Activity Filter 38 | 39 | The `activityFilter` object is passed to the `GET` `/activity` Directus API endpoint when determining the ID of the last activity item to compare to the stored activity ID associated with the most recent Netlify build. When the ID of the last activity item is greater than the stored activity ID of the most recent Netlify build, the module will indicate that updates are available (ie, data in the database has been updated since the last build). 40 | 41 | By default, the module will exclude any login and comment activity, as well as any changes to most of the internal Directus tables. You can modify the `activityFilter` to include additional tables to exclude when checking if an update is suggested. 42 | 43 | ### Enabled Roles 44 | 45 | By default, the module is available in the Directus app to any user associated with a Directus role that has **Admin Access** enabled. If you want to enable the module for non-admin roles: 46 | 47 | - Add the **Role ID** to the `additional_role_ids` array 48 | - You need to add the _ID_ of the role and _not_ the name. You can get the ID from the `directus_roles` table or from the URL of the Role Settings page (ie, `/admin/settings/roles/{id}`). 49 | - Ensure the role has **full read access** to the **Directus Activity** table. 50 | - The module checks the activity table to see if there has been a data change since the most recent Netlify build 51 | - By default, roles with _App Access_ have limited read access to the activity table (filtered to include only activity of their own account) 52 | - Without full read access, the module will not indicate that updates are available if changes were made by another user 53 | - Rebuild and Redeploy the extension 54 | - Restart Directus 55 | 56 | ### Deploy History 57 | 58 | By default, the module will display the last 25 Netlify builds in the Deploys table. You can modify the `deploy_history_count` property to change the max number of deploys displayed. 59 | 60 | ## Usage 61 | 62 | ### Setup 63 | 64 | There are two environment variables that can be set before the extension can be used: 65 | 66 | - **`NETLIFY_SITE`:** the name of the Netlify site (the part before `.netlify.app`) to manage with the extension 67 | - **`NETLIFY_TOKEN`:** a Netlify personal access token used to interact with the Netlify API (User Settings -> Applications -> Personal access tokens -> New access token) 68 | 69 | If either of these environment variables are missing, the variables can be set in the extension settings. 70 | 71 | ### Enable 72 | 73 | The custom module will need to be first enabled in the Directus app's settings. Go to the **Settings** module, **Project Settings** page, and enable the *Publish, /directus-extension-publish-netlify* module in the **Modules** section. 74 | 75 | ### Build 76 | 77 | To build a site, go to the module's Build Site page. This will display basic information about the configured Netlify site, including information on its published deploy. To start a build, just click the Build button. This will trigger a build on Netlify and its status will be monitored within Directus. 78 | 79 | If auto-publishing is enabled, the new deploy will be published (if the build is successful). When auto-publishing is disabled, a new build will be created but not published. When the build is complete, you can preview the build by viewing the specific deploy and then choose to publish the new deploy. 80 | 81 | ![Build Running](https://user-images.githubusercontent.com/7526014/137395847-edccced9-0459-4a0e-bb61-7eda7eda604e.png) 82 | 83 | The Deploys table lists the 25 most recent deploys for the site. Each deploy can be viewed and chosen as the new published deploy. 84 | 85 | ![Deploys Table](https://user-images.githubusercontent.com/7526014/137396368-d55441ad-da1a-4904-b191-ca1a616082da.png) 86 | -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | "extension": "directus-extension-publish-netlify", 3 | "activityFilter": { 4 | "action": { 5 | "_nin": ["login", "comment"] 6 | }, 7 | "collection": { 8 | "_nin": ["directus_dashboards", "directus_folders", "directus_migrations", "directus_panels", "directus_permissions", "directus_sessions", "directus_settings", "directus_webhooks"] 9 | } 10 | }, 11 | "additional_role_ids": [], 12 | "deploy_history_count": 25 13 | } -------------------------------------------------------------------------------- /docker-compose.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | directus: 3 | image: directus/directus 4 | ports: 5 | - 8055:8055 6 | volumes: 7 | - ./:/directus/extensions/directus-extension-publish-netlify 8 | environment: 9 | KEY: directus_key 10 | SECRET: directus_secret 11 | ADMIN_EMAIL: admin@admin.com 12 | ADMIN_PASSWORD: admin 13 | PUBLIC_URL: "http://localhost:8055" 14 | EXTENSIONS_AUTO_RELOAD: true 15 | NETLIFY_SITE: ${NETLIFY_SITE} 16 | NETLIFY_TOKEN: ${NETLIFY_TOKEN} 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "directus-extension-publish-netlify", 3 | "description": "A Directus extension that can be used to manage and run Netlify builds of your static site after updating your content in Directus", 4 | "icon": "extension", 5 | "version": "2.1.0", 6 | "keywords": [ 7 | "directus", 8 | "directus-extension", 9 | "directus-extension-bundle", 10 | "netlify", 11 | "static-site-generator" 12 | ], 13 | "type": "module", 14 | "files": [ 15 | "dist" 16 | ], 17 | "directus:extension": { 18 | "type": "bundle", 19 | "partial": false, 20 | "path": { 21 | "app": "dist/app.js", 22 | "api": "dist/api.js" 23 | }, 24 | "entries": [ 25 | { 26 | "type": "endpoint", 27 | "name": "directus-extension-publish-netlify-endpoint", 28 | "source": "src/directus-extension-publish-netlify-endpoint/index.js" 29 | }, 30 | { 31 | "type": "module", 32 | "name": "directus-extension-publish-netlify-module", 33 | "source": "src/directus-extension-publish-netlify-module/index.js" 34 | } 35 | ], 36 | "host": "^10.10.0", 37 | "sandbox": { 38 | "enabled": true, 39 | "requestedScopes": { 40 | "request": { 41 | "methods": [ 42 | "GET", 43 | "POST" 44 | ], 45 | "urls": [ 46 | "https://api.netlify.com/*" 47 | ] 48 | } 49 | } 50 | } 51 | }, 52 | "scripts": { 53 | "build": "directus-extension build", 54 | "dev": "directus-extension build -w --no-minify", 55 | "link": "directus-extension link", 56 | "add": "directus-extension add" 57 | }, 58 | "devDependencies": { 59 | "@directus/extensions-sdk": "12.0.2", 60 | "vue": "^3.5.8" 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/directus-extension-publish-netlify-endpoint/index.js: -------------------------------------------------------------------------------- 1 | import https from 'https'; 2 | import { existsSync, readFileSync, writeFileSync } from 'fs'; 3 | import { fileURLToPath } from 'url'; 4 | import config from '../../config'; 5 | 6 | // EXTENSION SETTINGS FILE 7 | const FILE = "settings.json"; 8 | const PATH = fileURLToPath(new URL(FILE, import.meta.url)); 9 | 10 | // NETLIFY SETTINGS 11 | let NETLIFY_SITE; 12 | let NETLIFY_TOKEN; 13 | let NETLIFY_SOURCE; 14 | 15 | // Read the Settings file and set NETLIFY_SOURCE and NETLIFY_TOKEN, 16 | // if the settings source is set to 'file' 17 | const _readSettings = () => { 18 | try { 19 | if ( existsSync(PATH) ) { 20 | const data = readFileSync(PATH, 'utf-8'); 21 | const parsed = JSON.parse(data) || {}; 22 | if ( NETLIFY_SOURCE === 'file' ) { 23 | NETLIFY_SITE = parsed.netlify_site; 24 | NETLIFY_TOKEN = parsed.netlify_token; 25 | } 26 | } 27 | } 28 | catch (err) { 29 | console.log(`ERROR: Could not read extension settings [${err}]`); 30 | } 31 | } 32 | 33 | // Write the settings to the settings file 34 | const _writeSettings = (netlify_site, netlify_token) => { 35 | try { 36 | netlify_token = netlify_token.includes('*') ? NETLIFY_TOKEN : netlify_token; 37 | const s = JSON.stringify({ netlify_site, netlify_token }); 38 | writeFileSync(PATH, s, 'utf-8'); 39 | } 40 | catch (err) { 41 | console.log(`ERROR: Could not write extension settings [${err}]`); 42 | } 43 | } 44 | 45 | export default { 46 | id: config.extension, 47 | handler: async (router, { env }) => { 48 | 49 | // Pull settings from environment variables 50 | if ( env.NETLIFY_SITE && env.NETLIFY_TOKEN ) { 51 | NETLIFY_SITE = env.NETLIFY_SITE; 52 | NETLIFY_TOKEN = env.NETLIFY_TOKEN; 53 | NETLIFY_SOURCE = "environment"; 54 | } 55 | 56 | // Pull settings from extension settings file 57 | else { 58 | NETLIFY_SOURCE = "file"; 59 | _readSettings(); 60 | } 61 | 62 | 63 | // Cached Netlify Site ID (used by other API requests) 64 | let NETLIFY_SITE_ID = undefined; 65 | 66 | 67 | // 68 | // CUSTOM ENDPOINTS 69 | // 70 | 71 | 72 | /** 73 | * GET /settings 74 | * Get the extension settings 75 | */ 76 | router.get('/settings', _checkAuth, async (req, res) => { 77 | let masked_token; 78 | if ( NETLIFY_TOKEN ) { 79 | const start = 8; 80 | const end = 4; 81 | if ( NETLIFY_TOKEN.length > start+end ) { 82 | masked_token = NETLIFY_TOKEN.slice(0, start); 83 | masked_token += "*".repeat(NETLIFY_TOKEN.length-start-end); 84 | masked_token += NETLIFY_TOKEN.slice(NETLIFY_TOKEN.length-end); 85 | } 86 | else { 87 | masked_token = NETLIFY_TOKEN; 88 | } 89 | } 90 | 91 | return res.send({ 92 | settings: { 93 | site: NETLIFY_SITE, 94 | token: masked_token, 95 | source: NETLIFY_SOURCE 96 | } 97 | }); 98 | }); 99 | 100 | 101 | /** 102 | * POST /settings 103 | * Update the saved netlify_site and netlify_token settings 104 | */ 105 | router.post('/settings', _checkAuth, async (req, res) => { 106 | const { netlify_site, netlify_token } = req.body || {}; 107 | _writeSettings(netlify_site, netlify_token); 108 | _readSettings(); 109 | return res.send(); 110 | }); 111 | 112 | 113 | /** 114 | * GET /site 115 | * Get the info for the configured Netlify site 116 | */ 117 | router.get('/site', _checkAuth, async (req, res) => { 118 | if ( !NETLIFY_SITE || NETLIFY_SITE === "" ) { 119 | return res.send({ error: "NETLIFY_SITE not set. Go to the Extension Settings to set the Netlify Site ID." }); 120 | } 121 | if ( !NETLIFY_TOKEN || NETLIFY_TOKEN === "" ) { 122 | return res.send({ error: "NETLIFY_TOKEN not set. Go to the Extension Settings to set the Netlify API token." }); 123 | } 124 | 125 | try { 126 | const site = await _netlify_get_site(); 127 | return res.send({ site }); 128 | } 129 | catch (error) { 130 | return res.send({ error: error.message }); 131 | } 132 | }); 133 | 134 | 135 | /** 136 | * GET /deploys 137 | * Get the deploys for the configured Netlify site 138 | */ 139 | router.get('/deploys', _checkAuth, async (req, res) => { 140 | try { 141 | const site_id = await _netlify_get_site_id(); 142 | const deploys = await _netlify_get(`/sites/${site_id}/deploys?per_page=${config.deploy_history_count}`); 143 | return res.send({ deploys }); 144 | } 145 | catch (error) { 146 | return res.send({ error: error.message }); 147 | } 148 | }); 149 | 150 | 151 | /** 152 | * POST /builds 153 | * Start a new build for the configured Netlify site 154 | */ 155 | router.post('/builds', _checkAuth, async (req, res) => { 156 | try { 157 | const site_id = await _netlify_get_site_id(); 158 | const build = await _netlify_post(`/sites/${site_id}/builds`); 159 | return res.send({ build }); 160 | } 161 | catch (error) { 162 | return res.send({ error: error.message }); 163 | } 164 | }); 165 | 166 | 167 | /** 168 | * POST /lock 169 | * Lock the currently debployed branch of the Netlify site 170 | * (Disable auto publishing) 171 | */ 172 | router.post('/lock', _checkAuth, async (req, res) => { 173 | try { 174 | const site = await _netlify_get_site(); 175 | const deploy = await _netlify_post(`/deploys/${site.published_deploy.id}/lock`); 176 | return res.send({ success: deploy && deploy.locked }); 177 | } 178 | catch(error) { 179 | return res.send({ error: error.message }); 180 | } 181 | }); 182 | 183 | 184 | /** 185 | * POST /unlock 186 | * Unlock the currently deployed branch of the Netlify site 187 | * (Enable auto publishing) 188 | */ 189 | router.post('/unlock', _checkAuth, async (req, res) => { 190 | try { 191 | const site = await _netlify_get_site(); 192 | const deploy = await _netlify_post(`/deploys/${site.published_deploy.id}/unlock`); 193 | return res.send({ success: deploy && !deploy.locked }); 194 | } 195 | catch(error) { 196 | return res.send({ error: error.message }); 197 | } 198 | }); 199 | 200 | 201 | /** 202 | * POST /publish/:deploy_id 203 | * Set the specified deploy as the currenly published deploy 204 | */ 205 | router.post('/publish/:deploy_id', _checkAuth, async (req, res) => { 206 | try { 207 | const site_id = await _netlify_get_site_id(); 208 | const deploy = await _netlify_post(`/sites/${site_id}/deploys/${req.params.deploy_id}/restore`); 209 | return res.send({ deploy }); 210 | } 211 | catch (error) { 212 | return res.send({ error: error.message }); 213 | } 214 | }); 215 | 216 | 217 | // 218 | // MIDDLEWARE 219 | // 220 | 221 | /** 222 | * Check to see if a User is logged in and has admin privileges 223 | * Return with an error if not an admin 224 | */ 225 | function _checkAuth(req, res, next) { 226 | if ( req.accountability.admin || (req.accountability.app && config.additional_role_ids && config.additional_role_ids.includes(req.accountability.role)) ) { 227 | next(); 228 | } 229 | else { 230 | res.status(401).send({ error: "You must be logged in with admin privileges" }); 231 | } 232 | } 233 | 234 | 235 | // 236 | // NETLIFY API FUNCTIONS 237 | // 238 | 239 | /** 240 | * Get the Netlify Site ID (cached, if available) 241 | * @returns {Promise} 242 | */ 243 | async function _netlify_get_site_id() { 244 | if ( !NETLIFY_SITE_ID ) { 245 | const site = await _netlify_get_site(); 246 | NETLIFY_SITE_ID = site ? site.site_id : undefined; 247 | } 248 | return NETLIFY_SITE_ID; 249 | } 250 | 251 | /** 252 | * Get the configured Netlify site 253 | * @returns {Promise} Site info 254 | */ 255 | function _netlify_get_site() { 256 | return new Promise(async function(resolve, reject) { 257 | try { 258 | const resp = await _netlify_get(`/sites?name=${NETLIFY_SITE}`); 259 | let site = resp && resp.length === 1 ? resp[0] : undefined; 260 | if ( !site ) { 261 | return reject('The configured Netlify site could not be found'); 262 | } 263 | return resolve(site); 264 | } 265 | catch (err) { 266 | return reject(err); 267 | } 268 | }); 269 | } 270 | 271 | /** 272 | * Make a GET request to the Nelify API 273 | * @param {String} path API Path 274 | * @returns {Promise} API Response 275 | */ 276 | async function _netlify_get(path) { 277 | return await _netlify_api("GET", path, undefined); 278 | } 279 | 280 | /** 281 | * Make a POST request to the Netlify API 282 | * @param {String} path API Path 283 | * @param {Object} body Post Request Body 284 | * @returns {Promise} API Response 285 | */ 286 | async function _netlify_post(path, body) { 287 | return await _netlify_api("POST", path, body); 288 | } 289 | 290 | /** 291 | * Make a generic request to the Netlify API 292 | * @param {string} method HTTP Method 293 | * @param {string} path API Path 294 | * @param {Object} body POST / PUT Request Body 295 | * @returns {Promise} API Response 296 | */ 297 | async function _netlify_api(method, path, body) { 298 | return new Promise(function(resolve, reject) { 299 | let headers = { 300 | Authorization: 'Bearer ' + NETLIFY_TOKEN 301 | } 302 | 303 | if ( body ) { 304 | body = JSON.stringify(body); 305 | headers['Content-Type'] = 'application/json'; 306 | headers['Content-Length'] = body.length 307 | } 308 | 309 | const options = { 310 | headers: headers, 311 | method: method, 312 | hostname: 'api.netlify.com', 313 | path: '/api/v1/' + path, 314 | port: 443 315 | } 316 | 317 | const req = https.request(options, (res) => { 318 | 319 | // Return failed API Request (not a 200 response) 320 | let status = res.statusCode; 321 | if ( status < 200 || status >= 300 ) { 322 | return reject(new Error("Netlify API Request Failed [" + status + "]")); 323 | } 324 | 325 | // Collect response data 326 | let body = []; 327 | res.on('data', (chunk) => { 328 | body.push(chunk); 329 | }); 330 | 331 | // Handle response data - return JSON data 332 | res.on('end', () => { 333 | try { 334 | body = JSON.parse(Buffer.concat(body).toString()); 335 | } 336 | catch (e) { 337 | return reject(new Error("Netlify API Request Failed [" + e + "]")); 338 | } 339 | return resolve(body); 340 | }); 341 | 342 | }); 343 | 344 | // Handle Network Error 345 | req.on('error', (err) => { 346 | console.log("Could not make Netlify API Request [" + err + "]"); 347 | return reject(err); 348 | }); 349 | 350 | // Add Body 351 | if ( body ) req.write(body); 352 | 353 | req.end(); 354 | }); 355 | } 356 | 357 | } 358 | }; 359 | -------------------------------------------------------------------------------- /src/directus-extension-publish-netlify-module/api.js: -------------------------------------------------------------------------------- 1 | import config from '../../config' 2 | 3 | /** 4 | * Get the extension settings 5 | * @param {API} api Directus API 6 | * @returns {Object} Extension Settings 7 | */ 8 | const getSettings = async(api) => { 9 | const { data } = await api.get(`/${config.extension}/settings`); 10 | if ( data && data.error ) throw new Error(data.error); 11 | return data && data.settings ? data.settings : {}; 12 | } 13 | 14 | /** 15 | * Save the extension settings 16 | * @param {API} api Directus API 17 | * @param {String} netlify_site Netlify Site ID 18 | * @param {String} netlify_token Netlify Token 19 | * @returns {Promise} Update status 20 | */ 21 | const saveSettings = async (api, netlify_site, netlify_token) => { 22 | const { data } = await api.post(`/${config.extension}/settings`, { netlify_site, netlify_token}); 23 | if ( data && data.error ) throw new Error(data.error); 24 | return data && data.success ? data.success : false; 25 | } 26 | 27 | /** 28 | * Get the info for the configured Netlify site 29 | * @param {API} api Directus API 30 | * @returns {Object} Site info 31 | */ 32 | const getSite = async (api) => { 33 | const { data } = await api.get(`/${config.extension}/site`); 34 | if ( data && data.error ) throw new Error(data.error); 35 | return data && data.site ? data.site : undefined; 36 | } 37 | 38 | /** 39 | * Get the deploys for the configured Netlify site 40 | * @param {API} api Directus API 41 | * @returns {Object[]} Site deploys 42 | */ 43 | const getDeploys = async (api) => { 44 | const { data } = await api.get(`/${config.extension}/deploys`); 45 | if ( data && data.error ) throw new Error(data.error); 46 | return data && data.deploys ? data.deploys : []; 47 | } 48 | 49 | /** 50 | * Start a new build for the configured Netlify site 51 | * @param {API} api Directus API 52 | * @returns {Object} Site build 53 | */ 54 | const startBuild = async (api) => { 55 | const { data } = await api.post(`/${config.extension}/builds`); 56 | if ( data && data.error ) throw new Error(data.error); 57 | return data && data.build ? data.build : undefined; 58 | } 59 | 60 | /** 61 | * Lock the currently published deploy 62 | * @param {API} api Directus API 63 | * @returns {Boolean} Lock success 64 | */ 65 | const lockDeploy = async (api) => { 66 | const { data } = await api.post(`${config.extension}/lock`); 67 | if ( data && data.error ) throw new Error(data.error); 68 | return data && data.success ? data.success : false; 69 | } 70 | 71 | /** 72 | * Unlock the currently published deploy 73 | * @param {API} api Directus API 74 | * @returns {Boolean} Unlock success 75 | */ 76 | const unlockDeploy = async (api) => { 77 | const { data } = await api.post(`${config.extension}/unlock`); 78 | if ( data && data.error ) throw new Error(data.error); 79 | return data && data.success ? data.success : false; 80 | } 81 | 82 | /** 83 | * Set the specified deploy as the currently published deploy 84 | * @param {API} api Directus API 85 | * @param {String} deploy_id ID of deploy to publish 86 | * @returns {Object} new currently published deploy 87 | */ 88 | const publishDeploy = async (api, deploy_id) => { 89 | const { data } = await api.post(`${config.extension}/publish/${deploy_id}`); 90 | if ( data && data.error ) throw new Error(data.error); 91 | return data && data.deploy ? data.deploy : undefined; 92 | } 93 | 94 | /** 95 | * Get info on the latest Activity Item from the Directus DB 96 | * @param {API} api Directus API 97 | * @returns {Object} Most recent activity 98 | */ 99 | const getLatestDirectusActivity = async (api) => { 100 | let filter = JSON.stringify(config.activityFilter); 101 | const { data } = await api.get(`/activity?filter=${filter}&sort=-timestamp&limit=1&fields=*.*`) 102 | return data && data.data && data.data.length > 0 ? data.data[0] : undefined; 103 | } 104 | 105 | export { 106 | getSettings, 107 | saveSettings, 108 | getSite, 109 | getDeploys, 110 | getLatestDirectusActivity, 111 | startBuild, 112 | lockDeploy, 113 | unlockDeploy, 114 | publishDeploy 115 | }; -------------------------------------------------------------------------------- /src/directus-extension-publish-netlify-module/components/deploys.vue: -------------------------------------------------------------------------------- 1 | 78 | 79 | 80 | 210 | 211 | 212 | -------------------------------------------------------------------------------- /src/directus-extension-publish-netlify-module/components/dialog.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 15 | 54 | -------------------------------------------------------------------------------- /src/directus-extension-publish-netlify-module/components/error.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 23 | -------------------------------------------------------------------------------- /src/directus-extension-publish-netlify-module/components/message.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 28 | 29 | -------------------------------------------------------------------------------- /src/directus-extension-publish-netlify-module/components/site.vue: -------------------------------------------------------------------------------- 1 | 113 | 114 | 232 | 233 | -------------------------------------------------------------------------------- /src/directus-extension-publish-netlify-module/index.js: -------------------------------------------------------------------------------- 1 | import BuildComponent from './routes/build.vue'; 2 | import SettingsComponent from './routes/settings.vue'; 3 | import config from '../../config'; 4 | 5 | export default { 6 | id: config.extension, 7 | name: 'Publish', 8 | icon: 'cloud_upload', 9 | routes: [ 10 | { 11 | path: '', 12 | component: BuildComponent, 13 | }, 14 | { 15 | path: 'settings', 16 | component: SettingsComponent 17 | } 18 | ], 19 | preRegisterCheck(user) { 20 | // Allow access to the module if: 21 | // - the user has admin access OR 22 | // - the user has app access AND the user's rols id is defined in the extension's config of additional role ids 23 | const has_admin_access = user.admin_access || user.role.admin_access; 24 | const has_app_access = user.app_access || user.role.app_access; 25 | const config_additional_roles = config.additional_role_ids || []; 26 | return has_admin_access || (has_app_access && config_additional_roles.includes(user.role.id)); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /src/directus-extension-publish-netlify-module/routes/build.vue: -------------------------------------------------------------------------------- 1 | 62 | 63 | -------------------------------------------------------------------------------- /src/directus-extension-publish-netlify-module/routes/settings.vue: -------------------------------------------------------------------------------- 1 | 68 | 69 | 112 | 113 | --------------------------------------------------------------------------------