remove kintone-pretty-fields library dependency.
This commit is contained in:
@@ -1,12 +1,15 @@
|
||||
import React from 'react';
|
||||
|
||||
import { KintoneRestAPIClient } from '@kintone/rest-api-client';
|
||||
import { Properties as KintoneFormFieldProperties } from '@kintone/rest-api-client/lib/src/client/types';
|
||||
import { KintoneRecord } from '@shin-chan/kypes/types/page';
|
||||
import Docxtemplater from 'docxtemplater';
|
||||
import expressionParser from 'docxtemplater/expressions';
|
||||
import { saveAs } from 'file-saver';
|
||||
import moize from 'moize';
|
||||
import PizZip from 'pizzip';
|
||||
import { PLUGIN_ID } from '../common/global';
|
||||
import invariant from 'tiny-invariant';
|
||||
import { LANGUAGE, PLUGIN_ID } from '../common/global';
|
||||
import KintonePluginAlert from '../common/ui/KintonePluginAlert';
|
||||
import KintonePluginButton from '../common/ui/KintonePluginButton';
|
||||
|
||||
@@ -22,15 +25,23 @@ interface MenuPanelProps {
|
||||
event: kintone.events.AppRecordDetailShowEvent | kintone.events.MobileAppRecordDetailShowEvent;
|
||||
}
|
||||
|
||||
const record2data = (record: Partial<KintoneRecord>): TemplateData => {
|
||||
const cachedFormFieldsProperties = moize.promise(async (appId: number): Promise<KintoneFormFieldProperties> => {
|
||||
const client = new KintoneRestAPIClient();
|
||||
const { properties } = await client.app.getFormFields({ app: appId, lang: 'en', preview: false });
|
||||
return properties;
|
||||
});
|
||||
|
||||
const record2data = (properties: KintoneFormFieldProperties, record: Partial<KintoneRecord>): TemplateData => {
|
||||
const data: TemplateData = {};
|
||||
for (const key in record) {
|
||||
if (Object.prototype.hasOwnProperty.call(record, key)) {
|
||||
const field = record[key];
|
||||
if (field == null) continue;
|
||||
const { type, value } = field;
|
||||
if (value == null) continue;
|
||||
if (type === 'CREATOR' || type === 'MODIFIER') {
|
||||
if (Object.prototype.hasOwnProperty.call(record, key) && Object.prototype.hasOwnProperty.call(properties, key)) {
|
||||
const item = record[key];
|
||||
const property = properties[key];
|
||||
if (item == null) continue;
|
||||
const { type, value } = item;
|
||||
if (value == null) {
|
||||
data[key] = '';
|
||||
} else if (type === 'CREATOR' || type === 'MODIFIER') {
|
||||
data[key] = {
|
||||
name: value.name,
|
||||
code: value.code,
|
||||
@@ -47,7 +58,45 @@ const record2data = (record: Partial<KintoneRecord>): TemplateData => {
|
||||
return { name: v.name, code: v.code };
|
||||
});
|
||||
} else if (type === 'SUBTABLE') {
|
||||
data[key] = value.map((subRecord) => record2data(subRecord.value));
|
||||
invariant(property.type === 'SUBTABLE', `Expected property type to be SUBTABLE, but got ${property.type}`);
|
||||
data[key] = value.map((subRecord) => record2data(property.fields, subRecord.value));
|
||||
} else if (type === 'CALC') {
|
||||
invariant(property.type === 'CALC', `Expected property type to be CALC, but got ${property.type}`);
|
||||
if (value === '') {
|
||||
data[key] = '';
|
||||
} else if (property.format === 'NUMBER_DIGIT') {
|
||||
// "1234567" -> "1,234,567"
|
||||
data[key] = Number(value).toLocaleString('en-US');
|
||||
} else if (property.format === 'HOUR_MINUTE') {
|
||||
// "49:30" -> en:"49 hours 30 minutes", ja: "49時間30分"
|
||||
const [hours, minutes] = value.split(':').map((v) => Number(v));
|
||||
invariant(
|
||||
!isNaN(hours) && !isNaN(minutes),
|
||||
`Expected hours and minutes to be numbers, but got hours: ${hours}, minutes: ${minutes}`,
|
||||
);
|
||||
if (LANGUAGE === 'ja') {
|
||||
data[key] = `${hours}時間${minutes}分`;
|
||||
} else {
|
||||
data[key] = `${hours} hours ${minutes} minutes`;
|
||||
}
|
||||
} else if (property.format === 'DAY_HOUR_MINUTE') {
|
||||
// "49:30" -> en: "2 days 1 hour 30 minutes", ja: "2日1時間30分
|
||||
const [hours, minutes] = value.split(':').map((v) => Number(v));
|
||||
invariant(
|
||||
!isNaN(hours) && !isNaN(minutes),
|
||||
`Expected hours and minutes to be numbers, but got hours: ${hours}, minutes: ${minutes}`,
|
||||
);
|
||||
const days = Math.floor(Number(hours) / 24);
|
||||
const remainingHours = Number(hours) % 24;
|
||||
if (LANGUAGE === 'ja') {
|
||||
data[key] = `${days}日${remainingHours}時間${minutes}分`;
|
||||
} else {
|
||||
data[key] = `${days} days ${remainingHours} hours ${minutes} minutes`;
|
||||
}
|
||||
} else {
|
||||
// NUMBER, DATETIME, DATE, TIME
|
||||
data[key] = value;
|
||||
}
|
||||
} else {
|
||||
data[key] = value;
|
||||
}
|
||||
@@ -58,6 +107,8 @@ const record2data = (record: Partial<KintoneRecord>): TemplateData => {
|
||||
|
||||
const MenuPanel: React.FC<MenuPanelProps> = (props) => {
|
||||
const { event } = props;
|
||||
const appId = event.appId;
|
||||
const properties = React.use(cachedFormFieldsProperties(appId));
|
||||
const config = kintone.plugin.app.getConfig(PLUGIN_ID);
|
||||
const template: string = config.template ?? '';
|
||||
if (template === '') {
|
||||
@@ -94,11 +145,6 @@ const MenuPanel: React.FC<MenuPanelProps> = (props) => {
|
||||
}
|
||||
const handleOnClickOutputButton = (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.preventDefault();
|
||||
const appId = event.type === 'app.record.detail.show' ? kintone.app.getId() : kintone.mobile.app.getId();
|
||||
if (!appId) {
|
||||
alert('The app ID is not available. Please ensure you are on a Kintone app page.');
|
||||
return;
|
||||
}
|
||||
const client = new KintoneRestAPIClient();
|
||||
client.file
|
||||
.downloadFile({ fileKey })
|
||||
@@ -109,7 +155,7 @@ const MenuPanel: React.FC<MenuPanelProps> = (props) => {
|
||||
linebreaks: true,
|
||||
parser: expressionParser,
|
||||
});
|
||||
doc.render(record2data(event.record));
|
||||
doc.render(record2data(properties, event.record));
|
||||
const out = doc.getZip().generate({ type: 'blob', mimeType: DOCX_CONTENTTYPE });
|
||||
saveAs(out, 'output.docx');
|
||||
})
|
||||
|
Reference in New Issue
Block a user