Skip to content

Commit

Permalink
Bulk edit instructions and confirmation modal (#2151)
Browse files Browse the repository at this point in the history
* add detailed instructions to bulk edit

* add bulk confirmation page

* transifex fixes

* remove comment
  • Loading branch information
jschwarz2030 authored Nov 6, 2023
1 parent e808f1a commit 6bc33af
Show file tree
Hide file tree
Showing 6 changed files with 266 additions and 57 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import { jsSchema as basemapJsSchema,
uiSchema as basemapUiSchema } from './BulkSchemas/BasemapSchema'
import { jsSchema as dataSourceJsSchema,
uiSchema as dataSourceUiSchema } from './BulkSchemas/DataSourceSchema'
import { jsSchema as instructionsJsSchema,
uiSchema as instructionsUiSchema } from './BulkSchemas/InstructionsSchema'
import messages from './Messages'

// Define individual workflow steps. Steps can be driven by either schemas or
Expand Down Expand Up @@ -72,6 +74,15 @@ const prioritiesStep = {
viewBox: "0 0 100 125",
}

const instructionsStep = {
id: 'Instructions',
description: <FormattedMessage {...messages.instructionsStepDescription} />,
jsSchema: instructionsJsSchema,
uiSchema: instructionsUiSchema,
icon: "priority-icon",
viewBox: "0 0 100 125",
}

// String together workflow steps for creating a new challenge
const bulkEditSteps = {
'Data Source': Object.assign({}, dataSourceStep, {
Expand All @@ -84,6 +95,11 @@ const bulkEditSteps = {
previous: 'AdvancedOptions',
canFinish: true,
}),
'Instructions': Object.assign({}, instructionsStep, {
next: 'AdvancedOptions',
previous: 'AdvancedOptions',
canFinish: true,
}),
'Tags': Object.assign({}, tagsStep, {
next: 'AdvancedOptions',
previous: 'AdvancedOptions',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import messages from '../Messages'

export const jsSchema = (intl) => {
const schemaFields = {
"$schema": "http://json-schema.org/draft-07/schema#",
type: "object",
properties: {
instruction: {
title: intl.formatMessage(messages.instructionLabel),
type: "string",
minLength: 150,
description: intl.formatMessage(messages.instructionsDescription),
},
},
}

return schemaFields
}

export const uiSchema = (intl) => {
const uiSchemaFields = {
"ui:order": [ "instruction" ],
instruction: {
"ui:field": "markdown",
"ui:help": intl.formatMessage(messages.instructionDescription),
"ui:previewNote": intl.formatMessage(messages.addMustachePreviewNote),
},
}

return uiSchemaFields
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ import WithChallengeManagement from "../../../HOCs/WithChallengeManagement/WithC
import WithCurrentUser from "../../../../HOCs/WithCurrentUser/WithCurrentUser";
import WithTallied from "../../../HOCs/WithTallied/WithTallied";
import WithTaskPropertyStyleRules from "../../../HOCs/WithTaskPropertyStyleRules/WithTaskPropertyStyleRules";
import External from "../../../../External/External";
import Modal from "../../../../Modal/Modal";
import { Light as SyntaxHighlighter } from 'react-syntax-highlighter'
import jsonLang from 'react-syntax-highlighter/dist/esm/languages/hljs/json'
import highlightColors from 'react-syntax-highlighter/dist/esm/styles/hljs/agate'
import {
ChallengeCategoryKeywords
} from "../../../../../services/Challenge/ChallengeKeywords/ChallengeKeywords";
Expand All @@ -36,6 +41,10 @@ import manageMessages from "../../Messages";
import messages from "./Messages";
import "./EditChallenge.scss";

SyntaxHighlighter.registerLanguage('json', jsonLang)

highlightColors.hljs.background="rgba(0, 0, 0, 0.15)"

export class EditChallenges extends Component {
challengeState = null;

Expand All @@ -46,6 +55,7 @@ export class EditChallenges extends Component {
isSaving: false,
expandedFieldGroups: {},
challengeNumberSaving: 0,
confirmModal: false,
};

validationPromise = null;
Expand Down Expand Up @@ -83,6 +93,7 @@ export class EditChallenges extends Component {
preferredTags: formData.preferredTags,
exportableProperties: formData.exportableProperties,
customBasemap: formData.customBasemap,
instruction: formData.instruction,
defaultBasemap: formData.defaultBasemap,
defaultBasemapId: formData.defaultBasemapId,
defaultPriority: formData.defaultPriority,
Expand Down Expand Up @@ -148,6 +159,16 @@ export class EditChallenges extends Component {
return challengeData;
};

toggleConfirmModal = (bool) => {
if (bool) {
this.prepareFormDataForSaving().then(async (formData) => {
this.setState({ confirmModal: formData })
})
} else {
this.setState({ confirmModal: false })
}
}

/**
* Performs the reverse of prepareChallengeDataForForm, taking the form data
* and massaging it back into the format of challenge data expected by the
Expand Down Expand Up @@ -302,65 +323,81 @@ export class EditChallenges extends Component {
};

return (
<BreadcrumbWrapper
{...this.props}
cancel={this.cancel}
isCloningChallenge={false}
isNewChallenge={false}
challengeState={this.challengeState}
>
<div className="mr-flex">
<div className="mr-p-4 md:mr-p-8 mr-w-full">
<Form
schema={activeStep.jsSchema(
this.props.intl,
this.props.user,
challengeData,
this.state.extraErrors,
{
longForm: true,
}
)}
uiSchema={activeStep.uiSchema(
this.props.intl,
this.props.user,
challengeData,
this.state.extraErrors,
{
longForm: true,
<>
<BreadcrumbWrapper
{...this.props}
cancel={this.cancel}
isCloningChallenge={false}
isNewChallenge={false}
challengeState={this.challengeState}
>
<div className="mr-flex">
<div className="mr-p-4 md:mr-p-8 mr-w-full">
<Form
schema={activeStep.jsSchema(
this.props.intl,
this.props.user,
challengeData,
this.state.extraErrors,
{
longForm: true,
}
)}
uiSchema={activeStep.uiSchema(
this.props.intl,
this.props.user,
challengeData,
this.state.extraErrors,
{
longForm: true,
}
)}
className="form"
validate={(formData, errors) =>
this.validate(formData, errors, activeStep)
}
)}
className="form"
validate={(formData, errors) =>
this.validate(formData, errors, activeStep)
}
transformErrors={this.transformErrors(this.props.intl)}
widgets={{
SelectWidget: CustomSelectWidget,
TextWidget: CustomTextWidget,
}}
ArrayFieldTemplate={CustomArrayFieldTemplate}
FieldTemplate={CustomFieldTemplate}
fields={customFields}
tagType={"challenges"}
noHtml5Validate
showErrorList={false}
formData={challengeData}
formContext={_merge(this.state.formContext, {
bounding: _get(challengeData, "bounding"),
buttonAction: BoundsSelectorModal,
})}
onChange={this.changeHandler}
onSubmit={(formData) =>
this.handleSubmit(formData, nextStep)
}
onError={() => null}
extraErrors={this.state.extraErrors}
>
</Form>
transformErrors={this.transformErrors(this.props.intl)}
widgets={{
SelectWidget: CustomSelectWidget,
TextWidget: CustomTextWidget,
}}
ArrayFieldTemplate={CustomArrayFieldTemplate}
FieldTemplate={CustomFieldTemplate}
fields={customFields}
tagType={"challenges"}
noHtml5Validate
showErrorList={false}
formData={challengeData}
formContext={_merge(this.state.formContext, {
bounding: _get(challengeData, "bounding"),
buttonAction: BoundsSelectorModal,
})}
onChange={this.changeHandler}
onSubmit={(formData) => {
this.toggleConfirmModal(formData)
}}
onError={() => null}
extraErrors={this.state.extraErrors}
>
</Form>
</div>
</div>
</div>
</BreadcrumbWrapper>
</BreadcrumbWrapper>
{
this.state.confirmModal
? <ConfirmationModal
formData={this.state.confirmModal}
submit={() => {
this.toggleConfirmModal(false)
this.handleSubmit(formData, nextStep)}
}
cancel={() => {
this.toggleConfirmModal(false)
}}
/>
: null
}
</>
);
}}
/>
Expand Down Expand Up @@ -444,6 +481,110 @@ const BreadcrumbWrapper = (props) => {
);
};

const confirmationMap = () => {
return [
{
id: 'additionalKeywords',
displayName: <FormattedMessage {...messages.additionalKeywordsLabel} />
},
{
id: 'taskTags',
displayName: <FormattedMessage {...messages.preferredTagsLabel} />
},
{
id: 'exportableProperties',
displayName: <FormattedMessage {...messages.exportablePropertiesLabel} />
},
{
id: 'customBasemap',
displayName: <FormattedMessage {...messages.customBasemapLabel} />
},
{
id: 'instruction',
displayName: <FormattedMessage {...messages.instructionLabel} />,
props: {
wrapLines: true,
lineProps: { style: { wordBreak: 'break-all', whiteSpace: 'pre-wrap'} }
}
},
{
id: 'defaultBasemapId',
displayName: <FormattedMessage {...messages.defaultBasemapLabel} />,
},
{
id: 'defaultPriority',
displayName: <FormattedMessage {...messages.defaultPriorityLabel} />,
},
{
id: 'dataOriginDate',
displayName: <FormattedMessage {...messages.dataOriginDateLabel} />,
},
{
id: 'highPriorityRule',
default: "{}",
json: true,
displayName: <FormattedMessage {...messages.highPriorityRulesLabel} />,
},
{
id: 'mediumPriorityRule',
default: "{}",
json: true,
displayName: <FormattedMessage {...messages.mediumPriorityRulesLabel} />,
},
{
id: 'lowPriorityRule',
default: "{}",
json: true,
displayName: <FormattedMessage {...messages.lowPriorityRulesLabel} />,
}
]
}

class ConfirmationModal extends Component {
render() {
const { formData } = this.props
return (
<External>
<Modal
fullScreen
isActive={true}
onClose={this.props.onClose}
>
<h1 style={{ marginBottom: 10 }}><FormattedMessage {...messages.reviewAndSubmitLabel} /></h1>
<div className="mr-text-red mr-text-lg" style={{ marginBottom: 14 }}><FormattedMessage {...messages.bulkEditWarningLabel} /></div>
{confirmationMap().map((data) => {
if (formData[data.id] && formData[data.id] !== data.default) {
const val = data.json ? JSON.parse(formData[data.id]) : formData[data.id]
return (
<div key={data.id} style={{ marginBottom: 10 }}>
<div>{data.displayName || data.id}</div>
<SyntaxHighlighter language="json" style={{ ...highlightColors }} {...data.props}>
{JSON.stringify(val, null, 4)}
</SyntaxHighlighter>
</div>
)
}
})}
<button
type="button"
className="mr-button mr-button--white mr-button--small mr-mr-8 mr-text-red mr-border-red"
onClick={() => this.props.submit()}
>
<FormattedMessage {...messages.submitChallenges} />
</button>
<button
type="button"
className="mr-button mr-button--white mr-button--small"
onClick={() => this.props.cancel()}
>
<FormattedMessage {...messages.cancelChallenges} />
</button>
</Modal>
</External>
)
}
}

export default WithCurrentUser(
WithCurrentProject(
(WithTaskPropertyStyleRules(
Expand Down
Loading

0 comments on commit 6bc33af

Please sign in to comment.