optimize whole environment

This commit is contained in:
2025-06-02 18:13:18 +09:00
parent 4fbf2a4e81
commit 3f85eb8338
15 changed files with 578 additions and 483 deletions

23
.cspell.json Normal file
View File

@ -0,0 +1,23 @@
{
"version": "0.2",
"language": "en,en-gb",
"ignoreWords": [],
"words": [
"blankspace",
"docxtemplater",
"Heiti",
"Kaku",
"kintone",
"kintoneplugin",
"kypes",
"Ligh",
"moize",
"officedocument",
"openxmlformats",
"pizzip",
"rspack",
"SUBTABLE",
"wordprocessingml"
],
"ignorePaths": [".env"]
}

View File

@ -1,3 +1,8 @@
{ {
"recommendations": ["esbenp.prettier-vscode"] "recommendations": [
"esbenp.prettier-vscode",
"streetsidesoftware.code-spell-checker",
"dbaeumer.vscode-eslint",
"jawandarajbir.react-vscode-extension-pack"
]
} }

View File

@ -27,6 +27,8 @@
"[jsonc]": { "[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "esbenp.prettier-vscode"
}, },
// Exteions - cSpell
// - see: .cspell.json
// Extensions - HTML // Extensions - HTML
"html.format.wrapLineLength": 0, "html.format.wrapLineLength": 0,
// Extentions - Prettier // Extentions - Prettier

View File

@ -1,4 +1,17 @@
import presetsPrettier from "@cybozu/eslint-config/flat/presets/react-typescript-prettier.js"; import presetsPrettier from '@cybozu/eslint-config/flat/presets/react-typescript-prettier.js';
import globals from 'globals';
/** @type {import("eslint").Linter.Config[]} */ /** @type {import("eslint").Linter.Config[]} */
export default [...presetsPrettier]; export default [
...presetsPrettier,
{
languageOptions: {
globals: {
...globals.node,
},
},
rules: {
'spaced-comment': ['error', 'always', { markers: ['/'] }],
},
},
];

901
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -12,7 +12,7 @@
"upload": "env-cmd --silent kintone-plugin-uploader dist/plugin.zip --watch --waiting-dialog-ms 3000" "upload": "env-cmd --silent kintone-plugin-uploader dist/plugin.zip --watch --waiting-dialog-ms 3000"
}, },
"dependencies": { "dependencies": {
"@kintone/rest-api-client": "^5.7.3", "@kintone/rest-api-client": "^5.7.4",
"angular-expressions": "^1.4.3", "angular-expressions": "^1.4.3",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"dayjs": "^1.11.13", "dayjs": "^1.11.13",
@ -42,6 +42,7 @@
"env-cmd": "^10.1.0", "env-cmd": "^10.1.0",
"eslint": "^9.28.0", "eslint": "^9.28.0",
"eslint-plugin-react": "^7.37.5", "eslint-plugin-react": "^7.37.5",
"globals": "^16.2.0",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"prettier": "^3.5.3", "prettier": "^3.5.3",
"style-loader": "^4.0.0", "style-loader": "^4.0.0",

View File

@ -20,7 +20,7 @@
"ja": "Word出力プラグイン" "ja": "Word出力プラグイン"
}, },
"description": { "description": {
"en": "Data can be formatted and downloaded using WORD template files.", "en": "Data can be formatted and downloaded using Word template files.",
"ja": "WORDテンプレートファイルを使用して、データを整形してダウンロードできます。" "ja": "Wordテンプレートファイルを使用して、データを整形してダウンロードできます。"
} }
} }

View File

@ -4,12 +4,15 @@
const fs = require('fs'); const fs = require('fs');
const RSA = require('node-rsa'); const RSA = require('node-rsa');
const key = new RSA({ b: 1024 });
const privateKey = key.exportKey('pkcs1-private');
const privateKeyFile = './private.ppk'; const privateKeyFile = './private.ppk';
if (!fs.existsSync(privateKeyFile)) { if (!fs.existsSync(privateKeyFile)) {
const key = new RSA({ b: 1024 });
const privateKey = key.exportKey('pkcs1-private');
fs.writeFile(privateKeyFile, privateKey, (err) => { fs.writeFile(privateKeyFile, privateKey, (err) => {
err && console.error(err); if (err) {
console.error(err);
process.exitCode = 1;
}
}); });
} }

