commit
8ad30f8301
14
README.md
14
README.md
|
@ -66,7 +66,17 @@ npm run build
|
||||||
npm run develop
|
npm run develop
|
||||||
```
|
```
|
||||||
|
|
||||||
The **Config Sync** plugin should appear in the **Plugins** section of Strapi sidebar after you run app again.
|
The **Config Sync** plugin should now appear in the **Settings** section of your Strapi app.
|
||||||
|
|
||||||
|
To start tracking your config changes you have to make the first export. This will dump all your configuration data to the `/config/sync` directory. To export, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# using yarn
|
||||||
|
yarn config-sync export
|
||||||
|
|
||||||
|
# using npm
|
||||||
|
npm run config-sync export
|
||||||
|
```
|
||||||
|
|
||||||
Enjoy 🎉
|
Enjoy 🎉
|
||||||
|
|
||||||
|
@ -76,7 +86,7 @@ Complete installation requirements are the exact same as for Strapi itself and c
|
||||||
|
|
||||||
**Supported Strapi versions**:
|
**Supported Strapi versions**:
|
||||||
|
|
||||||
- Strapi 4.0.7 (recently tested)
|
- Strapi 4.1.5 (recently tested)
|
||||||
- Strapi ^4.x (use `strapi-plugin-config-sync@^1.0.0`)
|
- Strapi ^4.x (use `strapi-plugin-config-sync@^1.0.0`)
|
||||||
- Strapi ^3.4.x (use `strapi-plugin-config-sync@0.1.6`)
|
- Strapi ^3.4.x (use `strapi-plugin-config-sync@0.1.6`)
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ import React from 'react';
|
||||||
import ReactDiffViewer, { DiffMethod } from 'react-diff-viewer';
|
import ReactDiffViewer, { DiffMethod } from 'react-diff-viewer';
|
||||||
|
|
||||||
import { ModalLayout, ModalBody, ModalHeader } from '@strapi/design-system/ModalLayout';
|
import { ModalLayout, ModalBody, ModalHeader } from '@strapi/design-system/ModalLayout';
|
||||||
import { ButtonText } from '@strapi/design-system/Text';
|
|
||||||
import { Grid, GridItem } from '@strapi/design-system/Grid';
|
import { Grid, GridItem } from '@strapi/design-system/Grid';
|
||||||
import { Typography } from '@strapi/design-system/Typography';
|
import { Typography } from '@strapi/design-system/Typography';
|
||||||
|
|
||||||
|
@ -17,9 +16,9 @@ const ConfigDiff = ({ isOpen, onClose, oldValue, newValue, configName }) => {
|
||||||
labelledBy="title"
|
labelledBy="title"
|
||||||
>
|
>
|
||||||
<ModalHeader>
|
<ModalHeader>
|
||||||
<ButtonText textColor="neutral800" as="h2" id="title">
|
<Typography variant="omega" fontWeight="bold" textColor="neutral800">
|
||||||
Config changes for {configName}
|
Config changes for {configName}
|
||||||
</ButtonText>
|
</Typography>
|
||||||
</ModalHeader>
|
</ModalHeader>
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
<Grid paddingBottom={4} style={{ textAlign: 'center' }}>
|
<Grid paddingBottom={4} style={{ textAlign: 'center' }}>
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { isEmpty } from 'lodash';
|
||||||
import { useDispatch } from 'react-redux';
|
import { useDispatch } from 'react-redux';
|
||||||
|
|
||||||
import { Table, Thead, Tbody, Tr, Th } from '@strapi/design-system/Table';
|
import { Table, Thead, Tbody, Tr, Th } from '@strapi/design-system/Table';
|
||||||
import { TableLabel } from '@strapi/design-system/Text';
|
import { Typography } from '@strapi/design-system/Typography';
|
||||||
import { BaseCheckbox } from '@strapi/design-system/BaseCheckbox';
|
import { BaseCheckbox } from '@strapi/design-system/BaseCheckbox';
|
||||||
import { Loader } from '@strapi/design-system/Loader';
|
import { Loader } from '@strapi/design-system/Loader';
|
||||||
|
|
||||||
|
@ -127,13 +127,13 @@ const ConfigList = ({ diff, isLoading }) => {
|
||||||
/>
|
/>
|
||||||
</Th>
|
</Th>
|
||||||
<Th>
|
<Th>
|
||||||
<TableLabel>Config name</TableLabel>
|
<Typography variant="sigma">Config name</Typography>
|
||||||
</Th>
|
</Th>
|
||||||
<Th>
|
<Th>
|
||||||
<TableLabel>Config type</TableLabel>
|
<Typography variant="sigma">Config type</Typography>
|
||||||
</Th>
|
</Th>
|
||||||
<Th>
|
<Th>
|
||||||
<TableLabel>State</TableLabel>
|
<Typography variant="sigma">State</Typography>
|
||||||
</Th>
|
</Th>
|
||||||
</Tr>
|
</Tr>
|
||||||
</Thead>
|
</Thead>
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { useIntl } from 'react-intl';
|
||||||
|
|
||||||
import { Dialog, DialogBody, DialogFooter } from '@strapi/design-system/Dialog';
|
import { Dialog, DialogBody, DialogFooter } from '@strapi/design-system/Dialog';
|
||||||
import { Flex } from '@strapi/design-system/Flex';
|
import { Flex } from '@strapi/design-system/Flex';
|
||||||
import { Text } from '@strapi/design-system/Text';
|
import { Typography } from '@strapi/design-system/Typography';
|
||||||
import { Stack } from '@strapi/design-system/Stack';
|
import { Stack } from '@strapi/design-system/Stack';
|
||||||
import { Button } from '@strapi/design-system/Button';
|
import { Button } from '@strapi/design-system/Button';
|
||||||
import ExclamationMarkCircle from '@strapi/icons/ExclamationMarkCircle';
|
import ExclamationMarkCircle from '@strapi/icons/ExclamationMarkCircle';
|
||||||
|
@ -22,10 +22,10 @@ const ConfirmModal = ({ isOpen, onClose, onSubmit, type }) => {
|
||||||
<DialogBody icon={<ExclamationMarkCircle />}>
|
<DialogBody icon={<ExclamationMarkCircle />}>
|
||||||
<Stack size={2}>
|
<Stack size={2}>
|
||||||
<Flex justifyContent="center">
|
<Flex justifyContent="center">
|
||||||
<Text id="confirm-description" style={{ textAlign: 'center' }}>
|
<Typography variant="omega" id="confirm-description" style={{ textAlign: 'center' }}>
|
||||||
{formatMessage({ id: `config-sync.popUpWarning.warning.${type}_1` })}<br />
|
{formatMessage({ id: `config-sync.popUpWarning.warning.${type}_1` })}<br />
|
||||||
{formatMessage({ id: `config-sync.popUpWarning.warning.${type}_2` })}
|
{formatMessage({ id: `config-sync.popUpWarning.warning.${type}_2` })}
|
||||||
</Text>
|
</Typography>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Stack>
|
</Stack>
|
||||||
</DialogBody>
|
</DialogBody>
|
||||||
|
|
|
@ -2,6 +2,7 @@ import React, { useEffect } from 'react';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
import { Map } from 'immutable';
|
import { Map } from 'immutable';
|
||||||
import { Box } from '@strapi/design-system/Box';
|
import { Box } from '@strapi/design-system/Box';
|
||||||
|
import { ContentLayout } from '@strapi/design-system/Layout';
|
||||||
import { useNotification } from '@strapi/helper-plugin';
|
import { useNotification } from '@strapi/helper-plugin';
|
||||||
import { Alert } from '@strapi/design-system/Alert';
|
import { Alert } from '@strapi/design-system/Alert';
|
||||||
import { Typography } from '@strapi/design-system/Typography';
|
import { Typography } from '@strapi/design-system/Typography';
|
||||||
|
@ -23,7 +24,7 @@ const ConfigPage = () => {
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box paddingLeft={8} paddingRight={8} paddingBottom={8}>
|
<ContentLayout paddingBottom={8}>
|
||||||
{appEnv === 'production' && (
|
{appEnv === 'production' && (
|
||||||
<Box paddingBottom={4}>
|
<Box paddingBottom={4}>
|
||||||
<Alert variant="danger">
|
<Alert variant="danger">
|
||||||
|
@ -35,7 +36,7 @@ const ConfigPage = () => {
|
||||||
)}
|
)}
|
||||||
<ActionButtons />
|
<ActionButtons />
|
||||||
<ConfigList isLoading={isLoading} diff={configDiff.toJS()} />
|
<ConfigList isLoading={isLoading} diff={configDiff.toJS()} />
|
||||||
</Box>
|
</ContentLayout>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { prefixPluginTranslations } from '@strapi/helper-plugin';
|
import { prefixPluginTranslations } from '@strapi/helper-plugin';
|
||||||
import pluginPkg from '../../package.json';
|
import pluginPkg from '../../package.json';
|
||||||
import pluginId from './helpers/pluginId';
|
import pluginId from './helpers/pluginId';
|
||||||
import pluginIcon from './components/PluginIcon';
|
|
||||||
import pluginPermissions from './permissions';
|
import pluginPermissions from './permissions';
|
||||||
|
// import pluginIcon from './components/PluginIcon';
|
||||||
// import getTrad from './helpers/getTrad';
|
// import getTrad from './helpers/getTrad';
|
||||||
|
|
||||||
const pluginDescription = pluginPkg.strapi.description || pluginPkg.description;
|
const pluginDescription = pluginPkg.strapi.description || pluginPkg.description;
|
||||||
|
@ -18,22 +18,33 @@ export default {
|
||||||
name,
|
name,
|
||||||
});
|
});
|
||||||
|
|
||||||
app.addMenuLink({
|
app.createSettingSection(
|
||||||
to: `/plugins/${pluginId}`,
|
{
|
||||||
icon: pluginIcon,
|
id: pluginId,
|
||||||
intlLabel: {
|
intlLabel: {
|
||||||
id: `${pluginId}.plugin.name`,
|
id: `${pluginId}.plugin.name`,
|
||||||
defaultMessage: 'Config Sync',
|
defaultMessage: 'Config Sync',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Component: async () => {
|
[
|
||||||
const component = await import(
|
{
|
||||||
/* webpackChunkName: "config-sync-settings-page" */ './containers/App'
|
intlLabel: {
|
||||||
);
|
id: `${pluginId}.Settings.Tool.Title`,
|
||||||
|
defaultMessage: 'Tools',
|
||||||
|
},
|
||||||
|
id: 'config-sync-page',
|
||||||
|
to: `/settings/${pluginId}`,
|
||||||
|
Component: async () => {
|
||||||
|
const component = await import(
|
||||||
|
/* webpackChunkName: "config-sync-settings-page" */ './containers/App'
|
||||||
|
);
|
||||||
|
|
||||||
return component;
|
return component;
|
||||||
},
|
},
|
||||||
permissions: pluginPermissions['menu-link'],
|
permissions: pluginPermissions['settings'],
|
||||||
});
|
},
|
||||||
|
],
|
||||||
|
);
|
||||||
},
|
},
|
||||||
bootstrap(app) {},
|
bootstrap(app) {},
|
||||||
async registerTrads({ locales }) {
|
async registerTrads({ locales }) {
|
||||||
|
|
|
@ -10,5 +10,7 @@
|
||||||
"Header.Title": "Config Sync",
|
"Header.Title": "Config Sync",
|
||||||
"Header.Description": "Manage your database config across environments.",
|
"Header.Description": "Manage your database config across environments.",
|
||||||
|
|
||||||
|
"Settings.Tool.Title": "Tool",
|
||||||
|
|
||||||
"plugin.name": "Config Sync"
|
"plugin.name": "Config Sync"
|
||||||
}
|
}
|
||||||
|
|
12
package.json
12
package.json
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "strapi-plugin-config-sync",
|
"name": "strapi-plugin-config-sync",
|
||||||
"version": "1.0.0-beta.8",
|
"version": "1.0.0-beta.8",
|
||||||
"description": "CLI & GUI for syncing config data across environments.",
|
"description": "Migrate your config data across environments using the CLI or Strapi admin panel.",
|
||||||
"strapi": {
|
"strapi": {
|
||||||
"displayName": "Config Sync",
|
"displayName": "Config Sync",
|
||||||
"name": "config-sync",
|
"name": "config-sync",
|
||||||
"icon": "sync",
|
"icon": "sync",
|
||||||
"description": "CLI & GUI for syncing config data across environments.",
|
"description": "Migrate your config data across environments using the CLI or Strapi admin panel.",
|
||||||
"required": false,
|
"required": false,
|
||||||
"kind": "plugin"
|
"kind": "plugin"
|
||||||
},
|
},
|
||||||
|
@ -57,10 +57,10 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@fortawesome/react-fontawesome": "^0.1.16",
|
"@fortawesome/react-fontawesome": "^0.1.16",
|
||||||
"@strapi/design-system": "^0.0.1-alpha.75",
|
"@strapi/design-system": "^0.0.1-alpha.79",
|
||||||
"@strapi/helper-plugin": "^4.0.7",
|
"@strapi/helper-plugin": "^4.1.5",
|
||||||
"@strapi/icons": "^0.0.1-alpha.75",
|
"@strapi/icons": "^0.0.1-alpha.79",
|
||||||
"@strapi/utils": "^4.0.7",
|
"@strapi/utils": "^4.1.5",
|
||||||
"babel-eslint": "9.0.0",
|
"babel-eslint": "9.0.0",
|
||||||
"eslint": "^7.32.0",
|
"eslint": "^7.32.0",
|
||||||
"eslint-config-airbnb": "^18.2.1",
|
"eslint-config-airbnb": "^18.2.1",
|
||||||
|
|
|
@ -15,9 +15,9 @@
|
||||||
"jest-cli": "^26.0.1"
|
"jest-cli": "^26.0.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@strapi/plugin-i18n": "^4.0.2",
|
"@strapi/plugin-i18n": "^4.0.0",
|
||||||
"@strapi/plugin-users-permissions": "^4.0.2",
|
"@strapi/plugin-users-permissions": "^4.0.0",
|
||||||
"@strapi/strapi": "^4.0.2",
|
"@strapi/strapi": "^4.0.0",
|
||||||
"sqlite3": "5.0.2",
|
"sqlite3": "5.0.2",
|
||||||
"strapi-plugin-config-sync": "boazpoolman/strapi-plugin-config-sync"
|
"strapi-plugin-config-sync": "boazpoolman/strapi-plugin-config-sync"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
const { Command } = require('commander');
|
const { Command } = require('commander');
|
||||||
const Table = require('cli-table');
|
const Table = require('cli-table');
|
||||||
const chalk = require('chalk');
|
const chalk = require('chalk');
|
||||||
|
@ -68,6 +69,14 @@ const getConfigState = (diff, configName, syncType) => {
|
||||||
|
|
||||||
const handleAction = async (syncType, skipConfirm, configType, partials) => {
|
const handleAction = async (syncType, skipConfirm, configType, partials) => {
|
||||||
const app = await strapi().load();
|
const app = await strapi().load();
|
||||||
|
const hasSyncDir = fs.existsSync(app.config.get('plugin.config-sync.syncDir'));
|
||||||
|
|
||||||
|
// No import with empty sync dir.
|
||||||
|
if (!hasSyncDir && syncType === 'import') {
|
||||||
|
console.log(`${chalk.yellow.bold('[warning]')} You can't import an empty sync directory. Please export before continuing.`);
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
const diff = await app.plugin('config-sync').service('main').getFormattedDiff();
|
const diff = await app.plugin('config-sync').service('main').getFormattedDiff();
|
||||||
|
|
||||||
// No changes.
|
// No changes.
|
||||||
|
@ -109,7 +118,9 @@ const handleAction = async (syncType, skipConfirm, configType, partials) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Print table.
|
// Print table.
|
||||||
console.log(table.toString(), '\n');
|
if (hasSyncDir) {
|
||||||
|
console.log(table.toString(), '\n');
|
||||||
|
}
|
||||||
|
|
||||||
// Prompt to confirm.
|
// Prompt to confirm.
|
||||||
let answer = {};
|
let answer = {};
|
||||||
|
|
34
yarn.lock
34
yarn.lock
|
@ -814,19 +814,19 @@
|
||||||
dependencies:
|
dependencies:
|
||||||
"@sinonjs/commons" "^1.7.0"
|
"@sinonjs/commons" "^1.7.0"
|
||||||
|
|
||||||
"@strapi/design-system@^0.0.1-alpha.75":
|
"@strapi/design-system@^0.0.1-alpha.79":
|
||||||
version "0.0.1-alpha.75"
|
version "0.0.1-alpha.79"
|
||||||
resolved "https://registry.yarnpkg.com/@strapi/design-system/-/design-system-0.0.1-alpha.75.tgz#8a06eb07a0d25791a93537578387e401dff116d2"
|
resolved "https://registry.yarnpkg.com/@strapi/design-system/-/design-system-0.0.1-alpha.79.tgz#23e6a7f73383b72148c926fa74ed0ba1acc32f0a"
|
||||||
integrity sha512-JSIRFCiAOtTbjMDIa/KULSkfyPP/mphBhJDdeBx8bLNDKhU0SX3/zSXghjMWQ48aHvmyWTfwm8SVdw6EolzpIQ==
|
integrity sha512-o/F55Qjwao1HkqKcL8ovQ280QijJH8dLfzP+t3XMNL5Ihh3HBD2wcMS6dOsrnNDGdDE0LWQfG8bDbLPmWHmk1A==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@internationalized/number" "^3.0.2"
|
"@internationalized/number" "^3.0.2"
|
||||||
compute-scroll-into-view "^1.0.17"
|
compute-scroll-into-view "^1.0.17"
|
||||||
prop-types "^15.7.2"
|
prop-types "^15.7.2"
|
||||||
|
|
||||||
"@strapi/helper-plugin@^4.0.7":
|
"@strapi/helper-plugin@^4.1.5":
|
||||||
version "4.0.7"
|
version "4.1.5"
|
||||||
resolved "https://registry.yarnpkg.com/@strapi/helper-plugin/-/helper-plugin-4.0.7.tgz#5eb91e0faf4496769ad5a2bd90a06be58f1840d2"
|
resolved "https://registry.yarnpkg.com/@strapi/helper-plugin/-/helper-plugin-4.1.5.tgz#f6032b38af88a02d64552cbb48ca382bc48c5288"
|
||||||
integrity sha512-0rFjdr7ZBi7P//dD56eL3LEaA2bQ9+ooqqYz9v9hMm9NCWJm8j7ybKUghLpoIUca48DKGItb9ap2BDt0CYKSAw==
|
integrity sha512-Pog53h0W+dgA+QjZpcrPgtt+hkBcRx9LYJ/CAW+BMCtqnqP0qcqQFtP5xPPxSJCkkmPX4GJT3XRWJUnjdPEq/A==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@fortawesome/fontawesome-free" "^5.15.2"
|
"@fortawesome/fontawesome-free" "^5.15.2"
|
||||||
"@fortawesome/fontawesome-svg-core" "^1.2.35"
|
"@fortawesome/fontawesome-svg-core" "^1.2.35"
|
||||||
|
@ -850,15 +850,17 @@
|
||||||
styled-components "^5.2.3"
|
styled-components "^5.2.3"
|
||||||
whatwg-fetch "^3.6.2"
|
whatwg-fetch "^3.6.2"
|
||||||
|
|
||||||
"@strapi/icons@^0.0.1-alpha.75":
|
"@strapi/icons@^0.0.1-alpha.79":
|
||||||
version "0.0.1-alpha.75"
|
version "0.0.1-alpha.79"
|
||||||
resolved "https://registry.yarnpkg.com/@strapi/icons/-/icons-0.0.1-alpha.75.tgz#12a38c2c921cedc26f5bd8c3aa91c5b82246c066"
|
resolved "https://registry.yarnpkg.com/@strapi/icons/-/icons-0.0.1-alpha.79.tgz#eff8790ea3897419489a61cbfd72a436661d1420"
|
||||||
integrity sha512-h9ZlIPVg95+WaBsXEthKSw9eZQ/VsuuZE5aad/4Cx0NBEUyQl+0h5Z/JqIUSNMX4KMyJJjo9Ad4FGUyOLNHLmw==
|
integrity sha512-mIPzpwOir92939rSRuRS22GLWFpLfQDyoK0vMZUsGD7uujNnRon//TUa9DJTjTHjdEjRwWO60JbJOePgJ+2cvg==
|
||||||
|
dependencies:
|
||||||
|
rimraf "^3.0.2"
|
||||||
|
|
||||||
"@strapi/utils@^4.0.7":
|
"@strapi/utils@^4.1.5":
|
||||||
version "4.0.7"
|
version "4.1.5"
|
||||||
resolved "https://registry.yarnpkg.com/@strapi/utils/-/utils-4.0.7.tgz#718823fcf23c028a65ce8c317a36cc6d7321eb0c"
|
resolved "https://registry.yarnpkg.com/@strapi/utils/-/utils-4.1.5.tgz#3e80f59476cab470ba0fdb42a075b5ae47e998f2"
|
||||||
integrity sha512-coGjVudsnlXvb20mobyeoguCfXKnLjXnKhYiMoS6wqy4ozazu12+5MsCh7Hs9UAkvK4Fzhf7+urvyoj/UpSkaQ==
|
integrity sha512-Oz7ur7TsoqA4IOPdk6H3YwsVZ+FOi9wp+iRReKao8yfo4YKJjSYlHQlNXUaAqOOlFnT0ol7G3KF+uF8jLcfxDA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@sindresorhus/slugify" "1.1.0"
|
"@sindresorhus/slugify" "1.1.0"
|
||||||
date-fns "2.24.0"
|
date-fns "2.24.0"
|
||||||
|
|
Loading…
Reference in New Issue