diff --git a/package-lock.json b/package-lock.json index 8d577d7..9de3fe5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "dummyi", - "version": "0.1.0", + "version": "0.2.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "dummyi", - "version": "0.1.0", + "version": "0.2.2", "dependencies": { "@douyinfe/semi-next": "^2.51.0", "@douyinfe/semi-ui": "^2.51.0", @@ -19,7 +19,7 @@ "@uiw/codemirror-extensions-langs": "^4.21.9", "@uiw/codemirror-themes": "^4.21.9", "@uiw/react-codemirror": "^4.21.20", - "@vercel/analytics": "^1.0.2", + "@vercel/analytics": "^1.2.2", "autoprefixer": "10.4.16", "emoji-picker-react": "^4.5.3", "eslint": "8.47.0", @@ -49,7 +49,7 @@ "cypress": "^12.17.4", "mini-css-extract-plugin": "^2.7.6", "typescript": "^5.1.6", - "webpack": "^5.88.2" + "webpack": "^5.90.3" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -1512,9 +1512,9 @@ } }, "node_modules/@jridgewell/source-map": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.3.tgz", - "integrity": "sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", "dependencies": { "@jridgewell/gen-mapping": "^0.3.0", "@jridgewell/trace-mapping": "^0.3.9" @@ -1526,19 +1526,14 @@ "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" - }, "node_modules/@lezer/common": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@lezer/common/-/common-1.0.2.tgz", @@ -2008,9 +2003,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", - "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==" + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" }, "node_modules/@types/hoist-non-react-statics": { "version": "3.3.1", @@ -2307,9 +2302,24 @@ } }, "node_modules/@vercel/analytics": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@vercel/analytics/-/analytics-1.0.2.tgz", - "integrity": "sha512-BZFxVrv24VbNNl5xMxqUojQIegEeXMI6rX3rg1uVLYUEXsuKNBSAEQf4BWEcjQDp/8aYJOj6m8V4PUA3x/cxgg==" + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@vercel/analytics/-/analytics-1.2.2.tgz", + "integrity": "sha512-X0rctVWkQV1e5Y300ehVNqpOfSOufo7ieA5PIdna8yX/U7Vjz0GFsGf4qvAhxV02uQ2CVt7GYcrFfddXXK2Y4A==", + "dependencies": { + "server-only": "^0.0.1" + }, + "peerDependencies": { + "next": ">= 13", + "react": "^18 || ^19" + }, + "peerDependenciesMeta": { + "next": { + "optional": true + }, + "react": { + "optional": true + } + } }, "node_modules/@webassemblyjs/ast": { "version": "1.11.5", @@ -8074,13 +8084,18 @@ } }, "node_modules/serialize-javascript": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", - "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dependencies": { "randombytes": "^2.1.0" } }, + "node_modules/server-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/server-only/-/server-only-0.0.1.tgz", + "integrity": "sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==" + }, "node_modules/set-function-name": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", @@ -8529,12 +8544,12 @@ } }, "node_modules/terser": { - "version": "5.17.1", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.17.1.tgz", - "integrity": "sha512-hVl35zClmpisy6oaoKALOpS0rDYLxRFLHhRuDlEGTKey9qHjS1w9GMORjuwIMt70Wan4lwsLYyWDVnWgF+KUEw==", + "version": "5.28.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.28.1.tgz", + "integrity": "sha512-wM+bZp54v/E9eRRGXb5ZFDvinrJIOaTapx3WUokyVGZu5ucVCK55zEgGd5Dl2fSr3jUo5sDiERErUWLY6QPFyA==", "dependencies": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", "commander": "^2.20.0", "source-map-support": "~0.5.20" }, @@ -8546,15 +8561,15 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.7", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.7.tgz", - "integrity": "sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw==", + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.17", + "@jridgewell/trace-mapping": "^0.3.20", "jest-worker": "^27.4.5", "schema-utils": "^3.1.1", "serialize-javascript": "^6.0.1", - "terser": "^5.16.5" + "terser": "^5.26.0" }, "engines": { "node": ">= 10.13.0" @@ -8579,9 +8594,9 @@ } }, "node_modules/terser-webpack-plugin/node_modules/schema-utils": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz", - "integrity": "sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dependencies": { "@types/json-schema": "^7.0.8", "ajv": "^6.12.5", @@ -9032,18 +9047,18 @@ } }, "node_modules/webpack": { - "version": "5.88.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz", - "integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==", + "version": "5.90.3", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.3.tgz", + "integrity": "sha512-h6uDYlWCctQRuXBs1oYpVe6sFcWedl0dpcVaTf/YF67J9bKvwJajFulMVSYKHrksMB3I/pIagRzDxwxkebuzKA==", "dependencies": { "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.0", + "@types/estree": "^1.0.5", "@webassemblyjs/ast": "^1.11.5", "@webassemblyjs/wasm-edit": "^1.11.5", "@webassemblyjs/wasm-parser": "^1.11.5", "acorn": "^8.7.1", "acorn-import-assertions": "^1.9.0", - "browserslist": "^4.14.5", + "browserslist": "^4.21.10", "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^5.15.0", "es-module-lexer": "^1.2.1", @@ -9057,7 +9072,7 @@ "neo-async": "^2.6.2", "schema-utils": "^3.2.0", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.7", + "terser-webpack-plugin": "^5.3.10", "watchpack": "^2.4.0", "webpack-sources": "^3.2.3" }, diff --git a/package.json b/package.json index 7b9fbaf..e0590dc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dummyi", - "version": "0.2.2", + "version": "0.2.3", "private": true, "scripts": { "dev": "next dev", @@ -23,7 +23,7 @@ "@uiw/codemirror-extensions-langs": "^4.21.9", "@uiw/codemirror-themes": "^4.21.9", "@uiw/react-codemirror": "^4.21.20", - "@vercel/analytics": "^1.0.2", + "@vercel/analytics": "^1.2.2", "autoprefixer": "10.4.16", "emoji-picker-react": "^4.5.3", "eslint": "8.47.0", @@ -53,6 +53,6 @@ "cypress": "^12.17.4", "mini-css-extract-plugin": "^2.7.6", "typescript": "^5.1.6", - "webpack": "^5.88.2" + "webpack": "^5.90.3" } } diff --git a/scripts/addNewGenerator.ts b/scripts/addNewGenerator.ts index e81710c..5403898 100644 --- a/scripts/addNewGenerator.ts +++ b/scripts/addNewGenerator.ts @@ -106,7 +106,7 @@ export const ${generatorName}GeneratorDefaultOptions:${generatorName}GeneratorOp // ------------------------------------------------------------------------------------------------------------- // generate method -export const generate = (options: any): GenerateResult => { +export const generate = (options: ${generatorName}GeneratorOptions): GenerateResult => { // TODO: implement your own generate method here return { @@ -125,9 +125,9 @@ export const ${generatorName}GeneratorOptionsComponent: React.FunctionComponent< // TODO: implement your own options component here return ( -
+ <> NOT IMPLEMENTED -
+ ); }`; } diff --git a/src/components/DevTools/src/GenerateResultsPreviewer.tsx b/src/components/DevTools/src/GenerateResultsPreviewer.tsx index 595aa5a..5c90700 100644 --- a/src/components/DevTools/src/GenerateResultsPreviewer.tsx +++ b/src/components/DevTools/src/GenerateResultsPreviewer.tsx @@ -77,7 +77,7 @@ export const GenerateResultsPreviewer: React.FunctionComponent - + {formatType} {isError && ERROR} diff --git a/src/components/InputPanel/src/InputPanel.tsx b/src/components/InputPanel/src/InputPanel.tsx index 3f66bee..bdc375e 100644 --- a/src/components/InputPanel/src/InputPanel.tsx +++ b/src/components/InputPanel/src/InputPanel.tsx @@ -23,7 +23,7 @@ export const InputPanel: React.FunctionComponent = () => { setPanelHeight(containerHeight); - if (containerWidth > 1000) { + if (containerWidth > 900) { setComponentSize(ComponentSize.LARGE); } else if (containerWidth > 550) { setComponentSize(ComponentSize.MEDIUM); diff --git a/src/components/InputPanel/src/components/DataTypeSelectModal.tsx b/src/components/InputPanel/src/components/DataTypeSelectModal.tsx index 72a0037..2200c79 100644 --- a/src/components/InputPanel/src/components/DataTypeSelectModal.tsx +++ b/src/components/InputPanel/src/components/DataTypeSelectModal.tsx @@ -21,7 +21,7 @@ export interface DataTypeSelectModalProps { export const DataTypeSelectModal: React.FunctionComponent = ({...props}) => { const intl = useIntl(); - const {Title} = Typography; + const {Title, Text} = Typography; const dispatch = useDispatch(); const [searchText, setSearchText] = React.useState(null); const data = useMemo(() => getGeneratorList(searchText, intl), [intl, searchText]); @@ -34,7 +34,7 @@ export const DataTypeSelectModal: React.FunctionComponent { - dispatch(doChangeDataType(currentTargetDataFieldId,item.type)); + dispatch(doChangeDataType(currentTargetDataFieldId, item.type)); onCancel(); } @@ -106,7 +106,9 @@ export const DataTypeSelectModal: React.FunctionComponent (
- {example} + + {example} +
)) } diff --git a/src/components/Utils/src/OptionsDatetimePicker.tsx b/src/components/Utils/src/OptionsDatetimePicker.tsx new file mode 100644 index 0000000..cf6a92e --- /dev/null +++ b/src/components/Utils/src/OptionsDatetimePicker.tsx @@ -0,0 +1,55 @@ +import React from "react"; +import {ErrorTooltip, InfoTooltip} from "@/components/Utils"; +import {useIntl} from "@/locale"; +import {isNullOrWhiteSpace} from "@/utils/stringUtils"; +import {DatePicker} from "@douyinfe/semi-ui"; +import {hasValue} from "@/utils/typeUtils"; + +export interface OptionsDatetimePickerProps { + label: string | React.ReactNode; + type?: "date" | "dateTime" | "dateRange" | "dateTimeRange"; + infoTooltip?: string | React.ReactNode; + errorMessage?: string; + value: string | number | Date | string[] | number[] | Date[]; + onChange: (value: any) => void; + style?: React.CSSProperties; + required?: boolean; +} + +export const OptionsDatetimePicker: React.FunctionComponent = ({...props}) => { + const {label, type, infoTooltip, errorMessage, value, style, onChange, required} = props; + const intl = useIntl(); + + // Add a new useState to manage the validation error message + const [validationError, setValidationError] = React.useState(); + + // Add effect to validate value when it changes or when required status changes + React.useEffect(() => { + if (required && !hasValue(value)) { + setValidationError(intl.formatMessage({id: 'error.input.isRequired'})); // Set default required error message or use props.errorMessage + } else { + setValidationError(undefined); // Clear error message when input is valid + } + }, [value, required]); + + return ( +
+
+ {label} + {infoTooltip && + {infoTooltip} + } +
+ + onChange(dateString)} + value={value} + style={style} + validateStatus={!isNullOrWhiteSpace(validationError || errorMessage) ? 'error' : 'default'} + /> + +
+ ) +} \ No newline at end of file diff --git a/src/components/Utils/src/OptionsSwitch.tsx b/src/components/Utils/src/OptionsSwitch.tsx index 05eb65d..9c4acd7 100644 --- a/src/components/Utils/src/OptionsSwitch.tsx +++ b/src/components/Utils/src/OptionsSwitch.tsx @@ -27,7 +27,7 @@ export const OptionsSwitch: React.FunctionComponent = ({...p diff --git a/src/constants/enums.ts b/src/constants/enums.ts index 918d080..50de53a 100644 --- a/src/constants/enums.ts +++ b/src/constants/enums.ts @@ -1,4 +1,3 @@ - // export format export enum ExportFormatCategory { FILE_TYPES = "file_types", @@ -18,17 +17,18 @@ export enum ExportFormat { export enum ValueType { STRING = "string", - TEXT= "text", + TEXT = "text", ONE_BIT = "1bit", INT = "integer", BIGINT = "bigint", DOUBLE = "double", BOOLEAN = "boolean", INT_LIST = "int_list", - STRING_LIST = "string_list" + STRING_LIST = "string_list", + DATE_TIME = "date_time" } -export enum ExportProcessStage{ +export enum ExportProcessStage { PREVIEW = "preview", GENERATING = "generating", COMPLETED = "completed", @@ -36,14 +36,20 @@ export enum ExportProcessStage{ // data types export enum DataTypeCategory { - ALL= "all", + ALL = "all", BASIC = "basic", PERSON = "person", NETWORK = "network", COMMERCE = "commerce", + DATETIME = "datetime" } export enum DataType { + IPADDRESS = "ipaddress", + BIRTHDAY = "birthday", + MONTH = "month", + WEEKDAY = "weekday", + DATETIME = "datetime", URL = "url", DOMAINSUFFIX = "domainsuffix", DOMAINNAME = "domainname", @@ -81,18 +87,18 @@ export enum Locales { JA_JP = "ja-JP", } -export enum ComponentSize{ +export enum ComponentSize { SMALL = "small", MEDIUM = "medium", LARGE = "large", } -export enum PreviewType{ +export enum PreviewType { TABLE = "table", RAW = "raw" } -export enum CollectionNodeType{ +export enum CollectionNodeType { COLLECTION = "collection", SCHEMA = "schema" } @@ -102,7 +108,7 @@ export enum EndOfLineChars { CRLF = '\r\n' } -export enum Sex{ +export enum Sex { ALL = "all", MALE = "male", FEMALE = "female" diff --git a/src/core/formatters/CSharp/CSharp.tsx b/src/core/formatters/CSharp/CSharp.tsx index cff70b9..ed4d198 100644 --- a/src/core/formatters/CSharp/CSharp.tsx +++ b/src/core/formatters/CSharp/CSharp.tsx @@ -72,6 +72,9 @@ export const format = (request: FormatRequest): string => { case ValueType.ONE_BIT: fieldType = `int${field.emptyRate !== 0 ? "?" : ""}`; break; + case ValueType.DATE_TIME: + fieldType = `DateTime${field.emptyRate !== 0 ? "?" : ""}` + break; // Add more cases as necessary } csharpCode += ` public ${fieldType} ${field.fieldName} { get; set; }\n`; diff --git a/src/core/formatters/CSharp/CSharpFormatterUtils.ts b/src/core/formatters/CSharp/CSharpFormatterUtils.ts index f3cfed2..8eea719 100644 --- a/src/core/formatters/CSharp/CSharpFormatterUtils.ts +++ b/src/core/formatters/CSharp/CSharpFormatterUtils.ts @@ -26,7 +26,20 @@ export function formatValueForCSharp(generateResult: GenerateResult, valueType: return `new List { ${value.join(", ")} }` case ValueType.STRING_LIST: return `new List { ${value.map(item => `"${item}"`).join(', ')})} }` + case ValueType.DATE_TIME: + return `DateTime.Parse("${toCSharpDateTimeFormat(value)}")` default: return 'null'; // Or some other default case } +} + +export function toCSharpDateTimeFormat(date: Date): string { + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份是从0开始的 + const day = String(date.getDate()).padStart(2, '0'); + + const hours = String(date.getHours()).padStart(2, '0'); + const minutes = String(date.getMinutes()).padStart(2, '0'); + + return `${year}-${month}-${day} ${hours}:${minutes}`; } \ No newline at end of file diff --git a/src/core/formatters/Sql/Sql.tsx b/src/core/formatters/Sql/Sql.tsx index 161922c..86d10df 100644 --- a/src/core/formatters/Sql/Sql.tsx +++ b/src/core/formatters/Sql/Sql.tsx @@ -61,14 +61,16 @@ const addCreateTableColumn = (field: DataField, sqlType: SqlType) => { fieldType = (sqlType === SqlType.ORACLE || sqlType === SqlType.IBMDB2) ? "CLOB" : "TEXT"; break; case ValueType.ONE_BIT: - fieldType = "TINYINT(1)"; - break; case ValueType.BOOLEAN: fieldType = "TINYINT(1)"; break; case ValueType.BIGINT: fieldType = "BIGINT"; break; + case ValueType.DATE_TIME: // Add this line + // Define default DATETIME format, then override per SQL type if necessary + fieldType = "DATETIME"; + break; default: fieldType = "VARCHAR(255)"; break; @@ -77,23 +79,29 @@ const addCreateTableColumn = (field: DataField, sqlType: SqlType) => { // Apply SQL type-specific modifications switch (sqlType) { case SqlType.ORACLE: - // Oracle-specific adaptations, e.g., use NUMBER instead of INT + // Oracle-specific adaptations if (fieldType === "INT") { fieldType = "NUMBER"; } else if (fieldType === "TINYINT(1)") { fieldType = "NUMBER(1)"; + } else if (fieldType === "DATETIME") { // Add this line + fieldType = "TIMESTAMP"; // Or DATE, depending on your needs } break; case SqlType.POSTGRES: - // Postgres-specific adaptations, e.g., use BOOLEAN instead of TINYINT(1) + // Postgres-specific adaptations if (fieldType === "TINYINT(1)") { fieldType = "BOOLEAN"; + } else if (fieldType === "DATETIME") { // Add this line + fieldType = "TIMESTAMP"; // Or TIMESTAMP WITHOUT TIME ZONE, depending on your needs } break; case SqlType.SQLITE: - // SQLite uses a more dynamic type system + // SQLite adaptations if (fieldType === "TINYINT(1)") { fieldType = "INTEGER"; + } else if (fieldType === "DATETIME") { // Add this line + fieldType = "TEXT"; // SQLite uses TEXT for date and time types } break; // Add cases for other SQL types as necessary @@ -116,7 +124,29 @@ const formatValueForSQL = (value: any, sqlType: SqlType, valueType: ValueType): case ValueType.INT_LIST: return `'${value.join(", ")}'` case ValueType.STRING_LIST: - return `'${value.map(item => `"${item}"`).join(', ')}'` + return `'${value.map((item: string): string => `"${item}"`).join(', ')}'` + case ValueType.DATE_TIME: + let formattedDate: string; + // Assuming value is a JavaScript Date object for simplicity + const date = (value instanceof Date) ? value : new Date(value); + + switch (sqlType) { + case SqlType.ORACLE: + // Oracle format: 'YYYY-MM-DD HH24:MI:SS' + formattedDate = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')} ${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}:${String(date.getSeconds()).padStart(2, '0')}`; + break; + case SqlType.POSTGRES: + // PostgreSQL format: 'YYYY-MM-DD HH:MM:SS' + formattedDate = date.toISOString().slice(0, 19).replace('T', ' '); + break; + // Add additional cases for different SQL types as needed + default: + // Default to ISO format 'YYYY-MM-DD HH:MM:SS' + formattedDate = date.toISOString().slice(0, 19).replace('T', ' '); + break; + } + + return `'${formattedDate}'`; default: return value; } diff --git a/src/core/formatters/Typescript/Typescript.tsx b/src/core/formatters/Typescript/Typescript.tsx index 5d5f286..7a645d1 100644 --- a/src/core/formatters/Typescript/Typescript.tsx +++ b/src/core/formatters/Typescript/Typescript.tsx @@ -63,6 +63,9 @@ export const format = (request: FormatRequest): string => { case ValueType.STRING_LIST: fieldType = 'string[]' break; + case ValueType.DATE_TIME: + fieldType = "Date" + break; } output += ` ${field.fieldName}${field.emptyRate !== 0 ? "?" : ""}: ${fieldType};\n`; }); diff --git a/src/core/generators/Birthday/Birthday.tsx b/src/core/generators/Birthday/Birthday.tsx new file mode 100644 index 0000000..d7912d1 --- /dev/null +++ b/src/core/generators/Birthday/Birthday.tsx @@ -0,0 +1,143 @@ +import React from "react"; +import {GenerateResult, GeneratorOptionsComponentInterface} from "@/types/generator"; +import {DateTimeFormat, DateTimeFormatSelectOptions, formatDateTime} from "@/core/generators/DateTime/DateTime"; +import {OptionsNumberInput, OptionsSelect, SelectOption} from "@/components/Utils"; +import {FormattedMessage} from "@/locale"; +import {faker} from "@faker-js/faker"; +import {ValueType} from "@/constants/enums"; + +// ------------------------------------------------------------------------------------------------------------- +// types + +export enum BirthdayGeneratorMode { + AGE = "age", + YEAR = "year" +} + +export interface BirthdayGeneratorOptions { + format: DateTimeFormat; + mode: BirthdayGeneratorMode; + minAge: number; + maxAge: number; + fromYear: number; + toYear: number; +} + +// ------------------------------------------------------------------------------------------------------------- +// default options +export const BirthdayGeneratorDefaultOptions: BirthdayGeneratorOptions = { + format: DateTimeFormat.DATETIME, + mode: BirthdayGeneratorMode.AGE, + minAge: 1, + maxAge: 80, + fromYear: 1960, + toYear: 2000, +} + +// ------------------------------------------------------------------------------------------------------------- +// generate method +export const generate = (options: BirthdayGeneratorOptions): GenerateResult => { + + const value = faker.date.birthdate({ + mode: options.mode, + min: options.mode === BirthdayGeneratorMode.AGE ? options.minAge : options.fromYear, + max: options.mode === BirthdayGeneratorMode.AGE ? options.maxAge : options.toYear, + refDate: Date.now() + }) + const output = formatDateTime(value, options.format); + + return { + value: output, + stringValue: (output instanceof Date) ? output.toISOString() : output.toString() + }; +} + +// ------------------------------------------------------------------------------------------------------------- +// options component +export const BirthdayGeneratorOptionsComponent: React.FunctionComponent = ({...props}) => { + const {options, handleOptionValueChange} = props as { + options: BirthdayGeneratorOptions, + handleOptionValueChange: typeof props.handleOptionValueChange + }; + + const handleChangeFormat = (format: DateTimeFormat) => { + if (format === DateTimeFormat.TIMESTAMP) { + handleOptionValueChange("format", format, ValueType.INT); + } else if (format === DateTimeFormat.TEXT) { + handleOptionValueChange("format", format, ValueType.STRING); + } else if (format === DateTimeFormat.DATETIME) { + handleOptionValueChange("format", format, ValueType.DATE_TIME); + } + } + + return ( + <> + } + selectOptions={BirthdayGeneratorModeSelectOptions} + value={options.mode} + onChange={(v) => handleOptionValueChange("mode", v)} + /> + + {options.mode === BirthdayGeneratorMode.AGE && <> + } + value={options.minAge} + onChange={(v) => handleOptionValueChange("minAge", v)} + style={{width: "70px"}} + min={0} + max={options.maxAge} + /> + + } + value={options.maxAge} + onChange={(v) => handleOptionValueChange("maxAge", v)} + style={{width: "70px"}} + min={options.minAge} + max={150} + /> + } + + + {options.mode === BirthdayGeneratorMode.YEAR && <> + } + value={options.fromYear} + onChange={(v) => handleOptionValueChange("fromYear", v)} + style={{width: "90px"}} + min={1000} + max={options.toYear} + /> + + } + value={options.toYear} + onChange={(v) => handleOptionValueChange("toYear", v)} + style={{width: "100px"}} + min={options.toYear} + max={2500} + /> + } + + } + selectOptions={DateTimeFormatSelectOptions} + value={options.format} + onChange={handleChangeFormat} + style={{width: "200px"}} + /> + + + ); +} + +const BirthdayGeneratorModeSelectOptions: SelectOption[] = [ + { + label: , + value: BirthdayGeneratorMode.AGE + }, { + label: , + value: BirthdayGeneratorMode.YEAR + } +] \ No newline at end of file diff --git a/src/core/generators/Birthday/index.ts b/src/core/generators/Birthday/index.ts new file mode 100644 index 0000000..f915ab9 --- /dev/null +++ b/src/core/generators/Birthday/index.ts @@ -0,0 +1,14 @@ +import {Generator} from "@/types/generator"; +import {DataType, DataTypeCategory, ValueType} from "@/constants/enums"; +import {BirthdayGeneratorDefaultOptions, BirthdayGeneratorOptionsComponent, generate} from "./Birthday"; + +export const BirthdayGenerator: Generator = { + type: DataType.BIRTHDAY, + category: DataTypeCategory.PERSON, + generate: generate, + optionsComponent: BirthdayGeneratorOptionsComponent, + defaultOptions: BirthdayGeneratorDefaultOptions, + defaultValueType: ValueType.DATE_TIME, + exampleLines: ["1949-08-11T20:00:14.636Z", "-640186506999", "18-02-1968 20:14:50"] +} + \ No newline at end of file diff --git a/src/core/generators/DateTime/DateTime.tsx b/src/core/generators/DateTime/DateTime.tsx new file mode 100644 index 0000000..ed66fe4 --- /dev/null +++ b/src/core/generators/DateTime/DateTime.tsx @@ -0,0 +1,189 @@ +import React from "react"; +import {GenerateResult, GeneratorOptionsComponentInterface} from "@/types/generator"; +import {OptionsSelect, SelectOption} from "@/components/Utils"; +import {FormattedMessage} from "@/locale"; +import {OptionsDatetimePicker} from "@/components/Utils/src/OptionsDatetimePicker"; +import {faker} from "@faker-js/faker"; +import {ValueType} from "@/constants/enums"; +import style from "@/core/generators/Boolean/Boolean.module.scss"; +import {Tag} from "@douyinfe/semi-ui"; +import {toDateTimeString} from "@/utils/typeUtils"; + +// ------------------------------------------------------------------------------------------------------------- +// types +export enum DateTimeTerms { + ANYTIME = "anytime", + BETWEEN = "between", + FUTURE = "future", + PAST = "past", + RECENT = "recent", + SOON = "soon" +} + +export enum DateTimeFormat { + TEXT = "text", + TIMESTAMP = "timestamp", + DATETIME = "datetime" +} + +export interface DateTimeGeneratorOptions { + terms: DateTimeTerms; + ref: Date | number | string; + format: DateTimeFormat; + timeRange: Date[] | number[] | string[]; +} + +// ------------------------------------------------------------------------------------------------------------- +// default options +export const DateTimeGeneratorDefaultOptions: DateTimeGeneratorOptions = { + terms: DateTimeTerms.ANYTIME, + ref: Date.now(), + format: DateTimeFormat.DATETIME, + timeRange: [new Date(2023, 0, 1), new Date()] +} + +// ------------------------------------------------------------------------------------------------------------- +// generate method +export const generate = (options: DateTimeGeneratorOptions): GenerateResult => { + const {terms, ref, format} = options; + + let value: Date; + const fakerOptions = {refDate: ref} + + switch (terms) { + case DateTimeTerms.FUTURE: + value = faker.date.future(fakerOptions); + break; + case DateTimeTerms.PAST: + value = faker.date.past(fakerOptions); + break; + case DateTimeTerms.RECENT: + value = faker.date.recent(fakerOptions); + break; + case DateTimeTerms.SOON: + value = faker.date.soon(fakerOptions); + break; + case DateTimeTerms.BETWEEN: + value = faker.date.between({from: options.timeRange[0], to: options.timeRange[1]}); + break; + default: + value = faker.date.anytime(fakerOptions); + } + + const output = formatDateTime(value, format); + + return { + value: output, + stringValue: (output instanceof Date) ? output.toISOString() : output.toString() + }; +} + +// ------------------------------------------------------------------------------------------------------------- +// options component +export const DateTimeGeneratorOptionsComponent: React.FunctionComponent = ({...props}) => { + + const {options, handleOptionValueChange} = props as { + options: DateTimeGeneratorOptions, + handleOptionValueChange: typeof props.handleOptionValueChange + }; + + const handleChangeFormat = (format: DateTimeFormat) => { + if (format === DateTimeFormat.TIMESTAMP) { + handleOptionValueChange("format", format, ValueType.INT); + } else if (format === DateTimeFormat.TEXT) { + handleOptionValueChange("format", format, ValueType.STRING); + } else if (format === DateTimeFormat.DATETIME) { + handleOptionValueChange("format", format, ValueType.DATE_TIME); + } + } + + return ( + <> + } + selectOptions={DateTimeTermsSelectOptions} + value={options.terms} + onChange={(v) => handleOptionValueChange("terms", v)} + style={{width: "130px"}} + /> + + { + options.terms === DateTimeTerms.BETWEEN ? } + type={'dateTimeRange'} + value={options.timeRange} + onChange={(v) => handleOptionValueChange("timeRange", v)} + style={{width: "260px"}} + required + /> + : + } + infoTooltip={} + type={'dateTime'} + value={options.ref} + onChange={(v) => handleOptionValueChange("ref", v)} + style={{width: "185px"}} + required + /> + } + + } + selectOptions={DateTimeFormatSelectOptions} + value={options.format} + onChange={handleChangeFormat} + style={{width: "200px"}} + /> + + ); +} + +export const formatDateTime = (date: Date, format: DateTimeFormat) => { + switch (format) { + case DateTimeFormat.DATETIME: + return date; + case DateTimeFormat.TIMESTAMP: + return date.getTime(); + case DateTimeFormat.TEXT: + return toDateTimeString(date); + } +} + +export const DateTimeTermsSelectOptions: SelectOption[] = Object.values(DateTimeTerms).map((term) => { + return { + value: term, + label: + }; +}) + +export const DateTimeFormatSelectOptions: SelectOption[] = [ + { + value: DateTimeFormat.DATETIME, + label: + <> + Date + + + }, + { + value: DateTimeFormat.TIMESTAMP, + label: + <> + number + + + }, + { + value: DateTimeFormat.TEXT, + label: + <> + string + + + }, + +] \ No newline at end of file diff --git a/src/core/generators/DateTime/index.ts b/src/core/generators/DateTime/index.ts new file mode 100644 index 0000000..1251e07 --- /dev/null +++ b/src/core/generators/DateTime/index.ts @@ -0,0 +1,14 @@ +import {Generator} from "@/types/generator"; +import {DataType, DataTypeCategory, ValueType} from "@/constants/enums"; +import {DateTimeGeneratorDefaultOptions, DateTimeGeneratorOptionsComponent, generate} from "./DateTime"; + +export const DateTimeGenerator: Generator = { + type: DataType.DATETIME, + category: DataTypeCategory.DATETIME, + generate: generate, + optionsComponent: DateTimeGeneratorOptionsComponent, + defaultOptions: DateTimeGeneratorDefaultOptions, + defaultValueType: ValueType.DATE_TIME, + exampleLines: ["1725842513046", "29-01-2025 20:15:40", "13-06-2023 08:16:09"] +} + \ No newline at end of file diff --git a/src/core/generators/IpAddress/IpAddress.tsx b/src/core/generators/IpAddress/IpAddress.tsx new file mode 100644 index 0000000..37dc75c --- /dev/null +++ b/src/core/generators/IpAddress/IpAddress.tsx @@ -0,0 +1,69 @@ +import React from "react"; +import {GenerateResult, GeneratorOptionsComponentInterface} from "@/types/generator"; +import {OptionsSelect, SelectOption} from "@/components/Utils"; +import {FormattedMessage} from "@/locale"; +import {faker} from "@faker-js/faker"; +// ------------------------------------------------------------------------------------------------------------- +// types + +export type IpType = 'IPv4' | 'IPv6' + +export interface IpAddressGeneratorOptions { + types: IpType[] +} + + +// ------------------------------------------------------------------------------------------------------------- +// default options +export const IpAddressGeneratorDefaultOptions: IpAddressGeneratorOptions = { + types: ["IPv4", "IPv6"] +} + + +// ------------------------------------------------------------------------------------------------------------- +// generate method +export const generate = (options: IpAddressGeneratorOptions): GenerateResult => { + let value: string; + + if (options.types.length === 2) { + value = faker.internet.ip(); + } else if (options.types.includes("IPv4")) { + value = faker.internet.ipv4(); + } else if (options.types.includes("IPv6")){ + value = faker.internet.ipv6(); + } + + return { + value: value, + stringValue: value, + }; +} + +// ------------------------------------------------------------------------------------------------------------- +// options component +export const IpAddressGeneratorOptionsComponent: React.FunctionComponent = ({...props}) => { + const {options, handleOptionValueChange} = props as { + options: IpAddressGeneratorOptions, + handleOptionValueChange: typeof props.handleOptionValueChange + }; + + return ( +
+ } + selectOptions={IpTypeSelectOptions} + value={options.types} + onChange={(v) => handleOptionValueChange("types", v)} + style={{width: '160px'}} + /> +
+ ); +} + + +export const IpTypeSelectOptions: SelectOption[] = [ + {label: "IPv4", value: "IPv4",}, + {label: "IPv6", value: "IPv6"} +] \ No newline at end of file diff --git a/src/core/generators/IpAddress/index.ts b/src/core/generators/IpAddress/index.ts new file mode 100644 index 0000000..5fbac02 --- /dev/null +++ b/src/core/generators/IpAddress/index.ts @@ -0,0 +1,14 @@ +import {Generator} from "@/types/generator"; +import {DataType, DataTypeCategory, ValueType} from "@/constants/enums"; +import {IpAddressGeneratorDefaultOptions, IpAddressGeneratorOptionsComponent, generate} from "./IpAddress"; + +export const IpAddressGenerator: Generator = { + type: DataType.IPADDRESS, + category: DataTypeCategory.NETWORK, + generate: generate, + optionsComponent: IpAddressGeneratorOptionsComponent, + defaultOptions: IpAddressGeneratorDefaultOptions, + defaultValueType: ValueType.STRING, + exampleLines: ["245.108.222.0", "64.239.253.171", "e106:aa3c:59ac:6d0f:4c2c:bfef:86a3:62d7"] +} + \ No newline at end of file diff --git a/src/core/generators/Month/Month.tsx b/src/core/generators/Month/Month.tsx new file mode 100644 index 0000000..314b1b1 --- /dev/null +++ b/src/core/generators/Month/Month.tsx @@ -0,0 +1,49 @@ +import React from "react"; +import {GenerateResult, GeneratorOptionsComponentInterface} from "@/types/generator"; +import {OptionsSwitch} from "@/components/Utils/src/OptionsSwitch"; +import {FormattedMessage} from "@/locale"; +import {faker} from "@faker-js/faker"; + +// ------------------------------------------------------------------------------------------------------------- +// types +export interface MonthGeneratorOptions { + abbreviated: boolean; +} + +// ------------------------------------------------------------------------------------------------------------- +// default options +export const MonthGeneratorDefaultOptions: MonthGeneratorOptions = { + abbreviated: false +} + +// ------------------------------------------------------------------------------------------------------------- +// generate method +export const generate = (options: MonthGeneratorOptions): GenerateResult => { + const {abbreviated} = options; + const value = faker.date.month({abbreviated:abbreviated}) + return { + value: value, + stringValue: value + }; +} + +// ------------------------------------------------------------------------------------------------------------- +// options component +export const MonthGeneratorOptionsComponent: React.FunctionComponent = ({...props}) => { + const {options, handleOptionValueChange} = props as { + options: MonthGeneratorOptions, + handleOptionValueChange: typeof props.handleOptionValueChange + }; + + // TODO: implement your own options component here + return ( + <> + } + value={options.abbreviated} + onChange={(v) => handleOptionValueChange("abbreviated", v)} + /> + + + ); +} \ No newline at end of file diff --git a/src/core/generators/Month/index.ts b/src/core/generators/Month/index.ts new file mode 100644 index 0000000..825940f --- /dev/null +++ b/src/core/generators/Month/index.ts @@ -0,0 +1,14 @@ +import {Generator} from "@/types/generator"; +import {DataType, DataTypeCategory, ValueType} from "@/constants/enums"; +import {MonthGeneratorDefaultOptions, MonthGeneratorOptionsComponent, generate} from "./Month"; + +export const MonthGenerator: Generator = { + type: DataType.MONTH, + category: DataTypeCategory.DATETIME, + generate: generate, + optionsComponent: MonthGeneratorOptionsComponent, + defaultOptions: MonthGeneratorDefaultOptions, + defaultValueType: ValueType.STRING, + exampleLines: ["September", "Feb", "December"] +} + \ No newline at end of file diff --git a/src/core/generators/Number/Number.tsx b/src/core/generators/Number/Number.tsx index 29a6119..f975519 100644 --- a/src/core/generators/Number/Number.tsx +++ b/src/core/generators/Number/Number.tsx @@ -95,18 +95,14 @@ export const NumberGeneratorOptionsComponent: React.FunctionComponent { const newErrorMessages = {...errorMessages}; // min - if (isNullOrWhiteSpace(options.min.toString())) { - newErrorMessages.min = intl.formatMessage({id: 'dataType.number.min.errorMessage.empty'}) - } else if (options.min > options.max) { + if (options.min > options.max) { newErrorMessages.min = intl.formatMessage({id: 'dataType.number.min.errorMessage.greaterThanMax'}) } else { newErrorMessages.min = ''; } // max - if (isNullOrWhiteSpace(options.max.toString())) { - newErrorMessages.max = intl.formatMessage({id: 'dataType.number.max.errorMessage.empty'}) - } else if (options.max < options.min) { + if (options.max < options.min) { newErrorMessages.max = intl.formatMessage({id: 'dataType.number.max.errorMessage.lessThanMin'}) } else { newErrorMessages.max = ''; diff --git a/src/core/generators/Weekday/Weekday.tsx b/src/core/generators/Weekday/Weekday.tsx new file mode 100644 index 0000000..a9ed699 --- /dev/null +++ b/src/core/generators/Weekday/Weekday.tsx @@ -0,0 +1,47 @@ +import React from "react"; +import {GenerateResult, GeneratorOptionsComponentInterface} from "@/types/generator"; +import {OptionsSwitch} from "@/components/Utils/src/OptionsSwitch"; +import {FormattedMessage} from "@/locale"; +import {faker} from "@faker-js/faker"; + +// ------------------------------------------------------------------------------------------------------------- +// types +export interface WeekdayGeneratorOptions { + abbreviated: boolean; +} + +// ------------------------------------------------------------------------------------------------------------- +// default options +export const WeekdayGeneratorDefaultOptions: WeekdayGeneratorOptions = { + abbreviated: false +} + +// ------------------------------------------------------------------------------------------------------------- +// generate method +export const generate = (options: WeekdayGeneratorOptions): GenerateResult => { + const {abbreviated} = options; + const value = faker.date.weekday({abbreviated: abbreviated}) + return { + value: value, + stringValue: value + }; +} + +// ------------------------------------------------------------------------------------------------------------- +// options component +export const WeekdayGeneratorOptionsComponent: React.FunctionComponent = ({...props}) => { + const {options, handleOptionValueChange} = props as { + options: WeekdayGeneratorOptions, + handleOptionValueChange: typeof props.handleOptionValueChange + }; + + return ( + <> + } + value={options.abbreviated} + onChange={(v) => handleOptionValueChange("abbreviated", v)} + /> + + ); +} \ No newline at end of file diff --git a/src/core/generators/Weekday/index.ts b/src/core/generators/Weekday/index.ts new file mode 100644 index 0000000..8fe15f1 --- /dev/null +++ b/src/core/generators/Weekday/index.ts @@ -0,0 +1,14 @@ +import {Generator} from "@/types/generator"; +import {DataType, DataTypeCategory, ValueType} from "@/constants/enums"; +import {WeekdayGeneratorDefaultOptions, WeekdayGeneratorOptionsComponent, generate} from "./Weekday"; + +export const WeekdayGenerator: Generator = { + type: DataType.WEEKDAY, + category: DataTypeCategory.DATETIME, + generate: generate, + optionsComponent: WeekdayGeneratorOptionsComponent, + defaultOptions: WeekdayGeneratorDefaultOptions, + defaultValueType: ValueType.STRING, + exampleLines: ["Wednesday", "Wed", "Thursday"] +} + \ No newline at end of file diff --git a/src/core/generators/index.ts b/src/core/generators/index.ts index 8d6ffd1..b490ee4 100644 --- a/src/core/generators/index.ts +++ b/src/core/generators/index.ts @@ -1,3 +1,8 @@ +import {IpAddressGenerator} from "@/core/generators/IpAddress"; +import {BirthdayGenerator} from "@/core/generators/Birthday"; +import {MonthGenerator} from "@/core/generators/Month"; +import {WeekdayGenerator} from "@/core/generators/Weekday"; +import {DateTimeGenerator} from "@/core/generators/DateTime"; import {UrlGenerator} from "@/core/generators/Url"; import {DomainSuffixGenerator} from "@/core/generators/DomainSuffix"; import {DomainNameGenerator} from "@/core/generators/DomainName"; @@ -19,6 +24,11 @@ import {CompanyNameGenerator} from "@/core/generators/CompanyName"; import {DataType} from "@/constants/enums"; export const generators = { + [DataType.IPADDRESS]: IpAddressGenerator, + [DataType.BIRTHDAY]: BirthdayGenerator, + [DataType.MONTH]: MonthGenerator, + [DataType.WEEKDAY]: WeekdayGenerator, + [DataType.DATETIME]: DateTimeGenerator, [DataType.URL]: UrlGenerator, [DataType.DOMAINSUFFIX]: DomainSuffixGenerator, [DataType.DOMAINNAME]: DomainNameGenerator, diff --git a/src/locale/translations/en.ts b/src/locale/translations/en.ts index bcbef4e..e50a227 100644 --- a/src/locale/translations/en.ts +++ b/src/locale/translations/en.ts @@ -85,6 +85,47 @@ export const en = { // ------------------------------------------------------------------------------------------------------------- // data types + // ipaddress + "dataType.ipaddress": "IP Address", + "dataType.ipaddress.types":"Types", + + // birthday + "dataType.birthday": "Birthday", + "dataType.birthday.mode":"Mode", + "dataType.birthday.mode.age":"Age", + "dataType.birthday.mode.year":"Year", + "dataType.birthday.mode.minAge":"Min. Age", + "dataType.birthday.mode.maxAge":"Max. Age", + "dataType.birthday.mode.fromYear":"From year", + "dataType.birthday.mode.toYear":"To year", + + // month + "dataType.month": "Month", + "dataType.month.abbreviated": "Abbreviated", + + // weekday + "dataType.weekday": "Weekday", + "dataType.weekday.abbreviated": "Abbreviated", + + // datetime + "dataType.datetime": "DateTime", + "dataType.datetime.terms": "Terms", + "dataType.datetime.terms.anytime": "Anytime", + "dataType.datetime.terms.between": "Between", + "dataType.datetime.terms.future": "Future", + "dataType.datetime.terms.past": "Past", + "dataType.datetime.terms.recent": "Recent past", + "dataType.datetime.terms.soon": "Soon", + "dataType.datetime.ref": "Reference date", + "dataType.datetime.ref.tooltip": "The date to use as reference point", + "dataType.datetime.format": "Format", + "dataType.datetime.format.text": "Text", + "dataType.datetime.format.timestamp": "Timestamp", + "dataType.datetime.format.datetime": "DateTime", + "dataType.datetime.timeRange": "Range", + + // anytime + "dataType.anytime": "Anytime", // url "dataType.url": "Url", @@ -159,9 +200,6 @@ export const en = { "dataType.number.max.errorMessage.empty": "Max. value cannot be empty", "dataType.number.max.errorMessage.lessThanMin": "Max. value cannot be less than min. value", - // dateTime - "dataType.dateTime": "Date time", - // boolean "dataType.boolean": "Boolean", "dataType.boolean.true.label": "Prob of True", @@ -195,6 +233,7 @@ export const en = { "dataType.category.person": "Person", "dataType.category.commerce": "Commerce", "dataType.category.network": "Network", + "dataType.category.datetime": "Datetime", // ------------------------------------------------------------------------------------------------------------- // pages diff --git a/src/locale/translations/jaJP.ts b/src/locale/translations/jaJP.ts index 3653901..b22809b 100644 --- a/src/locale/translations/jaJP.ts +++ b/src/locale/translations/jaJP.ts @@ -1,106 +1,220 @@ -// Translated by ChatGPT export const jaJP = { - // ------------------------------------------------------------------------------------------------------------- // export // export category - "export.category.fileTypes": "一般的なファイルタイプ", - "export.category.databases" : "Databases", - "export.category.programmingLanguages": "プログラミング言語", + "export.category.file_types": "一般的な形式", + "export.category.databases": "データベース", + "export.category.programming_languages": "プログラミング言語", // export format modal - "export.configurator.modal.title": "エクスポート形式", - "export.configurator.modal.closeButton.text": "閉じる", + "export.configurator.modal.title": "形式を生成", + "export.configurator.modal.confirmButton.text": "確認", "export.configurator.config.label": "設定", - "export.configurator.config.empty": "現在、このエクスポート形式の設定は利用できません。", + "export.configurator.config.empty": "この出力形式の設定は現在利用できません", + + // export modal + "export.modal.title": "データを一括生成", + "export.modal.exportNumOfRows.label": "生成するデータ行数", + "export.modal.exportNumOfRows.empty": "データ行数を空にすることはできません", + "export.modal.exportFormat.label": "生成形式", + "export.modal.estimatedSize.label": "推定サイズ", + "export.modal.estimatedTime.label": "推定時間", + "export.modal.exportFileName.label": "ファイル名", + "export.modal.exportFileName.empty": "ファイル名は空にできません", + "export.modal.cancel.button.text": "キャンセル", + "export.modal.generate.button.text": "生成", + "export.modal.hide.button.text": "隠す", + "export.modal.terminate.button.text": "終了", + "export.modal.generating.rows.text": "行数", + "export.modal.generating.time.text": "時間", + "export.modal.generating.done.text": "完了", + "export.modal.toast.details.button.text": "詳細", + "export.modal.toast.download.button.text": "ダウンロード", // csv "export.configurator.csv.delimiter": "区切り文字", - "export.configurator.csv.includeHeader": "ヘッダーを含める", - "export.configurator.csv.endLineChar": "行末文字", + "export.configurator.csv.delimiter.required": "区切り文字を空にすることはできません", + "export.configurator.csv.includeHeader": "ヘッダを含む", + "export.configurator.csv.endLineChar": "行終了文字", + + // xml + "export.configurator.xml.rootNodeName": "ルートノード", + "export.configurator.xml.childNodeName": "子ノード", + "export.configurator.xml.encoding": "エンコーディング", + "export.configurator.xml.indentSize": "インデントのサイズ", + + // json + "export.configurator.json.insideArray": "配列内", + "export.configurator.json.includeNullValues": "null値を含む", + + // javascript + "export.configurator.javascript.format": "形式", + "export.configurator.javascript.format.variable": "変数", + "export.configurator.javascript.format.export": "エクスポート", + "export.configurator.javascript.varName": "変数名", + "export.configurator.javascript.varName.required": "変数名を空にすることはできません", + "export.configurator.javascript.declarationKeyword": "宣言タイプ", + "export.configurator.javascript.module": "モジュール", + + // sql + "export.configurator.sql.type": "データベースのタイプ", + "export.configurator.sql.tableName": "テーブル名", + "export.configurator.sql.tableName.required": "テーブル名を空にすることはできません", + "export.configurator.sql.statement": "SQLステートメント", + "export.configurator.sql.batchSize": "バッチサイズ", + "export.configurator.sql.includeDropTable": "`DROP TABLE` を含む", + "export.configurator.sql.includeCreateTable": "`CREATE TABLE` を含む", + "export.configurator.sql.includePrimaryKey": "主キーを含む", + "export.configurator.sql.primaryKeyColumnName": "主キーカラム名", + + // c# + "export.configurator.csharp.collectionType": "コレクションタイプ", + "export.configurator.csharp.collectionName": "コレクションの変数名", + "export.configurator.csharp.dtoClass": "DTOクラスを作成", + "export.configurator.csharp.dtoClassName": "クラス名", + + // typescript + + + "export.configurator.typescript.declarationType": "宣言のタイプ", + "export.configurator.typescript.declarationType.interface.name": "Interfaceの名前", + "export.configurator.typescript.declarationType.type.name": "Typeの名前", + "export.configurator.typescript.variableName": "変数名", // ------------------------------------------------------------------------------------------------------------- // data types - - + + // ipaddress + "dataType.ipaddress": "IpAddress", + + // birthday + "dataType.birthday": "Birthday", + + // month + "dataType.month": "Month", + + // weekday + "dataType.weekday": "Weekday", + + // datetimerange + "dataType.datetimerange": "DateTimeRange", + + // datetime + "dataType.datetime": "DateTime", + + // anytime + "dataType.anytime": "Anytime", + // url - "dataType.url": "Url", + "dataType.url": "URL", + "dataType.url.appendSlash.label": "スラッシュ", + "dataType.url.protocol.label": "プロトコル", // domainsuffix - "dataType.domainsuffix": "DomainSuffix", + "dataType.domainsuffix": "ドメインサフィックス", // domainname - "dataType.domainname": "DomainName", + "dataType.domainname": "ドメイン名", // accountnumber - "dataType.accountnumber": "AccountNumber", + "dataType.accountnumber": "銀行口座番号", + "dataType.accountnumber.length": "長さ", + "dataType.accountnumber.empty": "長さは空にできません", // accountname - "dataType.accountname": "AccountName", + "dataType.accountname": "アカウント名", // color - "dataType.color": "Color", + "dataType.color": "色", + "dataType.color.kind.label": "タイプ", + "dataType.color.format.humanWord": "言葉での形式", + "dataType.color.format.label": "形式", // phone - "dataType.phone": "Phone Number", - "dataType.phone.formats.label": "Formats", - "dataType.phone.formats.tooltips": "Phone number format, please use \"#\" to represent digits, press Enter key to confirm", + "dataType.phone": "電話番号", + "dataType.phone.formats.label": "形式", + "dataType.phone.formats.tooltips": "電話番号の形式は、「#」を数字の代わりに使用してください。エンターキーで確定", // emoji - "dataType.emoji": "Emoji", - "dataType.emoji.type": "Type", - "dataType.emoji.type.all": "All", - "dataType.emoji.type.smiley": "Smiley", - "dataType.emoji.type.body" : "Body", - "dataType.emoji.type.person" : "Person", - "dataType.emoji.type.nature" : "Nature", - "dataType.emoji.type.food" : "Food", - "dataType.emoji.type.travel" : "Travel", - "dataType.emoji.type.activity" : "Activity", - "dataType.emoji.type.object" : "Object", - "dataType.emoji.type.symbol" : "Symbol", - "dataType.emoji.type.flag" : "Flag", + "dataType.emoji": "絵文字", + "dataType.emoji.type": "タイプ", + "dataType.emoji.type.all": "全て", + "dataType.emoji.type.smiley": "スマイリー", + "dataType.emoji.type.body": "ボディ", + "dataType.emoji.type.person": "人", + "dataType.emoji.type.nature": "自然", + "dataType.emoji.type.food": "食べ物", + "dataType.emoji.type.travel": "旅行", + "dataType.emoji.type.activity": "アクティビティ", + "dataType.emoji.type.object": "オブジェクト", + "dataType.emoji.type.symbol": "シンボル", + "dataType.emoji.type.flag": "フラグ", // persontitle - "dataType.persontitle": "PersonTitle", + "dataType.persontitle": "称号", // middlename - "dataType.middlename": "MiddleName", + "dataType.middlename": "ミドルネーム", // lastname - "dataType.lastname": "LastName", + "dataType.lastname": "姓", // firstname - "dataType.firstname": "FirstName", + "dataType.firstname": "名", // sex - "dataType.sex": "Sex", - - // data type category - "dataType.category.all": "全て", - "dataType.category.basic": "基本", - "dataType.category.person": "個人", - "dataType.category.commerce": "商業", + "dataType.sex": "性別", // number - "dataType.number": "数値", + "dataType.number": "数字", "dataType.number.kind.label": "種類", "dataType.number.precision.label": "精度", "dataType.number.min.label": "最小値", + "dataType.number.min.tooltip": "生成するデータの最小値", + "dataType.number.min.errorMessage.empty": "最小値は空にできません", + "dataType.number.min.errorMessage.greaterThanMax": "最小値は最大値より大きくできません", "dataType.number.max.label": "最大値", + "dataType.number.max.tooltip": "生成するデータの最大値", + "dataType.number.max.errorMessage.empty": "最大値は空にできません", + "dataType.number.max.errorMessage.lessThanMin": "最大値は最小値より小さくできません", // dateTime "dataType.dateTime": "日時", // boolean "dataType.boolean": "ブール値", + "dataType.boolean.true.label": "真の確率", + "dataType.boolean.true.tooltip": "真(true)を生成する確率", + "dataType.boolean.true.errorMessage.empty": "真の確率を空にすることはできません", + "dataType.boolean.format.label": "形式", + + // full name + "dataType.fullName": "フルネーム", + "dataType.fullName.sex.label": "性別", + "dataType.fullName.sex.selectOptions.all": "男性、女性", + "dataType.fullName.sex.selectOptions.male": "男性", + "dataType.fullName.sex.selectOptions.female": "女性", + "dataType.fullName.firstName.label": "名", + "dataType.fullName.lastName.label": "姓", - // person name - "dataType.personName": "氏名", + //email + "dataType.email": "メールアドレス", + "dataType.email.provider.label": "メールプロバイダー", + "dataType.email.allowSpecialCharacters.label": "特殊文字を許可", - // account mi,ner - "dataType.accountNumber": "口座番号", + // company name + "dataType.companyName": "会社名", + + // account number + "dataType.accountNumber": "アカウント番号", + + // data type category + "dataType.category.all": "全て", + "dataType.category.basic": "基本", + "dataType.category.person": "人物", + "dataType.category.commerce": "商業", + "dataType.category.network": "ネットワーク", // ------------------------------------------------------------------------------------------------------------- // pages @@ -108,45 +222,52 @@ export const jaJP = { // nav bar "nav.item.home": "ホーム", "nav.item.workspace": "ワークスペース", - "nav.item.about": "について", + "nav.item.about": "紹介", "nav.colorModeSwitchButton.switchToDarkMode.text": "ダークモードに切り替え", "nav.colorModeSwitchButton.switchToLightMode.text": "ライトモードに切り替え", "nav.languageSwitchButton.tooltip": "言語", - "nav.languageSwitchModal.title": "言語の選択", - "nav.languageSwitchModal.footer.chatGPT.text": "多言語翻訳はChatGPTによって生成されました", + "nav.languageSwitchModal.title": "言語を選択", + "nav.languageSwitchModal.footer.chatGPT.text": "多言語翻訳はChatGPTによって生成されます", // workspace "toolbar.numOfRowInput.suffix": "行", - "toolbar.generateButton.text": "批量生成", - "toolbar.panelsOrientationButton.tooltip.switchToColumn": "パネルを列に切り替え", - "toolbar.panelsOrientationButton.tooltip.switchToRow": "パネルを行に切り替え", - "toolbar.emptyPageButton.tooltip": "ワークスペースを空にする", - "toolbar.emptyPageButton.confirmation.title": "ワークスペースを空にする", - "toolbar.emptyPageButton.confirmation.text": "本当にワークスペースを空にしますか?設定したワークスペースの構成が失われます。", - "toolbar.exportSchemaButton.tooltip": "スキーマのエクスポート", - "toolbar.importSchemaButton.tooltip": "スキーマのインポート", + "toolbar.generateButton.text": "一括生成", + "toolbar.panelsOrientationButton.tooltip.switchToColumn": "パネルを横向きに切り替え", + "toolbar.panelsOrientationButton.tooltip.switchToRow": "パネルを縦向きに切り替え", + "toolbar.emptyPageButton.tooltip": "ワークスペースをクリア", + "toolbar.emptyPageButton.confirmation.title": "ワークスペースをクリアしますか?", + "toolbar.emptyPageButton.confirmation.text": "ワークスペースをクリアしますか?すべての設定が削除されます。", + "toolbar.exportSchemaButton.tooltip": "スキーマをエクスポート", + "toolbar.importSchemaButton.tooltip": "スキーマをインポート", "preview.setting.regenerateButton.tooltip": "再生成", "preview.setting.lineNumberSwitch.tooltip.show": "行番号を表示", "preview.setting.lineNumberSwitch.tooltip.hide": "行番号を非表示", - "preview.setting.lineWarpSwitch.tooltip.enable": "行の折り返しを有効にする", - "preview.setting.lineWarpSwitch.tooltip.disable": "行の折り返しを無効にする", + "preview.setting.lineWarpSwitch.tooltip.enable": "自動改行を有効にする", + "preview.setting.lineWarpSwitch.tooltip.disable": "自動改行を無効にする", "preview.setting.copyToClipboard.tooltip": "クリップボードにコピー", "preview.setting.copyToClipboard.notification.success": "成功", - "preview.setting.copyToClipboard.notification.content": "内容がクリップボードにコピーされました。", - "preview.setting.rawView.text": "生データ", - "preview.setting.tableView.text": "表形式", - "dataFields.list.addNewFieldButton.text": "フィールドを追加", + "preview.setting.copyToClipboard.notification.content": "クリップボードにコピーされました", + "preview.setting.rawView.text": "原文", + "preview.setting.tableView.text": "テーブル", + "dataFields.list.addNewFieldButton.text": "新しいフィールドを追加", + "dataFields.list.noDataFields.text": "フィールドがまだありません", + "dataFields.list.createFirstField.text": "最初のフィールドを作成しましょう!", "dataFields.input.fieldName.label": "フィールド名", - "dataFields.input.type.label": "タイプ", - "dataFields.input.type.placeholder": "タイプを選択", - "dataFields.input.emptyRate.label": "空の確率", + "dataFields.input.fieldName.errorMessage.empty": "フィールド名は空にできません", + "dataFields.input.type.label": "データタイプ", + "dataFields.input.type.placeholder": "タイプを選択...", + "dataFields.input.emptyRate.label": "空値の確率", + "dataFields.input.emptyRate.tooltip": "空値(null)を生成する確率", + "dataFields.input.emptyRate.errorMessage.empty": "空値の確率は空にできません", "dataFields.input.options.label": "オプション", - "dataFields.type.modal.title": "データタイプ", - "dataFields.type.modal.search.placeholder": "データタイプを検索...", + "dataFields.type.modal.title": "タイプを選択", + "dataFields.type.modal.search.placeholder": "タイプを検索...", // error pages + "error.input.isRequired": "この項目は必須です", "error.404.description": "ページが存在しません", "error.404.button.text": "ホームページ", - "error.general.description": "おっと!エラーが発生しました。", + "error.general.description": "おっと!エラーが発生しました!", "error.general.button.text": "ホームページ", -}; \ No newline at end of file + +} diff --git a/src/locale/translations/zhCN.ts b/src/locale/translations/zhCN.ts index 2cdb78d..b850f83 100644 --- a/src/locale/translations/zhCN.ts +++ b/src/locale/translations/zhCN.ts @@ -3,10 +3,12 @@ export const zhCN = { // export // export category + "export.category.file_types": "常见格式", "export.category.databases": "数据库", "export.category.programming_languages": "编程语言", + // export format modal "export.configurator.modal.title": "生成格式", "export.configurator.modal.confirmButton.text": "确认", @@ -83,6 +85,44 @@ export const zhCN = { // ------------------------------------------------------------------------------------------------------------- // data types + // ipaddress + "dataType.ipaddress": "IP地址", + "dataType.ipaddress.types": "类型", + + // birthday + "dataType.birthday": "生日", + "dataType.birthday.mode":"模式", + "dataType.birthday.mode.age":"年龄", + "dataType.birthday.mode.year":"出生年份", + "dataType.birthday.mode.minAge":"最小年龄", + "dataType.birthday.mode.maxAge":"最大年龄", + "dataType.birthday.mode.fromYear":"最小年份", + "dataType.birthday.mode.toYear":"最大年份", + + // month + "dataType.month": "月份", + "dataType.month.abbreviated": "缩写", + + // weekday + "dataType.weekday": "星期", + "dataType.weekday.abbreviated": "缩写", + + // datetime + "dataType.datetime": "日期时间", + "dataType.datetime.terms": "条件", + "dataType.datetime.terms.anytime": "任意时间", + "dataType.datetime.terms.between": "区间", + "dataType.datetime.terms.future": "未来", + "dataType.datetime.terms.past": "过去", + "dataType.datetime.terms.recent": "不久之前", + "dataType.datetime.terms.soon": "不久之后", + "dataType.datetime.ref": "参考日期", + "dataType.datetime.ref.tooltip": "用于生成数据的参考日期", + "dataType.datetime.format": "格式", + "dataType.datetime.format.text": "文本", + "dataType.datetime.format.timestamp": "时间戳", + "dataType.datetime.format.datetime": "Date对象", + "dataType.datetime.timeRange": "区间", // url "dataType.url": "网址", @@ -157,9 +197,6 @@ export const zhCN = { "dataType.number.max.errorMessage.empty": "最大值不能为空", "dataType.number.max.errorMessage.lessThanMin": "最大值不能小于最小值", - // dateTime - "dataType.dateTime": "日期时间", - // boolean "dataType.boolean": "布尔值", "dataType.boolean.true.label": "真值概率", @@ -193,6 +230,7 @@ export const zhCN = { "dataType.category.person": "人物", "dataType.category.commerce": "商业", "dataType.category.network": "网络", + "dataType.category.datetime": "时间", // ------------------------------------------------------------------------------------------------------------- // pages diff --git a/src/utils/formatterUtils.ts b/src/utils/formatterUtils.ts index ad475d2..4e1f73b 100644 --- a/src/utils/formatterUtils.ts +++ b/src/utils/formatterUtils.ts @@ -1,5 +1,5 @@ import {FormatRequest, Formatter} from "@/types/formatter"; -import {ExportFormat} from "@/constants/enums"; +import {ExportFormat, ValueType} from "@/constants/enums"; import {formatters} from "@/core/formatters"; import {langs} from '@uiw/codemirror-extensions-langs'; import {DataFieldList} from "@/types/generator"; @@ -103,6 +103,8 @@ export function toJsonListStringWithoutQuotes(fields: DataFieldList, sortedField if (Array.isArray(value)) { // 处理数组格式 const elements = value.map(element => convert(element, indent + 2)); return `[\n${nextIndentSpace}${elements.join(`,\n${nextIndentSpace}`)}\n${indentSpace}]`; + } else if (value instanceof Date) { + return `new Date("${toISOString(value)}")` } else if (typeof value === 'object' && value !== null) { // 处理对象格式 const entries = Object.entries(value).map(([key, val]) => { const formattedValue = convert(val, indent + 2); @@ -137,3 +139,19 @@ export function toJsonListStringWithoutQuotes(fields: DataFieldList, sortedField output += "]"; // 结束数组 return output; } + + +function toISOString(date) { + // 获取日期部分 + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份是从0开始的 + const day = String(date.getDate()).padStart(2, '0'); + + // 获取时间部分 + const hours = String(date.getHours()).padStart(2, '0'); + const minutes = String(date.getMinutes()).padStart(2, '0'); + const seconds = String(date.getSeconds()).padStart(2, '0'); + + // 拼接成 YYYY-MM-DDTHH:mm:ss 格式 + return `${year}-${month}-${day}T${hours}:${minutes}:${seconds}`; +} \ No newline at end of file diff --git a/src/utils/typeUtils.ts b/src/utils/typeUtils.ts index b6f247c..1c50988 100644 --- a/src/utils/typeUtils.ts +++ b/src/utils/typeUtils.ts @@ -13,4 +13,19 @@ export const calculateByteSize = (str: string) => { // check variable has value export function hasValue(variable: any): boolean { return variable !== null && variable !== undefined; +} + +export function toDateString(date: Date): string { + const day = date.getDate().toString().padStart(2, '0'); + const month = (date.getMonth() + 1).toString().padStart(2, '0'); + const year = date.getFullYear(); + return `${day}-${month}-${year}`; +} + +export function toDateTimeString(date: Date): string { + const formattedDate = toDateString(date); // Reuse formatDate function + const hours = date.getHours().toString().padStart(2, '0'); + const minutes = date.getMinutes().toString().padStart(2, '0'); + const seconds = date.getSeconds().toString().padStart(2, '0'); + return `${formattedDate} ${hours}:${minutes}:${seconds}`; } \ No newline at end of file