List all config changes & show diff on click
parent
19bb84df78
commit
5f21ac9fc5
|
@ -0,0 +1,49 @@
|
||||||
|
import React from 'react';
|
||||||
|
import ReactDiffViewer, { DiffMethod } from 'react-diff-viewer';
|
||||||
|
import { AttributeIcon } from '@buffetjs/core';
|
||||||
|
import {
|
||||||
|
HeaderModal,
|
||||||
|
HeaderModalTitle,
|
||||||
|
Modal,
|
||||||
|
ModalBody,
|
||||||
|
ModalFooter,
|
||||||
|
} from 'strapi-helper-plugin';
|
||||||
|
|
||||||
|
const ConfigDiff = ({ isOpen, onClose, onToggle, oldValue, newValue, configName }) => {
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
isOpen={isOpen}
|
||||||
|
onClosed={onClose}
|
||||||
|
onToggle={onToggle}
|
||||||
|
>
|
||||||
|
<HeaderModal>
|
||||||
|
<section style={{ alignItems: 'center' }}>
|
||||||
|
<AttributeIcon type='enum' />
|
||||||
|
<HeaderModalTitle style={{ marginLeft: 15 }}>Config changes for {configName}</HeaderModalTitle>
|
||||||
|
</section>
|
||||||
|
</HeaderModal>
|
||||||
|
<ModalBody style={{
|
||||||
|
paddingTop: '0.5rem',
|
||||||
|
paddingBottom: '3rem'
|
||||||
|
}}>
|
||||||
|
<div className="container-fluid">
|
||||||
|
<section style={{ marginTop: 20 }}>
|
||||||
|
<ReactDiffViewer
|
||||||
|
oldValue={JSON.stringify(oldValue, null, 2)}
|
||||||
|
newValue={JSON.stringify(newValue, null, 2)}
|
||||||
|
splitView={true}
|
||||||
|
compareMethod={DiffMethod.WORDS}
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</ModalBody>
|
||||||
|
<ModalFooter>
|
||||||
|
<section style={{ alignItems: 'center' }}>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
</ModalFooter>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ConfigDiff;
|
|
@ -0,0 +1,66 @@
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import { Table } from '@buffetjs/core';
|
||||||
|
import difference from '../../helpers/getObjectDiff';
|
||||||
|
import ConfigDiff from '../ConfigDiff';
|
||||||
|
|
||||||
|
const headers = [
|
||||||
|
{
|
||||||
|
name: 'Id',
|
||||||
|
value: 'id',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Config name',
|
||||||
|
value: 'name',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Database table',
|
||||||
|
value: 'lastname',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Change',
|
||||||
|
value: 'change_type',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const ConfigList = ({ fileConfig, databaseConfig }) => {
|
||||||
|
const diff = difference(fileConfig.toJS(), databaseConfig.toJS());
|
||||||
|
const [openModal, setOpenModal] = useState(false);
|
||||||
|
const [originalConfig, setOriginalConfig] = useState({});
|
||||||
|
const [newConfig, setNewConfig] = useState({});
|
||||||
|
const [configName, setConfigName] = useState('');
|
||||||
|
let rows = [];
|
||||||
|
|
||||||
|
Object.keys(diff).map((config) => rows.push({ name: config }));
|
||||||
|
|
||||||
|
const closeModal = () => {
|
||||||
|
setOriginalConfig({});
|
||||||
|
setNewConfig({});
|
||||||
|
setConfigName('');
|
||||||
|
setOpenModal(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<ConfigDiff
|
||||||
|
isOpen={openModal}
|
||||||
|
oldValue={originalConfig}
|
||||||
|
newValue={newConfig}
|
||||||
|
onClose={closeModal}
|
||||||
|
onToggle={closeModal}
|
||||||
|
configName={configName}
|
||||||
|
/>
|
||||||
|
<Table
|
||||||
|
headers={headers}
|
||||||
|
onClickRow={(e, data) => {
|
||||||
|
setOriginalConfig(fileConfig.get(data.name));
|
||||||
|
setNewConfig(databaseConfig.get(data.name));
|
||||||
|
setConfigName(data.name);
|
||||||
|
setOpenModal(true);
|
||||||
|
}}
|
||||||
|
rows={rows}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ConfigList;
|
|
@ -6,21 +6,15 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Switch, Route } from 'react-router-dom';
|
|
||||||
import { NotFound } from 'strapi-helper-plugin';
|
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
|
|
||||||
import { store } from "../../helpers/configureStore";
|
import { store } from "../../helpers/configureStore";
|
||||||
import pluginId from '../../helpers/pluginId';
|
|
||||||
import ConfigPage from '../ConfigPage';
|
import ConfigPage from '../ConfigPage';
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
return (
|
return (
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<Switch>
|
<ConfigPage />
|
||||||
<Route path={`/plugins/${pluginId}`} component={ConfigPage} exact />
|
|
||||||
<Route component={NotFound} />
|
|
||||||
</Switch>
|
|
||||||
</Provider>
|
</Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import React, { useEffect } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
import ReactDiffViewer from 'react-diff-viewer';
|
|
||||||
import { Map } from 'immutable';
|
import { Map } from 'immutable';
|
||||||
|
|
||||||
import { getAllDatabaseConfig, getAllFileConfig } from '../../state/actions/Config';
|
import { getAllDatabaseConfig, getAllFileConfig } from '../../state/actions/Config';
|
||||||
|
import ConfigList from '../../components/ConfigList';
|
||||||
|
|
||||||
const ConfigPage = () => {
|
const ConfigPage = () => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
@ -15,17 +15,14 @@ const ConfigPage = () => {
|
||||||
dispatch(getAllFileConfig());
|
dispatch(getAllFileConfig());
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (!fileConfig || !databaseConfig) {
|
if (fileConfig.size === 0 || databaseConfig.size === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ReactDiffViewer
|
<div>
|
||||||
oldValue={JSON.stringify(fileConfig.get('plugin_users-permissions_email'), null, 2)}
|
<ConfigList fileConfig={fileConfig} databaseConfig={databaseConfig} />
|
||||||
newValue={JSON.stringify(databaseConfig.get('plugin_users-permissions_email'), null, 2)}
|
</div>
|
||||||
splitView={true}
|
|
||||||
disableWordDiff
|
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { transform, isEqual, isArray, isObject } from 'lodash';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find difference between two objects
|
||||||
|
* @param {object} origObj - Source object to compare newObj against
|
||||||
|
* @param {object} newObj - New object with potential changes
|
||||||
|
* @return {object} differences
|
||||||
|
*/
|
||||||
|
const difference = (origObj, newObj) => {
|
||||||
|
function changes(newObj, origObj) {
|
||||||
|
let arrayIndexCounter = 0
|
||||||
|
return transform(newObj, function (result, value, key) {
|
||||||
|
if (!isEqual(value, origObj[key])) {
|
||||||
|
let resultKey = isArray(origObj) ? arrayIndexCounter++ : key
|
||||||
|
result[resultKey] = (isObject(value) && isObject(origObj[key])) ? changes(value, origObj[key]) : value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return changes(newObj, origObj)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default difference;
|
|
@ -13,7 +13,6 @@
|
||||||
"react-diff-viewer": "^3.1.1",
|
"react-diff-viewer": "^3.1.1",
|
||||||
"react-dom": "^17.0.1",
|
"react-dom": "^17.0.1",
|
||||||
"react-redux": "^7.2.2",
|
"react-redux": "^7.2.2",
|
||||||
"react-router-dom": "^5.2.0",
|
|
||||||
"redux": "^4.0.5",
|
"redux": "^4.0.5",
|
||||||
"redux-immutable": "^4.0.0",
|
"redux-immutable": "^4.0.0",
|
||||||
"redux-logger": "^3.0.6",
|
"redux-logger": "^3.0.6",
|
||||||
|
|
Loading…
Reference in New Issue