Compare commits
6 Commits
b8d9e8e804
...
32ce981d40
| Author | SHA1 | Date | |
|---|---|---|---|
| 32ce981d40 | |||
| e7a4389fde | |||
| f03f8374c8 | |||
| 78ffcb9b71 | |||
| 0a657dca4b | |||
| 8941d69ba4 |
@@ -159,7 +159,7 @@ class Contract(CrudDocument):
|
||||
title: str = Field(title="Titre")
|
||||
parties: List[Party] = Field(title="Parties")
|
||||
provisions: List[Provision] = Field(
|
||||
props={"items-per-row": "1", "numbered": True},
|
||||
props={"items_per_row": "1", "numbered": True},
|
||||
title='Clauses'
|
||||
)
|
||||
status: ContractStatus = Field(default=ContractStatus.published, title="Statut")
|
||||
|
||||
@@ -20,12 +20,12 @@ class ContractDraftCreate(Writer):
|
||||
title: str = Field(title='Titre')
|
||||
parties: List[DraftParty] = Field(title='Parties')
|
||||
provisions: List[DraftProvision] = Field(
|
||||
props={"items-per-row": "1", "numbered": True},
|
||||
props={"items_per_row": "1", "numbered": True},
|
||||
title='Clauses'
|
||||
)
|
||||
variables: List[DictionaryEntry] = Field(
|
||||
default=[],
|
||||
format="dictionary",
|
||||
props={"display": "dictionary"},
|
||||
title='Variables'
|
||||
)
|
||||
|
||||
@@ -50,7 +50,7 @@ class ForeignEntityRead(BaseModel):
|
||||
|
||||
class PartyRead(BaseModel):
|
||||
signature_affixed: bool = Field(title='Signature apposée?')
|
||||
signature_uuid: str = Field(format="signature-link", title="Lien vers signature")
|
||||
signature_uuid: str = Field(props={"display": "signature-link"}, title="Lien vers signature")
|
||||
part: str = Field(title='Rôle')
|
||||
entity: ForeignEntityRead = Field(title='Client')
|
||||
|
||||
@@ -59,7 +59,10 @@ class PartyRead(BaseModel):
|
||||
|
||||
|
||||
class ContractRead(Reader, Contract):
|
||||
parties: List[PartyRead]
|
||||
parties: List[PartyRead] = Field(
|
||||
props={"items_per_row": "2"},
|
||||
title='Parties'
|
||||
)
|
||||
lawyer: ForeignEntityRead
|
||||
|
||||
class Config:
|
||||
|
||||
@@ -21,7 +21,7 @@ class Individual(EntityType):
|
||||
lastname: Indexed(str) = Field(title='Nom de famille')
|
||||
surnames: List[Indexed(str)] = Field(
|
||||
default=[],
|
||||
props={"items-per-row": "4", "numbered": True},
|
||||
props={"items_per_row": "4", "numbered": True},
|
||||
title="Surnoms"
|
||||
)
|
||||
day_of_birth: Optional[date] = Field(default=None, title='Date de naissance')
|
||||
|
||||
@@ -16,13 +16,12 @@ class ContractTemplateCreate(Writer):
|
||||
parties: List[PartyTemplate] = Field(default=[], title="Parties")
|
||||
provisions: List[ProvisionTemplateReference] = Field(
|
||||
default=[],
|
||||
props={"items-per-row": "1", "numbered": True},
|
||||
props={"items_per_row": "1", "numbered": True},
|
||||
title="Clauses"
|
||||
)
|
||||
variables: List[DictionaryEntry] = Field(
|
||||
default=[],
|
||||
format="dictionary",
|
||||
props={"required": False},
|
||||
props={"display": "dictionary", "required": False},
|
||||
title="Variables"
|
||||
)
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import Form from "@rjsf/mui";
|
||||
import { RegistryFieldsType, RegistryWidgetsType, RJSFSchema, UiSchema } from "@rjsf/utils";
|
||||
import CrudTextWidget from "./widgets/crud-text-widget";
|
||||
import UnionEnumField from "./fields/union-enum";
|
||||
import ArrayFieldTemplate from "./templates/ArrayFieldTemplate"
|
||||
import { ResourceContext } from "../contexts/ResourceContext";
|
||||
import { ReactNode } from "react";
|
||||
|
||||
@@ -24,6 +25,10 @@ export const customFields: RegistryFieldsType = {
|
||||
AnyOfField: UnionEnumField
|
||||
}
|
||||
|
||||
const customTemplates = {
|
||||
ArrayFieldTemplate
|
||||
}
|
||||
|
||||
export const BaseForm: React.FC<BaseFormProps> = (props) => {
|
||||
const { schema, uiSchema, resourceBasePath, formData, children, onSubmit, onChange } = props;
|
||||
|
||||
@@ -38,6 +43,7 @@ export const BaseForm: React.FC<BaseFormProps> = (props) => {
|
||||
omitExtraData={true}
|
||||
widgets={customWidgets}
|
||||
fields={customFields}
|
||||
templates={customTemplates}
|
||||
onChange={(e, id) => onChange != undefined && onChange(e.formData)}
|
||||
children={children}
|
||||
/>
|
||||
|
||||
@@ -10,21 +10,30 @@ type CrudFormProps = {
|
||||
uiSchema?: UiSchema,
|
||||
record?: any,
|
||||
resourceBasePath: string,
|
||||
onSubmit: (data: any) => void,
|
||||
onSubmit?: (data: any) => void,
|
||||
defaultValue?: any,
|
||||
children?: ReactNode
|
||||
card?: boolean
|
||||
}
|
||||
|
||||
export const CrudForm: React.FC<CrudFormProps> = (props) => {
|
||||
const { schemaName, uiSchema, record, resourceBasePath, defaultValue, children, onSubmit } = props;
|
||||
const { schemaName, uiSchema, record, resourceBasePath, defaultValue, children, onSubmit=(data: any) => {}, card=false } = props;
|
||||
|
||||
const [schema, setSchema] = useState({});
|
||||
const [schemaLoading, setSchemaLoading] = useState(true);
|
||||
useEffect(() => {
|
||||
const fetchSchema = async () => {
|
||||
try {
|
||||
const resourceSchema = record === undefined ? await jsonschemaProvider.getCreateResourceSchema(schemaName)
|
||||
: await jsonschemaProvider.getUpdateResourceSchema(schemaName);
|
||||
let resourceSchema
|
||||
if (record === undefined) {
|
||||
resourceSchema = await jsonschemaProvider.getCreateResourceSchema(schemaName);
|
||||
} else {
|
||||
if (card) {
|
||||
resourceSchema = await jsonschemaProvider.getCardResourceSchema(schemaName);
|
||||
} else {
|
||||
resourceSchema = await jsonschemaProvider.getUpdateResourceSchema(schemaName);
|
||||
}
|
||||
}
|
||||
setSchema(resourceSchema);
|
||||
setSchemaLoading(false);
|
||||
} catch (error) {
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
import Box from '@mui/material/Box';
|
||||
import Grid2 from '@mui/material/Grid2';
|
||||
import Paper from '@mui/material/Paper';
|
||||
import {
|
||||
getTemplate,
|
||||
getUiOptions,
|
||||
ArrayFieldTemplateProps,
|
||||
ArrayFieldTemplateItemType,
|
||||
FormContextType,
|
||||
} from '@rjsf/utils';
|
||||
import { CrudTextRJSFSchema } from "../widgets/crud-text-widget";
|
||||
|
||||
/** The `ArrayFieldTemplate` component is the template used to render all items in an array.
|
||||
*
|
||||
* @param props - The `ArrayFieldTemplateItemType` props for the component
|
||||
*/
|
||||
export default function ArrayFieldTemplate<
|
||||
T = any,
|
||||
S extends CrudTextRJSFSchema = CrudTextRJSFSchema,
|
||||
F extends FormContextType = any
|
||||
>(props: ArrayFieldTemplateProps<T, S, F>) {
|
||||
const { canAdd, disabled, idSchema, uiSchema, items, onAddClick, readonly, registry, required, schema, title } =
|
||||
props;
|
||||
|
||||
let gridSize = 12;
|
||||
if (schema.props) {
|
||||
if (schema.props.hasOwnProperty("items_per_row")) {
|
||||
gridSize = gridSize / schema.props.items_per_row;
|
||||
}
|
||||
}
|
||||
const uiOptions = getUiOptions<T, S, F>(uiSchema);
|
||||
const ArrayFieldDescriptionTemplate = getTemplate<'ArrayFieldDescriptionTemplate', T, S, F>(
|
||||
'ArrayFieldDescriptionTemplate',
|
||||
registry,
|
||||
uiOptions
|
||||
);
|
||||
const ArrayFieldItemTemplate = getTemplate<'ArrayFieldItemTemplate', T, S, F>(
|
||||
'ArrayFieldItemTemplate',
|
||||
registry,
|
||||
uiOptions
|
||||
);
|
||||
const ArrayFieldTitleTemplate = getTemplate<'ArrayFieldTitleTemplate', T, S, F>(
|
||||
'ArrayFieldTitleTemplate',
|
||||
registry,
|
||||
uiOptions
|
||||
);
|
||||
// Button templates are not overridden in the uiSchema
|
||||
const {
|
||||
ButtonTemplates: { AddButton },
|
||||
} = registry.templates;
|
||||
return (
|
||||
<Paper elevation={2}>
|
||||
<Box p={2}>
|
||||
<ArrayFieldTitleTemplate
|
||||
idSchema={idSchema}
|
||||
title={uiOptions.title || title}
|
||||
schema={schema}
|
||||
uiSchema={uiSchema}
|
||||
required={required}
|
||||
registry={registry}
|
||||
/>
|
||||
<ArrayFieldDescriptionTemplate
|
||||
idSchema={idSchema}
|
||||
description={uiOptions.description || schema.description}
|
||||
schema={schema}
|
||||
uiSchema={uiSchema}
|
||||
registry={registry}
|
||||
/>
|
||||
<Grid2 container justifyContent='flex-end'>
|
||||
{items &&
|
||||
items.map(({ key, ...itemProps }: ArrayFieldTemplateItemType<T, S, F>) => (
|
||||
<Grid2 key={key} size={gridSize} ><ArrayFieldItemTemplate key={key} {...itemProps} /></Grid2>
|
||||
))}
|
||||
</Grid2>
|
||||
{canAdd && (
|
||||
<Grid2 container justifyContent='flex-end'>
|
||||
<Grid2>
|
||||
<Box mt={2}>
|
||||
<AddButton
|
||||
className='array-item-add'
|
||||
onClick={onAddClick}
|
||||
disabled={disabled || readonly}
|
||||
uiSchema={uiSchema}
|
||||
registry={registry}
|
||||
/>
|
||||
</Box>
|
||||
</Grid2>
|
||||
</Grid2>
|
||||
)}
|
||||
</Box>
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
@@ -57,7 +57,7 @@ const StyledLabelledOutlined = styled(LabelledOutlined)(({ theme }) => [{
|
||||
const RichtextWidget = <T = any, S extends CrudTextRJSFSchema = CrudTextRJSFSchema, F extends FormContextType = any>(
|
||||
props: WidgetProps<T, S, F>
|
||||
) => {
|
||||
const { schema, value, onChange, label, id } = props;
|
||||
const { schema, value, onChange, label, id, readonly } = props;
|
||||
const isMultiline = schema.props.multiline === true;
|
||||
|
||||
let editorOptions: UseEditorOptions;
|
||||
@@ -92,14 +92,15 @@ const RichtextWidget = <T = any, S extends CrudTextRJSFSchema = CrudTextRJSFSche
|
||||
<TextContainer>
|
||||
<RichTextEditorProvider editor={editor}>
|
||||
<TableBubbleMenu />
|
||||
<RichTextField
|
||||
controls={
|
||||
<MenuControlsContainer>
|
||||
{isMultiline ? multilineButtons : singlelineButtons}
|
||||
</MenuControlsContainer>
|
||||
}
|
||||
variant="standard"
|
||||
/>
|
||||
{!readonly && <RichTextField
|
||||
controls={
|
||||
<MenuControlsContainer>
|
||||
{isMultiline ? multilineButtons : singlelineButtons}
|
||||
</MenuControlsContainer>
|
||||
}
|
||||
variant="standard"
|
||||
/>}
|
||||
{readonly && <RichTextField variant="standard" disabled={true}/>}
|
||||
</RichTextEditorProvider>
|
||||
</TextContainer>
|
||||
<RightContainer> </RightContainer>
|
||||
|
||||
@@ -12,13 +12,17 @@ type CrudRJSFSchema = RJSFSchema & {
|
||||
} | undefined;
|
||||
}
|
||||
|
||||
const meta_fields = ["label", "created_at", "created_by", "updated_at", "updated_by"]
|
||||
|
||||
export const jsonschemaProvider = {
|
||||
getCardResourceSchema: async (resourceName: string): Promise<CrudRJSFSchema> => {
|
||||
const updateSchema = await getResourceSchema(`${resourceName}Update`);
|
||||
const readSchema = await getResourceSchema(`${resourceName}Read`);
|
||||
|
||||
for (let prop_name in readSchema.properties) {
|
||||
if (! updateSchema.hasOwnProperty(prop_name)) {
|
||||
if (meta_fields.indexOf(prop_name) > -1) {
|
||||
delete readSchema.properties[prop_name];
|
||||
} else if (! updateSchema.hasOwnProperty(prop_name)) {
|
||||
if (is_reference(readSchema.properties[prop_name])) {
|
||||
let subresourceName = get_reference_name(readSchema.properties[prop_name]);
|
||||
readSchema.components.schemas[subresourceName].readOnly = true;
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import { Route, Routes } from "react-router";
|
||||
import { useContext } from "react";
|
||||
import { Route, Routes, useParams } from "react-router";
|
||||
import { useOne, useTranslation } from "@refinedev/core";
|
||||
import { DeleteButton } from "@refinedev/mui";
|
||||
import { CircularProgress, Stack } from "@mui/material";
|
||||
import { CrudForm } from "../../lib/crud/components/crud-form";
|
||||
import { FirmContext } from "../../contexts/FirmContext";
|
||||
import List from "./base-page/List";
|
||||
import Edit from "./base-page/Edit";
|
||||
import Cartouche from "../../components/Cartouche";
|
||||
|
||||
export type Contract = {
|
||||
id: string,
|
||||
@@ -24,5 +30,39 @@ const ListContract = () => {
|
||||
}
|
||||
|
||||
const EditContract = () => {
|
||||
return <Edit<Contract> resource={`contracts`} schemaName={"Contract"} />
|
||||
}
|
||||
const { currentFirm } = useContext(FirmContext);
|
||||
const { translate: t } = useTranslation();
|
||||
const resourceBasePath = `firm/${currentFirm.instance}/${currentFirm.firm}`
|
||||
const { record_id } = useParams();
|
||||
|
||||
const { data, isLoading } = useOne({resource: `${resourceBasePath}/contracts`, id: record_id,});
|
||||
|
||||
if (isLoading || data?.data === undefined) {
|
||||
return <CircularProgress />
|
||||
}
|
||||
|
||||
const record = data.data;
|
||||
return (
|
||||
<>
|
||||
<h2>{record.label}</h2>
|
||||
<Cartouche record={record}/>
|
||||
<CrudForm
|
||||
resourceBasePath={resourceBasePath}
|
||||
schemaName={"Contract"}
|
||||
uiSchema={{"ui:readonly": true }}
|
||||
record={record}
|
||||
card={true}
|
||||
>
|
||||
<Stack
|
||||
direction="row"
|
||||
spacing={2}
|
||||
sx={{
|
||||
justifyContent: "flex-end",
|
||||
alignItems: "center",
|
||||
}}>
|
||||
{ record.status == "published" && (<DeleteButton variant="contained" size="large" color="error" recordItemId={record_id}/>) }
|
||||
</Stack>
|
||||
</CrudForm>
|
||||
</>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user