Compare commits
12 Commits
40e20d0e64
...
ef43369425
| Author | SHA1 | Date | |
|---|---|---|---|
| ef43369425 | |||
| 37193d2246 | |||
| 87f9119b0b | |||
| f9b6aae927 | |||
| 6683d60be5 | |||
| 3942c54ad9 | |||
| 0a22bc1b8f | |||
| 237f8d5742 | |||
| 8d72172e0a | |||
| 90aa5e06f2 | |||
| 178f27cfe2 | |||
| f4c6cdab3b |
@@ -31,8 +31,7 @@ async def create(schema: ContractCreate, reg=Depends(get_authed_tenant_registry)
|
|||||||
contract_dict = schema.model_dump()
|
contract_dict = schema.model_dump()
|
||||||
del(contract_dict['draft_id'])
|
del(contract_dict['draft_id'])
|
||||||
|
|
||||||
lawyer = await Entity.get(reg.db, reg.user.entity_id)
|
contract_dict['lawyer'] = reg.partner.model_dump()
|
||||||
contract_dict['lawyer'] = lawyer.model_dump()
|
|
||||||
|
|
||||||
contract_dict['name'] = draft.name
|
contract_dict['name'] = draft.name
|
||||||
contract_dict['title'] = draft.title
|
contract_dict['title'] = draft.title
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
import datetime
|
import datetime
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
|
from beanie import PydanticObjectId
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
from firm.contract.models import ContractDraft, DraftProvision, DraftParty, Contract
|
from firm.contract.models import ContractDraft, DraftProvision, DraftParty, Contract
|
||||||
|
|
||||||
from firm.entity.models import Entity
|
from firm.entity.models import Entity
|
||||||
from firm.core.schemas import Writer, Reader
|
from firm.core.schemas import Writer, Reader
|
||||||
from firm.core.models import DictionaryEntry
|
from firm.core.models import DictionaryEntry, ForeignKey
|
||||||
|
|
||||||
|
|
||||||
class ContractDraftRead(Reader, ContractDraft):
|
class ContractDraftRead(Reader, ContractDraft):
|
||||||
@@ -68,7 +69,7 @@ class ContractRead(Reader, Contract):
|
|||||||
class ContractCreate(Writer):
|
class ContractCreate(Writer):
|
||||||
date: datetime.date
|
date: datetime.date
|
||||||
location: str
|
location: str
|
||||||
draft_id: str
|
draft_id: PydanticObjectId = ForeignKey(resource="contracts/drafts", schema="ContractDraft")
|
||||||
|
|
||||||
class ContractInit(BaseModel):
|
class ContractInit(BaseModel):
|
||||||
date: datetime.date
|
date: datetime.date
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
from fastapi import HTTPException, Depends
|
from fastapi import HTTPException, Depends
|
||||||
|
|
||||||
from hub.auth import get_current_user
|
from hub.auth import get_current_user
|
||||||
|
|
||||||
|
from firm.current_firm import CurrentFirmModel, Partner
|
||||||
from firm.db import get_db_client
|
from firm.db import get_db_client
|
||||||
from firm.current_firm import CurrentFirmModel
|
from firm.entity.models import Entity
|
||||||
|
|
||||||
|
|
||||||
class Registry:
|
class Registry:
|
||||||
user = None
|
user = None
|
||||||
|
partner = None
|
||||||
|
|
||||||
def __init__(self, db_client, instance, firm):
|
def __init__(self, db_client, instance, firm):
|
||||||
self.db = db_client[f"tenant_{instance}_{firm}"]
|
self.db = db_client[f"tenant_{instance}_{firm}"]
|
||||||
@@ -14,11 +18,14 @@ class Registry:
|
|||||||
|
|
||||||
self.current_firm = CurrentFirmModel.get_current(self.db)
|
self.current_firm = CurrentFirmModel.get_current(self.db)
|
||||||
|
|
||||||
def set_user(self, user):
|
async def set_user(self, user):
|
||||||
for firm in user.firms:
|
for firm in user.firms:
|
||||||
if firm.instance == self.instance and firm.firm == self.firm:
|
if firm.instance == self.instance and firm.firm == self.firm:
|
||||||
|
partner = await Partner.get_by_user_id(self.db, user.id)
|
||||||
|
partner_entity = await Entity.get(self.db, partner.entity_id)
|
||||||
self.user = user
|
self.user = user
|
||||||
self.db.user = user
|
self.partner = partner_entity
|
||||||
|
self.db.partner = partner_entity
|
||||||
return
|
return
|
||||||
|
|
||||||
raise PermissionError
|
raise PermissionError
|
||||||
@@ -30,9 +37,9 @@ async def get_tenant_registry(instance: str, firm: str, db_client=Depends(get_db
|
|||||||
|
|
||||||
return registry
|
return registry
|
||||||
|
|
||||||
def get_authed_tenant_registry(registry=Depends(get_tenant_registry), user=Depends(get_current_user)) -> Registry:
|
async def get_authed_tenant_registry(registry=Depends(get_tenant_registry), user=Depends(get_current_user)) -> Registry:
|
||||||
try:
|
try:
|
||||||
registry.set_user(user)
|
await registry.set_user(user)
|
||||||
except PermissionError:
|
except PermissionError:
|
||||||
raise HTTPException(status_code=404, detail="This firm doesn't exist or you are not allowed to access it.")
|
raise HTTPException(status_code=404, detail="This firm doesn't exist or you are not allowed to access it.")
|
||||||
|
|
||||||
@@ -44,7 +51,7 @@ async def get_uninitialized_registry(instance: str, firm: str, db_client=Depends
|
|||||||
raise HTTPException(status_code=409, detail="Firm configuration already exists")
|
raise HTTPException(status_code=409, detail="Firm configuration already exists")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
registry.set_user(user)
|
await registry.set_user(user)
|
||||||
except PermissionError:
|
except PermissionError:
|
||||||
raise HTTPException(status_code=404, detail="This firm doesn't exist or you are not allowed to access it.")
|
raise HTTPException(status_code=404, detail="This firm doesn't exist or you are not allowed to access it.")
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class CrudDocument(BaseModel):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def create(cls, db, create_schema):
|
async def create(cls, db, create_schema):
|
||||||
model_dict = create_schema.model_dump() | {"created_by": db.user.id, "updated_by": db.user.id}
|
model_dict = create_schema.model_dump() | {"created_by": db.partner.id, "updated_by": db.partner.id}
|
||||||
document = cls.model_validate(model_dict).model_dump(mode="json")
|
document = cls.model_validate(model_dict).model_dump(mode="json")
|
||||||
result = await cls._get_collection(db).insert_one(document)
|
result = await cls._get_collection(db).insert_one(document)
|
||||||
|
|
||||||
@@ -52,8 +52,13 @@ class CrudDocument(BaseModel):
|
|||||||
}
|
}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def list(cls, db):
|
async def list(cls, db, criteria={}):
|
||||||
return cls._get_collection(db).find({})
|
result = []
|
||||||
|
for document in await cls._get_collection(db).find(criteria).to_list():
|
||||||
|
document["id"] = document.pop("_id")
|
||||||
|
result.append(cls.model_validate(document))
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def get(cls, db, model_id):
|
async def get(cls, db, model_id):
|
||||||
@@ -66,7 +71,7 @@ class CrudDocument(BaseModel):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
async def update(cls, db, model, update_schema):
|
async def update(cls, db, model, update_schema):
|
||||||
model_dict = update_schema.model_dump(mode="json") | {"updated_by": db.user.id}
|
model_dict = update_schema.model_dump(mode="json") | {"updated_by": db.partner.id}
|
||||||
update_query = {
|
update_query = {
|
||||||
"$set": {field: value for field, value in model_dict.items() if field!= "id" }
|
"$set": {field: value for field, value in model_dict.items() if field!= "id" }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,14 +36,15 @@ class CurrentFirmModel(CrudDocument):
|
|||||||
class CurrentFirmSchemaRead(Reader):
|
class CurrentFirmSchemaRead(Reader):
|
||||||
entity: EntityRead
|
entity: EntityRead
|
||||||
partner: EntityRead
|
partner: EntityRead
|
||||||
|
partner_list: list[EntityRead]
|
||||||
instance: str
|
instance: str
|
||||||
firm: str
|
firm: str
|
||||||
primary_color: str
|
primary_color: str
|
||||||
secondary_color: str
|
secondary_color: str
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_model_and_entities(cls, model, entity, partner):
|
def from_model_and_entities(cls, model, entity, partner, partner_list):
|
||||||
schema = cls(**model.model_dump(mode="json"), entity=entity, partner=partner)
|
schema = cls(**model.model_dump(mode="json"), entity=entity, partner=partner, partner_list=partner_list)
|
||||||
return schema
|
return schema
|
||||||
|
|
||||||
class CurrentFirmSchemaCreate(Writer):
|
class CurrentFirmSchemaCreate(Writer):
|
||||||
|
|||||||
@@ -10,10 +10,17 @@ current_firm_router = APIRouter()
|
|||||||
@current_firm_router.get("/", response_model=CurrentFirmSchemaRead, response_description=f"Current Firm records retrieved")
|
@current_firm_router.get("/", response_model=CurrentFirmSchemaRead, response_description=f"Current Firm records retrieved")
|
||||||
async def read(reg=Depends(get_authed_tenant_registry)) -> CurrentFirmSchemaRead:
|
async def read(reg=Depends(get_authed_tenant_registry)) -> CurrentFirmSchemaRead:
|
||||||
document = await CurrentFirmModel.get_current(reg.db)
|
document = await CurrentFirmModel.get_current(reg.db)
|
||||||
entity = await Entity.get(reg.db, document.entity_id)
|
firm_entity = await Entity.get(reg.db, document.entity_id)
|
||||||
partner = await Partner.get_by_user_id(reg.db, reg.user.id)
|
partner = await Partner.get_by_user_id(reg.db, reg.user.id)
|
||||||
partner = await Entity.get(reg.db, partner.entity_id)
|
partner = await Entity.get(reg.db, partner.entity_id)
|
||||||
return CurrentFirmSchemaRead.from_model_and_entities(document, EntityRead.from_model(entity), EntityRead.from_model(partner))
|
partner_list = await Partner.list(reg.db)
|
||||||
|
partner_list = await Entity.list(reg.db, {"_id": {"$in": [p.entity_id for p in partner_list]}})
|
||||||
|
return CurrentFirmSchemaRead.from_model_and_entities(
|
||||||
|
document,
|
||||||
|
EntityRead.from_model(firm_entity),
|
||||||
|
EntityRead.from_model(partner),
|
||||||
|
[EntityRead.from_model(p) for p in partner_list]
|
||||||
|
)
|
||||||
|
|
||||||
@current_firm_router.post("/", response_description=f"Current Firm added to the database")
|
@current_firm_router.post("/", response_description=f"Current Firm added to the database")
|
||||||
async def create(schema: CurrentFirmSchemaCreate, reg=Depends(get_uninitialized_registry)) -> CurrentFirmSchemaRead:
|
async def create(schema: CurrentFirmSchemaCreate, reg=Depends(get_uninitialized_registry)) -> CurrentFirmSchemaRead:
|
||||||
|
|||||||
1
gui/rpk-gui/package-lock.json
generated
1
gui/rpk-gui/package-lock.json
generated
@@ -35,6 +35,7 @@
|
|||||||
"@tiptap/extension-underline": "^2.11.7",
|
"@tiptap/extension-underline": "^2.11.7",
|
||||||
"@tiptap/react": "^2.11.7",
|
"@tiptap/react": "^2.11.7",
|
||||||
"@tiptap/starter-kit": "^2.11.7",
|
"@tiptap/starter-kit": "^2.11.7",
|
||||||
|
"dayjs": "^1.11.13",
|
||||||
"i18next": "^25.0.1",
|
"i18next": "^25.0.1",
|
||||||
"i18next-browser-languagedetector": "^8.0.5",
|
"i18next-browser-languagedetector": "^8.0.5",
|
||||||
"i18next-http-backend": "^3.0.2",
|
"i18next-http-backend": "^3.0.2",
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
"@tiptap/extension-underline": "^2.11.7",
|
"@tiptap/extension-underline": "^2.11.7",
|
||||||
"@tiptap/react": "^2.11.7",
|
"@tiptap/react": "^2.11.7",
|
||||||
"@tiptap/starter-kit": "^2.11.7",
|
"@tiptap/starter-kit": "^2.11.7",
|
||||||
|
"dayjs": "^1.11.13",
|
||||||
"i18next": "^25.0.1",
|
"i18next": "^25.0.1",
|
||||||
"i18next-browser-languagedetector": "^8.0.5",
|
"i18next-browser-languagedetector": "^8.0.5",
|
||||||
"i18next-http-backend": "^3.0.2",
|
"i18next-http-backend": "^3.0.2",
|
||||||
|
|||||||
33
gui/rpk-gui/src/components/Cartouche.tsx
Normal file
33
gui/rpk-gui/src/components/Cartouche.tsx
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
import { useTranslation } from "@refinedev/core";
|
||||||
|
import { useContext } from "react";
|
||||||
|
import { FirmContext } from "../contexts/FirmContext";
|
||||||
|
|
||||||
|
type CartoucheProps = {
|
||||||
|
record: any
|
||||||
|
}
|
||||||
|
|
||||||
|
const Cartouche = (props: CartoucheProps) => {
|
||||||
|
const { record } = props;
|
||||||
|
const { translate: t } = useTranslation();
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<ul>
|
||||||
|
{ record.created_at && <li>{t("resource.created_at")}: {record.created_at} {t("resource.created_at")}: <AuthorField partnerId={record.created_by} /></li> }
|
||||||
|
{ record.updated_at && <li>{t("resource.updated_at")}: {record.updated_at} {t("resource.updated_by")}: <AuthorField partnerId={record.updated_by} /></li> }
|
||||||
|
</ul>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Cartouche;
|
||||||
|
|
||||||
|
const AuthorField = (props: {partnerId: string})=> {
|
||||||
|
const { partnerId } = props;
|
||||||
|
const { partnerMap } = useContext(FirmContext);
|
||||||
|
const { translate: t } = useTranslation();
|
||||||
|
|
||||||
|
if (partnerMap && partnerMap.has(partnerId)) {
|
||||||
|
return <>{ partnerMap.get(partnerId) }</>
|
||||||
|
}
|
||||||
|
return <>{t("REDACTED")}</>
|
||||||
|
}
|
||||||
@@ -1,9 +1,12 @@
|
|||||||
import React, { createContext, PropsWithChildren } from 'react';
|
import React, { createContext, PropsWithChildren } from 'react';
|
||||||
import { IFirm } from "../interfaces";
|
import { IFirm } from "../interfaces";
|
||||||
import { useParams } from "react-router";
|
import { useParams } from "react-router";
|
||||||
|
import { useOne } from "@refinedev/core";
|
||||||
|
import { CircularProgress } from "@mui/material";
|
||||||
|
|
||||||
type FirmContextType = {
|
type FirmContextType = {
|
||||||
currentFirm: IFirm,
|
currentFirm: IFirm,
|
||||||
|
partnerMap?: Map<string, string>
|
||||||
}
|
}
|
||||||
|
|
||||||
export const FirmContext = createContext<FirmContextType>(
|
export const FirmContext = createContext<FirmContextType>(
|
||||||
@@ -12,13 +15,27 @@ export const FirmContext = createContext<FirmContextType>(
|
|||||||
|
|
||||||
|
|
||||||
export const FirmContextProvider: React.FC<PropsWithChildren> = ({ children }: PropsWithChildren) => {
|
export const FirmContextProvider: React.FC<PropsWithChildren> = ({ children }: PropsWithChildren) => {
|
||||||
const { instance, firm } = useParams<IFirm>()
|
const { instance, firm } = useParams<IFirm>();
|
||||||
|
const { data, isError, error, isLoading } = useOne({resource: 'firm', id: `${instance}/${firm}/`, errorNotification: false});
|
||||||
|
|
||||||
if (instance === undefined || firm === undefined) {
|
if (instance === undefined || firm === undefined) {
|
||||||
return "Error"
|
return "Error"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return <CircularProgress />
|
||||||
|
}
|
||||||
|
|
||||||
|
let value: FirmContextType = {
|
||||||
|
currentFirm: {instance, firm}
|
||||||
|
}
|
||||||
|
if (!isError || error?.statusCode != 405) {
|
||||||
|
value.currentFirm.entity = data?.data.entity;
|
||||||
|
value.partnerMap = new Map(data?.data.partner_list.map((item: any) => [item.id, item.label]));
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FirmContext.Provider value={{currentFirm: {instance, firm}}} >
|
<FirmContext.Provider value={value} >
|
||||||
{ children }
|
{ children }
|
||||||
</FirmContext.Provider>
|
</FirmContext.Provider>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
export type IFirm = {
|
export type IFirm = {
|
||||||
instance: string,
|
instance: string,
|
||||||
firm: string
|
firm: string
|
||||||
|
entity?: any
|
||||||
}
|
}
|
||||||
|
|
||||||
type User = {
|
type User = {
|
||||||
|
|||||||
@@ -8,32 +8,23 @@ import { BaseForm } from "./base-form";
|
|||||||
type CrudFormProps = {
|
type CrudFormProps = {
|
||||||
schemaName: string,
|
schemaName: string,
|
||||||
uiSchema?: UiSchema,
|
uiSchema?: UiSchema,
|
||||||
resourceBasePath?: string,
|
record?: any,
|
||||||
resource: string,
|
resourceBasePath: string,
|
||||||
id?: string,
|
onSubmit: (data: any) => void,
|
||||||
onSuccess?: (data: any) => void,
|
|
||||||
defaultValue?: any,
|
defaultValue?: any,
|
||||||
children?: ReactNode
|
children?: ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CrudForm: React.FC<CrudFormProps> = (props) => {
|
export const CrudForm: React.FC<CrudFormProps> = (props) => {
|
||||||
const { schemaName, uiSchema, resourceBasePath="" ,resource, id, onSuccess, defaultValue, children } = props;
|
const { schemaName, uiSchema, record, resourceBasePath, defaultValue, children, onSubmit } = props;
|
||||||
|
|
||||||
const { onFinish, query, formLoading } = useForm({
|
|
||||||
resource: resourceBasePath == "" ? resource : `${resourceBasePath}/${resource}`,
|
|
||||||
action: id === undefined ? "create" : "edit",
|
|
||||||
redirect: "show",
|
|
||||||
id,
|
|
||||||
onMutationSuccess: (data: any) => { if (onSuccess) { onSuccess(data) } },
|
|
||||||
});
|
|
||||||
|
|
||||||
const [schema, setSchema] = useState({});
|
const [schema, setSchema] = useState({});
|
||||||
const [schemaLoading, setSchemaLoading] = useState(true);
|
const [schemaLoading, setSchemaLoading] = useState(true);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchSchema = async () => {
|
const fetchSchema = async () => {
|
||||||
try {
|
try {
|
||||||
const resourceSchema = id === undefined ? await jsonschemaProvider.getCreateResourceSchema(schemaName)
|
const resourceSchema = record === undefined ? await jsonschemaProvider.getCreateResourceSchema(schemaName)
|
||||||
: await jsonschemaProvider.getCardResourceSchema(schemaName);
|
: await jsonschemaProvider.getUpdateResourceSchema(schemaName);
|
||||||
setSchema(resourceSchema);
|
setSchema(resourceSchema);
|
||||||
setSchemaLoading(false);
|
setSchemaLoading(false);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -44,19 +35,18 @@ export const CrudForm: React.FC<CrudFormProps> = (props) => {
|
|||||||
fetchSchema();
|
fetchSchema();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if(formLoading || schemaLoading) {
|
if(schemaLoading) {
|
||||||
return <CircularProgress />
|
return <CircularProgress />
|
||||||
}
|
}
|
||||||
|
|
||||||
const record = query?.data?.data || defaultValue;
|
|
||||||
return (
|
return (
|
||||||
<BaseForm
|
<BaseForm
|
||||||
schema={schema}
|
schema={schema}
|
||||||
uiSchema={uiSchema}
|
uiSchema={uiSchema}
|
||||||
formData={record}
|
formData={record || defaultValue}
|
||||||
resourceBasePath={resourceBasePath}
|
resourceBasePath={resourceBasePath}
|
||||||
onSubmit={
|
onSubmit={
|
||||||
(data: any) => onFinish(data)
|
(data: any) => onSubmit(data)
|
||||||
}
|
}
|
||||||
children={children}
|
children={children}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -25,9 +25,11 @@ declare module "@tiptap/core" {
|
|||||||
export default Extension.create<IndentOptions>({
|
export default Extension.create<IndentOptions>({
|
||||||
name: "indent",
|
name: "indent",
|
||||||
|
|
||||||
defaultOptions: {
|
addOptions() {
|
||||||
types: ["paragraph", "heading"],
|
return {
|
||||||
margin: 40
|
types: ["paragraph", "heading"],
|
||||||
|
margin: 40
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
addGlobalAttributes() {
|
addGlobalAttributes() {
|
||||||
|
|||||||
@@ -32,6 +32,21 @@ export const jsonschemaProvider = {
|
|||||||
return readSchema
|
return readSchema
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getReadOnlyResourceSchema: 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)) {
|
||||||
|
delete readSchema.properties[prop_name];
|
||||||
|
} else {
|
||||||
|
readSchema.properties[prop_name].readOnly = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return readSchema
|
||||||
|
},
|
||||||
|
|
||||||
getUpdateResourceSchema: async (resourceName: string): Promise<CrudRJSFSchema> => {
|
getUpdateResourceSchema: async (resourceName: string): Promise<CrudRJSFSchema> => {
|
||||||
return getResourceSchema(`${resourceName}Update`)
|
return getResourceSchema(`${resourceName}Update`)
|
||||||
},
|
},
|
||||||
@@ -59,10 +74,12 @@ function convertCamelToSnake(str: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function buildResource(rawSchemas: RJSFSchema, resourceName: string) {
|
function buildResource(rawSchemas: RJSFSchema, resourceName: string) {
|
||||||
let resource;
|
if (rawSchemas.components.schemas[resourceName] === undefined) {
|
||||||
|
throw new Error(`Resource "${resourceName}" not found in schema.`);
|
||||||
|
}
|
||||||
|
|
||||||
const shortResourceName = convertCamelToSnake(resourceName.replace(/(-Input|Create|Update)$/g, ""));
|
const shortResourceName = convertCamelToSnake(resourceName.replace(/(-Input|Create|Update)$/g, ""));
|
||||||
resource = structuredClone(rawSchemas.components.schemas[resourceName]);
|
let resource = structuredClone(rawSchemas.components.schemas[resourceName]);
|
||||||
resource.components = { schemas: {} };
|
resource.components = { schemas: {} };
|
||||||
for (let prop_name in resource.properties) {
|
for (let prop_name in resource.properties) {
|
||||||
let prop = resource.properties[prop_name];
|
let prop = resource.properties[prop_name];
|
||||||
@@ -110,23 +127,35 @@ function resolveReference(rawSchemas: RJSFSchema, resource: any, prop_reference:
|
|||||||
|
|
||||||
function changePropertiesOrder(resource: any) {
|
function changePropertiesOrder(resource: any) {
|
||||||
let created_at;
|
let created_at;
|
||||||
|
let created_by;
|
||||||
let updated_at;
|
let updated_at;
|
||||||
|
let updated_by;
|
||||||
let new_properties: any = {};
|
let new_properties: any = {};
|
||||||
for (let prop_name in resource.properties) {
|
for (let prop_name in resource.properties) {
|
||||||
if (prop_name == 'created_at') {
|
if (prop_name == 'created_at') {
|
||||||
created_at = resource.properties[prop_name];
|
created_at = resource.properties[prop_name];
|
||||||
|
} else if (prop_name == 'created_by') {
|
||||||
|
created_by = resource.properties[prop_name];
|
||||||
} else if (prop_name == 'updated_at') {
|
} else if (prop_name == 'updated_at') {
|
||||||
updated_at = resource.properties[prop_name];
|
updated_at = resource.properties[prop_name];
|
||||||
} else {
|
} else if (prop_name == 'updated_by') {
|
||||||
|
updated_by = resource.properties[prop_name];
|
||||||
|
}else {
|
||||||
new_properties[prop_name] = resource.properties[prop_name];
|
new_properties[prop_name] = resource.properties[prop_name];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (created_at) {
|
if (created_at) {
|
||||||
new_properties['created_at'] = created_at;
|
new_properties['created_at'] = created_at;
|
||||||
}
|
}
|
||||||
|
if (created_by) {
|
||||||
|
new_properties['created_by'] = created_by;
|
||||||
|
}
|
||||||
if (updated_at) {
|
if (updated_at) {
|
||||||
new_properties['updated_at'] = updated_at;
|
new_properties['updated_at'] = updated_at;
|
||||||
}
|
}
|
||||||
|
if (updated_by) {
|
||||||
|
new_properties['updated_by'] = updated_by;
|
||||||
|
}
|
||||||
resource.properties = new_properties
|
resource.properties = new_properties
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import { Route, Routes } from "react-router";
|
import { Route, Routes } from "react-router";
|
||||||
import List from "./base-page/List";
|
import List from "./base-page/List";
|
||||||
import Edit from "./base-page/Edit";
|
import Edit from "./base-page/Edit";
|
||||||
import New from "./base-page/New";
|
|
||||||
|
|
||||||
type Contract = {
|
export type Contract = {
|
||||||
id: string,
|
id: string,
|
||||||
label: string
|
label: string
|
||||||
}
|
}
|
||||||
@@ -13,7 +12,6 @@ export const ContractRoutes = () => {
|
|||||||
<Routes>
|
<Routes>
|
||||||
<Route index element={ <ListContract /> } />
|
<Route index element={ <ListContract /> } />
|
||||||
<Route path="/edit/:record_id" element={ <EditContract /> } />
|
<Route path="/edit/:record_id" element={ <EditContract /> } />
|
||||||
<Route path="/create" element={ <CreateContract /> } />
|
|
||||||
</Routes>
|
</Routes>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -28,7 +26,3 @@ const ListContract = () => {
|
|||||||
const EditContract = () => {
|
const EditContract = () => {
|
||||||
return <Edit<Contract> resource={`contracts`} schemaName={"Contract"} />
|
return <Edit<Contract> resource={`contracts`} schemaName={"Contract"} />
|
||||||
}
|
}
|
||||||
|
|
||||||
const CreateContract = () => {
|
|
||||||
return <New<Contract> resource={`contracts`} schemaName={"Contract"} />
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Route, Routes } from "react-router";
|
import { Navigate, Route, Routes, useParams } from "react-router";
|
||||||
import { CircularProgress } from "@mui/material";
|
import { CircularProgress } from "@mui/material";
|
||||||
import React, { useContext, useState } from "react";
|
import React, { useContext, useState } from "react";
|
||||||
import { useOne } from "@refinedev/core";
|
import { useOne, useTranslation } from "@refinedev/core";
|
||||||
import { BaseForm } from "../../lib/crud/components/base-form";
|
import { BaseForm } from "../../lib/crud/components/base-form";
|
||||||
import { ForeignKeyReference, ForeignKeySchema } from "../../lib/crud/components/widgets/foreign-key";
|
import { ForeignKeyReference, ForeignKeySchema } from "../../lib/crud/components/widgets/foreign-key";
|
||||||
|
|
||||||
@@ -9,6 +9,8 @@ import { FirmContext } from "../../contexts/FirmContext";
|
|||||||
import List from "./base-page/List";
|
import List from "./base-page/List";
|
||||||
import Edit from "./base-page/Edit";
|
import Edit from "./base-page/Edit";
|
||||||
import New from "./base-page/New";
|
import New from "./base-page/New";
|
||||||
|
import { Contract } from "./ContractRoutes";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
type Draft = {
|
type Draft = {
|
||||||
id: string,
|
id: string,
|
||||||
@@ -33,7 +35,63 @@ const ListDraft = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const EditDraft = () => {
|
const EditDraft = () => {
|
||||||
return <Edit<Draft> resource={`contracts/drafts`} schemaName={"ContractDraft"} />
|
const { currentFirm } = useContext(FirmContext);
|
||||||
|
const { record_id } = useParams();
|
||||||
|
const resourceBasePath = `firm/${currentFirm.instance}/${currentFirm.firm}`
|
||||||
|
|
||||||
|
const { data, isLoading } = useOne({
|
||||||
|
resource: `${resourceBasePath}/contracts/drafts`,
|
||||||
|
id: record_id
|
||||||
|
})
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return <CircularProgress />
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!data?.data) {
|
||||||
|
return <Navigate to="../" />
|
||||||
|
}
|
||||||
|
|
||||||
|
const draft = data?.data
|
||||||
|
const readOnly = draft.status === "published";
|
||||||
|
|
||||||
|
const uiSchema = {
|
||||||
|
"ui:readonly": readOnly
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Edit<Draft> resource={"contracts/drafts"} schemaName={"ContractDraft"} uiSchema={uiSchema} />
|
||||||
|
<ContractCreate draft={draft}></ContractCreate>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const ContractCreate = (props: { draft: any}) => {
|
||||||
|
const { translate: t } = useTranslation();
|
||||||
|
const { draft } = props;
|
||||||
|
|
||||||
|
if (draft.status === "published") {
|
||||||
|
return <h4>{t("resource.draft.already_published") }</h4>
|
||||||
|
}
|
||||||
|
if (draft.status === "in_progress") {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h4>{ t("resource.draft.todo") + ":" }</h4>
|
||||||
|
<ul>{ draft.todo.map((item: any) => <li>{ item }</li>) }</ul>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return <New<Contract>
|
||||||
|
resource={"contracts"}
|
||||||
|
schemaName={"Contract"}
|
||||||
|
defaultValue={{
|
||||||
|
date: dayjs().format("YYYY-MM-DD"),
|
||||||
|
location: "Los Santos, SA",
|
||||||
|
draft_id: draft.id
|
||||||
|
}}
|
||||||
|
uiSchema={{ draft_id: { 'ui:widget': 'hidden' } }}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
|
|
||||||
type ForeignKeySubSchema = ForeignKeySchema & {
|
type ForeignKeySubSchema = ForeignKeySchema & {
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
import { UiSchema } from "@rjsf/utils";
|
import { UiSchema } from "@rjsf/utils";
|
||||||
import { useParams } from "react-router";
|
|
||||||
import { useContext } from "react";
|
import { useContext } from "react";
|
||||||
import { Button } from "@mui/material";
|
import { useParams, Navigate } from "react-router";
|
||||||
import DeleteIcon from '@mui/icons-material/Delete';
|
import { Button, CircularProgress } from "@mui/material";
|
||||||
|
import Stack from "@mui/material/Stack";
|
||||||
import SaveIcon from '@mui/icons-material/Save';
|
import SaveIcon from '@mui/icons-material/Save';
|
||||||
|
import { useForm, useTranslation } from "@refinedev/core";
|
||||||
|
import { DeleteButton } from "@refinedev/mui";
|
||||||
import { FirmContext } from "../../../contexts/FirmContext";
|
import { FirmContext } from "../../../contexts/FirmContext";
|
||||||
import { CrudForm } from "../../../lib/crud/components/crud-form";
|
import { CrudForm } from "../../../lib/crud/components/crud-form";
|
||||||
import Stack from "@mui/material/Stack";
|
import Cartouche from "../../../components/Cartouche";
|
||||||
import { DeleteButton } from "@refinedev/mui";
|
|
||||||
|
|
||||||
type EditProps = {
|
type EditProps = {
|
||||||
resource: string,
|
resource: string,
|
||||||
@@ -18,17 +19,36 @@ type EditProps = {
|
|||||||
const Edit = <T,>(props: EditProps) => {
|
const Edit = <T,>(props: EditProps) => {
|
||||||
const { schemaName, resource, uiSchema } = props;
|
const { schemaName, resource, uiSchema } = props;
|
||||||
const { currentFirm } = useContext(FirmContext);
|
const { currentFirm } = useContext(FirmContext);
|
||||||
|
const { translate: t } = useTranslation();
|
||||||
const resourceBasePath = `firm/${currentFirm.instance}/${currentFirm.firm}`
|
const resourceBasePath = `firm/${currentFirm.instance}/${currentFirm.firm}`
|
||||||
const { record_id } = useParams();
|
const { record_id } = useParams();
|
||||||
|
|
||||||
|
const { onFinish, query, formLoading } = useForm({
|
||||||
|
resource: `${resourceBasePath}/${resource}`,
|
||||||
|
action: "edit",
|
||||||
|
redirect: "show",
|
||||||
|
id: record_id,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (formLoading) {
|
||||||
|
return <CircularProgress />
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!query?.data?.data) {
|
||||||
|
return <Navigate to="../" />
|
||||||
|
}
|
||||||
|
|
||||||
|
const record = query.data.data;
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<h2>{record.label}</h2>
|
||||||
|
<Cartouche record={record}/>
|
||||||
<CrudForm
|
<CrudForm
|
||||||
|
resourceBasePath={resourceBasePath}
|
||||||
schemaName={schemaName}
|
schemaName={schemaName}
|
||||||
uiSchema={uiSchema}
|
uiSchema={uiSchema}
|
||||||
resourceBasePath={resourceBasePath}
|
record={record}
|
||||||
resource={resource}
|
onSubmit={(data: any) => onFinish(data)}
|
||||||
id={record_id}
|
|
||||||
>
|
>
|
||||||
<Stack
|
<Stack
|
||||||
direction="row"
|
direction="row"
|
||||||
@@ -37,7 +57,7 @@ const Edit = <T,>(props: EditProps) => {
|
|||||||
justifyContent: "space-between",
|
justifyContent: "space-between",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
}}>
|
}}>
|
||||||
<Button type='submit' variant="contained" size="large"><SaveIcon />Save</Button>
|
<Button type='submit' variant="contained" size="large"><SaveIcon />{t("buttons.save")}</Button>
|
||||||
<DeleteButton variant="contained" size="large" color="error" recordItemId={record_id}/>
|
<DeleteButton variant="contained" size="large" color="error" recordItemId={record_id}/>
|
||||||
</Stack>
|
</Stack>
|
||||||
</CrudForm>
|
</CrudForm>
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
import { CrudForm } from "../../../lib/crud/components/crud-form";
|
|
||||||
import { UiSchema } from "@rjsf/utils";
|
import { UiSchema } from "@rjsf/utils";
|
||||||
import { useContext } from "react";
|
import { useContext } from "react";
|
||||||
|
import { useForm, useTranslation } from "@refinedev/core";
|
||||||
|
import { CrudForm } from "../../../lib/crud/components/crud-form";
|
||||||
import { FirmContext } from "../../../contexts/FirmContext";
|
import { FirmContext } from "../../../contexts/FirmContext";
|
||||||
|
import SaveIcon from "@mui/icons-material/Save";
|
||||||
|
import { Button } from "@mui/material";
|
||||||
|
|
||||||
type NewProps = {
|
type NewProps = {
|
||||||
resource: string,
|
resource: string,
|
||||||
@@ -13,16 +16,25 @@ type NewProps = {
|
|||||||
const New = <T,>(props: NewProps) => {
|
const New = <T,>(props: NewProps) => {
|
||||||
const { schemaName, resource, uiSchema, defaultValue } = props;
|
const { schemaName, resource, uiSchema, defaultValue } = props;
|
||||||
const { currentFirm } = useContext(FirmContext);
|
const { currentFirm } = useContext(FirmContext);
|
||||||
|
const { translate: t } = useTranslation();
|
||||||
const resourceBasePath = `firm/${currentFirm.instance}/${currentFirm.firm}`
|
const resourceBasePath = `firm/${currentFirm.instance}/${currentFirm.firm}`
|
||||||
|
|
||||||
|
const { onFinish } = useForm({
|
||||||
|
resource: `${resourceBasePath}/${resource}`,
|
||||||
|
action: "create",
|
||||||
|
redirect: "show",
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CrudForm
|
<CrudForm
|
||||||
schemaName={schemaName}
|
schemaName={schemaName}
|
||||||
uiSchema={uiSchema}
|
uiSchema={uiSchema}
|
||||||
resourceBasePath={resourceBasePath}
|
resourceBasePath={resourceBasePath}
|
||||||
resource={resource}
|
|
||||||
defaultValue={defaultValue}
|
defaultValue={defaultValue}
|
||||||
/>
|
onSubmit={(data: any) => onFinish(data)}
|
||||||
|
>
|
||||||
|
<Button type='submit' variant="contained" size="large"><SaveIcon />{t("buttons.create")}</Button>
|
||||||
|
</CrudForm>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { Route, Routes, Link } from "react-router";
|
import { Route, Routes, Link } from "react-router";
|
||||||
import React, { useContext } from "react";
|
import React, { useContext } from "react";
|
||||||
|
import { useForm, useOne, useTranslation } from "@refinedev/core";
|
||||||
import { FirmContext, FirmContextProvider } from "../../contexts/FirmContext";
|
import { FirmContext, FirmContextProvider } from "../../contexts/FirmContext";
|
||||||
import { Header } from "../../components";
|
import { Header } from "../../components";
|
||||||
import { useOne } from "@refinedev/core";
|
|
||||||
import { CrudForm } from "../../lib/crud/components/crud-form";
|
import { CrudForm } from "../../lib/crud/components/crud-form";
|
||||||
import { IFirm } from "../../interfaces";
|
import { IFirm } from "../../interfaces";
|
||||||
import { EntityRoutes } from "./EntityRoutes";
|
import { EntityRoutes } from "./EntityRoutes";
|
||||||
@@ -33,15 +33,7 @@ export const FirmRoutes = () => {
|
|||||||
|
|
||||||
const FirmHome = () => {
|
const FirmHome = () => {
|
||||||
const { currentFirm } = useContext(FirmContext);
|
const { currentFirm } = useContext(FirmContext);
|
||||||
const { data: firm, isError, error, isLoading } = useOne({resource: 'firm', id: `${currentFirm.instance}/${currentFirm.firm}/`, errorNotification: false})
|
const { translate: t } = useTranslation();
|
||||||
|
|
||||||
if (isLoading) {
|
|
||||||
return <h1>Loading...</h1>
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isError && error?.statusCode == 405) {
|
|
||||||
return <FirmInitForm currentFirm={currentFirm} />
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -64,16 +56,26 @@ type FirmInitFormPros = {
|
|||||||
|
|
||||||
const FirmInitForm = (props: FirmInitFormPros) => {
|
const FirmInitForm = (props: FirmInitFormPros) => {
|
||||||
const { currentFirm } = props;
|
const { currentFirm } = props;
|
||||||
|
const { translate: t } = useTranslation();
|
||||||
|
const resourceBasePath = `firm`
|
||||||
|
|
||||||
|
const { onFinish } = useForm({
|
||||||
|
resource: `${resourceBasePath}/${currentFirm.instance}/${currentFirm.firm}`,
|
||||||
|
action: "create",
|
||||||
|
redirect: "show",
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<h1>Initialization of {`${currentFirm.instance} / ${currentFirm.firm}`}</h1>
|
<h1>Initialization of {`${currentFirm.instance} / ${currentFirm.firm}`}</h1>
|
||||||
|
|
||||||
<CrudForm
|
<CrudForm
|
||||||
schemaName={"CurrentFirmSchemaCreate"}
|
schemaName={"CurrentFirmSchema"}
|
||||||
resource={`firm/${currentFirm.instance}/${currentFirm.firm}/`}
|
resourceBasePath={resourceBasePath}
|
||||||
|
defaultValue={{corporation: {entity_data: {activity: t("firm.default_activity") }}}}
|
||||||
uiSchema={{
|
uiSchema={{
|
||||||
corporation: {entity_data: {employees: {"ui:style": {"display": "none"}}}},
|
corporation: {entity_data: {employees: {"ui:style": {"display": "none"}}}},
|
||||||
}}
|
}}
|
||||||
|
onSubmit={(data: any) => onFinish(data)}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { useInvalidateAuthStore } from "@refinedev/core";
|
import { useForm, useInvalidateAuthStore } from "@refinedev/core";
|
||||||
import { CrudForm } from "../../lib/crud/components/crud-form";
|
import { CrudForm } from "../../lib/crud/components/crud-form";
|
||||||
import {empty_user} from "../../providers/auth-provider";
|
import { empty_user } from "../../providers/auth-provider";
|
||||||
|
|
||||||
export const CreateFirm = () => {
|
export const CreateFirm = () => {
|
||||||
const invalidateAuthStore = useInvalidateAuthStore()
|
const invalidateAuthStore = useInvalidateAuthStore()
|
||||||
@@ -9,11 +9,19 @@ export const CreateFirm = () => {
|
|||||||
invalidateAuthStore().then();
|
invalidateAuthStore().then();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const resourceBasePath = "hub/users";
|
||||||
|
const { onFinish } = useForm({
|
||||||
|
resource: `${resourceBasePath}/firms`,
|
||||||
|
action: "create",
|
||||||
|
redirect: "list",
|
||||||
|
onMutationSuccess: data => refreshUser()
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CrudForm
|
<CrudForm
|
||||||
schemaName={"FirmCreate"}
|
schemaName={"Firm"}
|
||||||
resource={"hub/users/firms/"}
|
resourceBasePath={resourceBasePath}
|
||||||
onSuccess={() => { refreshUser() }}
|
onSubmit={(data: any) => onFinish(data)}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user