Skip to content

Commit

Permalink
Implemented contention functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
rmathis committed May 20, 2021
1 parent 7a2cbec commit 5796c10
Show file tree
Hide file tree
Showing 26 changed files with 594 additions and 129 deletions.
5 changes: 3 additions & 2 deletions ui/public/assets/schema/provider/dynamic-http.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@
{
"properties": {
"initializeFromPersistentCacheInBackground": {
"const": true
"enum": [true]
},
"backgroundInitializationFromCacheDelay": {
"title": "label.background-init-from-cache-delay",
Expand All @@ -129,9 +129,10 @@
{
"properties": {
"initializeFromPersistentCacheInBackground": {
"const": false
"enum": [false]
}
}

}
]
}
Expand Down
51 changes: 27 additions & 24 deletions ui/src/app/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { UserConfirmation, ConfirmWindow } from './core/components/UserConfirmat
import { NewSource } from './metadata/new/NewSource';
import { NewProvider } from './metadata/new/NewProvider';
import { Filter } from './metadata/Filter';
import { Contention } from './metadata/contention/ContentionContext';


function App() {
Expand All @@ -43,30 +44,32 @@ function App() {
<Notifications>
<UserProvider>
<I18nProvider>
<UserConfirmation>
{(message, confirm, confirmCallback, setConfirm, getConfirmation) =>
<Router getUserConfirmation={getConfirmation}>
<ConfirmWindow message={message} confirm={confirm} confirmCallback={confirmCallback} setConfirm={setConfirm} />
<QueryParamProvider ReactRouterRoute={Route}>
<Header />
<main className="pad-content">
<Switch>
<Route exact path="/">
<Redirect to="/dashboard" />
</Route>
<Route path="/dashboard" component={Dashboard} />
<Route path="/metadata/source/new" component={NewSource} />
<Route path="/metadata/provider/new" component={NewProvider} />
<Route path={`/metadata/provider/:id/filter`} component={Filter} />
<Route path="/metadata/:type/:id" component={Metadata} />
</Switch>
<NotificationList />
</main>
<Footer />
</QueryParamProvider>
</Router>
}
</UserConfirmation>
<Contention>
<UserConfirmation>
{(message, confirm, confirmCallback, setConfirm, getConfirmation) =>
<Router getUserConfirmation={getConfirmation}>
<ConfirmWindow message={message} confirm={confirm} confirmCallback={confirmCallback} setConfirm={setConfirm} />
<QueryParamProvider ReactRouterRoute={Route}>
<Header />
<main className="pad-content">
<Switch>
<Route exact path="/">
<Redirect to="/dashboard" />
</Route>
<Route path="/dashboard" component={Dashboard} />
<Route path="/metadata/source/new" component={NewSource} />
<Route path="/metadata/provider/new" component={NewProvider} />
<Route path={`/metadata/provider/:id/filter`} component={Filter} />
<Route path="/metadata/:type/:id" component={Metadata} />
</Switch>
<NotificationList />
</main>
<Footer />
</QueryParamProvider>
</Router>
}
</UserConfirmation>
</Contention>
</I18nProvider>
</UserProvider>
</Notifications>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ const AttributeReleaseWidget = ({
const all = (enumOptions).map(({ value }) => value);

if (checked) {
console.log(selectValue(option.value, value, all))
onChange(selectValue(option.value, value, all));
} else {
onChange(deselectValue(option.value, value));
Expand Down
3 changes: 3 additions & 0 deletions ui/src/app/form/component/widgets/OptionWidget.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ const OptionWidget = ({
uiSchema,
...props
}) => {

console.log(value, props)

const _onChange = (selected) => onChange(selected[0] === '' ? options.emptyValue : selected[0]);
const _onBlur = ({ target: { value } }) => onBlur(id, value);
const _onFocus = ({ target: { value } }) => onFocus(id, value);
Expand Down
5 changes: 4 additions & 1 deletion ui/src/app/metadata/Filter.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { Switch, Route, useRouteMatch, Redirect } from 'react-router-dom';
import { MetadataFilterList } from './editor/MetadataFilterList';
import MetadataFilterSelector from './hoc/MetadataFilterSelector';
import MetadataSchema from './hoc/MetadataSchema';
import MetadataSelector from './hoc/MetadataSelector';
import { NewFilter } from './new/NewFilter';
Expand All @@ -25,7 +26,9 @@ export function Filter() {
<NewFilter />
} />
<Route path={`${path}/:filterId/edit/:section`} render={() =>
<EditFilter />
<MetadataFilterSelector>
<EditFilter />
</MetadataFilterSelector>
} />
<Redirect exact path={`${path}/new`} to={`${path}/new/common`} />
</Switch>
Expand Down
3 changes: 0 additions & 3 deletions ui/src/app/metadata/component/properties/ObjectProperty.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ export function ObjectProperty ({ property, columns, onPreview }) {
case 'array':
return <ArrayProperty key={ `p-${idx}` } property={prop} columns={columns} />
case 'object':
if (prop.widget && prop.widget.id && prop.widget.id === 'filter-target') {
console.log(prop);
}
return <React.Fragment key={`p-${idx}`}>
{prop.widget && prop.widget.id && prop.widget.id === 'filter-target' ?
<FilterTargetProperty property={prop} columns={columns} onPreview={onPreview} />
Expand Down
157 changes: 157 additions & 0 deletions ui/src/app/metadata/contention/ContentionContext.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import React from "react";

import { updatedDiff } from 'deep-object-diff';
import { removeNull } from '../../core/utility/remove_null';

import {ContentionModal} from './component/ContentionModal';

const ContentionContext = React.createContext();

const { Provider, Consumer } = ContentionContext;

const initialState = {
theirs: null,
ours: null,
base: null,
ourChanges: null,
theirChanges: null,
resolution: null,
reject: null,
resolve: null,
show: false
};

export const ContentionActions = {
OPEN_CONTENTION_MODAL: 'open contention',
END_CONTENTION: 'end contention'
};

const keys = [
'version',
'modifiedDate',
'createdDate',
'createdBy',
'modifiedBy',
'audId',
'resourceId',
'current',
'@type'
];

const filterKeys = (key => (keys.indexOf(key) === -1));


const getContention = (base, ours, theirs) => {

let theirDiff = updatedDiff(base, theirs);
let ourDiff = updatedDiff(base, removeNull(ours));
let ourKeys = Object.keys(ourDiff).filter(filterKeys);
let theirKeys = Object.keys(theirDiff).filter(filterKeys);

const ourChanges = ourKeys.map(key => getChangeItem(key, ours));
const theirChanges = theirKeys.map(key => getChangeItem(key, theirs, ourKeys));
const resolution = { ...base, ...ours, version: theirs.version }

return {
ourChanges,
theirChanges,
resolution
};
}

const getChangeItem = (key, collection, compare = []) => {
return {
label: key,
value: collection[key],
conflict: compare.some(o => o === key)
};
}


export const openContentionModalAction = (base, theirs, ours, resolve, reject) => {

const { ourChanges, theirChanges, resolution } = getContention(base, ours, theirs);

return {
type: ContentionActions.OPEN_CONTENTION_MODAL,
payload: {
base,
theirs,
ours,
theirChanges,
ourChanges,
resolution,
reject,
resolve
}
}
}

export const resolveContentionAction = () => {
return {
type: ContentionActions.END_CONTENTION,
}
}

function reducer(state, action) {
switch (action.type) {
case ContentionActions.OPEN_CONTENTION_MODAL:
return {
...action.payload,
show: true
};
case ContentionActions.END_CONTENTION:
return {
...initialState,
show: false
};
default:
throw new Error();
}
}

/*eslint-disable react-hooks/exhaustive-deps*/
function Contention({ children }) {
const [state, dispatch] = React.useReducer(reducer, initialState);

const { show, theirs, theirChanges, ourChanges, resolution, reject, resolve } = state;

const onReject = () => {
reject(theirs);
dispatch(resolveContentionAction());
}

const onResolve = () => {
resolve(resolution);
dispatch(resolveContentionAction());
}

const contextValue = React.useMemo(() => ({ state, dispatch }), [state, dispatch]);

return (
<React.Fragment>
<ContentionModal
theirs={theirChanges}
ours={ourChanges}
show={show}
onUseTheirs={() => onReject()}
onUseOurs={() => onResolve(resolution)}
backdrop="static"
keyboard={false} />
<Provider value={contextValue}>{children}</Provider>
</React.Fragment>
);
}

function useContentionDispatcher() {
const { dispatch } = React.useContext(ContentionContext);
return dispatch;
}

export {
Contention,
ContentionContext,
useContentionDispatcher,
Provider as ContentionProvider,
Consumer as ContentionConsumer
};
Loading

0 comments on commit 5796c10

Please sign in to comment.