Dependency updates + full ESM (#327)

* Dependency updates

* Fix eslint issues

* Switch to esm fully

* Fix Jest tests

* Update to node 16, force mini-css-extract-plugin to 1.x

* More dep updates

* Use correct NPM version in Actions

* Fix mini-css-extract-plugin version overrides

* Don't rely on Webpack for available languages
pull/326/head
Matt (IPv4) Cowley 2022-02-04 21:10:20 +00:00 committed by GitHub
parent 26e907bd81
commit 387a47b014
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 28690 additions and 8945 deletions

View File

@ -8,9 +8,10 @@ module.exports = {
'plugin:vue/recommended', 'plugin:vue/recommended',
], ],
parserOptions: { parserOptions: {
parser: 'babel-eslint', parser: '@babel/eslint-parser',
ecmaVersion: 2018, ecmaVersion: 2018,
sourceType: 'module', sourceType: 'module',
requireConfigFile: false,
}, },
rules: { rules: {
'linebreak-style': ['error', 'unix'], 'linebreak-style': ['error', 'unix'],
@ -27,6 +28,7 @@ module.exports = {
}], }],
'vue/no-unused-vars': 0, 'vue/no-unused-vars': 0,
'vue/html-self-closing': 0, 'vue/html-self-closing': 0,
'vue/multi-word-component-names': 0,
}, },
globals: { globals: {
'describe': true, 'describe': true,

View File

@ -7,35 +7,40 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v2
- name: Read .nvmrc - name: Read Node.js & NPM versions
run: echo "##[set-output name=NVMRC;]$(cat .nvmrc)" run: |
id: nvm echo "##[set-output name=NODE;]$(cat package.json | jq -r '.engines.node')"
echo "##[set-output name=NPM;]$(cat package.json | jq -r '.engines.npm')"
id: versions
- name: Use Node.js (.nvmrc) - name: Use correct Node.js version
uses: actions/setup-node@v1 uses: actions/setup-node@v2
with: with:
node-version: "${{ steps.nvm.outputs.NVMRC }}" node-version: "${{ steps.versions.outputs.NODE }}"
- name: Install dependencies - name: Use correct NPM version
run: npm ci run: npm i -g npm@"${{ steps.versions.outputs.NPM }}"
- name: Build tool - name: Install dependencies
run: npm run build run: npm ci
- name: Deploy commit to DigitalOcean Spaces - name: Build tool
run: aws s3 sync ./dist s3://${{ secrets.SPACES_BUCKET }}/commits/nginxconfig/${{ github.sha }} --endpoint=https://${{ secrets.SPACES_REGION }}.digitaloceanspaces.com --acl public-read --content-encoding utf8 run: npm run build
env:
AWS_ACCESS_KEY_ID: ${{ secrets.SPACES_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.SPACES_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: ${{ secrets.SPACES_REGION }}
- name: Leave a comment - name: Deploy commit to DigitalOcean Spaces
run: npm run deploy:spaces:comment run: aws s3 sync ./dist s3://${{ secrets.SPACES_BUCKET }}/commits/nginxconfig/${{ github.sha }} --endpoint=https://${{ secrets.SPACES_REGION }}.digitaloceanspaces.com --acl public-read --content-encoding utf8
env: env:
REPO_NAME: ${{ github.repository }} AWS_ACCESS_KEY_ID: ${{ secrets.SPACES_ACCESS_KEY_ID }}
COMMIT_SHA: ${{ github.sha }} AWS_SECRET_ACCESS_KEY: ${{ secrets.SPACES_SECRET_ACCESS_KEY }}
GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }} AWS_DEFAULT_REGION: ${{ secrets.SPACES_REGION }}
SPACES_REGION: ${{ secrets.SPACES_REGION }}
SPACES_BUCKET: ${{ secrets.SPACES_BUCKET }} - name: Leave a comment
run: npm run deploy:spaces:comment
env:
REPO_NAME: ${{ github.repository }}
COMMIT_SHA: ${{ github.sha }}
GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SPACES_REGION: ${{ secrets.SPACES_REGION }}
SPACES_BUCKET: ${{ secrets.SPACES_BUCKET }}

View File

@ -10,30 +10,35 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v2
- name: Read .nvmrc - name: Read Node.js & NPM versions
run: echo "##[set-output name=NVMRC;]$(cat .nvmrc)" run: |
id: nvm echo "##[set-output name=NODE;]$(cat package.json | jq -r '.engines.node')"
echo "##[set-output name=NPM;]$(cat package.json | jq -r '.engines.npm')"
id: versions
- name: Use Node.js (.nvmrc) - name: Use correct Node.js version
uses: actions/setup-node@v1 uses: actions/setup-node@v2
with: with:
node-version: "${{ steps.nvm.outputs.NVMRC }}" node-version: "${{ steps.versions.outputs.NODE }}"
- name: Install dependencies - name: Use correct NPM version
run: npm ci run: npm i -g npm@"${{ steps.versions.outputs.NPM }}"
- name: Test before production - name: Install dependencies
run: npm test run: npm ci
- name: Build tool - name: Test before production
run: npm run build run: npm test
- name: Deploy master to GitHub Pages - name: Build tool
uses: JamesIves/github-pages-deploy-action@2.0.0 run: npm run build
env:
ACCESS_TOKEN: ${{ secrets.DEV_GITHUB_TOKEN }} - name: Deploy master to GitHub Pages
BASE_BRANCH: master uses: JamesIves/github-pages-deploy-action@2.0.0
BRANCH: gh-pages env:
FOLDER: dist ACCESS_TOKEN: ${{ secrets.DEV_GITHUB_TOKEN }}
BASE_BRANCH: master
BRANCH: gh-pages
FOLDER: dist

View File

@ -7,37 +7,47 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v2
- name: Read .nvmrc - name: Read Node.js & NPM versions
run: echo "##[set-output name=NVMRC;]$(cat .nvmrc)" run: |
id: nvm echo "##[set-output name=NODE;]$(cat package.json | jq -r '.engines.node')"
echo "##[set-output name=NPM;]$(cat package.json | jq -r '.engines.npm')"
id: versions
- name: Use Node.js (.nvmrc) - name: Use correct Node.js version
uses: actions/setup-node@v1 uses: actions/setup-node@v2
with: with:
node-version: "${{ steps.nvm.outputs.NVMRC }}" node-version: "${{ steps.versions.outputs.NODE }}"
- name: Install dependencies - name: Use correct NPM version
run: npm ci run: npm i -g npm@"${{ steps.versions.outputs.NPM }}"
- name: Test with eslint - name: Install dependencies
run: npm run test:eslint run: npm ci
- name: Test with eslint
run: npm run test:eslint
sass-lint: sass-lint:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v2
- name: Read .nvmrc - name: Read Node.js & NPM versions
run: echo "##[set-output name=NVMRC;]$(cat .nvmrc)" run: |
id: nvm echo "##[set-output name=NODE;]$(cat package.json | jq -r '.engines.node')"
echo "##[set-output name=NPM;]$(cat package.json | jq -r '.engines.npm')"
id: versions
- name: Use Node.js (.nvmrc) - name: Use correct Node.js version
uses: actions/setup-node@v1 uses: actions/setup-node@v2
with: with:
node-version: "${{ steps.nvm.outputs.NVMRC }}" node-version: "${{ steps.versions.outputs.NODE }}"
- name: Use correct NPM version
run: npm i -g npm@"${{ steps.versions.outputs.NPM }}"
- name: Install dependencies - name: Install dependencies
run: npm ci run: npm ci
@ -49,16 +59,21 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v2
- name: Read .nvmrc - name: Read Node.js & NPM versions
run: echo "##[set-output name=NVMRC;]$(cat .nvmrc)" run: |
id: nvm echo "##[set-output name=NODE;]$(cat package.json | jq -r '.engines.node')"
echo "##[set-output name=NPM;]$(cat package.json | jq -r '.engines.npm')"
id: versions
- name: Use Node.js (.nvmrc) - name: Use correct Node.js version
uses: actions/setup-node@v1 uses: actions/setup-node@v2
with: with:
node-version: "${{ steps.nvm.outputs.NVMRC }}" node-version: "${{ steps.versions.outputs.NODE }}"
- name: Use correct NPM version
run: npm i -g npm@"${{ steps.versions.outputs.NPM }}"
- name: Install dependencies - name: Install dependencies
run: npm ci run: npm ci

2
.nvmrc
View File

@ -1 +1 @@
v14.17.5 v16.13.2

36400
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -5,9 +5,11 @@
"private": true, "private": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": "14.17.5" "node": "16.13.2",
"npm": "8.4.1"
}, },
"main": "src/nginxconfig/mount.js", "main": "src/nginxconfig/mount.js",
"type": "module",
"scripts": { "scripts": {
"build": "npm run build:clean && npm run build:template && npm run build:prism && npm run build:static && npm run build:tool", "build": "npm run build:clean && npm run build:template && npm run build:prism && npm run build:static && npm run build:tool",
"build:clean": "do-vue clean", "build:clean": "do-vue clean",
@ -19,12 +21,12 @@
"dev:tool": "vue-cli-service serve src/nginxconfig/mount.js", "dev:tool": "vue-cli-service serve src/nginxconfig/mount.js",
"deploy:spaces:comment": "do-vue comment nginxconfig", "deploy:spaces:comment": "do-vue comment nginxconfig",
"test": "npm run test:eslint && npm run test:sass-lint && npm run test:i18n-packs && npm run test:jest", "test": "npm run test:eslint && npm run test:sass-lint && npm run test:i18n-packs && npm run test:jest",
"test:jest": "jest /test/.*.js?$", "test:jest": "jest --env=jsdom /test/.*.js?$",
"test:fix": "npm run test:eslint:fix", "test:fix": "npm run test:eslint:fix",
"test:eslint": "eslint 'src/**/*.{js,vue}'", "test:eslint": "eslint 'src/**/*.{js,vue}'",
"test:eslint:fix": "npm run test:eslint -- --fix", "test:eslint:fix": "npm run test:eslint -- --fix",
"test:sass-lint": "sass-lint 'src/**/*.scss' --verbose --no-exit --config .sasslintrc", "test:sass-lint": "sass-lint 'src/**/*.scss' --verbose --no-exit --config .sasslintrc",
"test:i18n-packs": "node -r esm src/nginxconfig/i18n/verify.js" "test:i18n-packs": "node --es-module-specifier-resolution=node src/nginxconfig/i18n/verify.js"
}, },
"jest": { "jest": {
"testRegex": "/test/.*.js?$" "testRegex": "/test/.*.js?$"
@ -42,7 +44,7 @@
}, },
"homepage": "https://github.com/digitalocean/nginxconfig.io#readme", "homepage": "https://github.com/digitalocean/nginxconfig.io#readme",
"dependencies": { "dependencies": {
"clipboard": "^2.0.8", "clipboard": "^2.0.10",
"clone": "^2.1.2", "clone": "^2.1.2",
"do-bulma": "git+https://github.com/do-community/do-bulma.git", "do-bulma": "git+https://github.com/do-community/do-bulma.git",
"do-vue": "git+https://github.com/do-community/do-vue.git", "do-vue": "git+https://github.com/do-community/do-vue.git",
@ -51,35 +53,39 @@
"json-to-pretty-yaml": "^1.2.2", "json-to-pretty-yaml": "^1.2.2",
"memory-tar-create": "0.0.3", "memory-tar-create": "0.0.3",
"pretty-checkbox-vue": "^1.1.9", "pretty-checkbox-vue": "^1.1.9",
"prismjs": "^1.25.0", "prismjs": "^1.26.0",
"qs": "^6.10.1", "qs": "^6.10.3",
"simple-js-sha2-256": "^1.0.7", "simple-js-sha2-256": "^1.0.7",
"vue": "^2.6.12", "vue": "^2.6.14",
"vue-i18n": "^8.24.4", "vue-i18n": "^8.27.0",
"vue-select": "^3.11.2", "vue-select": "^3.16.0",
"webpack-require-from": "^1.8.4" "webpack-require-from": "^1.8.6"
}, },
"devDependencies": { "devDependencies": {
"@babel/plugin-proposal-class-properties": "^7.13.0", "@babel/eslint-parser": "^7.17.0",
"@babel/plugin-transform-runtime": "^7.14.3", "@babel/plugin-proposal-class-properties": "^7.16.7",
"@babel/preset-env": "^7.14.2", "@babel/plugin-transform-runtime": "^7.17.0",
"@babel/runtime": "^7.14.0", "@babel/preset-env": "^7.16.11",
"@vue/cli-service": "^5.0.0-beta.1", "@babel/runtime": "^7.17.0",
"babel-eslint": "^10.1.0", "@vue/cli-service": "^5.0.0-rc.2",
"chalk": "^4.1.1", "ajv": "^8.10.0",
"chalk": "^5.0.0",
"copyfiles": "^2.4.1", "copyfiles": "^2.4.1",
"core-js": "^3.12.1", "core-js": "^3.21.0",
"duplicate-package-checker-webpack-plugin": "^3.0.0", "duplicate-package-checker-webpack-plugin": "^3.0.0",
"eslint": "^7.26.0", "eslint": "^8.8.0",
"eslint-plugin-vue": "^7.9.0", "eslint-plugin-vue": "^8.4.1",
"esm": "^3.2.25", "esm": "^3.2.25",
"jest": "^26.6.3", "jest": "^27.4.7",
"node-fetch": "^2.6.7", "node-fetch": "^3.2.0",
"postcss": "^8.2.15", "postcss": "^8.4.6",
"sass": "^1.32.13", "sass": "^1.49.7",
"sass-lint": "git+https://github.com/do-community/sass-lint.git", "sass-lint": "git+https://github.com/do-community/sass-lint.git",
"sass-loader": "^11.1.1", "sass-loader": "^11.1.1",
"vue-template-compiler": "^2.6.12", "vue-template-compiler": "^2.6.14",
"webpack-bundle-analyzer": "^4.4.2" "webpack-bundle-analyzer": "^4.5.0"
},
"overrides": {
"mini-css-extract-plugin": "^1.6.2"
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2020 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -24,9 +24,9 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
*/ */
const fs = require('fs').promises; import { promises as fs } from 'fs';
const path = require('path'); import { URL } from 'url';
const fetch = require('node-fetch'); import fetch from 'node-fetch';
const main = async () => { const main = async () => {
const resp = await fetch('https://assets.digitalocean.com/prism/prism.css'); const resp = await fetch('https://assets.digitalocean.com/prism/prism.css');
@ -35,8 +35,11 @@ const main = async () => {
// Fix $676767 -> #676767 // Fix $676767 -> #676767
const fixed = text.replace(/:\s*\$((?:[0-9a-fA-F]{3}){1,2});/g, ':#$1;'); const fixed = text.replace(/:\s*\$((?:[0-9a-fA-F]{3}){1,2});/g, ':#$1;');
const buildDir = path.join(__dirname, '..', '..', '..', 'build'); const buildDir = '../../../build';
await fs.writeFile(path.join(buildDir, 'prism.css'), fixed); await fs.writeFile(new URL(`${buildDir}/prism.css`, import.meta.url), fixed);
}; };
main().then(() => {}); main().then(() => {}).catch(err => {
console.error(err);
process.exit(1);
});

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2021 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -24,25 +24,21 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
*/ */
const path = require('path'); import fs from 'fs';
const fs = require('fs'); import { URL } from 'url';
// Fetch the posthtml template and convert it to an ejs template // Fetch the posthtml template and convert it to an ejs template
const main = () => { const main = () => {
const buildDir = path.join(__dirname, '..', '..', '..', 'build'); const buildDir = '../../../build';
let template = fs.readFileSync(path.join(buildDir, 'base.html'), 'utf8'); let template = fs.readFileSync(new URL(`${buildDir}/base.html`, import.meta.url), 'utf8');
// Inject our title now // Inject our title now
template = template.replace('<block name="title"><title>DigitalOcean</title></block>', '<title>NGINXConfig | DigitalOcean</title>'); template = template.replace('<block name="title"><title>DigitalOcean</title></block>', '<title>NGINXConfig | DigitalOcean</title>');
// We don't need the head/script blocks, vue-cli-service handles those
template = template.replace('<block name="head"></block>', '');
template = template.replace('<block name="script"></block>', '');
// Inject our app mounting point // Inject our app mounting point
template = template.replace('<block name="content"></block>', '<div id="app"></div>'); template = template.replace('<block name="content"></block>', '<div id="app"></div>');
fs.writeFileSync(path.join(buildDir, 'index.html'), template); fs.writeFileSync(new URL(`${buildDir}/index.html`, import.meta.url), template);
}; };
main(); main();

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2020 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -24,7 +24,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
*/ */
const yaml = require('json-to-pretty-yaml'); import yaml from 'json-to-pretty-yaml';
export default yamlConf => { export default yamlConf => {
return yaml.stringify(yamlConf); return yaml.stringify(yamlConf);

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2021 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -26,9 +26,7 @@ THE SOFTWARE.
import Vue from 'vue'; import Vue from 'vue';
import VueI18n from 'vue-i18n'; import VueI18n from 'vue-i18n';
import { defaultPack, defaultPackData } from '../util/language_pack_default'; import { defaultPack, defaultPackData, toSep, availablePacks } from '../util/language_packs';
import { toSep } from '../util/language_pack_name';
import { languagePackContext, availablePacks } from '../util/language_pack_context';
Vue.use(VueI18n); Vue.use(VueI18n);
@ -37,32 +35,58 @@ const i18nPacks = {};
i18nPacks[defaultPack] = defaultPackData; i18nPacks[defaultPack] = defaultPackData;
const loadedI18nPacks = [defaultPack]; const loadedI18nPacks = [defaultPack];
// Load in languages data from other packs // Cache the i18n instance
// Use webpack magic to only build chunks for lang/languages.js let i18n = null;
const languagesContext = require.context('.', true, /^\.\/[^/]+\/languages\.js$/, 'sync');
for (const availablePack of availablePacks) {
if (availablePack === defaultPack) continue;
i18nPacks[availablePack] = { languages: languagesContext(`./${toSep(availablePack, '-')}/languages.js`).default };
}
export const i18n = new VueI18n({ export const getI18n = async () => {
locale: defaultPack, // Use cached if available
fallbackLocale: defaultPack, if (i18n) return i18n;
messages: i18nPacks,
});
const loadLanguagePack = pack => { // Load in languages data from other packs
// Use webpack magic to only build chunks for lang/languages.js
// These are eagerly loaded by Webpack, so don't generate extra chunks, and return an already resolved Promise
for (const availablePack of availablePacks) {
if (availablePack === defaultPack) continue;
if (i18nPacks[availablePack]) continue;
const { default: languageData } = await import(
/* webpackInclude: /i18n\/[^/]+\/languages\.js$/ */
/* webpackMode: "eager" */
`./${toSep(availablePack, '-')}/languages.js`
);
i18nPacks[availablePack] = { languages: languageData };
}
// Store and return the i18n instance with the loaded packs
i18n = new VueI18n({
locale: defaultPack,
fallbackLocale: defaultPack,
messages: i18nPacks,
});
return i18n;
};
const loadLanguagePack = async pack => {
// If same language, do nothing // If same language, do nothing
if (i18n.locale === pack) return; if (i18n.locale === pack) return;
// If language already loaded, do nothing // If language already loaded, do nothing
if (loadedI18nPacks.includes(pack)) return; if (loadedI18nPacks.includes(pack)) return;
// Load the pack with webpack magic // Load in the full pack
return languagePackContext(`./${toSep(pack, '-')}/index.js`).then(packData => i18nPacks[pack] = packData.default); // Use webpack magic to only build chunks for lang/index.js
const { default: packData } = await import(
/* webpackInclude: /i18n\/[^/]+\/index\.js$/ */
/* webpackMode: "lazy" */
`./${toSep(pack, '-')}/index.js`
);
i18nPacks[pack] = packData;
}; };
export const setLanguagePack = async pack => { export const setLanguagePack = async pack => {
// If i18n not loaded, do nothing
if (!i18n) return;
// Load the pack if not already loaded, and set it as active
await loadLanguagePack(pack); await loadLanguagePack(pack);
i18n.locale = pack; i18n.locale = pack;
}; };

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2020 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -26,19 +26,11 @@ THE SOFTWARE.
import { readdirSync, readFileSync } from 'fs'; import { readdirSync, readFileSync } from 'fs';
import { join, sep } from 'path'; import { join, sep } from 'path';
import { URL } from 'url';
import chalk from 'chalk'; import chalk from 'chalk';
import { defaultPack } from '../util/language_pack_default'; import { defaultPack, availablePacks, toSep, fromSep } from '../util/language_packs';
import { toSep, fromSep } from '../util/language_pack_name';
import snakeToCamel from '../util/snake_to_camel'; import snakeToCamel from '../util/snake_to_camel';
// Load all the packs in
const packs = {};
const packDirectories = readdirSync(__dirname, { withFileTypes: true })
.filter(dirent => dirent.isDirectory())
.map(dirent => dirent.name);
for (const packDirectory of packDirectories)
packs[fromSep(packDirectory, '-')] = require(`./${packDirectory}/index.js`).default;
// Recursively get all keys in a i18n pack object fragment // Recursively get all keys in a i18n pack object fragment
const explore = packFragment => { const explore = packFragment => {
const foundKeys = new Set(); const foundKeys = new Set();
@ -61,7 +53,7 @@ const explore = packFragment => {
const files = directory => { const files = directory => {
const foundFiles = new Set(); const foundFiles = new Set();
for (const dirent of readdirSync(join(__dirname, directory), { withFileTypes: true })) { for (const dirent of readdirSync(new URL(`./${directory}`, import.meta.url), { withFileTypes: true })) {
const base = join(directory, dirent.name); const base = join(directory, dirent.name);
// If this is a file, store it // If this is a file, store it
@ -83,7 +75,7 @@ const files = directory => {
// Get all the todo items in a file // Get all the todo items in a file
const todos = file => { const todos = file => {
const content = readFileSync(join(__dirname, file), 'utf8'); const content = readFileSync(new URL(`./${file}`, import.meta.url), 'utf8');
const lines = content.split('\n'); const lines = content.split('\n');
const items = []; const items = [];
@ -105,63 +97,88 @@ const fileToObject = file => file
// Replace sep with period and use camelCase // Replace sep with period and use camelCase
.split(sep).map(dir => snakeToCamel(dir)).join('.'); .split(sep).map(dir => snakeToCamel(dir)).join('.');
// Get all the keys for the default "source" language pack const main = async () => {
const defaultKeys = explore(packs[defaultPack]); // Load all the packs in
const packs = {};
const packDirectories = readdirSync(new URL('./', import.meta.url), { withFileTypes: true })
.filter(dirent => dirent.isDirectory())
.map(dirent => dirent.name);
for (const packDirectory of packDirectories)
packs[fromSep(packDirectory, '-')] = await import(`./${packDirectory}/index.js`).then(pack => pack.default);
// Track if we need to exit with an error // Get all the keys for the default "source" language pack
let hadError = false; const defaultKeys = explore(packs[defaultPack]);
// Work through all the packs and compare to default // Track if we need to exit with an error
for (const [pack, packData] of Object.entries(packs)) { let hadError = false;
console.log(chalk.underline(`Language pack \`${pack}\``));
// Get the base data // Work through all the packs and compare to default
const packKeys = explore(packData); for (const [pack, packData] of Object.entries(packs)) {
const packFiles = files(toSep(pack, '-')); console.log(chalk.underline(`Language pack \`${pack}\``));
console.log(` Found ${packKeys.size.toLocaleString()} keys, ${packFiles.size.toLocaleString()} files`);
// Track all our errors and warnings // Get the base data
const errors = [], warnings = []; const packKeys = explore(packData);
const packFiles = files(toSep(pack, '-'));
console.log(` Found ${packKeys.size.toLocaleString()} keys, ${packFiles.size.toLocaleString()} files`);
// Get all the keys and the set differences // Track all our errors and warnings
const missingKeys = [...defaultKeys].filter(x => !packKeys.has(x)); const errors = [], warnings = [];
const extraKeys = [...packKeys].filter(x => !defaultKeys.has(x));
// Missing keys and extra keys are errors // Get all the keys and the set differences
missingKeys.forEach(key => errors.push(`Missing key \`${key}\``)); const missingKeys = [...defaultKeys].filter(x => !packKeys.has(x));
extraKeys.forEach(key => errors.push(`Unexpected key \`${key}\``)); const extraKeys = [...packKeys].filter(x => !defaultKeys.has(x));
// Get all the files in the pack directory // Missing keys and extra keys are errors
const packKeyFiles = new Set([...packFiles].filter(file => file.split(sep).slice(-1)[0] !== 'index.js')); missingKeys.forEach(key => errors.push(`Missing key \`${key}\``));
extraKeys.forEach(key => errors.push(`Unexpected key \`${key}\``));
// Get the objects from the pack keys // Get all the files in the pack directory
const packKeyObjects = new Set([...packKeys] const packKeyFiles = new Set([...packFiles].filter(file => file.split(sep).slice(-1)[0] !== 'index.js'));
.map(key => key.split('.').slice(0, -1).join('.')));
// Warn for any files that aren't used as pack objects // Get the objects from the pack keys
[...packKeyFiles].filter(file => !packKeyObjects.has(fileToObject(file))) const packKeyObjects = new Set([...packKeys]
.forEach(file => warnings.push(`Unused file \`${file}\``)); .map(key => key.split('.').slice(0, -1).join('.')));
// Locate any todos in each file as a warning // Warn for any files that aren't used as pack objects
for (const file of packFiles) [...packKeyFiles].filter(file => !packKeyObjects.has(fileToObject(file)))
todos(file).forEach(todo => warnings.push(`TODO in \`${file}\` on line ${todo[0]}`)); .forEach(file => warnings.push(`Unused file \`${file}\``));
// Output the pack results // Locate any todos in each file as a warning
if (warnings.length) for (const file of packFiles)
for (const warning of warnings) todos(file).forEach(todo => warnings.push(`TODO in \`${file}\` on line ${todo[0]}`));
console.log(` ${chalk.yellow('warning')} ${warning}`);
if (errors.length)
for (const error of errors)
console.log(` ${chalk.red('error')} ${error}`);
if (!errors.length && !warnings.length)
console.log(` ${chalk.green('No issues')}`);
// If we had errors, script should exit 1 // Output the pack results
if (errors.length) hadError = true; if (warnings.length)
for (const warning of warnings)
console.warn(` ${chalk.yellow('warning')} ${warning}`);
if (errors.length)
for (const error of errors)
console.error(` ${chalk.red('error')} ${error}`);
if (!errors.length && !warnings.length)
console.log(` ${chalk.green('No issues')}`);
// Linebreak before next pack or exit // If we had errors, script should exit 1
console.log(chalk.reset()); if (errors.length) hadError = true;
}
// Exit 1 if we had errors // Linebreak before next pack or exit
if (hadError) process.exit(1); console.log(chalk.reset());
}
// Check available language packs
const packKeys = Object.keys(packs);
const missingPacks = packKeys.filter(x => !availablePacks.includes(x));
const extraPacks = availablePacks.filter(x => !packKeys.includes(x));
// Missing packs and extra packs are errors
missingPacks.forEach(pack => console.error(`${chalk.red('error')} Language pack \`${pack}\` not included in \`availablePacks\``));
extraPacks.forEach(pack => console.error(`${chalk.red('error')} Language pack \`${pack}\` included in \`availablePacks\` but not found`));
if (missingPacks.length || extraPacks.length) hadError = true;
// Exit 1 if we had errors
if (hadError) process.exit(1);
};
main().then(() => {}).catch(err => {
console.error(err);
process.exit(1);
});

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2021 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -28,11 +28,14 @@ THE SOFTWARE.
import './scss/style.scss'; import './scss/style.scss';
import Vue from 'vue'; import Vue from 'vue';
import './util/prism_bundle'; import './util/prism_bundle';
import { i18n } from './i18n/setup'; import { getI18n } from './i18n/setup';
import App from './templates/app'; import App from './templates/app';
// Run the app // Load the i18n languages and run the app
new Vue({ getI18n().then(i18n => {
i18n, new Vue({
render: h => h(App), i18n,
}).$mount('#app'); render: h => h(App),
}).$mount('#app');
});

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2021 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -214,7 +214,7 @@ THE SOFTWARE.
color: $dark-grey; color: $dark-grey;
font-size: 14px; font-size: 14px;
padding-left: calc(#{$margin / 2} + 1.5em); padding-left: calc(#{$margin * .5} + 1.5em);
text-indent: initial; text-indent: initial;
&::before, &::before,

View File

@ -1,5 +1,5 @@
<!-- <!--
Copyright 2021 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -33,11 +33,12 @@ THE SOFTWARE.
<template #header> <template #header>
</template> </template>
<template #buttons> <template #buttons>
<VueSelect v-model="lang" <VueSelect
:options="i18nPacks" v-model="lang"
:clearable="false" :options="i18nPacks"
:reduce="s => s.value" :clearable="false"
:disabled="languageLoading" :reduce="s => s.value"
:disabled="languageLoading"
> >
<template #selected-option="{ label }"> <template #selected-option="{ label }">
<span class="has-icon"> <span class="has-icon">
@ -79,10 +80,11 @@ THE SOFTWARE.
</div> </div>
<template v-for="data in activeDomains"> <template v-for="data in activeDomains">
<Domain :key="data[1]" <Domain
:ref="`domain-${data[1]}`" :key="data[1]"
:data="data[0]" :ref="`domain-${data[1]}`"
:style="{ display: data[1] === active ? undefined : 'none' }" :data="data[0]"
:style="{ display: data[1] === active ? undefined : 'none' }"
></Domain> ></Domain>
</template> </template>
@ -131,8 +133,7 @@ THE SOFTWARE.
import isObject from '../util/is_object'; import isObject from '../util/is_object';
import analytics from '../util/analytics'; import analytics from '../util/analytics';
import browserLanguage from '../util/browser_language'; import browserLanguage from '../util/browser_language';
import { defaultPack } from '../util/language_pack_default'; import { defaultPack, availablePacks } from '../util/language_packs';
import { availablePacks } from '../util/language_pack_context';
import { setLanguagePack } from '../i18n/setup'; import { setLanguagePack } from '../i18n/setup';
import generators from '../generators'; import generators from '../generators';

View File

@ -1,5 +1,5 @@
<!-- <!--
Copyright 2021 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -34,10 +34,11 @@ THE SOFTWARE.
<i class="fas fa-times"></i> <i class="fas fa-times"></i>
</a> </a>
</div> </div>
<a href="https://github.com/digitalocean/nginxconfig.io" <a
class="button is-primary" href="https://github.com/digitalocean/nginxconfig.io"
target="_blank" class="button is-primary"
@click="linkClickEvent" target="_blank"
@click="linkClickEvent"
> >
{{ $t('templates.callouts.contribute.getInvolvedOnGitHub') }} {{ $t('templates.callouts.contribute.getInvolvedOnGitHub') }}
</a> </a>

View File

@ -1,5 +1,5 @@
<!-- <!--
Copyright 2021 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -28,9 +28,10 @@ THE SOFTWARE.
<div class="callout"> <div class="callout">
<p> <p>
{{ $t('templates.callouts.droplet.lookingForAPlaceToDeploy') }} {{ $t('templates.callouts.droplet.lookingForAPlaceToDeploy') }}
<ExternalLink :text="$t('templates.callouts.droplet.tryOutDigitalOceansDroplet')" <ExternalLink
link="https://marketplace.digitalocean.com/apps/lemp" :text="$t('templates.callouts.droplet.tryOutDigitalOceansDroplet')"
@click.native="linkClickEvent" link="https://marketplace.digitalocean.com/apps/lemp"
@click.native="linkClickEvent"
></ExternalLink> ></ExternalLink>
</p> </p>
</div> </div>

View File

@ -1,5 +1,5 @@
<!-- <!--
Copyright 2021 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -42,13 +42,14 @@ THE SOFTWARE.
</ul> </ul>
</div> </div>
<component :is="tab" <component
v-for="tab in tabs" :is="tab"
:key="tab.key" v-for="tab in tabs"
:ref="tab.key" :key="tab.key"
:data="$props.data[tab.key]" :ref="tab.key"
:style="{ display: active === tab.key ? undefined : 'none' }" :data="$props.data[tab.key]"
class="container" :style="{ display: active === tab.key ? undefined : 'none' }"
class="container"
></component> ></component>
<div class="navigation-buttons"> <div class="navigation-buttons">

View File

@ -1,5 +1,5 @@
<!-- <!--
Copyright 2021 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -81,12 +81,14 @@ THE SOFTWARE.
<label class="text message is-warning"> <label class="text message is-warning">
<span class="message-body"> <span class="message-body">
{{ $t('templates.domainSections.https.http3IsANonStandardModule') }} {{ $t('templates.domainSections.https.http3IsANonStandardModule') }}
<ExternalLink :text="$t('templates.domainSections.https.http3NginxQuicReadme')" <ExternalLink
link="https://quic.nginx.org/README" :text="$t('templates.domainSections.https.http3NginxQuicReadme')"
link="https://quic.nginx.org/README"
></ExternalLink> ></ExternalLink>
{{ $t('templates.domainSections.https.http3OrThe') }} {{ $t('templates.domainSections.https.http3OrThe') }}
<ExternalLink :text="$t('templates.domainSections.https.http3CloudflareQuicheProject')" <ExternalLink
link="https://github.com/cloudflare/quiche/tree/master/extras/nginx" :text="$t('templates.domainSections.https.http3CloudflareQuicheProject')"
link="https://github.com/cloudflare/quiche/tree/master/extras/nginx"
></ExternalLink> ></ExternalLink>
{{ $t('templates.domainSections.https.http3ForBuildingNginxWithHttp3') }} {{ $t('templates.domainSections.https.http3ForBuildingNginxWithHttp3') }}
</span> </span>
@ -158,8 +160,9 @@ THE SOFTWARE.
</div> </div>
<div class="field-body"> <div class="field-body">
<div class="field"> <div class="field">
<div v-for="(name, value) in $props.data.certType.options" <div
:class="`control${certTypeChanged && value === certType ? ' is-changed' : ''}`" v-for="(name, value) in $props.data.certType.options"
:class="`control${certTypeChanged && value === certType ? ' is-changed' : ''}`"
> >
<div class="radio"> <div class="radio">
<PrettyRadio v-model="certType" :value="value" class="p-default p-round p-fill p-icon"> <PrettyRadio v-model="certType" :value="value" class="p-default p-round p-fill p-icon">
@ -179,10 +182,11 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div class="field"> <div class="field">
<div :class="`control${letsEncryptEmailChanged ? ' is-changed' : ''}`"> <div :class="`control${letsEncryptEmailChanged ? ' is-changed' : ''}`">
<input v-model="letsEncryptEmail" <input
class="input" v-model="letsEncryptEmail"
type="text" class="input"
:placeholder="$props.data.letsEncryptEmail.computed" type="text"
:placeholder="$props.data.letsEncryptEmail.computed"
/> />
</div> </div>
</div> </div>
@ -196,10 +200,11 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div class="field"> <div class="field">
<div :class="`control${sslCertificateChanged ? ' is-changed' : ''}`"> <div :class="`control${sslCertificateChanged ? ' is-changed' : ''}`">
<input v-model="sslCertificate" <input
class="input" v-model="sslCertificate"
type="text" class="input"
:placeholder="`${$parent.$parent.$data.global.nginx.nginxConfigDirectory.computed}/ssl/${$parent.$props.data.server.domain.computed}.crt`" type="text"
:placeholder="`${$parent.$parent.$data.global.nginx.nginxConfigDirectory.computed}/ssl/${$parent.$props.data.server.domain.computed}.crt`"
/> />
</div> </div>
</div> </div>
@ -213,10 +218,11 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div class="field"> <div class="field">
<div :class="`control${sslCertificateKeyChanged ? ' is-changed' : ''}`"> <div :class="`control${sslCertificateKeyChanged ? ' is-changed' : ''}`">
<input v-model="sslCertificateKey" <input
class="input" v-model="sslCertificateKey"
type="text" class="input"
:placeholder="`${$parent.$parent.$data.global.nginx.nginxConfigDirectory.computed}/ssl/${$parent.$props.data.server.domain.computed}.key`" type="text"
:placeholder="`${$parent.$parent.$data.global.nginx.nginxConfigDirectory.computed}/ssl/${$parent.$props.data.server.domain.computed}.key`"
/> />
</div> </div>
</div> </div>

View File

@ -1,5 +1,5 @@
<!-- <!--
Copyright 2021 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -49,8 +49,9 @@ THE SOFTWARE.
</div> </div>
<div class="control"> <div class="control">
<label class="text"> <label class="text">
<ExternalLink :text="$t('templates.domainSections.onion.learnMoreAboutOnionServices')" <ExternalLink
link="https://community.torproject.org/onion-services/" :text="$t('templates.domainSections.onion.learnMoreAboutOnionServices')"
link="https://community.torproject.org/onion-services/"
></ExternalLink> ></ExternalLink>
</label> </label>
</div> </div>

View File

@ -1,5 +1,5 @@
<!-- <!--
Copyright 2021 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -72,16 +72,18 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div class="field"> <div class="field">
<div :class="`control${phpServerChanged ? ' is-changed' : ''}`"> <div :class="`control${phpServerChanged ? ' is-changed' : ''}`">
<VueSelect ref="phpServerSelect" <VueSelect
v-model="phpServer" ref="phpServerSelect"
:options="phpServerOptions" v-model="phpServer"
:clearable="false" :options="phpServerOptions"
:reduce="s => s.value" :clearable="false"
:reduce="s => s.value"
></VueSelect> ></VueSelect>
</div> </div>
<div v-if="phpServerCustomEnabled" <div
:class="`control${phpServerCustomChanged ? ' is-changed' : ''}`" v-if="phpServerCustomEnabled"
:class="`control${phpServerCustomChanged ? ' is-changed' : ''}`"
> >
<input v-model="phpServerCustom" class="input" type="text" :placeholder="$props.data.phpServerCustom.default" /> <input v-model="phpServerCustom" class="input" type="text" :placeholder="$props.data.phpServerCustom.default" />
</div> </div>
@ -96,16 +98,18 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div class="field"> <div class="field">
<div :class="`control${phpBackupServerChanged ? ' is-changed' : ''}`"> <div :class="`control${phpBackupServerChanged ? ' is-changed' : ''}`">
<VueSelect ref="phpBackupServerSelect" <VueSelect
v-model="phpBackupServer" ref="phpBackupServerSelect"
:options="phpBackupServerOptions" v-model="phpBackupServer"
:clearable="false" :options="phpBackupServerOptions"
:reduce="s => s.value" :clearable="false"
:reduce="s => s.value"
></VueSelect> ></VueSelect>
</div> </div>
<div v-if="phpBackupServerCustomEnabled" <div
:class="`control${phpBackupServerCustomChanged ? ' is-changed' : ''}`" v-if="phpBackupServerCustomEnabled"
:class="`control${phpBackupServerCustomChanged ? ' is-changed' : ''}`"
> >
<input v-model="phpBackupServerCustom" class="input" type="text" :placeholder="$props.data.phpBackupServerCustom.default" /> <input v-model="phpBackupServerCustom" class="input" type="text" :placeholder="$props.data.phpBackupServerCustom.default" />
</div> </div>

View File

@ -1,5 +1,5 @@
<!-- <!--
Copyright 2021 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -41,9 +41,10 @@ THE SOFTWARE.
</div> </div>
<div class="buttons-group"> <div class="buttons-group">
<a v-for="(preset, key) in $props.data" <a
:class="`button${preset.computed ? ' is-primary' : ''}`" v-for="(preset, key) in $props.data"
@click="setPreset(key)" :class="`button${preset.computed ? ' is-primary' : ''}`"
@click="setPreset(key)"
> >
{{ $t(preset.display) }} {{ $t(preset.display) }}
</a> </a>

View File

@ -1,5 +1,5 @@
<!-- <!--
Copyright 2020 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -192,12 +192,13 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div class="field"> <div class="field">
<div :class="`control${responseCodeChanged ? ' is-changed' : ''}`"> <div :class="`control${responseCodeChanged ? ' is-changed' : ''}`">
<input v-model.number="responseCode" <input
:class="['input', validResponseCode ? '' : 'is-danger']" v-model.number="responseCode"
type="number" :class="['input', validResponseCode ? '' : 'is-danger']"
min="100" type="number"
step="1" min="100"
:placeholder="$props.data.responseCode.default" step="1"
:placeholder="$props.data.responseCode.default"
/> />
</div> </div>
</div> </div>

View File

@ -1,5 +1,5 @@
<!-- <!--
Copyright 2020 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -72,10 +72,11 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div :class="`field${pathChanged ? ' is-changed' : ''}`"> <div :class="`field${pathChanged ? ' is-changed' : ''}`">
<div class="control"> <div class="control">
<input v-model="path" <input
class="input" v-model="path"
type="text" class="input"
:placeholder="$props.data.path.default" type="text"
:placeholder="$props.data.path.default"
/> />
</div> </div>
</div> </div>
@ -89,10 +90,11 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div :class="`field${proxyPassChanged ? ' is-changed' : ''}`"> <div :class="`field${proxyPassChanged ? ' is-changed' : ''}`">
<div class="control"> <div class="control">
<input v-model="proxyPass" <input
class="input" v-model="proxyPass"
type="text" class="input"
:placeholder="$props.data.proxyPass.default" type="text"
:placeholder="$props.data.proxyPass.default"
/> />
</div> </div>
</div> </div>

View File

@ -1,5 +1,5 @@
<!-- <!--
Copyright 2020 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -50,8 +50,9 @@ THE SOFTWARE.
</div> </div>
<div class="field-body"> <div class="field-body">
<div class="field"> <div class="field">
<div v-for="value in $props.data.index.options" <div
:class="`control${indexChanged && value === index ? ' is-changed' : ''}`" v-for="value in $props.data.index.options"
:class="`control${indexChanged && value === index ? ' is-changed' : ''}`"
> >
<div class="radio"> <div class="radio">
<PrettyRadio v-model="index" :value="value" class="p-default p-round p-fill p-icon"> <PrettyRadio v-model="index" :value="value" class="p-default p-round p-fill p-icon">
@ -97,10 +98,11 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div :class="`field${fallbackPhpPathChanged ? ' is-changed' : ''}`"> <div :class="`field${fallbackPhpPathChanged ? ' is-changed' : ''}`">
<div class="control"> <div class="control">
<input v-model="fallbackPhpPath" <input
class="input" v-model="fallbackPhpPath"
type="text" class="input"
:placeholder="$props.data.fallbackPhpPath.default" type="text"
:placeholder="$props.data.fallbackPhpPath.default"
/> />
</div> </div>
</div> </div>

View File

@ -1,5 +1,5 @@
<!-- <!--
Copyright 2020 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -32,24 +32,28 @@ THE SOFTWARE.
</p> </p>
<p> <p>
{{ $t('templates.footer.thisToolIs') }} {{ $t('templates.footer.thisToolIs') }}
<ExternalLink :text="$t('templates.footer.openSourceOnGitHub')" <ExternalLink
link="https://github.com/digitalocean/nginxconfig.io" :text="$t('templates.footer.openSourceOnGitHub')"
link="https://github.com/digitalocean/nginxconfig.io"
></ExternalLink> ></ExternalLink>
{{ $t('templates.footer.underThe') }} {{ $t('templates.footer.underThe') }}
<ExternalLink :text="$t('templates.footer.mit')" <ExternalLink
link="https://github.com/digitalocean/nginxconfig.io/blob/master/LICENSE" :text="$t('templates.footer.mit')"
link="https://github.com/digitalocean/nginxconfig.io/blob/master/LICENSE"
></ExternalLink> ></ExternalLink>
{{ $t('templates.footer.license') }} {{ $t('templates.footer.license') }}
{{ $t('templates.footer.weWelcomeFeedbackAndContributions') }} {{ $t('templates.footer.weWelcomeFeedbackAndContributions') }}
</p> </p>
<p> <p>
{{ $t('templates.footer.originallyCreatedBy') }} {{ $t('templates.footer.originallyCreatedBy') }}
<ExternalLink :text="$t('templates.footer.balintSzekeres')" <ExternalLink
link="https://b4lint.hu/" :text="$t('templates.footer.balintSzekeres')"
link="https://b4lint.hu/"
></ExternalLink>, ></ExternalLink>,
{{ $t('templates.footer.maintainedBy') }} {{ $t('templates.footer.maintainedBy') }}
<ExternalLink :text="$t('templates.footer.digitalOcean')" <ExternalLink
link="https://github.com/digitalocean/nginxconfig.io" :text="$t('templates.footer.digitalOcean')"
link="https://github.com/digitalocean/nginxconfig.io"
></ExternalLink>. ></ExternalLink>.
</p> </p>
</div> </div>

View File

@ -1,5 +1,5 @@
<!-- <!--
Copyright 2021 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -37,13 +37,14 @@ THE SOFTWARE.
</ul> </ul>
</div> </div>
<component :is="tab" <component
v-for="tab in tabs" :is="tab"
:key="tab.key" v-for="tab in tabs"
:ref="tab.key" :key="tab.key"
:data="$props.data[tab.key]" :ref="tab.key"
:style="{ display: active === tab.key ? undefined : 'none' }" :data="$props.data[tab.key]"
class="container" :style="{ display: active === tab.key ? undefined : 'none' }"
class="container"
></component> ></component>
<div class="navigation-buttons"> <div class="navigation-buttons">

View File

@ -1,5 +1,5 @@
<!-- <!--
Copyright 2021 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -67,8 +67,9 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div class="field"> <div class="field">
<div class="field"> <div class="field">
<div v-for="(name, value) in $props.data.sslProfile.options" <div
:class="`control${sslProfileChanged && value === sslProfile ? ' is-changed' : ''}`" v-for="(name, value) in $props.data.sslProfile.options"
:class="`control${sslProfileChanged && value === sslProfile ? ' is-changed' : ''}`"
> >
<div class="radio"> <div class="radio">
<PrettyRadio v-model="sslProfile" :value="value" class="p-default p-round p-fill p-icon"> <PrettyRadio v-model="sslProfile" :value="value" class="p-default p-round p-fill p-icon">
@ -97,8 +98,9 @@ THE SOFTWARE.
</div> </div>
</div> </div>
<div v-if="$props.data.ocspCloudflare.computed" class="control field is-horizontal is-expanded"> <div v-if="$props.data.ocspCloudflare.computed" class="control field is-horizontal is-expanded">
<div v-for="(name, value) in $props.data.ocspCloudflareType.options" <div
:class="`control${ocspCloudflareTypeChanged && value === ocspCloudflareType ? ' is-changed' : ''}`" v-for="(name, value) in $props.data.ocspCloudflareType.options"
:class="`control${ocspCloudflareTypeChanged && value === ocspCloudflareType ? ' is-changed' : ''}`"
> >
<div class="radio"> <div class="radio">
<PrettyRadio v-model="ocspCloudflareType" :value="value" class="p-default p-round p-fill p-icon"> <PrettyRadio v-model="ocspCloudflareType" :value="value" class="p-default p-round p-fill p-icon">
@ -118,8 +120,9 @@ THE SOFTWARE.
</div> </div>
</div> </div>
<div v-if="$props.data.ocspGoogle.computed" class="control field is-horizontal is-expanded"> <div v-if="$props.data.ocspGoogle.computed" class="control field is-horizontal is-expanded">
<div v-for="(name, value) in $props.data.ocspGoogleType.options" <div
:class="`control${ocspGoogleTypeChanged && value === ocspGoogleType ? ' is-changed' : ''}`" v-for="(name, value) in $props.data.ocspGoogleType.options"
:class="`control${ocspGoogleTypeChanged && value === ocspGoogleType ? ' is-changed' : ''}`"
> >
<div class="radio"> <div class="radio">
<PrettyRadio v-model="ocspGoogleType" :value="value" class="p-default p-round p-fill p-icon"> <PrettyRadio v-model="ocspGoogleType" :value="value" class="p-default p-round p-fill p-icon">
@ -139,8 +142,9 @@ THE SOFTWARE.
</div> </div>
</div> </div>
<div v-if="$props.data.ocspOpenDns.computed" class="control field is-horizontal is-expanded"> <div v-if="$props.data.ocspOpenDns.computed" class="control field is-horizontal is-expanded">
<div v-for="(name, value) in $props.data.ocspOpenDnsType.options" <div
:class="`control${ocspOpenDnsTypeChanged && value === ocspOpenDnsType ? ' is-changed' : ''}`" v-for="(name, value) in $props.data.ocspOpenDnsType.options"
:class="`control${ocspOpenDnsTypeChanged && value === ocspOpenDnsType ? ' is-changed' : ''}`"
> >
<div class="radio"> <div class="radio">
<PrettyRadio v-model="ocspOpenDnsType" :value="value" class="p-default p-round p-fill p-icon"> <PrettyRadio v-model="ocspOpenDnsType" :value="value" class="p-default p-round p-fill p-icon">
@ -160,8 +164,9 @@ THE SOFTWARE.
</div> </div>
</div> </div>
<div v-if="$props.data.ocspQuad9.computed" class="control field is-horizontal is-expanded"> <div v-if="$props.data.ocspQuad9.computed" class="control field is-horizontal is-expanded">
<div v-for="(name, value) in $props.data.ocspQuad9Type.options" <div
:class="`control${ocspQuad9TypeChanged && value === ocspQuad9Type ? ' is-changed' : ''}`" v-for="(name, value) in $props.data.ocspQuad9Type.options"
:class="`control${ocspQuad9TypeChanged && value === ocspQuad9Type ? ' is-changed' : ''}`"
> >
<div class="radio"> <div class="radio">
<PrettyRadio v-model="ocspQuad9Type" :value="value" class="p-default p-round p-fill p-icon"> <PrettyRadio v-model="ocspQuad9Type" :value="value" class="p-default p-round p-fill p-icon">
@ -181,8 +186,9 @@ THE SOFTWARE.
</div> </div>
</div> </div>
<div v-if="$props.data.ocspVerisign.computed" class="control field is-horizontal is-expanded"> <div v-if="$props.data.ocspVerisign.computed" class="control field is-horizontal is-expanded">
<div v-for="(name, value) in $props.data.ocspVerisignType.options" <div
:class="`control${ocspVerisignTypeChanged && value === ocspVerisignType ? ' is-changed' : ''}`" v-for="(name, value) in $props.data.ocspVerisignType.options"
:class="`control${ocspVerisignTypeChanged && value === ocspVerisignType ? ' is-changed' : ''}`"
> >
<div class="radio"> <div class="radio">
<PrettyRadio v-model="ocspVerisignType" :value="value" class="p-default p-round p-fill p-icon"> <PrettyRadio v-model="ocspVerisignType" :value="value" class="p-default p-round p-fill p-icon">
@ -203,10 +209,11 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div class="field"> <div class="field">
<div :class="`control${letsEncryptRootChanged ? ' is-changed' : ''}`"> <div :class="`control${letsEncryptRootChanged ? ' is-changed' : ''}`">
<input v-model="letsEncryptRoot" <input
class="input" v-model="letsEncryptRoot"
type="text" class="input"
:placeholder="$props.data.letsEncryptRoot.default" type="text"
:placeholder="$props.data.letsEncryptRoot.default"
/> />
</div> </div>
</div> </div>
@ -220,10 +227,11 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div class="field"> <div class="field">
<div :class="`control${letsEncryptCertRootChanged ? ' is-changed' : ''}`"> <div :class="`control${letsEncryptCertRootChanged ? ' is-changed' : ''}`">
<input v-model="letsEncryptCertRoot" <input
class="input" v-model="letsEncryptCertRoot"
type="text" class="input"
:placeholder="$props.data.letsEncryptCertRoot.default" type="text"
:placeholder="$props.data.letsEncryptCertRoot.default"
/> />
</div> </div>
</div> </div>

View File

@ -1,5 +1,5 @@
<!-- <!--
Copyright 2020 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -33,10 +33,11 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div class="field"> <div class="field">
<div :class="`control${accessLogChanged ? ' is-changed' : ''}`"> <div :class="`control${accessLogChanged ? ' is-changed' : ''}`">
<input v-model="accessLog" <input
class="input" v-model="accessLog"
type="text" class="input"
:placeholder="$props.data.accessLog.default" type="text"
:placeholder="$props.data.accessLog.default"
/> />
</div> </div>
</div> </div>
@ -50,10 +51,11 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div class="field"> <div class="field">
<div :class="`control${errorLogChanged ? ' is-changed' : ''}`"> <div :class="`control${errorLogChanged ? ' is-changed' : ''}`">
<input v-model="errorLog" <input
class="input" v-model="errorLog"
type="text" class="input"
:placeholder="$props.data.errorLog.default" type="text"
:placeholder="$props.data.errorLog.default"
/> />
</div> </div>
</div> </div>

View File

@ -1,5 +1,5 @@
<!-- <!--
Copyright 2020 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -33,10 +33,11 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div class="field"> <div class="field">
<div :class="`control${nginxConfigDirectoryChanged ? ' is-changed' : ''}`"> <div :class="`control${nginxConfigDirectoryChanged ? ' is-changed' : ''}`">
<input v-model="nginxConfigDirectory" <input
class="input" v-model="nginxConfigDirectory"
type="text" class="input"
:placeholder="$props.data.nginxConfigDirectory.default" type="text"
:placeholder="$props.data.nginxConfigDirectory.default"
/> />
</div> </div>
</div> </div>
@ -50,9 +51,10 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div class="field"> <div class="field">
<div :class="`control${workerProcessesChanged ? ' is-changed' : ''}`"> <div :class="`control${workerProcessesChanged ? ' is-changed' : ''}`">
<VueSelect v-model="workerProcesses" <VueSelect
:options="$props.data.workerProcesses.options" v-model="workerProcesses"
:clearable="false" :options="$props.data.workerProcesses.options"
:clearable="false"
></VueSelect> ></VueSelect>
</div> </div>
</div> </div>
@ -66,10 +68,11 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div class="field"> <div class="field">
<div :class="`control${userChanged ? ' is-changed' : ''}`"> <div :class="`control${userChanged ? ' is-changed' : ''}`">
<input v-model="user" <input
class="input" v-model="user"
type="text" class="input"
:placeholder="$props.data.user.default" type="text"
:placeholder="$props.data.user.default"
/> />
</div> </div>
</div> </div>
@ -83,10 +86,11 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div class="field"> <div class="field">
<div :class="`control${pidChanged ? ' is-changed' : ''}`"> <div :class="`control${pidChanged ? ' is-changed' : ''}`">
<input v-model="pid" <input
class="input" v-model="pid"
type="text" class="input"
:placeholder="$props.data.pid.default" type="text"
:placeholder="$props.data.pid.default"
/> />
</div> </div>
</div> </div>
@ -100,12 +104,13 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div class="field has-addons"> <div class="field has-addons">
<div :class="`control is-expanded${clientMaxBodySizeChanged ? ' is-changed' : ''}`"> <div :class="`control is-expanded${clientMaxBodySizeChanged ? ' is-changed' : ''}`">
<input v-model.number="clientMaxBodySize" <input
class="input" v-model.number="clientMaxBodySize"
type="number" class="input"
min="0" type="number"
step="1" min="0"
:placeholder="$props.data.clientMaxBodySize.default" step="1"
:placeholder="$props.data.clientMaxBodySize.default"
/> />
</div> </div>
<div class="control"> <div class="control">
@ -124,9 +129,10 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div class="field"> <div class="field">
<div :class="`control${typesHashMaxSizeChanged ? ' is-changed' : ''}`"> <div :class="`control${typesHashMaxSizeChanged ? ' is-changed' : ''}`">
<VueSelect v-model="typesHashMaxSize" <VueSelect
:options="$props.data.typesHashMaxSize.options" v-model="typesHashMaxSize"
:clearable="false" :options="$props.data.typesHashMaxSize.options"
:clearable="false"
></VueSelect> ></VueSelect>
</div> </div>
</div> </div>
@ -140,9 +146,10 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div class="field"> <div class="field">
<div :class="`control${typesHashBucketSizeChanged ? ' is-changed' : ''}`"> <div :class="`control${typesHashBucketSizeChanged ? ' is-changed' : ''}`">
<VueSelect v-model="typesHashBucketSize" <VueSelect
:options="$props.data.typesHashBucketSize.options" v-model="typesHashBucketSize"
:clearable="false" :options="$props.data.typesHashBucketSize.options"
:clearable="false"
></VueSelect> ></VueSelect>
</div> </div>
</div> </div>

View File

@ -1,5 +1,5 @@
<!-- <!--
Copyright 2020 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -82,10 +82,11 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div class="field"> <div class="field">
<div :class="`control${assetsExpirationChanged ? ' is-changed' : ''}`"> <div :class="`control${assetsExpirationChanged ? ' is-changed' : ''}`">
<input v-model="assetsExpiration" <input
class="input" v-model="assetsExpiration"
type="text" class="input"
:placeholder="$props.data.assetsExpiration.default" type="text"
:placeholder="$props.data.assetsExpiration.default"
/> />
</div> </div>
</div> </div>
@ -99,10 +100,11 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div class="field"> <div class="field">
<div :class="`control${mediaExpirationChanged ? ' is-changed' : ''}`"> <div :class="`control${mediaExpirationChanged ? ' is-changed' : ''}`">
<input v-model="mediaExpiration" <input
class="input" v-model="mediaExpiration"
type="text" class="input"
:placeholder="$props.data.mediaExpiration.default" type="text"
:placeholder="$props.data.mediaExpiration.default"
/> />
</div> </div>
</div> </div>
@ -116,10 +118,11 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div class="field"> <div class="field">
<div :class="`control${svgExpirationChanged ? ' is-changed' : ''}`"> <div :class="`control${svgExpirationChanged ? ' is-changed' : ''}`">
<input v-model="svgExpiration" <input
class="input" v-model="svgExpiration"
type="text" class="input"
:placeholder="$props.data.svgExpiration.default" type="text"
:placeholder="$props.data.svgExpiration.default"
/> />
</div> </div>
</div> </div>
@ -133,10 +136,11 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div class="field"> <div class="field">
<div :class="`control${fontsExpirationChanged ? ' is-changed' : ''}`"> <div :class="`control${fontsExpirationChanged ? ' is-changed' : ''}`">
<input v-model="fontsExpiration" <input
class="input" v-model="fontsExpiration"
type="text" class="input"
:placeholder="$props.data.fontsExpiration.default" type="text"
:placeholder="$props.data.fontsExpiration.default"
/> />
</div> </div>
</div> </div>

View File

@ -1,5 +1,5 @@
<!-- <!--
Copyright 2020 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -48,10 +48,11 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div class="field"> <div class="field">
<div :class="`control${pythonServerChanged ? ' is-changed' : ''}`"> <div :class="`control${pythonServerChanged ? ' is-changed' : ''}`">
<input v-model="pythonServer" <input
class="input" v-model="pythonServer"
type="text" class="input"
:placeholder="$props.data.pythonServer.default" type="text"
:placeholder="$props.data.pythonServer.default"
/> />
</div> </div>
</div> </div>

View File

@ -1,5 +1,5 @@
<!-- <!--
Copyright 2021 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -49,12 +49,13 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div class="field has-addons"> <div class="field has-addons">
<div :class="`control is-expanded${proxyConnectTimeoutChanged ? ' is-changed' : ''}`"> <div :class="`control is-expanded${proxyConnectTimeoutChanged ? ' is-changed' : ''}`">
<input v-model.number="proxyConnectTimeout" <input
class="input" v-model.number="proxyConnectTimeout"
type="number" class="input"
min="0" type="number"
step="1" min="0"
:placeholder="$props.data.proxyConnectTimeout.default" step="1"
:placeholder="$props.data.proxyConnectTimeout.default"
/> />
</div> </div>
<div class="control"> <div class="control">
@ -73,12 +74,13 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div class="field has-addons"> <div class="field has-addons">
<div :class="`control is-expanded${proxySendTimeoutChanged ? ' is-changed' : ''}`"> <div :class="`control is-expanded${proxySendTimeoutChanged ? ' is-changed' : ''}`">
<input v-model.number="proxySendTimeout" <input
class="input" v-model.number="proxySendTimeout"
type="number" class="input"
min="0" type="number"
step="1" min="0"
:placeholder="$props.data.proxySendTimeout.default" step="1"
:placeholder="$props.data.proxySendTimeout.default"
/> />
</div> </div>
<div class="control"> <div class="control">
@ -97,12 +99,13 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div class="field has-addons"> <div class="field has-addons">
<div :class="`control is-expanded${proxyReadTimeoutChanged ? ' is-changed' : ''}`"> <div :class="`control is-expanded${proxyReadTimeoutChanged ? ' is-changed' : ''}`">
<input v-model.number="proxyReadTimeout" <input
class="input" v-model.number="proxyReadTimeout"
type="number" class="input"
min="0" type="number"
step="1" min="0"
:placeholder="$props.data.proxyReadTimeout.default" step="1"
:placeholder="$props.data.proxyReadTimeout.default"
/> />
</div> </div>
<div class="control"> <div class="control">
@ -121,8 +124,9 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div class="field"> <div class="field">
<div class="field"> <div class="field">
<div v-for="(name, value) in $props.data.proxyCoexistenceXForwarded.options" <div
:class="`control${proxyCoexistenceXForwardedChanged && value === proxyCoexistenceXForwarded ? ' is-changed' : ''}`" v-for="(name, value) in $props.data.proxyCoexistenceXForwarded.options"
:class="`control${proxyCoexistenceXForwardedChanged && value === proxyCoexistenceXForwarded ? ' is-changed' : ''}`"
> >
<div class="radio"> <div class="radio">
<PrettyRadio v-model="proxyCoexistenceXForwarded" :value="value" class="p-default p-round p-fill p-icon"> <PrettyRadio v-model="proxyCoexistenceXForwarded" :value="value" class="p-default p-round p-fill p-icon">

View File

@ -1,5 +1,5 @@
<!-- <!--
Copyright 2021 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -33,9 +33,10 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div class="field"> <div class="field">
<div :class="`control${referrerPolicyChanged ? ' is-changed' : ''}`"> <div :class="`control${referrerPolicyChanged ? ' is-changed' : ''}`">
<VueSelect v-model="referrerPolicy" <VueSelect
:options="$props.data.referrerPolicy.options" v-model="referrerPolicy"
:clearable="false" :options="$props.data.referrerPolicy.options"
:clearable="false"
></VueSelect> ></VueSelect>
</div> </div>
</div> </div>
@ -49,16 +50,18 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div class="field"> <div class="field">
<div :class="`control${contentSecurityPolicyChanged ? ' is-changed' : ''}`"> <div :class="`control${contentSecurityPolicyChanged ? ' is-changed' : ''}`">
<input v-model="contentSecurityPolicy" <input
class="input" v-model="contentSecurityPolicy"
type="text" class="input"
:placeholder="$props.data.contentSecurityPolicy.default" type="text"
:placeholder="$props.data.contentSecurityPolicy.default"
/> />
</div> </div>
<div v-if="hasWordPress && !hasWordPressUnsafeEval" class="control"> <div v-if="hasWordPress && !hasWordPressUnsafeEval" class="control">
<label class="text message is-warning"> <label class="text message is-warning">
<span class="message-body" <span
v-html="$t('templates.globalSections.security.whenUsingWordPressUnsafeEvalIsOftenRequiredToAllowFunctionality')" class="message-body"
v-html="$t('templates.globalSections.security.whenUsingWordPressUnsafeEvalIsOftenRequiredToAllowFunctionality')"
></span> ></span>
</label> </label>
</div> </div>
@ -73,10 +76,11 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div class="field"> <div class="field">
<div :class="`control${permissionsPolicyChanged ? ' is-changed' : ''}`"> <div :class="`control${permissionsPolicyChanged ? ' is-changed' : ''}`">
<input v-model="permissionsPolicy" <input
class="input" v-model="permissionsPolicy"
type="text" class="input"
:placeholder="$props.data.permissionsPolicy.default" type="text"
:placeholder="$props.data.permissionsPolicy.default"
/> />
</div> </div>
</div> </div>
@ -144,10 +148,11 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div class="field"> <div class="field">
<div :class="`control${securityTxtChanged ? ' is-changed' : ''}`"> <div :class="`control${securityTxtChanged ? ' is-changed' : ''}`">
<input v-model="securityTxtPath" <input
class="input" v-model="securityTxtPath"
type="text" class="input"
:placeholder="$props.data.securityTxtPath.default" type="text"
:placeholder="$props.data.securityTxtPath.default"
/> />
</div> </div>
</div> </div>

View File

@ -1,5 +1,5 @@
<!-- <!--
Copyright 2021 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -70,11 +70,12 @@ THE SOFTWARE.
<div class="field-body"> <div class="field-body">
<div class="field"> <div class="field">
<div class="control"> <div class="control">
<input v-model="shareLink" <input
class="input" v-model="shareLink"
type="text" class="input"
readonly="readonly" type="text"
@click="select" readonly="readonly"
@click="select"
/> />
</div> </div>
</div> </div>

View File

@ -1,5 +1,5 @@
<!-- <!--
Copyright 2021 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -35,12 +35,13 @@ THE SOFTWARE.
</ul> </ul>
</div> </div>
<component :is="tab" <component
v-for="tab in tabs" :is="tab"
:key="tab.key" v-for="tab in tabs"
:data="$props.data" :key="tab.key"
:style="{ display: active === tab.key ? undefined : 'none' }" :data="$props.data"
class="container" :style="{ display: active === tab.key ? undefined : 'none' }"
class="container"
></component> ></component>
<div class="navigation-buttons"> <div class="navigation-buttons">

View File

@ -1,5 +1,5 @@
<!-- <!--
Copyright 2021 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -32,9 +32,10 @@ THE SOFTWARE.
{{ $t('templates.setupSections.certbot.commentOutSslDirectivesInConfiguration') }} {{ $t('templates.setupSections.certbot.commentOutSslDirectivesInConfiguration') }}
<br /> <br />
</p> </p>
<BashPrism :key="sitesAvailable" <BashPrism
:cmd="`sed -i -r 's/(listen .*443)/\\1; #/g; s/(ssl_(certificate|certificate_key|trusted_certificate) )/#;#\\1/g; s/(server \\{)/\\1\\n ssl off;/g' ${sitesAvailable}`" :key="sitesAvailable"
@copied="codeCopiedEvent('Disable ssl directives')" :cmd="`sed -i -r 's/(listen .*443)/\\1; #/g; s/(ssl_(certificate|certificate_key|trusted_certificate) )/#;#\\1/g; s/(server \\{)/\\1\\n ssl off;/g' ${sitesAvailable}`"
@copied="codeCopiedEvent('Disable ssl directives')"
></BashPrism> ></BashPrism>
</li> </li>
@ -43,8 +44,9 @@ THE SOFTWARE.
{{ $t('templates.setupSections.certbot.reloadYourNginxServer') }} {{ $t('templates.setupSections.certbot.reloadYourNginxServer') }}
<br /> <br />
</p> </p>
<BashPrism cmd="sudo nginx -t && sudo systemctl reload nginx" <BashPrism
@copied="codeCopiedEvent('Reload nginx')" cmd="sudo nginx -t && sudo systemctl reload nginx"
@copied="codeCopiedEvent('Reload nginx')"
></BashPrism> ></BashPrism>
</li> </li>
@ -53,9 +55,10 @@ THE SOFTWARE.
{{ $t('templates.setupSections.certbot.obtainSslCertificatesFromLetsEncrypt') }} {{ $t('templates.setupSections.certbot.obtainSslCertificatesFromLetsEncrypt') }}
<br /> <br />
</p> </p>
<BashPrism :key="certbotCmds" <BashPrism
:cmd="certbotCmds" :key="certbotCmds"
@copied="codeCopiedEvent('Obtain certificates using certbot')" :cmd="certbotCmds"
@copied="codeCopiedEvent('Obtain certificates using certbot')"
></BashPrism> ></BashPrism>
</li> </li>
@ -64,9 +67,10 @@ THE SOFTWARE.
{{ $t('templates.setupSections.certbot.uncommentSslDirectivesInConfiguration') }} {{ $t('templates.setupSections.certbot.uncommentSslDirectivesInConfiguration') }}
<br /> <br />
</p> </p>
<BashPrism :key="sitesAvailable" <BashPrism
:cmd="`sed -i -r -z 's/#?; ?#//g; s/(server \\{)\\n ssl off;/\\1/g' ${sitesAvailable}`" :key="sitesAvailable"
@copied="codeCopiedEvent('Enable ssl directives')" :cmd="`sed -i -r -z 's/#?; ?#//g; s/(server \\{)\\n ssl off;/\\1/g' ${sitesAvailable}`"
@copied="codeCopiedEvent('Enable ssl directives')"
></BashPrism> ></BashPrism>
</li> </li>
@ -75,8 +79,9 @@ THE SOFTWARE.
{{ $t('templates.setupSections.certbot.reloadYourNginxServer') }} {{ $t('templates.setupSections.certbot.reloadYourNginxServer') }}
<br /> <br />
</p> </p>
<BashPrism cmd="sudo nginx -t && sudo systemctl reload nginx" <BashPrism
@copied="codeCopiedEvent('Reload nginx (2)')" cmd="sudo nginx -t && sudo systemctl reload nginx"
@copied="codeCopiedEvent('Reload nginx (2)')"
></BashPrism> ></BashPrism>
</li> </li>
@ -85,11 +90,13 @@ THE SOFTWARE.
{{ $t('templates.setupSections.certbot.configureCertbotToReloadNginxOnCertificateRenewal') }} {{ $t('templates.setupSections.certbot.configureCertbotToReloadNginxOnCertificateRenewal') }}
<br /> <br />
</p> </p>
<BashPrism cmd="echo -e '#!/bin/bash\nnginx -t && systemctl reload nginx' | sudo tee /etc/letsencrypt/renewal-hooks/post/nginx-reload.sh" <BashPrism
@copied="codeCopiedEvent('Create nginx auto-restart on renewal')" cmd="echo -e '#!/bin/bash\nnginx -t && systemctl reload nginx' | sudo tee /etc/letsencrypt/renewal-hooks/post/nginx-reload.sh"
@copied="codeCopiedEvent('Create nginx auto-restart on renewal')"
></BashPrism> ></BashPrism>
<BashPrism cmd="sudo chmod a+x /etc/letsencrypt/renewal-hooks/post/nginx-reload.sh" <BashPrism
@copied="codeCopiedEvent('Enable execution of auto-restart')" cmd="sudo chmod a+x /etc/letsencrypt/renewal-hooks/post/nginx-reload.sh"
@copied="codeCopiedEvent('Enable execution of auto-restart')"
></BashPrism> ></BashPrism>
</li> </li>
</ol> </ol>

View File

@ -1,5 +1,5 @@
<!-- <!--
Copyright 2021 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -50,9 +50,10 @@ THE SOFTWARE.
<p> <p>
<span v-html="$t('templates.setupSections.download.navigateToYourNginxConfigurationDirectoryOnYourServer')"></span> <span v-html="$t('templates.setupSections.download.navigateToYourNginxConfigurationDirectoryOnYourServer')"></span>
<br /> <br />
<BashPrism :key="$props.data.global.nginx.nginxConfigDirectory.computed" <BashPrism
:cmd="`cd ${$props.data.global.nginx.nginxConfigDirectory.computed}`" :key="$props.data.global.nginx.nginxConfigDirectory.computed"
@copied="codeCopiedEvent('Navigate to nginx config directory')" :cmd="`cd ${$props.data.global.nginx.nginxConfigDirectory.computed}`"
@copied="codeCopiedEvent('Navigate to nginx config directory')"
></BashPrism> ></BashPrism>
</p> </p>
</li> </li>
@ -61,8 +62,9 @@ THE SOFTWARE.
<p> <p>
<span v-html="$t('templates.setupSections.download.createABackupOfYourCurrentNginxConfiguration')"></span> <span v-html="$t('templates.setupSections.download.createABackupOfYourCurrentNginxConfiguration')"></span>
<br /> <br />
<BashPrism cmd="tar -czvf nginx_$(date +'%F_%H-%M-%S').tar.gz nginx.conf sites-available/ sites-enabled/ nginxconfig.io/" <BashPrism
@copied="codeCopiedEvent('Create nginx config backup tar')" cmd="tar -czvf nginx_$(date +'%F_%H-%M-%S').tar.gz nginx.conf sites-available/ sites-enabled/ nginxconfig.io/"
@copied="codeCopiedEvent('Create nginx config backup tar')"
></BashPrism> ></BashPrism>
</p> </p>
</li> </li>
@ -71,9 +73,10 @@ THE SOFTWARE.
<p> <p>
<span v-html="$t('templates.setupSections.download.extractTheNewCompressedConfigurationArchiveUsingTar')"></span> <span v-html="$t('templates.setupSections.download.extractTheNewCompressedConfigurationArchiveUsingTar')"></span>
<br /> <br />
<BashPrism :key="$parent.tarName" <BashPrism
:cmd="`tar -xzvf ${$parent.tarName} | xargs chmod 0644`" :key="$parent.tarName"
@copied="codeCopiedEvent('Extract new nginx config tar')" :cmd="`tar -xzvf ${$parent.tarName} | xargs chmod 0644`"
@copied="codeCopiedEvent('Extract new nginx config tar')"
></BashPrism> ></BashPrism>
</p> </p>
</li> </li>

View File

@ -1,5 +1,5 @@
<!-- <!--
Copyright 2021 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -32,8 +32,9 @@ THE SOFTWARE.
<p> <p>
{{ $t('templates.setupSections.goLive.reloadNginxToLoadInYourNewConfiguration') }} {{ $t('templates.setupSections.goLive.reloadNginxToLoadInYourNewConfiguration') }}
<br /> <br />
<BashPrism cmd="sudo nginx -t && sudo systemctl reload nginx" <BashPrism
@copied="codeCopiedEvent('Reload nginx')" cmd="sudo nginx -t && sudo systemctl reload nginx"
@copied="codeCopiedEvent('Reload nginx')"
></BashPrism> ></BashPrism>
</p> </p>
</div> </div>

View File

@ -1,5 +1,5 @@
<!-- <!--
Copyright 2021 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -31,9 +31,10 @@ THE SOFTWARE.
<p> <p>
<span v-html="$t('templates.setupSections.ssl.generateDiffieHellmanKeysByRunningThisCommandOnYourServer')"></span> <span v-html="$t('templates.setupSections.ssl.generateDiffieHellmanKeysByRunningThisCommandOnYourServer')"></span>
<br /> <br />
<BashPrism :key="`${$props.data.global.nginx.nginxConfigDirectory.computed}-${diffieHellmanValue}`" <BashPrism
:cmd="`openssl dhparam -out ${$props.data.global.nginx.nginxConfigDirectory.computed}/dhparam.pem ${diffieHellmanValue}`" :key="`${$props.data.global.nginx.nginxConfigDirectory.computed}-${diffieHellmanValue}`"
@copied="codeCopiedEvent('Generate diffie-hellman keys')" :cmd="`openssl dhparam -out ${$props.data.global.nginx.nginxConfigDirectory.computed}/dhparam.pem ${diffieHellmanValue}`"
@copied="codeCopiedEvent('Generate diffie-hellman keys')"
></BashPrism> ></BashPrism>
</p> </p>
</li> </li>
@ -42,13 +43,15 @@ THE SOFTWARE.
<p> <p>
<span v-html="$t('templates.setupSections.ssl.createACommonAcmeChallengeDirectoryForLetsEncrypt')"></span> <span v-html="$t('templates.setupSections.ssl.createACommonAcmeChallengeDirectoryForLetsEncrypt')"></span>
<br /> <br />
<BashPrism :key="letsEncryptDir" <BashPrism
:cmd="`mkdir -p ${letsEncryptDir}`" :key="letsEncryptDir"
@copied="codeCopiedEvent('Create let\'s encrypt directory')" :cmd="`mkdir -p ${letsEncryptDir}`"
@copied="codeCopiedEvent('Create let\'s encrypt directory')"
></BashPrism> ></BashPrism>
<BashPrism :key="`${nginxUser}-${letsEncryptDir}`" <BashPrism
:cmd="`chown ${nginxUser} ${letsEncryptDir}`" :key="`${nginxUser}-${letsEncryptDir}`"
@copied="codeCopiedEvent('Set let\'s encrypt directory ownership')" :cmd="`chown ${nginxUser} ${letsEncryptDir}`"
@copied="codeCopiedEvent('Set let\'s encrypt directory ownership')"
></BashPrism> ></BashPrism>
</p> </p>
</li> </li>

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2020 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -24,7 +24,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
*/ */
import { fromSep } from './language_pack_name'; import { fromSep } from './language_packs';
export default availablePacks => { export default availablePacks => {
if (typeof window === 'object' && typeof window.navigator === 'object') { if (typeof window === 'object' && typeof window.navigator === 'object') {

View File

@ -1,37 +0,0 @@
/*
Copyright 2020 DigitalOcean
This code is licensed under the MIT License.
You may obtain a copy of the License at
https://github.com/digitalocean/nginxconfig.io/blob/master/LICENSE or https://mit-license.org/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
import { fromSep } from './language_pack_name';
// Use webpack magic to only build chunks for lang/index.js, not subdirectories (e.g. lang/templates/index.js)
export const languagePackContext = require.context('../i18n', true, /^\.\/[^/]+\/index\.js$/, 'lazy');
// Webpack magic to get all the packs that are available
export const availablePacks = Object.freeze(languagePackContext
.keys()
.map(pack => pack.match(/^\.\/([^/]+)\/index\.js$/))
.filter(pack => pack !== null)
.map(pack => fromSep(pack[1], '-')));

View File

@ -1,30 +0,0 @@
/*
Copyright 2020 DigitalOcean
This code is licensed under the MIT License.
You may obtain a copy of the License at
https://github.com/digitalocean/nginxconfig.io/blob/master/LICENSE or https://mit-license.org/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
export const defaultPack = 'en';
export { default as defaultPackData } from '../i18n/en';

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2020 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -24,6 +24,10 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
*/ */
export const defaultPack = 'en';
export { default as defaultPackData } from '../i18n/en';
export const toSep = (pack, sep) => pack export const toSep = (pack, sep) => pack
.match(/^([a-z]+)([A-Z]*)$/) .match(/^([a-z]+)([A-Z]*)$/)
.slice(1) .slice(1)
@ -32,3 +36,16 @@ export const toSep = (pack, sep) => pack
.join(sep); .join(sep);
export const fromSep = (pack, sep) => pack.split(sep, 2)[0].toLowerCase() + (pack.split(sep, 2)[1] || '').toUpperCase(); export const fromSep = (pack, sep) => pack.split(sep, 2)[0].toLowerCase() + (pack.split(sep, 2)[1] || '').toUpperCase();
// Export a static array of all language packs
export const availablePacks = Object.freeze([
'de',
'en',
'es',
'fr',
'pl',
'ptBR',
'ru',
'zhCN',
'zhTW',
]);

View File

@ -1,5 +1,5 @@
/* /*
Copyright 2021 DigitalOcean Copyright 2022 DigitalOcean
This code is licensed under the MIT License. This code is licensed under the MIT License.
You may obtain a copy of the License at You may obtain a copy of the License at
@ -24,12 +24,12 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.
*/ */
const path = require('path'); import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer';
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer'); import DuplicatePackageCheckerPlugin from 'duplicate-package-checker-webpack-plugin';
const DuplicatePackageCheckerPlugin = require('duplicate-package-checker-webpack-plugin'); import WebpackRequireFrom from 'webpack-require-from';
const WebpackRequireFrom = require('webpack-require-from'); import { URL, fileURLToPath } from 'url';
module.exports = { export default {
publicPath: './', publicPath: './',
outputDir: 'dist', outputDir: 'dist',
filenameHashing: false, // Don't hash the output, so we can embed on the DigitalOcean Community filenameHashing: false, // Don't hash the output, so we can embed on the DigitalOcean Community
@ -43,10 +43,10 @@ module.exports = {
// Fix dynamic imports from CDN (inject as first entry point before any imports can happen) // Fix dynamic imports from CDN (inject as first entry point before any imports can happen)
{ apply: compiler => { { apply: compiler => {
compiler.options.entry.app.import.unshift( compiler.options.entry.app.import.unshift(
path.join(__dirname, 'src', 'nginxconfig', 'build', 'webpack-dynamic-import.js'), fileURLToPath(new URL('src/nginxconfig/build/webpack-dynamic-import.js', import.meta.url)),
); );
} }, } },
new WebpackRequireFrom({ methodName: '__webpackDynamicImportURL' }), new WebpackRequireFrom({ methodName: '__webpackDynamicImportURL', suppressErrors: true }),
// Analyze the bundle // Analyze the bundle
new BundleAnalyzerPlugin({ analyzerMode: 'static', openAnalyzer: false }), new BundleAnalyzerPlugin({ analyzerMode: 'static', openAnalyzer: false }),
new DuplicatePackageCheckerPlugin(), new DuplicatePackageCheckerPlugin(),
@ -68,7 +68,7 @@ module.exports = {
// Use a custom HTML template // Use a custom HTML template
config.plugin('html').tap(options => { config.plugin('html').tap(options => {
options[0].template = path.join(__dirname, 'build', 'index.html'); options[0].template = fileURLToPath(new URL('build/index.html', import.meta.url));
return options; return options;
}); });
}, },