Skip to content

Commit

Permalink
feat: add FormSummary component and integrate it into BasicForm; impl…
Browse files Browse the repository at this point in the history
…ement FetchLabels for incident labels
  • Loading branch information
simlarsen committed Jan 27, 2025
1 parent 6d5bc60 commit c6ce43f
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 23 deletions.
27 changes: 4 additions & 23 deletions Common/UI/Components/Forms/BasicForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ import UiAnalytics from "../../Utils/Analytics";
import Alert, { AlertType } from "../Alerts/Alert";
import Button, { ButtonStyleType } from "../Button/Button";
import ButtonTypes from "../Button/ButtonTypes";
import Detail from "../Detail/Detail";

import { DropdownOption, DropdownValue } from "../Dropdown/Dropdown";
import ErrorMessage from "../ErrorMessage/ErrorMessage";
import FormField from "./Fields/FormField";
import FormSummary from "./FormSummary";
import Steps from "./Steps/Steps";
import Field from "./Types/Field";
import Fields from "./Types/Fields";
Expand Down Expand Up @@ -35,8 +36,7 @@ import React, {
useState,
} from "react";
import useAsyncEffect from "use-async-effect";
import DetailField from "../Detail/Field";
import FormFieldSchemaTypeUtil from "./Utils/FormFieldSchemaTypeUtil";


