Merge pull request #94 from The-Real-Established/master

feat: added option to download zip
pull/153/head
Boaz Poolman 2024-10-16 22:48:38 +02:00 committed by GitHub
commit 8ba4dbb728
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 95 additions and 6 deletions

View File

@ -8,7 +8,7 @@ import { getFetchClient, useNotification } from '@strapi/strapi/admin';
import { useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
import ConfirmModal from '../ConfirmModal'; import ConfirmModal from '../ConfirmModal';
import { exportAllConfig, importAllConfig } from '../../state/actions/Config'; import { exportAllConfig, importAllConfig, downloadZip } from '../../state/actions/Config';
const ActionButtons = () => { const ActionButtons = () => {
const { post, get } = getFetchClient(); const { post, get } = getFetchClient();
@ -40,6 +40,7 @@ const ActionButtons = () => {
{!isEmpty(partialDiff) && ( {!isEmpty(partialDiff) && (
<Typography variant="epsilon">{Object.keys(partialDiff).length} {Object.keys(partialDiff).length === 1 ? "config change" : "config changes"}</Typography> <Typography variant="epsilon">{Object.keys(partialDiff).length} {Object.keys(partialDiff).length === 1 ? "config change" : "config changes"}</Typography>
)} )}
<Button onClick={() => dispatch(downloadZip(toggleNotification, formatMessage, post, get))}>{formatMessage({ id: 'config-sync.Buttons.DownloadConfig' })}</Button>
</ActionButtonsStyling> </ActionButtonsStyling>
); );
}; };
@ -52,6 +53,9 @@ const ActionButtonsStyling = styled.div`
> button { > button {
margin-right: 10px; margin-right: 10px;
} }
> button:last-of-type {
margin-left: auto;
}
`; `;
export default ActionButtons; export default ActionButtons;

View File

@ -0,0 +1,9 @@
export function b64toBlob(dataURI, type) {
const byteString = atob(dataURI);
const ab = new ArrayBuffer(byteString.length);
const ia = new Uint8Array(ab);
for (let i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ab], { type });
}

View File

@ -3,6 +3,8 @@
* Main actions * Main actions
* *
*/ */
import { saveAs } from 'file-saver';
import { b64toBlob } from '../../helpers/blob';
export function getAllConfigDiff(toggleNotification, formatMessage, get) { export function getAllConfigDiff(toggleNotification, formatMessage, get) {
return async function(dispatch) { return async function(dispatch) {
@ -50,6 +52,23 @@ export function exportAllConfig(partialDiff, toggleNotification, formatMessage,
}; };
} }
export function downloadZip(toggleNotification, formatMessage, post, get) {
return async function(dispatch) {
dispatch(setLoadingState(true));
try {
const { message, base64Data, name } = (await get('/config-sync/zip')).data;
toggleNotification({ type: 'success', message });
if (base64Data) {
saveAs(b64toBlob(base64Data, 'application/zip'), name, { type: 'application/zip' });
}
dispatch(setLoadingState(false));
} catch (err) {
toggleNotification({ type: 'warning', message: formatMessage({ id: 'notification.error' }) });
dispatch(setLoadingState(false));
}
};
}
export function importAllConfig(partialDiff, force, toggleNotification, formatMessage, post, get) { export function importAllConfig(partialDiff, force, toggleNotification, formatMessage, post, get) {
return async function(dispatch) { return async function(dispatch) {
dispatch(setLoadingState(true)); dispatch(setLoadingState(true));

View File

@ -28,6 +28,7 @@
"ConfigDiff.Database": "Database", "ConfigDiff.Database": "Database",
"Buttons.Export": "Export", "Buttons.Export": "Export",
"Buttons.DownloadConfig": "Download Config",
"Buttons.Import": "Import", "Buttons.Import": "Import",
"FirstExport.Message": "Looks like this is your first time using config-sync for this project.", "FirstExport.Message": "Looks like this is your first time using config-sync for this project.",

View File

@ -30,6 +30,7 @@
"chalk": "^4.1.2", "chalk": "^4.1.2",
"cli-table": "^0.3.6", "cli-table": "^0.3.6",
"commander": "^8.3.0", "commander": "^8.3.0",
"file-saver": "^2.0.5",
"git-diff": "^2.0.6", "git-diff": "^2.0.6",
"immutable": "^3.8.2", "immutable": "^3.8.2",
"inquirer": "^8.2.0", "inquirer": "^8.2.0",

View File

@ -173,7 +173,7 @@ const ConfigType = class ConfigType {
* @param {string} configName - The name of the config file. * @param {string} configName - The name of the config file.
* @returns {void} * @returns {void}
*/ */
exportSingle = async (configName) => { exportSingle = async (configName) => {
const formattedDiff = await strapi.plugin('config-sync').service('main').getFormattedDiff(this.configPrefix); const formattedDiff = await strapi.plugin('config-sync').service('main').getFormattedDiff(this.configPrefix);
// Check if the config should be excluded. // Check if the config should be excluded.
@ -193,6 +193,17 @@ const ConfigType = class ConfigType {
} }
} }
/**
* Zip config files
*
* @param {string} configName - The name of the zip archive.
* @returns {void}
*/
zipConfig = async () => {
return strapi.plugin('config-sync').service('main').zipConfigFiles();
}
/** /**
* Get all role-permissions config from the db. * Get all role-permissions config from the db.
* *
@ -243,7 +254,7 @@ const ConfigType = class ConfigType {
* *
* @returns {void} * @returns {void}
*/ */
importAll = async () => { importAll = async () => {
// The main.importAllConfig service will loop the core-store.importSingle service. // The main.importAllConfig service will loop the core-store.importSingle service.
await strapi.plugin('config-sync').service('main').importAllConfig(this.configPrefix); await strapi.plugin('config-sync').service('main').importAllConfig(this.configPrefix);
} }
@ -253,7 +264,7 @@ const ConfigType = class ConfigType {
* *
* @returns {void} * @returns {void}
*/ */
exportAll = async () => { exportAll = async () => {
// The main.importAllConfig service will loop the core-store.importSingle service. // The main.importAllConfig service will loop the core-store.importSingle service.
await strapi.plugin('config-sync').service('main').exportAllConfig(this.configPrefix); await strapi.plugin('config-sync').service('main').exportAllConfig(this.configPrefix);
} }

View File

@ -84,6 +84,19 @@ module.exports = {
return strapi.plugin('config-sync').service('main').getFormattedDiff(); return strapi.plugin('config-sync').service('main').getFormattedDiff();
}, },
zipConfig: async (ctx) => {
// Check for existance of the config file sync dir.
if (!fs.existsSync(strapi.config.get('plugin.config-sync.syncDir'))) {
ctx.send({
message: 'No config files were found.',
});
return;
}
return strapi.plugin('config-sync').service('main').zipConfigFiles();
},
/** /**
* Get the current Strapi env. * Get the current Strapi env.
* @returns {string} The current Strapi environment. * @returns {string} The current Strapi environment.

View File

@ -27,6 +27,14 @@ module.exports = {
policies: [], policies: [],
}, },
}, },
{
method: "GET",
path: "/zip",
handler: "config.zipConfig",
config: {
policies: [],
},
},
{ {
method: "GET", method: "GET",
path: "/app-env", path: "/app-env",

View File

@ -3,6 +3,7 @@
const { isEmpty } = require('lodash'); const { isEmpty } = require('lodash');
const fs = require('fs'); const fs = require('fs');
const util = require('util'); const util = require('util');
const childProcess = require("child_process");
const difference = require('../utils/getObjectDiff'); const difference = require('../utils/getObjectDiff');
const { logMessage } = require('../utils'); const { logMessage } = require('../utils');
@ -54,7 +55,7 @@ module.exports = () => ({
* @param {string} configName - The name of the config file. * @param {string} configName - The name of the config file.
* @returns {void} * @returns {void}
*/ */
deleteConfigFile: async (configName) => { deleteConfigFile: async (configName) => {
// Check if the config should be excluded. // Check if the config should be excluded.
const shouldExclude = !isEmpty(strapi.config.get('plugin::config-sync.excludedConfig').filter((option) => configName.startsWith(option))); const shouldExclude = !isEmpty(strapi.config.get('plugin::config-sync.excludedConfig').filter((option) => configName.startsWith(option)));
if (shouldExclude) return; if (shouldExclude) return;
@ -65,6 +66,23 @@ module.exports = () => ({
fs.unlinkSync(`${strapi.config.get('plugin::config-sync.syncDir')}${configName}.json`); fs.unlinkSync(`${strapi.config.get('plugin::config-sync.syncDir')}${configName}.json`);
}, },
/**
* Zip config files.
*
* @param {string} configName - The name of the config file.
* @returns {void}
*/
zipConfigFiles: async () => {
const fileName = `config-${new Date().toJSON()}.zip`;
childProcess.execSync(`zip -r ${fileName} *`, {
cwd: strapi.config.get('plugin.config-sync.syncDir'),
});
const fullFilePath = `${strapi.config.get('plugin.config-sync.syncDir')}${fileName}`;
const base64Data = fs.readFileSync(fullFilePath, { encoding: 'base64' });
fs.unlinkSync(fullFilePath);
return { base64Data, name: fileName, message: 'Success' };
},
/** /**
* Read from a config file. * Read from a config file.
* *
@ -191,7 +209,7 @@ module.exports = () => ({
* @param {object} onSuccess - Success callback to run on each single successfull import. * @param {object} onSuccess - Success callback to run on each single successfull import.
* @returns {void} * @returns {void}
*/ */
exportAllConfig: async (configType = null, onSuccess) => { exportAllConfig: async (configType = null, onSuccess) => {
const fileConfig = await strapi.plugin('config-sync').service('main').getAllConfigFromFiles(); const fileConfig = await strapi.plugin('config-sync').service('main').getAllConfigFromFiles();
const databaseConfig = await strapi.plugin('config-sync').service('main').getAllConfigFromDatabase(); const databaseConfig = await strapi.plugin('config-sync').service('main').getAllConfigFromDatabase();

View File

@ -6610,6 +6610,11 @@ file-entry-cache@^6.0.1:
dependencies: dependencies:
flat-cache "^3.0.4" flat-cache "^3.0.4"
file-saver@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/file-saver/-/file-saver-2.0.5.tgz#d61cfe2ce059f414d899e9dd6d4107ee25670c38"
integrity sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==
fill-range@^4.0.0: fill-range@^4.0.0:
version "4.0.0" version "4.0.0"
resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7"