chore: use monorepo organization
This commit is contained in:
parent
deaf7d6ecc
commit
a687827f7e
1099 changed files with 8184 additions and 11535 deletions
249
packages/admin-ui/src/components/editableTable/Table.jsx
Normal file
249
packages/admin-ui/src/components/editableTable/Table.jsx
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
import { Form, Formik } from 'formik'
|
||||
import * as R from 'ramda'
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import PromptWhenDirty from 'src/components/PromptWhenDirty'
|
||||
import Link from 'src/components/buttons/Link'
|
||||
import { TBody, Table } from 'src/components/fake-table/Table'
|
||||
import { Info2, TL1 } from 'src/components/typography'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
|
||||
import { AddButton } from 'src/components/buttons/index'
|
||||
|
||||
import TableCtx from './Context'
|
||||
import Header from './Header'
|
||||
import ERow from './Row'
|
||||
import classes from './Table.module.css'
|
||||
|
||||
const ACTION_COL_SIZE = 87
|
||||
const DEFAULT_COL_SIZE = 100
|
||||
|
||||
const getWidth = R.compose(
|
||||
R.reduce(R.add)(0),
|
||||
R.map(it => it.width ?? DEFAULT_COL_SIZE)
|
||||
)
|
||||
|
||||
const ETable = ({
|
||||
name,
|
||||
title,
|
||||
titleLg,
|
||||
elements = [],
|
||||
data = [],
|
||||
save,
|
||||
error: externalError,
|
||||
rowSize = 'md',
|
||||
validationSchema,
|
||||
enableCreate,
|
||||
enableEdit,
|
||||
enableEditText,
|
||||
editWidth: outerEditWidth,
|
||||
enableDelete,
|
||||
deleteWidth = ACTION_COL_SIZE,
|
||||
enableToggle,
|
||||
toggleWidth = ACTION_COL_SIZE,
|
||||
onToggle,
|
||||
forceDisable,
|
||||
disableAdd,
|
||||
initialValues,
|
||||
setEditing,
|
||||
shouldOverrideEdit,
|
||||
editOverride,
|
||||
stripeWhen,
|
||||
disableRowEdit,
|
||||
groupBy,
|
||||
sortBy,
|
||||
createText = 'Add override',
|
||||
forceAdd = false,
|
||||
tbodyWrapperClass,
|
||||
orderedBy = null
|
||||
}) => {
|
||||
const [editingId, setEditingId] = useState(null)
|
||||
const [adding, setAdding] = useState(false)
|
||||
const [saving, setSaving] = useState(false)
|
||||
const [error, setError] = useState(null)
|
||||
|
||||
useEffect(() => setError(externalError), [externalError])
|
||||
useEffect(() => {
|
||||
setError(null)
|
||||
setAdding(forceAdd)
|
||||
}, [forceAdd])
|
||||
|
||||
const innerSave = async value => {
|
||||
if (saving) return
|
||||
|
||||
setSaving(true)
|
||||
|
||||
const it = validationSchema.cast(value, { assert: 'ignore-optionality' })
|
||||
const index = R.findIndex(R.propEq('id', it.id))(data)
|
||||
const list = index !== -1 ? R.update(index, it, data) : R.prepend(it, data)
|
||||
|
||||
if (!R.equals(data[index], it)) {
|
||||
try {
|
||||
await save({ [name]: list }, it)
|
||||
} catch (err) {
|
||||
setSaving(false)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
setAdding(false)
|
||||
setEditing && setEditing(false)
|
||||
setSaving(false)
|
||||
}
|
||||
|
||||
const onDelete = id => {
|
||||
const list = R.reject(it => it.id === id, data)
|
||||
return save({ [name]: list })
|
||||
}
|
||||
|
||||
const onReset = () => {
|
||||
setAdding(false)
|
||||
setEditingId(null)
|
||||
setEditing && setEditing(false)
|
||||
}
|
||||
|
||||
const onEdit = it => {
|
||||
if (shouldOverrideEdit && shouldOverrideEdit(it)) return editOverride(it)
|
||||
setEditingId(it)
|
||||
setError(null)
|
||||
setEditing && setEditing(it, true)
|
||||
}
|
||||
|
||||
const addField = () => {
|
||||
setAdding(true)
|
||||
setError(null)
|
||||
setEditing && setEditing(true, true)
|
||||
}
|
||||
|
||||
const widthIfEditNull =
|
||||
enableDelete || enableToggle ? ACTION_COL_SIZE : ACTION_COL_SIZE * 2
|
||||
|
||||
const editWidth = R.defaultTo(widthIfEditNull)(outerEditWidth)
|
||||
|
||||
const actionColSize =
|
||||
((enableDelete && deleteWidth) ?? 0) +
|
||||
((enableEdit && editWidth) ?? 0) +
|
||||
((enableToggle && toggleWidth) ?? 0)
|
||||
|
||||
const width = getWidth(elements) + actionColSize
|
||||
|
||||
const showButtonOnEmpty = !data.length && enableCreate && !adding
|
||||
const canAdd = !forceDisable && !editingId && !disableAdd && !adding
|
||||
const showTable = adding || data.length !== 0
|
||||
|
||||
const innerData = sortBy ? R.sortWith(sortBy)(data) : data
|
||||
|
||||
const ctxValue = {
|
||||
elements,
|
||||
enableEdit,
|
||||
enableEditText,
|
||||
onEdit,
|
||||
clearError: () => setError(null),
|
||||
error: error,
|
||||
disableRowEdit,
|
||||
editWidth,
|
||||
enableDelete,
|
||||
onDelete,
|
||||
deleteWidth,
|
||||
enableToggle,
|
||||
rowSize,
|
||||
onToggle,
|
||||
toggleWidth,
|
||||
actionColSize,
|
||||
stripeWhen,
|
||||
forceAdd,
|
||||
orderedBy,
|
||||
DEFAULT_COL_SIZE
|
||||
}
|
||||
|
||||
return (
|
||||
<TableCtx.Provider value={ctxValue}>
|
||||
<div style={{ width }}>
|
||||
{showButtonOnEmpty && canAdd && (
|
||||
<AddButton onClick={addField}>{createText}</AddButton>
|
||||
)}
|
||||
{showTable && (
|
||||
<>
|
||||
{(title || enableCreate) && (
|
||||
<div className={classes.outerHeader}>
|
||||
{title && titleLg && (
|
||||
<TL1 className={classes.title}>{title}</TL1>
|
||||
)}
|
||||
{title && !titleLg && (
|
||||
<Info2 className={classes.title}>{title}</Info2>
|
||||
)}
|
||||
{enableCreate && canAdd && (
|
||||
<Link className={classes.addLink} onClick={addField}>
|
||||
{createText}
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<Table>
|
||||
<Header />
|
||||
<div className={tbodyWrapperClass}>
|
||||
<TBody>
|
||||
{adding && (
|
||||
<Formik
|
||||
validateOnBlur={false}
|
||||
validateOnChange={false}
|
||||
initialValues={{ id: uuidv4(), ...initialValues }}
|
||||
onReset={onReset}
|
||||
validationSchema={validationSchema}
|
||||
onSubmit={innerSave}>
|
||||
<Form>
|
||||
<PromptWhenDirty />
|
||||
<ERow
|
||||
editing={true}
|
||||
disabled={forceDisable}
|
||||
newRow={true}
|
||||
/>
|
||||
</Form>
|
||||
</Formik>
|
||||
)}
|
||||
{innerData.map((it, idx) => {
|
||||
const nextElement = innerData[idx + 1]
|
||||
|
||||
const canGroup = !!groupBy && nextElement
|
||||
const isFunction = R.type(groupBy) === 'Function'
|
||||
const groupFunction = isFunction ? groupBy : R.prop(groupBy)
|
||||
|
||||
const isLastOfGroup =
|
||||
canGroup &&
|
||||
groupFunction(it) !== groupFunction(nextElement)
|
||||
|
||||
return (
|
||||
<Formik
|
||||
validateOnBlur={false}
|
||||
validateOnChange={false}
|
||||
key={it.id ?? idx}
|
||||
enableReinitialize
|
||||
initialValues={it}
|
||||
onReset={onReset}
|
||||
validationSchema={validationSchema}
|
||||
onSubmit={innerSave}>
|
||||
<Form>
|
||||
<PromptWhenDirty />
|
||||
<ERow
|
||||
lastOfGroup={isLastOfGroup}
|
||||
editing={editingId === it.id}
|
||||
disabled={
|
||||
forceDisable ||
|
||||
(editingId && editingId !== it.id) ||
|
||||
adding
|
||||
}
|
||||
/>
|
||||
</Form>
|
||||
</Formik>
|
||||
)
|
||||
})}
|
||||
</TBody>
|
||||
</div>
|
||||
</Table>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</TableCtx.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
export default ETable
|
||||
Loading…
Add table
Add a link
Reference in a new issue