export type FormProps<T> = FormikProps<T>;
export type FormErrors<T> = FormikErrors<T>;
Expand Down Expand Up @@ -633,26 +633,7 @@ const BasicForm: ForwardRefExoticComponent<any> = forwardRef(
{/* If Summary, show Model detail */}

{currentFormStepId === "summary" && (
<Detail
item={refCurrentValue.current as T}
fields={
formFields.map((field: Field<T>) => {
const detailField: DetailField<T> = {
title: field.title || "",
fieldType: FormFieldSchemaTypeUtil.toFieldType(
field.fieldType || FormFieldSchemaType.Text,
),
description: field.description || "",
// getElement: field.getSummaryElement,
sideLink: field.sideLink,
key: (Object.keys(
field.field || {},
)[0]?.toString() || "") as keyof T,
};
return detailField;
}) as DetailField<GenericObject>[]
}
/>
<FormSummary formValues={refCurrentValue.current} formFields={formFields} />
)}
</div>
</div>
Expand Down
62 changes: 62 additions & 0 deletions Common/UI/Components/Forms/FormSummary.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import React, { ReactElement } from "react";
import Detail from "../Detail/Detail";
import FormValues from "./Types/FormValues";
import GenericObject from "../../../Types/GenericObject";
import Fields from "./Types/Fields";
import FormFieldSchemaTypeUtil from "./Utils/FormFieldSchemaTypeUtil";
import FormFieldSchemaType from "./Types/FormFieldSchemaType";
import DetailField from "../Detail/Field";
import Field from "./Types/Field";
import FieldType from "../Types/FieldType";

export interface ComponentProps<T> {
formValues: FormValues<T>;
formFields: Fields<T>;
}

const FormSummary: <T extends GenericObject>(
props: ComponentProps<T>,
) => ReactElement = <T extends GenericObject>(
props: ComponentProps<T>,
): ReactElement => {
const { formValues, formFields } = props;

const getDetailForFormFields: <T extends GenericObject>(
formValues: FormValues<T>,
formFields: Fields<T>,
) => ReactElement = <T extends GenericObject>(
formValues: FormValues<T>,
formFields: Fields<T>,
): ReactElement => {
return (
<Detail
item={formValues as T}
fields={
formFields.map((field: Field<T>) => {
const detailField: DetailField<T> = {
title: field.title || "",
fieldType: field.getSummaryElement ?
FieldType.Element :
FormFieldSchemaTypeUtil.toFieldType(
field.fieldType || FormFieldSchemaType.Text,
),
description: field.description || "",
getElement: field.getSummaryElement as any,
sideLink: field.sideLink,
key: (Object.keys(
field.field || {},
)[0]?.toString() || "") as keyof T,
};
return detailField;
}) as DetailField<GenericObject>[]
}
/>

);
};

return getDetailForFormFields(formValues, formFields);
};

export default FormSummary;

91 changes: 91 additions & 0 deletions Dashboard/src/Components/Label/FetchLabels.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import LabelElement from "./Label";
import TableColumnListComponent from "Common/UI/Components/TableColumnList/TableColumnListComponent";
import Label from "Common/Models/DatabaseModels/Label";
import React, { FunctionComponent, ReactElement, useEffect } from "react";
import ObjectID from "Common/Types/ObjectID";
import API from "Common/UI/Utils/API/API";
import ModelAPI from "Common/UI/Utils/ModelAPI/ModelAPI";
import Includes from "Common/Types/BaseDatabase/Includes";
import { LIMIT_PER_PROJECT } from "Common/Types/Database/LimitMax";
import SortOrder from "Common/Types/BaseDatabase/SortOrder";
import ListResult from "Common/UI/Utils/BaseDatabase/ListResult";
import ErrorMessage from "Common/UI/Components/ErrorMessage/ErrorMessage";
import ComponentLoader from "Common/UI/Components/ComponentLoader/ComponentLoader";

export interface ComponentProps {
labelIds: Array<ObjectID>;
}

const FetchLabels: FunctionComponent<ComponentProps> = (
props: ComponentProps,
): ReactElement => {

const [isLoading, setIsLoading] = React.useState<boolean>(true);
const [error, setError] = React.useState<string>("");
const [labels, setLabels] = React.useState<Array<Label>>([]);


const fetchLabels = async () => {
setIsLoading(true);
setError("");

try{
const labels: ListResult<Label> = await ModelAPI.getList({
modelType: Label,
query: {
_id: new Includes(props.labelIds),
},
skip: 0,
limit: LIMIT_PER_PROJECT,
select: {
name: true,
color: true,
_id: true
},
sort: {
name: SortOrder.Ascending
}
});

setLabels(labels.data);

}catch(err){
setError(API.getFriendlyMessage(err));
}
};

useEffect(() => {
fetchLabels().catch((err) => {
setError(API.getFriendlyMessage(err));
});

}, []);

if(error){
return <ErrorMessage message={error} />;
}


if(isLoading){
return <ComponentLoader />;
}

return (
// {/** >4 because 3 labels are shown by default and then the more text is shown */}
<TableColumnListComponent
items={labels}
moreText={labels.length > 4 ? "more labels" : "more label"}
className={labels.length > 0 ? "-mb-1 -mt-1" : ""}
getEachElement={(label: Label) => {
return (
<div className={labels.length > 0 ? "my-2" : ""}>
<LabelElement label={label} />
</div>
);
}}
noItemsMessage="No labels attached."
/>
);
};

export default FetchLabels;
17 changes: 17 additions & 0 deletions Dashboard/src/Pages/Incidents/Create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import BaseModel from "Common/Models/DatabaseModels/DatabaseBaseModel/DatabaseBa
import API from "Common/UI/Utils/API/API";
import PageLoader from "Common/UI/Components/Loader/PageLoader";
import ErrorMessage from "Common/UI/Components/ErrorMessage/ErrorMessage";
import FetchLabels from "../../Components/Label/FetchLabels";

const IncidentCreate: FunctionComponent<
PageComponentProps
Expand Down Expand Up @@ -309,6 +310,22 @@ const IncidentCreate: FunctionComponent<
},
required: false,
placeholder: "Labels",
getSummaryElement: (item: Incident) => {

if(!item.labels){
return <p>No labels assigned.</p>
}

return (
<div>
<FetchLabels labelIds={item.labels?.map(
(label: Label) => {
return new ObjectID(label._id?.toString() || "");
},
)} />
</div>
);
}
},
{
field: {
Expand Down

0 comments on commit c6ce43f

Please sign in to comment.