import React from 'react'; import { produce } from 'immer'; import moize from 'moize'; import { useTranslation } from 'react-i18next'; import invariant from 'tiny-invariant'; import { loadPluginConfigLookup, PluginConfigLookup, PluginConfigLookupItem, savePluginConfigLookup, } from '../common/config'; import { filterConfigByPluginContext, getPluginContext, PluginContext } from '../common/context'; import KintonePluginAlert from '../common/ui/KintonePluginAlert'; import KintonePluginButton from '../common/ui/KintonePluginButton'; import KintonePluginDesc from '../common/ui/KintonePluginDesc'; import KintonePluginLabel from '../common/ui/KintonePluginLabel'; import KintonePluginRequire from '../common/ui/KintonePluginRequire'; import KintonePluginRow from '../common/ui/KintonePluginRow'; import KintonePluginSelect, { KintonePluginSelectOptionData } from '../common/ui/KintonePluginSelect'; import KintonePluginTable from '../common/ui/KintonePluginTable'; import KintonePluginTableTd from '../common/ui/KintonePluginTableTd'; import KintonePluginTableTh from '../common/ui/KintonePluginTableTh'; import KintonePluginTitle from '../common/ui/KintonePluginTitle'; import styles from './Settings.module.css'; const hasDuplicate = (items: T[], func: (a: T, b: T) => boolean = (a, b) => a === b): boolean => { return items.find((item, idx) => items.some((item2, idx2) => func(item, item2) && idx !== idx2)) != null; }; const hasDuplicateDestAttachmentFields = (rows: PluginConfigLookup): boolean => { return hasDuplicate(rows, (a, b) => a.destAttachmentFieldCode === b.destAttachmentFieldCode); }; interface FieldSelectTableRowProps { context: PluginContext; row: PluginConfigLookupItem; onUpdate: (item: PluginConfigLookupItem) => void; onClickAddRow: () => void; onClickRemoveRow: () => void; } const FieldSelectTableRow: React.FC = (props) => { const { context, row, onUpdate, onClickAddRow, onClickRemoveRow } = props; const defaultOption: KintonePluginSelectOptionData = React.useMemo(() => { return { value: '', label: '--', disabled: true }; }, []); const lookupOptions: KintonePluginSelectOptionData[] = React.useMemo(() => { return [ defaultOption, ...context.lookupFields.map((property) => ({ value: property.code, label: `${property.label} (${property.code})`, })), ]; }, [context.lookupFields, defaultOption]); const srcAppId = context.lookupFields.find((field) => field.code === row.lookupFieldCode)?.lookup.relatedApp.app; const srcFileOptions: KintonePluginSelectOptionData[] = React.useMemo(() => { return [ defaultOption, ...(srcAppId != null ? context.attachmentFields[srcAppId].map((property) => ({ value: property.code, label: `${property.label} (${property.code})`, })) : []), ]; }, [srcAppId, context.attachmentFields, defaultOption]); const destFileOptions: KintonePluginSelectOptionData[] = React.useMemo(() => { return [ defaultOption, ...(srcAppId != null ? context.attachmentFields[context.appId].map((property) => ({ value: property.code, label: `${property.label} (${property.code})`, })) : []), ]; }, [context.appId, context.attachmentFields, defaultOption, srcAppId]); const handleOnChangeLookup = (code: string) => { const draft = { lookupFieldCode: code, srcAttachmentFieldCode: '', destAttachmentFieldCode: '', }; onUpdate(draft); }; const handleOnChangeSrcFile = (code: string) => { const draft = { lookupFieldCode: row.lookupFieldCode, srcAttachmentFieldCode: code, destAttachmentFieldCode: '', }; onUpdate(draft); }; const handleOnChangeDestFile = (code: string) => { const draft = { lookupFieldCode: row.lookupFieldCode, srcAttachmentFieldCode: row.srcAttachmentFieldCode, destAttachmentFieldCode: code, }; onUpdate(draft); }; const handleOnClickAddRow: React.MouseEventHandler = (e) => { e.preventDefault(); onClickAddRow(); }; const handleOnClickRemoveRow: React.MouseEventHandler = (e) => { e.preventDefault(); onClickRemoveRow(); }; return ( ); }; const cachedPluginContext = moize.promise(getPluginContext); interface SettingsProps { pluginId: string; } const Settings: React.FC = (props) => { const { pluginId } = props; const { t } = useTranslation(); const appId = kintone.app.getId(); invariant(appId, 'The app ID is not available. Please ensure you are on a Kintone app page.'); const context = React.use(cachedPluginContext(appId, true)); const [mappings, setMappings] = React.useState( () => filterConfigByPluginContext(loadPluginConfigLookup(pluginId), context) ?? [ { lookupFieldCode: '', srcAttachmentFieldCode: '', destAttachmentFieldCode: '' }, ], ); const [error, setError] = React.useState(''); const handleOnUpdateFieldSelect = (idx: number, item: PluginConfigLookupItem) => { setError(''); setMappings( produce((draft) => { draft[idx] = item; }), ); }; const handleOnAddFieldSelect = (idx: number) => { setError(''); if (mappings.length < context.attachmentFields[context.appId].length) { setMappings( produce((draft) => { draft.splice(idx + 1, 0, { lookupFieldCode: '', srcAttachmentFieldCode: '', destAttachmentFieldCode: '', }); }), ); } }; const handleOnRemoveFieldSelect = (idx: number) => { setError(''); if (mappings.length === 1) { setMappings( produce((draft) => { draft[idx] = { lookupFieldCode: '', srcAttachmentFieldCode: '', destAttachmentFieldCode: '', }; }), ); } else if (mappings.length > 1) { setMappings( produce((draft) => { draft.splice(idx, 1); }), ); } }; const handleOnSubmit = (e: React.FormEvent) => { e.preventDefault(); if (mappings.find((item) => item.destAttachmentFieldCode === '') != null) { setError(t('settings.lookup.errors.incomplete-field-mapping-found')); } else if (hasDuplicateDestAttachmentFields(mappings)) { setError(t('settings.lookup.errors.same-destination-attachment-field-found')); } else { setError(''); savePluginConfigLookup(mappings, () => { alert(t('on-saved')); window.location.href = `../../flow?app=${appId}`; }); } }; const handleOnClickCancel = () => { setError(''); window.location.href = `../../${appId}/plugin/`; }; return (
{t('title')} {error !== '' && ( {error} )}
{t('settings.lookup.title')} * {t('settings.lookup.description')} {context.lookupFields.length === 0 ? ( {t('settings.lookup.errors.no-lookup-field-found')} ) : ( {t('settings.lookup.messages.lookup-field')} {t('settings.lookup.messages.source-attachment-field')} {t('settings.lookup.messages.destination-attachment-field')} {mappings.map((row, idx) => ( { handleOnUpdateFieldSelect(idx, draft); }} onClickAddRow={() => { handleOnAddFieldSelect(idx); }} onClickRemoveRow={() => { handleOnRemoveFieldSelect(idx); }} /> ))} )} {t('buttons.cancel')} {t('buttons.save')}
); }; export default Settings;