Passage en lecture seule du DAD lorsqu'il appartient à un groupe différent #21

Manually merged
wpetit merged 1 commits from feature/dsf-front-acl into develop 2020-09-10 11:20:19 +02:00
5 changed files with 76 additions and 39 deletions
Showing only changes of commit 17747e998d - Show all commits

View File

@ -7,7 +7,7 @@ export interface ClarificationSectionProps extends DecisionSupportFileUpdaterPro
const ClarificationSectionName = 'clarification';
export const ClarificationSection: FunctionComponent<ClarificationSectionProps> = ({ dsf, updateDSF }) => {
export const ClarificationSection: FunctionComponent<ClarificationSectionProps> = ({ dsf, updateDSF, readOnly }) => {
const [ state, setState ] = useState({
changed: false,
section: {
@ -51,15 +51,16 @@ export const ClarificationSection: FunctionComponent<ClarificationSectionProps>
<section>
<div className="box">
<div className="field">
<label className="label">Intitulé du dossier</label>
<label className="label is-medium">Intitulé du dossier</label>
<div className="control">
<input className="input" type="text" value={dsf.title} onChange={onTitleChange} />
<input className="input is-medium" type="text" readOnly={readOnly} value={dsf.title} onChange={onTitleChange} />
</div>
</div>
<div className="field">
<label className="label">Quelle décision devons nous prendre ?</label>
<label className="label is-medium">Quelle décision devons nous prendre ?</label>
<div className="control">
<textarea className="textarea"
<textarea className="textarea is-medium"
readOnly={readOnly}
value={state.section.objectives}
onChange={onSectionAttrChange.bind(null, 'objectives')}
placeholder="Décrire globalement les tenants et aboutissants de la décision à prendre."
@ -69,9 +70,10 @@ export const ClarificationSection: FunctionComponent<ClarificationSectionProps>
<p className="help is-info"><i className="fa fa-info-circle"></i> Ne pas essayer de rentrer trop dans les détails ici. Préférer l'utilisation des annexes et y faire référence.</p>
</div>
<div className="field">
<label className="label">Pourquoi devons nous prendre cette décision ?</label>
<label className="label is-medium">Pourquoi devons nous prendre cette décision ?</label>
<div className="control">
<textarea className="textarea"
<textarea className="textarea is-medium"
readOnly={readOnly}
value={state.section.motivations}
onChange={onSectionAttrChange.bind(null, 'motivations')}
placeholder="Décrire pourquoi il est important de prendre cette décision."
@ -81,10 +83,11 @@ export const ClarificationSection: FunctionComponent<ClarificationSectionProps>
<p className="help is-info"><i className="fa fa-info-circle"></i> Penser à indiquer si des obligations légales pèsent sur cette prise de décision.</p>
</div>
<div className="field">
<label className="label">Portée de la décision</label>
<label className="label is-medium">Portée de la décision</label>
<div className="control">
<div className="select">
<select
<div className="select is-medium">
<select
disabled={readOnly}
onChange={onSectionAttrChange.bind(null, 'scope')}
value={state.section.scope}>
<option></option>
@ -96,10 +99,12 @@ export const ClarificationSection: FunctionComponent<ClarificationSectionProps>
</div>
</div>
<div className="field">
<label className="label">Nature de la décision</label>
<label className="label is-medium">Nature de la décision</label>
<div className="control">
<div className="select">
<select onChange={onSectionAttrChange.bind(null, 'nature')}
<div className="select is-medium">
<select
disabled={readOnly}
onChange={onSectionAttrChange.bind(null, 'nature')}
value={state.section.nature}>
<option></option>
<option value="operational">Opérationnelle</option>
@ -114,16 +119,19 @@ export const ClarificationSection: FunctionComponent<ClarificationSectionProps>
<div className="column">
<label className="checkbox">
<input type="checkbox"
className="is-medium"
disabled={readOnly}
onChange={onSectionAttrChange.bind(null, 'hasDeadline')}
checked={state.section.hasDeadline} />
<span className="ml-1">Existe t'il une échéance particulière pour cette décision ?</span>
<span className="ml-1 has-text-weight-bold is-size-5">Existe t'il une échéance particulière pour cette décision ?</span>
</label>
<div className="field">
<div className="control">
<input disabled={!state.section.hasDeadline}
<input disabled={!state.section.hasDeadline}
readOnly={readOnly}
value={state.section.deadline ? asDate(state.section.deadline).toISOString().substr(0, 10) : ''}
onChange={onDeadlineChange}
type="date" className="input" />
type="date" className="input is-medium" />
</div>
</div>
</div>

View File

@ -7,8 +7,8 @@ import { DecisionSupportFile, newDecisionSupportFile, DecisionSupportFileStatus
import { useParams, useHistory } from 'react-router';
import { useDecisionSupportFiles } from '../../gql/queries/dsf';
import { useCreateDecisionSupportFileMutation, useUpdateDecisionSupportFileMutation } from '../../gql/mutations/dsf';
import { useDebounce } from '../../hooks/useDebounce';
import { OptionsSection } from './OptionsSection';
import { useIsAuthorized } from '../../gql/queries/authorization';
export interface DecisionSupportFilePageProps {
@ -31,6 +31,16 @@ export const DecisionSupportFilePage: FunctionComponent<DecisionSupportFilePageP
selectedTabIndex: 0,
});
const { isAuthorized } = useIsAuthorized({
variables: {
action: 'update',
object: {
decisionSupportFileId: state.dsf.id,
}
}
}, id === 'new');
useEffect(() => {
const dsf = decisionSupportFiles.length > 0 && decisionSupportFiles[0].id === id ? decisionSupportFiles[0] : {};
setState(state => ({ ...state, dsf: { ...state.dsf, ...dsf }}))
@ -96,7 +106,7 @@ export const DecisionSupportFilePage: FunctionComponent<DecisionSupportFilePageP
</div> :
<div className="level-item">
<div>
<h2 className="is-size-3 title is-spaced">{state.dsf.title}</h2>
<h2 className="is-size-3 title is-spaced">{state.dsf.title} <span className={`ml-3 tag is-warning is-medium ${ isAuthorized ? 'is-hidden' : ''}`}>Lecture seule</span></h2>
<h3 className="is-size-5 subtitle">Dossier d'Aide à la Décision <span className="is-italic">{ isClosed ? '(clos)' : null }</span></h3>
</div>
</div>
@ -141,17 +151,17 @@ export const DecisionSupportFilePage: FunctionComponent<DecisionSupportFilePageP
</div>
{
state.selectedTabIndex === 0 ?
<ClarificationSection dsf={state.dsf} updateDSF={updateDSF} /> :
<ClarificationSection readOnly={!isAuthorized} dsf={state.dsf} updateDSF={updateDSF} /> :
null
}
{
state.selectedTabIndex === 1 ?
<OptionsSection dsf={state.dsf} updateDSF={updateDSF} /> :
<OptionsSection readOnly={!isAuthorized} dsf={state.dsf} updateDSF={updateDSF} /> :
null
}
</div>
<div className="column is-3">
<MetadataPanel dsf={state.dsf} updateDSF={updateDSF} />
<MetadataPanel readOnly={!isAuthorized} dsf={state.dsf} updateDSF={updateDSF} />
<AppendixPanel dsf={state.dsf} />
</div>
</div>

View File

@ -3,4 +3,5 @@ import { DecisionSupportFile } from "../../types/decision";
export interface DecisionSupportFileUpdaterProps {
dsf: DecisionSupportFile
updateDSF: (dsf: DecisionSupportFile) => void
readOnly: boolean
}

View File

@ -5,10 +5,11 @@ import { useUserProfile } from '../../gql/queries/profile';
import { inWorkgroup } from '../../types/workgroup';
import { DecisionSupportFileUpdaterProps } from './DecisionSupportFileUpdaterProps';
import { asDate } from '../../util/date';
import { Link } from 'react-router-dom';
export interface MetadataPanelProps extends DecisionSupportFileUpdaterProps {};
export const MetadataPanel: FunctionComponent<MetadataPanelProps> = ({ dsf, updateDSF }) => {
export const MetadataPanel: FunctionComponent<MetadataPanelProps> = ({ dsf, updateDSF, readOnly }) => {
const { user } = useUserProfile();
const { workgroups } = useWorkgroups();
@ -39,26 +40,36 @@ export const MetadataPanel: FunctionComponent<MetadataPanelProps> = ({ dsf, upda
<div style={{width:'100%'}}>
<div className="field">
<div className="label">Groupe de travail</div>
<div className="control is-expanded">
<div className="select is-fullwidth">
<select onChange={onWorkgroupChanged} value={dsf.workgroup ? dsf.workgroup.id : ''}>
<option></option>
{
userOpenedWorkgroups.map(wg => {
return (
<option key={`wg-${wg.id}`} value={wg.id}>{wg.name}</option>
);
})
}
</select>
{
readOnly && dsf.workgroup !== null ?
<Link to={`/workgroups/${dsf.workgroup.id}`}>{dsf.workgroup.name}</Link> :
<div className="control is-expanded">
<div className="select is-fullwidth">
<select
disabled={readOnly}
onChange={onWorkgroupChanged}
value={dsf.workgroup ? dsf.workgroup.id : ''}>
<option></option>
{
userOpenedWorkgroups.map(wg => {
return (
<option key={`wg-${wg.id}`} value={wg.id}>{wg.name}</option>
);
})
}
</select>
</div>
</div>
</div>
}
</div>
<div className="field">
<div className="label">Statut</div>
<div className="control is-expanded">
<div className="select is-fullwidth">
<select onChange={onStatusChanged} value={dsf.status}>
<select
disabled={readOnly}
onChange={onStatusChanged}
value={dsf.status}>
<option value="draft">Brouillon</option>
<option value="ready">Prêt à voter</option>
<option value="voted">Voté</option>

View File

@ -6,7 +6,7 @@ export interface OptionsSectionProps extends DecisionSupportFileUpdaterProps {};
const OptionsSectionName = 'options';
export const OptionsSection: FunctionComponent<OptionsSectionProps> = ({ dsf, updateDSF }) => {
export const OptionsSection: FunctionComponent<OptionsSectionProps> = ({ dsf, updateDSF, readOnly }) => {
interface OptionsSectionState {
changed: boolean
section: OptionsSection
@ -94,6 +94,7 @@ export const OptionsSection: FunctionComponent<OptionsSectionProps> = ({ dsf, up
<tr key={`option-${o.id}`}>
<td>
<button
disabled={readOnly}
onClick={onRemoveOptionClick.bind(null, index)}
className="button is-danger is-small is-outlined">
🗑
@ -101,6 +102,7 @@ export const OptionsSection: FunctionComponent<OptionsSectionProps> = ({ dsf, up
</td>
<td>
<textarea className="textarea"
readOnly={readOnly}
value={o.label}
onChange={onOptionChange.bind(null, index, 'label')}
placeholder="Décrire cette décision."
@ -110,6 +112,7 @@ export const OptionsSection: FunctionComponent<OptionsSectionProps> = ({ dsf, up
<td>
<textarea className="textarea is-success"
value={o.pros}
readOnly={readOnly}
onChange={onOptionChange.bind(null, index, 'pros')}
placeholder="Décrire les avantages de cette décision."
rows={10}>
@ -118,6 +121,7 @@ export const OptionsSection: FunctionComponent<OptionsSectionProps> = ({ dsf, up
<td>
<textarea className="textarea is-danger"
value={o.cons}
readOnly={readOnly}
onChange={onOptionChange.bind(null, index, 'cons')}
placeholder="Décrire les désavantages de cette décision."
rows={10}>
@ -139,9 +143,12 @@ export const OptionsSection: FunctionComponent<OptionsSectionProps> = ({ dsf, up
<tfoot>
<tr>
<td colSpan={5}>
<a className="button is-primary is-pulled-right" onClick={onAddOptionClick}>
<button
disabled={readOnly}
className="button is-primary is-pulled-right"
onClick={onAddOptionClick}>
Ajouter
</a>
</button>
</td>
</tr>
</tfoot>