Files
kintone-data-aggregator-plugin/src/js/helper.ts

212 lines
7.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import type { FieldsInfo, FieldsJoinMapping, JoinTable, WhereCondition } from '@/types/model';
import {
client,
isType,
type FieldType,
type App,
type Layout,
type OneOf,
type Properties,
} from './kintone-rest-api-client';
import type { ComboboxItem, DropdownItem } from 'kintone-ui-component';
import { isSpecialType, type SpecialType } from './join';
export const EMPTY_OPTION = {
value: '',
label: '--------',
} as DropdownItem;
export function generateId(): string {
const timestamp = new Date().getTime().toString(36);
const randomNum = Math.random().toString(36).substring(2, 11);
return `${timestamp}-${randomNum}`;
}
export function search(list: Array<WhereCondition | FieldsJoinMapping>, id: string) {
if (!list) return;
return list.find((item) => item.id === id);
}
export const getEmptyWhereCondition = () =>
({ field: '', condition: '', data: '', id: generateId() }) as WhereCondition;
export const getEmptyOnCondition = () => ({ leftField: '', rightField: '', id: generateId() }) as FieldsJoinMapping;
export const getEmptyFieldsMapping = () => ({ leftField: '', rightField: '', id: generateId() }) as FieldsJoinMapping;
export function createEmptyJoinTable(id = generateId()) {
return resetTable({ id, app: '' } as JoinTable);
}
export function resetTable(table: JoinTable) {
table.table = '';
return resetConditions(table);
}
export function resetConditions(table: JoinTable) {
table.onConditions = [getEmptyOnCondition()];
table.fieldsMapping = [getEmptyFieldsMapping()];
table.whereConditions = [getEmptyWhereCondition()];
return table;
}
const LIMIT = 100; // 毎回請求の最大値
export const loadApps = async (offset = 0, _apps: DropdownItem[] = []): Promise<DropdownItem[]> => {
const { apps } = await client.app.getApps({ limit: LIMIT, offset });
const allApps: DropdownItem[] = [
..._apps,
...apps.map((app: App) => ({ value: app.appId, label: app.name + 'ID: ' + app.appId + '' })),
];
if (apps.length === LIMIT) {
return loadApps(offset + LIMIT, allApps);
}
allApps.sort((a, b) => Number(b.value) - Number(a.value));
allApps.unshift(EMPTY_OPTION);
return allApps;
};
export const loadAppFieldsAndLayout = async (appId: string | number = kintone.app.getId() as number) => {
const fields = (await client.app.getFormFields({ app: appId })).properties;
return {
fields: flatFields(fields),
layout: (await client.app.getFormLayout({ app: appId })).layout,
} as FieldsInfo;
};
function flatFields(fields: Properties) {
const subtableFields = {} as Properties;
Object.values(fields).forEach((field) => {
if (isType.SUBTABLE(field)) {
Object.values(field.fields).forEach((subField) => {
const copy = JSON.parse(JSON.stringify(subField)) as typeof subField & {originLabel:string, tableCode:string};
copy.label = '[' + field.label + '].' + subField.label;
copy.originLabel = subField.label;
copy.tableCode = field.code;
subtableFields[subField.code] = copy;
});
}
});
return { ...fields, ...subtableFields };
}
type FilterType = Array<FieldType | SpecialType>;
type Param = {
subTableCode: string | undefined;
filterType?: FilterType;
baseFilter: FieldType[] | undefined;
dependFilterField?: OneOf;
defaultLabel?: string;
defaultDisableCallback?: (field: OneOf) => boolean;
needAllSubTableField?: boolean;
};
export const getFieldsDropdownItems = (
{ fields, layout }: FieldsInfo,
{
subTableCode, // specified subTable
baseFilter, // set not allowed items hidden, undefined means no filter
defaultLabel, // label shown (default '--------')
filterType, // set not allowed items disabled, undefined and [] means no filter
dependFilterField, // used for filterType
defaultDisableCallback, // callback to control disabled items, like filterType
needAllSubTableField = false, // show all subtable fields
}: Param,
) => {
// get used field codes
const fieldOrder = extractFields(layout, baseFilter, !!needAllSubTableField, subTableCode);
const fieldMap = fields;
// create labels
const labels: ComboboxItem[] = [
{
value: EMPTY_OPTION.value,
label: defaultLabel || EMPTY_OPTION.label,
},
];
return fieldOrder.reduce((acc, fieldCode) => {
const field = fieldMap[fieldCode];
if (!fieldCode) return acc;
acc.push({
value: fieldCode,
label: field.label + 'FC: ' + fieldCode + '',
disabled:
(defaultDisableCallback && defaultDisableCallback(field)) ||
(filterType && !checkFilterType(field, dependFilterField, filterType)),
});
return acc;
}, labels);
};
const checkFilterType = (field: OneOf, dependFilterField: OneOf | undefined, filterType: FilterType) => {
if (!filterType.length) return true; // [] means no filter
return !!filterType.find((type) => {
if (isSpecialType(type)) {
return type.check(field, dependFilterField);
}
return isType[type](field);
});
};
export const getTableFieldsDropdownItems = ({ fields }: FieldsInfo, filterType?: FieldType) => {
return Object.keys(fields).reduce(
(acc, fieldCode) => {
const field = fields[fieldCode];
if (filterType && !isType[filterType](field)) return acc;
acc.push({
value: fieldCode,
label: field.label + 'FC: ' + fieldCode + '',
});
return acc;
},
[EMPTY_OPTION],
);
};
const extractFields = (layout: Layout, baseFilter: FieldType[] | undefined, needAllSubTableField: boolean, subTableCode?: string) => {
return layout.reduce((acc, each) => {
if (each.type === 'GROUP') {
acc.push(...extractFields(each.layout, baseFilter, needAllSubTableField, subTableCode));
} else if (each.type === 'ROW' || (!needAllSubTableField && each.code === subTableCode) || (needAllSubTableField && each.type === 'SUBTABLE')) {
acc.push(
...each.fields.map((field) => {
if (!('code' in field)) return '';
if (!baseFilter) return field.code;
return baseFilter.find((t) => t === field.type) ? field?.code || '' : '';
}),
);
}
return acc;
}, [] as string[]);
};
export function getFieldObj(fieldCode: string, { fields }: FieldsInfo, subTableCode?: string) {
const meta = getMeta(fields, subTableCode);
return meta[fieldCode];
}
export function getMeta(fields: Properties, subTableCode?: string, withNoSubTableField = true) {
if (!fields || !subTableCode) {
return fields;
}
let meta = fields;
const table = meta[subTableCode];
if (isType.SUBTABLE(table)) {
const subFields = table.fields;
Object.values(subFields).forEach((field) => {
if (typeof field === 'object' && field !== null) {
(field as Record<string, any>).subField = true;
}
});
if (withNoSubTableField) {
meta = { ...fields, ...subFields };
} else {
meta = subFields;
}
}
return meta;
}
export const isStringArray = (value: any) => {
if (Array.isArray(value) && value.every((x) => typeof x === 'string')) {
return true;
}
return false;
};