Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions i18n/en.pot
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
"POT-Creation-Date: 2026-06-02T09:10:34.358Z\n"
"PO-Revision-Date: 2026-06-02T09:10:34.359Z\n"
"POT-Creation-Date: 2026-08-19T10:07:50.833Z\n"
"PO-Revision-Date: 2026-08-19T10:07:50.834Z\n"

msgid "Data store keys created!"
msgstr "Data store keys created!"
Expand Down Expand Up @@ -449,6 +449,12 @@ msgstr "Remove plugin"
msgid "Validation Error"
msgstr "Validation Error"

msgid "Could not fetch the latest fields. Please try again."
msgstr "Could not fetch the latest fields. Please try again."

msgid "Update fields order"
msgstr "Update fields order"

msgid "All fields you add here will be shown in the form"
msgstr "All fields you add here will be shown in the form"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ type Props = {
formFieldId: string,
apps: Array<z.infer<typeof appsSchema>>
existingFormFieldConfig: FormFieldRecord | null | undefined,
refetchMetadata: () => Promise<{ data?: z.infer<typeof ConvertedMetadataSchema> }>,
isRefetchingMetadata: boolean,
}

const ValidationErrorToast = ({ errorMessage }: { errorMessage: string }) => {
Expand All @@ -33,7 +35,7 @@ const ValidationErrorToast = ({ errorMessage }: { errorMessage: string }) => {
)
}

export const FormController = ({ metadata, formFieldId, apps, existingFormFieldConfig }: Props) => {
export const FormController = ({ metadata, formFieldId, apps, existingFormFieldConfig, refetchMetadata, isRefetchingMetadata }: Props) => {
const availablePlugins = useMemo(() => {
const filteredApps = apps.filter(app => app.pluginLaunchUrl);

Expand All @@ -53,8 +55,18 @@ export const FormController = ({ metadata, formFieldId, apps, existingFormFieldC
onAddPlugin,
onRemovePlugin,
existingPluginConfigs,
updateFieldsOrder,
} = useFormFieldController({ metadata, availablePlugins, existingFormFieldConfig });

const handleUpdateFieldsOrder = async () => {
const { data: freshMetadata } = await refetchMetadata();
if (!freshMetadata) {
toast.error(i18n.t('Could not fetch the latest fields. Please try again.'));
return;
}
updateFieldsOrder(freshMetadata);
}

const {
pluginConfigurations,
addPluginConfiguration,
Expand All @@ -79,6 +91,14 @@ export const FormController = ({ metadata, formFieldId, apps, existingFormFieldC
plugins={availablePlugins}
onAddPlugin={onAddPlugin}
/>
<Button
onClick={handleUpdateFieldsOrder}
variant={'outline'}
size={'sm'}
>
{isRefetchingMetadata && <LoaderCircle className={'h-5 w-5 mr-2 animate-spin'} />}
{i18n.t('Update fields order')}
</Button>
<Button
onClick={validateAndSave}
size={'sm'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,12 +171,43 @@ export const useFormFieldController = ({ metadata, availablePlugins, existingFor
})
}

const updateFieldsOrder = (newMetadata: z.infer<typeof ConvertedMetadataSchema>) => {
setFormFields(prev => {
const pluginsBySection: Record<string, Array<z.infer<typeof PluginSchema>>> = {};
prev.forEach(section => {
const plugins = section.fields.filter((field): field is z.infer<typeof PluginSchema> => field.type === 'PLUGIN');
if (plugins.length > 0) {
pluginsBySection[section.id] = plugins;
}
});

const freshSections: Array<z.infer<typeof SectionSchema>> = newMetadata.sections.map(section => ({
id: section.id,
displayName: section.displayName,
fields: section.fields.map(field => ({
id: field.id,
displayName: field.displayName,
valueType: field.valueType,
type: 'TrackedEntityAttribute' as const,
})),
}));

Object.entries(pluginsBySection).forEach(([sectionId, plugins]) => {
const targetSection = freshSections.find(section => section.id === sectionId) ?? freshSections[freshSections.length - 1];
targetSection?.fields.push(...plugins);
});

return freshSections;
})
}

return {
formFields,
onAddPlugin,
onRemovePlugin,
onDragEnd,
setFormFields,
existingPluginConfigs
existingPluginConfigs,
updateFieldsOrder,
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ interface Props {
}

export const FormFieldConfigurator: React.FC<Props> = ({ formFieldId, metadataType }) => {
const { metadata, isLoading, isError } = useMetadataFromType({
const { metadata, isLoading, isError, isRefetchingMetadata, refetchMetadata } = useMetadataFromType({
resourceId: formFieldId,
metadataType,
});
Expand Down Expand Up @@ -49,6 +49,8 @@ export const FormFieldConfigurator: React.FC<Props> = ({ formFieldId, metadataTy
formFieldId={formFieldId}
apps={apps}
existingFormFieldConfig={existingFormFieldConfig}
refetchMetadata={refetchMetadata}
isRefetchingMetadata={isRefetchingMetadata}
/>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const useMetadataFromType = ({ resourceId, metadataType }: Props) => {
const dataEngine = useDataEngine();
const fetchFunction = FetchFunctionsByType[metadataType];

const { data, isLoading, isError, error } = useQuery({
const { data, isLoading, isError, isRefetching, error, refetch } = useQuery({
queryKey: [metadataType, resourceId],
queryFn: () => fetchFunction({ resourceId, dataEngine }),
staleTime: Infinity,
Expand All @@ -30,5 +30,7 @@ export const useMetadataFromType = ({ resourceId, metadataType }: Props) => {
metadata: data,
isLoading,
isError,
isRefetchingMetadata: isRefetching,
refetchMetadata: refetch,
}
}