Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sélectionne le modèle de métadonnées dans le panneau latéral #280

Closed
wants to merge 10 commits into from
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ L'application se lance en combinant Docker (pour avoir une base de données Mong

```bash
docker-compose pull mongodb-stylo
npm install --prefix graphql
npm install --prefix front/gatsby
npm ci --prefix graphql
npm ci --prefix front/gatsby
cp stylo-example.env stylo.env
```

Expand Down
10 changes: 7 additions & 3 deletions front/gatsby/src/components/Field.jsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
import React from 'react'
import React, { useState } from 'react'
import styles from './field.module.scss'

import uniqueId from 'lodash/uniqueId'

export default (props) => {
const [id] = useState(() => uniqueId('input-'))
const type = props.type ? props.type : 'text'
const classNames = [
styles.field
]
if (props.className) {
classNames.push(props.className)
}

return (<div className={classNames.join(' ')}>
{props.label && <label htmlFor={props.id}>{props.label}</label>}
{props.label && <label htmlFor={id}>{props.label}</label>}
<p className={`control${props.icon ? " has-icons-left" : ""}`}>
{props.children && {...props.children}}
{!props.children && <>
<input {...props} className="input" type={type} />
<input {...props} id={id} className="input" type={type} />
{props.icon && <span className="icon is-small is-left">
<props.icon/>
</span>}
Expand Down
44 changes: 28 additions & 16 deletions front/gatsby/src/components/Form.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import React, { Fragment, useMemo, useState } from 'react'
import Form from '@rjsf/core'
import { set } from 'object-path-immutable'
import basicUiSchema from '../schemas/ui-schema-basic-override.json'
import uiSchema from '../schemas/ui-schema-editor.json'
import staticKeywordsComponent from './Write/metadata/staticKeywords'
import schema from '../schemas/data-schema.json'
import staticKeywordsComponent from './Write/metadata/staticKeywords.js'
import schemas from '../schemas/index.js' // { default: { uiSchema, schema }}
import { toYaml } from './Write/metadata/yaml'

// REMIND: use a custom SelectWidget to support "ui:emptyValue"
Expand All @@ -20,9 +18,11 @@ const CustomSelect = function(props) {
<SelectWidget {...props}/>
</div>)
}
function ArrayFieldTemplate(props) {
const addItemTitle = props.uiSchema['ui:add-item-title'] || 'Ajouter'
const removeItemTitle = props.uiSchema['ui:remove-item-title'] || 'Supprimer'

function ArrayFieldTemplate (props) {

const addItemTitle = props.uiSchema['ui:add-item-title'] || 'Add'
const removeItemTitle = props.uiSchema['ui:remove-item-title'] || 'Remove'
const title = props.uiSchema['ui:title']

const inlineRemoveButton = props.schema?.items?.type === 'string'
Expand Down Expand Up @@ -67,11 +67,19 @@ function ArrayFieldTemplate(props) {
)
}

function ObjectFieldTemplate(props) {
function ObjectFieldTemplate (props) {
if (props.uiSchema['ui:groups']) {
const groups = props.uiSchema['ui:groups']
const groupedElements = groups.map(({ fields, title }) => {
const elements = fields
.filter((field) => {
const fieldExists = props.schema.properties.hasOwnProperty(field)
if (!fieldExists) {
console.error('Field %s is declared in ui:group, but does not exist in data schema', field)
}

return fieldExists
})
.filter(
(field) => (props.uiSchema[field] || {})['ui:widget'] !== 'hidden'
)
Expand Down Expand Up @@ -107,11 +115,10 @@ function ObjectFieldTemplate(props) {
}
}

export default ({
formData: initialFormData,
basicMode,
onChange = () => {},
}) => {
export default function MetadataForm (props) {
const { basicMode, metadataModelName } = props
const { formData: initialFormData, onChange = () => {} } = props

const [formData, setFormData] = useState(initialFormData)
const [errors, setErrors] = useState({})
const formContext = {
Expand All @@ -125,10 +132,15 @@ export default ({
},
}

const effectiveUiSchema = useMemo(
() => (basicMode ? { ...uiSchema, ...basicUiSchema } : uiSchema),
[basicMode]
const {basicUiSchema, uiSchema, schema} = schemas[metadataModelName]
const effectiveUiSchema = useMemo(() => {
return basicMode
? basicUiSchema
: uiSchema
},
[basicMode, metadataModelName]
)

// use static keywords component
effectiveUiSchema.controlledKeywords = {
...effectiveUiSchema.controlledKeywords,
Expand Down
4 changes: 2 additions & 2 deletions front/gatsby/src/components/Login.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ function Login ({ login, applicationConfig }) {
<fieldset>
<legend>Connect with a local Stylo account</legend>

<Field label="Username" id="username" required={true} autoComplete="username" onChange={event => setUsername(event.target.value)} />
<Field label="Password" id="password" required={true} type="password" autoComplete="current-password" onChange={event => setPassword(event.target.value)} />
<Field label="Username" required={true} autoComplete="username" onChange={event => setUsername(event.target.value)} />
<Field label="Password" required={true} type="password" autoComplete="current-password" onChange={event => setPassword(event.target.value)} />

<ul className={styles.actions}>
<li>
Expand Down
9 changes: 5 additions & 4 deletions front/gatsby/src/components/NavTab.jsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import React, { useState } from 'react'
import styles from './navTab.module.scss'

export default function NavTag (props) {
const [selector, setSelector] = useState(props.defaultValue)
export default function NavTag ({ items = [], defaultValue, onChange = () => {}}) {
const [selector, setSelector] = useState(defaultValue)

return (<nav className={styles.selector}>
{props.items.map((item) => (<button
{items.map((item) => (<button
key={item.value}
className={selector === item.value ? styles.selected : null}
onClick={() => {
setSelector(item.value)
props.onChange(item.value)
onChange(item.value)
}}
>
{item.name}
Expand Down
16 changes: 8 additions & 8 deletions front/gatsby/src/components/Register.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,19 +98,19 @@ const Register = (props) => {
<fieldset>
<legend>Required informations</legend>

<Field id="email" type="email" label="Email*" autoComplete="email" required={true} onChange={(e) => setEmail(etv(e))} />
<Field id="username" label="Username*" autoComplete="username" required={true} onChange={(e) => setUsername(etv(e))} />
<Field id="password" type="password" label="Password*" autoComplete="new-password" required={true} onChange={(e) => setPassword(etv(e))} />
<Field id="passwordc" type="password" label="Confirm Password*" autoComplete="new-password" required={true} onChange={(e) => setPasswordC(etv(e))} className={password === passwordC ? null : styles.beware} />
<Field type="email" label="Email*" autoComplete="email" required={true} onChange={(e) => setEmail(etv(e))} />
<Field label="Username*" autoComplete="username" required={true} onChange={(e) => setUsername(etv(e))} />
<Field type="password" label="Password*" autoComplete="new-password" required={true} onChange={(e) => setPassword(etv(e))} />
<Field type="password" label="Confirm Password*" autoComplete="new-password" required={true} onChange={(e) => setPasswordC(etv(e))} className={password === passwordC ? null : styles.beware} />
</fieldset>

<fieldset>
<legend>Optional details</legend>

<Field id="display-name" label="Display Name" onChange={(e) => setDisplayName(etv(e))} />
<Field id="first-name" label="First Name" onChange={(e) => setFirstName(etv(e))} />
<Field id="last-name" label="Last Name" onChange={(e) => setLastName(etv(e))} />
<Field id="institution" label="Organization" onChange={(e) => setInstitution(etv(e))} />
<Field label="Display Name" onChange={(e) => setDisplayName(etv(e))} />
<Field label="First Name" onChange={(e) => setFirstName(etv(e))} />
<Field label="Last Name" onChange={(e) => setLastName(etv(e))} />
<Field label="Organization" onChange={(e) => setInstitution(etv(e))} />
</fieldset>

<ul className={styles.actions}>
Expand Down
17 changes: 13 additions & 4 deletions front/gatsby/src/components/Select.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
import React from 'react'
import React, { useState } from 'react'
import styles from './button.module.scss'

import uniqueId from 'lodash/uniqueId'

export default function Select (props) {
const { className, containerClassName, label } = props
const [id] = useState(() => uniqueId('select-'))
const classNames = [
styles.select
]
if (props.className) {
classNames.push(props.className)
if (className) {
classNames.push(className)
}
return (<div className={styles.selectContainer}><select className={classNames.join(' ')} {...props}>{props.children}</select></div>)
return (<div className={[styles.selectContainer, containerClassName].join(' ')}>
{label && <label htmlFor={id} className={styles.label}>{props.label}</label>}
<select id={id} className={classNames.join(' ')} {...props}>
{props.children}
</select>
</div>)
}
5 changes: 0 additions & 5 deletions front/gatsby/src/components/UserInfos.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -194,31 +194,27 @@ const ConnectedUser = (props) => {
<h2>Account information</h2>
<form onSubmit={(e) => updateInfo(e)}>
<Field
id="displayNameField"
label="Display name"
type="text"
value={displayName}
onChange={(e) => setDisplayName(etv(e))}
placeholder="Display name"
/>
<Field
id="firstNameField"
label="First Name"
type="text"
value={firstName}
onChange={(e) => setFirstName(etv(e))}
placeholder="First name"
/>
<Field
id="lastNameField"
label="Last Name"
type="text"
value={lastName}
onChange={(e) => setLastName(etv(e))}
placeholder="Last name"
/>
<Field
id="institutionField"
label="Institution"
type="text"
value={institution}
Expand Down Expand Up @@ -248,7 +244,6 @@ const ConnectedUser = (props) => {
</Field>
<Field label="Default YAML">
<textarea
id="yamlField"
value={yaml}
onChange={(e) => setYaml(etv(e))}
placeholder=""
Expand Down
119 changes: 60 additions & 59 deletions front/gatsby/src/components/Write/WriteRight.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,27 @@ import styles from './writeRight.module.scss'
import YamlEditor from './yamleditor/YamlEditor'
import NavTag from '../NavTab'
import YAML from 'js-yaml'
import Button from '../Button'

export default (props) => {
export default function WriteRight (props) {
const [expanded, setExpanded] = useState(false)
const [selector, setSelector] = useState('basic')
const [rawYaml, setRawYaml] = useState(props.yaml)
const [error, setError] = useState('')
const [error, setError] = useState("")

return (
<nav className={`${expanded ? styles.expandRight : styles.retractRight}`}>
<nav
<Button
onClick={() => setExpanded(!expanded)}
className={expanded ? styles.close : styles.open}
className={[styles.openCloseButton, expanded ? styles.openCloseButtonRetract : styles.openCloseButtonExpand].join(' ')}
>
{expanded ? 'close' : 'Metadata'}
</nav>
</Button>
{expanded && (
<>
<div className={styles.yamlEditor}>
<header>
<h1>Metadata</h1>
</header>
<div className={styles.yamlEditor}>
<header className={styles.sidebarHeader}>
<h1>Metadata</h1>

<NavTag defaultValue={selector} onChange={(value) => setSelector(value)} items={[
{
value: 'basic',
Expand All @@ -40,58 +40,59 @@ export default (props) => {
}
]
}/>
{selector === 'raw' && (
<>
{error !== '' && <p className={styles.error}>{error}</p>}
<textarea
value={rawYaml}
rows={20}
onChange={(event) => {
const component = event.target
const yaml = component.value
try {
YAML.loadAll(yaml)
setError('')
props.handleYaml(yaml)
} catch (err) {
setError(err.message)
} finally {
setRawYaml(yaml)
}
}}
/>
</>
)}
{selector !== 'raw' && props.readOnly && (
<YamlEditor
yaml={props.yaml}
basicMode={selector === 'basic'}
error={(reason) => {
setError(reason)
if (reason !== '') {
setSelector('raw')
}
}}
/>
)}
{selector !== 'raw' && !props.readOnly && (
<YamlEditor
yaml={props.yaml}
basicMode={selector === 'basic'}
error={(reason) => {
setError(reason)
if (reason !== '') {
setSelector('raw')
</header>

{selector === 'raw' && (
<>
{error !== '' && <p className={styles.error}>{error}</p>}
<textarea
value={rawYaml}
rows={20}
onChange={(event) => {
const component = event.target
const yaml = component.value
try {
YAML.loadAll(yaml)
setError('')
props.handleYaml(yaml)
} catch (err) {
setError(err.message)
} finally {
setRawYaml(yaml)
}
}}
onChange={(yaml) => {
setRawYaml(yaml)
props.handleYaml(yaml)
}}
/>
)}
</div>
</>
</>
)}
{selector !== 'raw' && props.readOnly && (
<YamlEditor
yaml={props.yaml}
basicMode={selector === 'basic'}
error={(reason) => {
setError(reason)
if (reason !== '') {
setSelector('raw')
}
}}
/>
)}
{selector !== 'raw' && !props.readOnly && (
<YamlEditor
yaml={props.yaml}
basicMode={selector === 'basic'}
error={(reason) => {
setError(reason)
if (reason !== '') {
setSelector('raw')
}
}}
onChange={(yaml) => {
setRawYaml(yaml)
props.handleYaml(yaml)
}}
/>
)}
</div>
)}
</nav>
)
Expand Down
Loading