merge to kintone exec

This commit is contained in:
2025-01-26 20:18:17 +09:00
9 changed files with 134 additions and 36 deletions

View File

@@ -6,16 +6,28 @@
:disabled="selectedAppData.loading == undefined ? false : selectedAppData.loading"
/>
<kuc-combobox
v-if="type == 'kuc-combobox'"
v-else-if="type == 'kuc-combobox'"
:value="modelValue"
@change="updateValue"
:disabled="selectedAppData.loading == undefined ? false : selectedAppData.loading"
/>
<kuc-time-picker
v-else-if="type == 'kuc-time'"
:value="modelValue"
@change="updateValue"
:disabled="selectedAppData.loading == undefined ? false : selectedAppData.loading"
/>
<!-- <table-condition-value-date-time
v-else-if="type == 'time'|type == 'date"
:value="modelValue"
@change="updateValue"
:disabled="selectedAppData.loading == undefined ? false : selectedAppData.loading"
/> -->
</template>
<script setup lang="ts">
import { getComponent } from '@/js/conditions';
import { search } from '@/js/helper';
import { getFieldObj, search } from '@/js/helper';
import type { CachedSelectedAppData, WhereCondition } from '@/types/model';
import type { KucEvent } from '@/types/my-kintone';
import type { ComboboxChangeEventDetail, TextInputEventDetail } from 'kintone-ui-component';
@@ -30,7 +42,10 @@ const props = defineProps<{
const whereCondition = computed(() => search(props.whereConditions, props.id) as WhereCondition | undefined);
const type = computed(() => getComponent(whereCondition.value?.condition || ''));
const type = computed(() => {
const field = getFieldObj(whereCondition.value?.field || '', props.selectedAppData.appFields, '');
return getComponent(whereCondition.value?.condition || '', field);
});
type EmitData = {
obj?: WhereCondition;

View File

@@ -1,6 +1,6 @@
export default {
config: {
title: 'Settings for data fetch plugin',
desc: 'This message is displayed on the app page after the app has been updated.',
title: 'Data Fetch Plugin Settings',
desc: 'Set the aggregation button name, data source app, fetch fields, filter conditions, and linking conditions, then save.',
},
};

View File

@@ -1,6 +1,6 @@
export default {
config: {
title: 'Settings for data fetch plugin',
desc: 'This message is displayed on the app page after the app has been updated.',
title: 'データ取得プラグインの設定',
desc: '集約ボタン名とデータ取得元アプリ、取得フィールド、絞込条件や連結条件を設定後、保存してください。',
},
};

View File

@@ -1,5 +1,5 @@
import type { FieldLayout, FieldsJoinMapping, JoinTable, Record, RecordForParameter, SavedData, WhereCondition } from "@/types/model";
import type { isType, OneOf } from "./kintone-rest-api-client";
import { type OneOf ,isType} from "./field-types";
declare var KintoneRestAPIClient: typeof import("@kintone/rest-api-client").KintoneRestAPIClient;
export class KintoneIndexEventHandler {
private config: SavedData<FieldLayout>;

View File

@@ -23,22 +23,16 @@ type ConditionItem = {
};
export const conditionList: ConditionItem[] = [
{ value: '=', label: '=(等しい)', type: 'input' },
{ value: '!=', label: '≠ (等しくない)', type: 'input' },
{ value: '<=', label: (field) => isDateTimeType(field) ? '≦ (以前)' : '≦ (以下)', type: 'input' },
{ value: '<', label: '< (より前)', type: 'input' },
{ value: '>', label: '> (より後)', type: 'input' },
{ value: '>=', label: (field) => isDateTimeType(field) ? '≧ (以降)' : '≧ (以上)', type: 'input' },
{ value: 'like', label: '次のキーワードを含む', type: 'input' },
{ value: 'not like', label:'次のキーワードを含まない', type: 'input' },
{ value: 'in', label: '次のいずれかを含む', type: 'input' },
{ value: 'not in', label: '次のいずれも含まない', type: 'input' },
{ value: 'eq', label: '=(等しい)', type: 'input' },
{ value: 'ne', label: '≠ (等しくない)', type: 'input' },
{ value: 'le', label: (field) => isDateTimeType(field) ? '≦ (以前)' : '≦ (以下)', type: 'input' },
{ value: 'lt', label: '< (より前)', type: 'input' },
{ value: 'gt', label: '> (より後)', type: 'input' },
{ value: 'ge', label: (field) => isDateTimeType(field) ? '≧ (以降)' : '≧ (以上)', type: 'input' },
{ value: 'contains', label: '次のいずれかを含む', type: 'input' },
{ value: 'not_contain', label: '次のいずれも含まない', type: 'input' },
];
export const isDateTimeType = (field: OneOf) => {
return isType.DATETIME(field) || isType.TIME(field) || isType.DATE(field) || isType.CREATED_TIME(field) || isType.UPDATED_TIME(field);
}
// search from conditionList
// conditionItem = conditionMap[conditionValue]
export const conditionMap: Record<ConditionValue, ConditionItem> = conditionList.reduce(
@@ -50,7 +44,6 @@ export const conditionMap: Record<ConditionValue, ConditionItem> = conditionList
);
type FieldConditions = Partial<Record<FieldType, ConditionValue[]>>;
const textCondition: ConditionValue[] = ['=', '!=', 'in', 'like','not like'];
const numberCondition: ConditionValue[] = ['=', '!=', '<=', '>='];
const timeCondition: ConditionValue[] = ['=', '!=', '<=', '>=', '<', '>'];
@@ -98,11 +91,15 @@ export const getAvailableCondition = (fieldCode: string, fieldsInfo: FieldsInfo,
const component = {
input: 'kuc-text',
select: 'kuc-combobox',
time: 'time',
time: 'kuc-time',
date: 'date',
datetime: 'datetime',
};
export const isDateTimeType = (field: OneOf) => {
return field.type in dateTimeComponent;
}
const dateTimeComponent: Partial<Record<FieldType, ComponentType>> = {
TIME: 'time',
DATE: 'date',
@@ -112,7 +109,8 @@ const dateTimeComponent: Partial<Record<FieldType, ComponentType>> = {
}
export type ComponentType = keyof typeof component;
export const getComponent = (value: ConditionValue) => {
export const getComponent = (value: ConditionValue, fieldObj: OneOf) => {
if (!value) return;
return component[conditionMap[value].type];
const condition = conditionMap[value].type;
return component[typeof condition === 'function' ? condition(fieldObj) : condition];
};

View File

@@ -0,0 +1,55 @@
declare var KintoneRestAPIClient: typeof import("@kintone/rest-api-client").KintoneRestAPIClient;
const client = new KintoneRestAPIClient();
export type Properties = Awaited<ReturnType<typeof client.app.getFormFields>>['properties'];
export type Layout = Awaited<ReturnType<typeof client.app.getFormLayout>>['layout'];
export type OneOf = Properties[string];
export type FieldType = OneOf['type'];
const typeNames = [
'RECORD_NUMBER',
'CREATOR',
'CREATED_TIME',
'MODIFIER',
'UPDATED_TIME',
'CATEGORY',
'STATUS',
'STATUS_ASSIGNEE',
'SINGLE_LINE_TEXT',
'NUMBER',
'CALC',
'MULTI_LINE_TEXT',
'RICH_TEXT',
'LINK',
'CHECK_BOX',
'RADIO_BUTTON',
'DROP_DOWN',
'MULTI_SELECT',
'FILE',
'DATE',
'TIME',
'DATETIME',
'USER_SELECT',
'ORGANIZATION_SELECT',
'GROUP_SELECT',
'GROUP',
'REFERENCE_TABLE',
'SUBTABLE',
] as const satisfies readonly FieldType[];
export const types = typeNames.reduce(
(acc, name) => {
acc[name] = name;
return acc;
},
{} as Record<(typeof typeNames)[number], (typeof typeNames)[number]>,
);
type ExtractOneOf<T extends FieldType> = Extract<OneOf, { type: T }>;
function createTypeGuard<T extends FieldType>(type: T) {
return (value: OneOf): value is ExtractOneOf<T> => value?.type === type;
}
export const isType = Object.fromEntries(
typeNames.map((typeName) => [typeName, createTypeGuard(typeName as FieldType)]),
) as { [K in (typeof typeNames)[number]]: (value: OneOf) => value is ExtractOneOf<K> };

View File

@@ -63,12 +63,27 @@ export const loadApps = async (offset = 0, _apps: DropdownItem[] = []): Promise<
};
export const loadAppFieldsAndLayout = async (appId: string | number = kintone.app.getId() as number) => {
const fields = (await client.app.getFormFields({ app: appId })).properties;
return {
fields: (await client.app.getFormFields({ app: appId })).properties,
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;
copy.label = '[' + field.code + '].' + subField.label;
subtableFields[subField.code] = copy;
})
}
});
return { ...fields, ...subtableFields };
}
type FilterType = Array<FieldType | SpecialType>;
type Param = {
subTableCode: string | undefined;
@@ -77,10 +92,19 @@ type Param = {
dependFilterField?: OneOf;
defaultLabel?: string;
defaultDisableCallback?: (field: OneOf) => boolean;
needSubTableField?: boolean;
};
export const getFieldsDropdownItems = (
{ fields, layout }: FieldsInfo,
{ subTableCode, filterType, baseFilter, dependFilterField, defaultLabel, defaultDisableCallback }: Param,
{
subTableCode,
filterType,
baseFilter,
dependFilterField,
defaultLabel,
defaultDisableCallback,
needSubTableField = true,
}: Param,
) => {
// get used field codes
let fieldOrder: string[];
@@ -96,7 +120,7 @@ export const getFieldsDropdownItems = (
const subTableFieldMap = fieldMap[subTableCode] as { fields: Record<string, any> } | undefined;
fieldMap = subTableFieldMap?.fields || {};
} else {
fieldOrder = extractNoSubTableFields(layout, baseFilter);
fieldOrder = extractNoSubTableFields(layout, baseFilter, !!needSubTableField);
}
// create labels
@@ -145,19 +169,18 @@ export const getTableFieldsDropdownItems = ({ fields }: FieldsInfo, filterType?:
);
};
const extractNoSubTableFields = (layout: Layout, baseFilter: FieldType[] | undefined) => {
const extractNoSubTableFields = (layout: Layout, baseFilter: FieldType[] | undefined, needSubTableField: boolean) => {
return layout.reduce((acc, each) => {
if (each.type === 'SUBTABLE') {
return acc;
} else if (each.type === 'ROW') {
if (each.type === 'GROUP') {
acc.push(...extractNoSubTableFields(each.layout, baseFilter, needSubTableField));
} else if (each.type === 'ROW' || (needSubTableField && each.type === 'SUBTABLE')) {
acc.push(
...each.fields.map((field: any) => {
...each.fields.map((field) => {
if (!('code' in field)) return '';
if (!baseFilter) return field.code;
return baseFilter.find((t) => t === field.type) ? field?.code || '' : '';
}),
);
} else if (each.type === 'GROUP') {
acc.push(...extractNoSubTableFields(each.layout, baseFilter));
}
return acc;
}, [] as string[]);

View File

@@ -2,6 +2,8 @@ import type { ConditionValue } from '@/js/conditions';
import type { Layout, Properties } from '@/js/kintone-rest-api-client';
import type { DropdownItem } from 'kintone-ui-component';
export interface FieldsJoinMapping<FieldType = string> {
id: string;
leftField: FieldType;
@@ -59,4 +61,9 @@ export type RecordForParameter = {
export type Field={
type:string;
value:any;
}
export type FieldLayout={
type:string;
code:string;
}