View File

@ -11,5 +11,4 @@ invariant(
`Unsupported language: ${LANGUAGE}. Supported languages are: ${KintoneUserLanguages.join(', ')}`, `Unsupported language: ${LANGUAGE}. Supported languages are: ${KintoneUserLanguages.join(', ')}`,
); );
export const DOCX_CONTENTTYPE = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'; export const DOCX_CONTENT_TYPE = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
export const DOCX_EXTENSION = 'docx';

View File

@ -65,7 +65,7 @@ const Settings: React.FC = () => {
<KintonePluginTitle> <KintonePluginTitle>
Template<KintonePluginRequire>*</KintonePluginRequire> Template<KintonePluginRequire>*</KintonePluginRequire>
</KintonePluginTitle> </KintonePluginTitle>
<KintonePluginDesc>Select a file field that contains the WORD template file.</KintonePluginDesc> <KintonePluginDesc>Select a file field that contains the Word template file.</KintonePluginDesc>
{fileFields.length === 0 ? ( {fileFields.length === 0 ? (
<KintonePluginAlert> <KintonePluginAlert>
No file fields found in the app. Please add a file field to use this plugin. No file fields found in the app. Please add a file field to use this plugin.

45
src/declaration.d.ts vendored
View File

@ -1,45 +0,0 @@
// CSS modules
type CSSModuleClasses = { readonly [key: string]: string };
declare module '*.module.css' {
const classes: CSSModuleClasses;
export default classes;
}
declare module '*.module.scss' {
const classes: CSSModuleClasses;
export default classes;
}
declare module '*.module.sass' {
const classes: CSSModuleClasses;
export default classes;
}
declare module '*.module.less' {
const classes: CSSModuleClasses;
export default classes;
}
declare module '*.module.styl' {
const classes: CSSModuleClasses;
export default classes;
}
declare module '*.module.stylus' {
const classes: CSSModuleClasses;
export default classes;
}
declare module '*.module.pcss' {
const classes: CSSModuleClasses;
export default classes;
}
declare module '*.module.sss' {
const classes: CSSModuleClasses;
export default classes;
}
// CSS
declare module '*.css' {}
declare module '*.scss' {}
declare module '*.sass' {}
declare module '*.less' {}
declare module '*.styl' {}
declare module '*.stylus' {}
declare module '*.pcss' {}
declare module '*.sss' {}

View File

@ -5,8 +5,6 @@ import ErrorFallback from '../common/ErrorFallback';
import Loading from '../common/Loading'; import Loading from '../common/Loading';
import MenuPanel from './MenuPanel'; import MenuPanel from './MenuPanel';
import '@shin-chan/kypes';
interface DesktopAppProps { interface DesktopAppProps {
event: kintone.events.AppRecordDetailShowEvent | kintone.events.MobileAppRecordDetailShowEvent; event: kintone.events.AppRecordDetailShowEvent | kintone.events.MobileAppRecordDetailShowEvent;
} }

View File

@ -10,12 +10,10 @@ import { saveAs } from 'file-saver';
import moize from 'moize'; import moize from 'moize';
import PizZip from 'pizzip'; import PizZip from 'pizzip';
import invariant from 'tiny-invariant'; import invariant from 'tiny-invariant';
import { DOCX_CONTENTTYPE, LANGUAGE, PLUGIN_ID } from '../common/global'; import { DOCX_CONTENT_TYPE, LANGUAGE, PLUGIN_ID } from '../common/global';
import KintonePluginAlert from '../common/ui/KintonePluginAlert'; import KintonePluginAlert from '../common/ui/KintonePluginAlert';
import KintonePluginButton from '../common/ui/KintonePluginButton'; import KintonePluginButton from '../common/ui/KintonePluginButton';
import '@shin-chan/kypes';
interface TemplateData { interface TemplateData {
[key: string]: TemplateData | TemplateData[] | string | string[]; [key: string]: TemplateData | TemplateData[] | string | string[];
} }
@ -191,32 +189,32 @@ const MenuPanel: React.FC<MenuPanelProps> = (props) => {
if (template === '') { if (template === '') {
return ( return (
<KintonePluginAlert> <KintonePluginAlert>
WORD output plugin: Template field is not set. Please configure the plugin. Word output plugin: Template field is not set. Please configure the plugin.
</KintonePluginAlert> </KintonePluginAlert>
); );
} }
const record = event.record[template]; const record = event.record[template];
if (record == null) { if (record == null) {
return <KintonePluginAlert>WORD output plugin: Template field is not available in this app.</KintonePluginAlert>; return <KintonePluginAlert>Word output plugin: Template field is not available in this app.</KintonePluginAlert>;
} }
if (record.type !== 'FILE') { if (record.type !== 'FILE') {
return <KintonePluginAlert>WORD output plugin: Template field must be a file field.</KintonePluginAlert>; return <KintonePluginAlert>Word output plugin: Template field must be a file field.</KintonePluginAlert>;
} }
if (record.value.length === 0) { if (record.value.length === 0) {
return <KintonePluginAlert>WORD output plugin: Template field does not contain any files.</KintonePluginAlert>; return <KintonePluginAlert>Word output plugin: Template field does not contain any files.</KintonePluginAlert>;
} }
if (record.value.length > 1) { if (record.value.length > 1) {
return ( return (
<KintonePluginAlert> <KintonePluginAlert>
WORD output plugin: Template field contains multiple files. Please ensure it contains only one file. Word output plugin: Template field contains multiple files. Please ensure it contains only one file.
</KintonePluginAlert> </KintonePluginAlert>
); );
} }
const { fileKey, contentType } = record.value[0]; const { fileKey, contentType } = record.value[0];
if (contentType !== DOCX_CONTENTTYPE) { if (contentType !== DOCX_CONTENT_TYPE) {
return ( return (
<KintonePluginAlert> <KintonePluginAlert>
WORD output plugin: The template file must be a DOCX file. The current file type is {contentType}. Word output plugin: The template file must be a DOCX file. The current file type is {contentType}.
</KintonePluginAlert> </KintonePluginAlert>
); );
} }
@ -233,18 +231,18 @@ const MenuPanel: React.FC<MenuPanelProps> = (props) => {
parser: expressionParser, parser: expressionParser,
}); });
doc.render(record2data(properties, event.record)); doc.render(record2data(properties, event.record));
const out = doc.getZip().generate({ type: 'blob', mimeType: DOCX_CONTENTTYPE }); const out = doc.getZip().generate({ type: 'blob', mimeType: DOCX_CONTENT_TYPE });
saveAs(out, 'output.docx'); saveAs(out, 'output.docx');
}) })
.catch((error) => { .catch((error) => {
console.error('Error downloading file:', error); console.error('Error downloading file:', error);
alert('Failed to download the WORD template file.'); alert('Failed to download the Word template file.');
}); });
}; };
return ( return (
<KintonePluginButton variant="normal" onClick={handleOnClickOutputButton}> <KintonePluginButton variant="normal" onClick={handleOnClickOutputButton}>
WORD出力 Word出力
</KintonePluginButton> </KintonePluginButton>
); );
}; };

View File

@ -4,8 +4,6 @@ import ReactDOM from 'react-dom/client';
import invariant from 'tiny-invariant'; import invariant from 'tiny-invariant';
import DesktopApp from './DesktopApp'; import DesktopApp from './DesktopApp';
import '@shin-chan/kypes';
import '../common/ui/51-modern-default.css'; import '../common/ui/51-modern-default.css';
kintone.events.on( kintone.events.on(

17
src/kintone-env.d.ts vendored Normal file
View File

@ -0,0 +1,17 @@
/// <reference types="@shin-chan/kypes" />
// CSS modules
type CSSModuleClasses = { readonly [key: string]: string };
declare module '*.module.css' {
const classes: CSSModuleClasses;
export default classes;
}
declare module '*.module.scss' {
const classes: CSSModuleClasses;
export default classes;
}
// CSS
declare module '*.css' {}
declare module '*.scss' {}