feat: add datetime transforms
All checks were successful
/ deploy_site (push) Successful in 3m11s

This commit is contained in:
Minhyeok Park 2024-10-28 21:33:41 +09:00
parent 248880aa9a
commit 314e0e76f8
Signed by: pmh_only
SSH Key Fingerprint: SHA256:g/OyGvi2pcd8ub9mqge/ohmDP0fZX/xOPWPIcM+9XpI
8 changed files with 132 additions and 20 deletions

View File

@ -15,10 +15,12 @@
"clsx": "^2.1.1", "clsx": "^2.1.1",
"framer-motion": "^11.11.10", "framer-motion": "^11.11.10",
"json5": "^2.2.3", "json5": "^2.2.3",
"moment": "^2.30.1",
"normalize.css": "^8.0.1", "normalize.css": "^8.0.1",
"react": "^18.3.1", "react": "^18.3.1",
"react-dom": "^18.3.1", "react-dom": "^18.3.1",
"recoil": "^0.7.7", "recoil": "^0.7.7",
"strtime": "^1.1.2",
"styled-components": "^6.1.13", "styled-components": "^6.1.13",
"yaml": "^2.6.0" "yaml": "^2.6.0"
}, },

View File

@ -23,6 +23,9 @@ importers:
json5: json5:
specifier: ^2.2.3 specifier: ^2.2.3
version: 2.2.3 version: 2.2.3
moment:
specifier: ^2.30.1
version: 2.30.1
normalize.css: normalize.css:
specifier: ^8.0.1 specifier: ^8.0.1
version: 8.0.1 version: 8.0.1
@ -35,6 +38,9 @@ importers:
recoil: recoil:
specifier: ^0.7.7 specifier: ^0.7.7
version: 0.7.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1) version: 0.7.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
strtime:
specifier: ^1.1.2
version: 1.1.2
styled-components: styled-components:
specifier: ^6.1.13 specifier: ^6.1.13
version: 6.1.13(react-dom@18.3.1(react@18.3.1))(react@18.3.1) version: 6.1.13(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
@ -994,6 +1000,9 @@ packages:
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
engines: {node: '>=16 || 14 >=14.17'} engines: {node: '>=16 || 14 >=14.17'}
moment@2.30.1:
resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==}
monaco-editor@0.52.0: monaco-editor@0.52.0:
resolution: {integrity: sha512-OeWhNpABLCeTqubfqLMXGsqf6OmPU6pHM85kF3dhy6kq5hnhuVS1p3VrEW/XhWHc71P2tHyS5JFySD8mgs1crw==} resolution: {integrity: sha512-OeWhNpABLCeTqubfqLMXGsqf6OmPU6pHM85kF3dhy6kq5hnhuVS1p3VrEW/XhWHc71P2tHyS5JFySD8mgs1crw==}
@ -1269,6 +1278,9 @@ packages:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'} engines: {node: '>=8'}
strtime@1.1.2:
resolution: {integrity: sha512-FI4KG8T6kTckaD17M8MJrde8p/OVrVbfbXZV1Q5CUsBBuxkxtS3LZmWnGKC38lIZHKFJ7L6RU+fZ9GPuQgZEzQ==}
styled-components@6.1.13: styled-components@6.1.13:
resolution: {integrity: sha512-M0+N2xSnAtwcVAQeFEsGWFFxXDftHUD7XrKla06QbpUMmbmtFBMMTcKWvFXtWxuD5qQkB8iU5gk6QASlx2ZRMw==} resolution: {integrity: sha512-M0+N2xSnAtwcVAQeFEsGWFFxXDftHUD7XrKla06QbpUMmbmtFBMMTcKWvFXtWxuD5qQkB8iU5gk6QASlx2ZRMw==}
engines: {node: '>= 16'} engines: {node: '>= 16'}
@ -2169,6 +2181,8 @@ snapshots:
dependencies: dependencies:
brace-expansion: 2.0.1 brace-expansion: 2.0.1
moment@2.30.1: {}
monaco-editor@0.52.0: {} monaco-editor@0.52.0: {}
ms@2.1.3: {} ms@2.1.3: {}
@ -2422,6 +2436,8 @@ snapshots:
strip-json-comments@3.1.1: {} strip-json-comments@3.1.1: {}
strtime@1.1.2: {}
styled-components@6.1.13(react-dom@18.3.1(react@18.3.1))(react@18.3.1): styled-components@6.1.13(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies: dependencies:
'@emotion/is-prop-valid': 1.2.2 '@emotion/is-prop-valid': 1.2.2

View File

@ -16,7 +16,7 @@ export const Editor: FC = () => {
loading={<></>} loading={<></>}
value={value} value={value}
language="yaml" language="yaml"
onChange={(v) => setValue(v?.trim() ?? '')} onChange={(v) => setValue(v ?? '')}
options={{ options={{
automaticLayout: true, automaticLayout: true,
lineNumbersMinChars: 3, lineNumbersMinChars: 3,

View File

@ -7,11 +7,9 @@ import clsx from "clsx";
import { useRecoilState } from "recoil"; import { useRecoilState } from "recoil";
import { EditorValueState } from "../GlobalStates/EditorValueState"; import { EditorValueState } from "../GlobalStates/EditorValueState";
import { import {
isTransformCheckboxOption,
isTransformIntboxOption,
isTransformTextboxOption,
TransformCheckboxOption, TransformCheckboxOption,
TransformIntboxOption, TransformIntboxOption,
TransformRadioOption,
TransformTextboxOption, TransformTextboxOption,
WrappedTransform, WrappedTransform,
WrappedTransformResult WrappedTransformResult
@ -71,6 +69,18 @@ export const TransformGridItem: FC<TransformGridItemProp> = ({ transform }) => {
setOptions(new Map(options)) setOptions(new Map(options))
} }
const onRadioOptionChanged =
(option: TransformRadioOption) =>
(event: ChangeEvent<HTMLInputElement>) => {
options.set(option.key, {
...option,
value: event.target.value
})
setOptions(new Map(options))
}
const onForwardButtonPressed = () => { const onForwardButtonPressed = () => {
if (result.error) if (result.error)
@ -90,7 +100,7 @@ export const TransformGridItem: FC<TransformGridItemProp> = ({ transform }) => {
<div className={style.options}> <div className={style.options}>
{[...options.values()] {[...options.values()]
?.filter(isTransformCheckboxOption) ?.filter((v) => v.type === 'CHECKBOX')
.map((option, i) => ( .map((option, i) => (
<label key={i} className={style.optionItem}> <label key={i} className={style.optionItem}>
<p>{option.label ?? option.key}:</p> <p>{option.label ?? option.key}:</p>
@ -102,7 +112,7 @@ export const TransformGridItem: FC<TransformGridItemProp> = ({ transform }) => {
</label>))} </label>))}
{[...options.values()] {[...options.values()]
?.filter(isTransformTextboxOption) ?.filter((v) => v.type === 'TEXTBOX')
.map((option, i) => ( .map((option, i) => (
<label key={i} className={style.optionItem}> <label key={i} className={style.optionItem}>
<p>{option.label ?? option.key}:</p> <p>{option.label ?? option.key}:</p>
@ -115,7 +125,7 @@ export const TransformGridItem: FC<TransformGridItemProp> = ({ transform }) => {
{[...options.values()] {[...options.values()]
?.filter(isTransformIntboxOption) ?.filter((v) => v.type === 'INTBOX')
.map((option, i) => ( .map((option, i) => (
<label key={i} className={style.optionItem}> <label key={i} className={style.optionItem}>
<p>{option.label ?? option.key}:</p> <p>{option.label ?? option.key}:</p>
@ -126,6 +136,31 @@ export const TransformGridItem: FC<TransformGridItemProp> = ({ transform }) => {
onChange={onIntboxOptionChanged(option)} onChange={onIntboxOptionChanged(option)}
type="number" /> type="number" />
</label>))} </label>))}
{[...options.values()]
?.filter((v) => v.type === 'RADIO')
.map((option, i) => (
<div
key={i}
onChange={onRadioOptionChanged(option)}
className={style.optionItem}>
<p>{option.label ?? option.key}:</p>
{option.radios.map((radio, i2) => (
<label key={i2}>
<p>{radio.label ?? radio.value}:</p>
<Input
min={1}
name={option.key}
defaultChecked={radio.value === option.value}
value={radio.value}
type="radio" />
</label>
))}
</div>))}
</div> </div>
</div> </div>

View File

@ -30,7 +30,7 @@
scrollbar-color: gray #323232; scrollbar-color: gray #323232;
align-items: center; align-items: center;
.optionItem { * {
display: flex; display: flex;
gap: 6px; gap: 6px;
} }

View File

@ -0,0 +1,50 @@
import { Transform } from "./Transform";
import { strptime } from 'strtime'
import moment from "moment";
export const DatetimeTransform: Transform = {
name: 'datetime',
fn: async (v, o) => {
const [expression, samples] = v.split('\n\n')
const format = o.get('f')?.value
const parsedSamples = samples
.split('\n')
.map((sample) => {
if (format === 'c')
return strptime(sample, expression.replace(/'/g, ''))
if (format === 'java')
return moment(sample, expression.replace(/'/g, '')).toDate()
throw new Error('Unknown Format')
})
.map((date) => JSON.stringify({
year: date.getFullYear(),
month: date.getMonth() + 1,
date: date.getDate(),
hour: date.getHours(),
minute: date.getMinutes(),
second: date.getSeconds(),
milli: date.getMilliseconds()
}))
.join('\n')
return [
expression,
samples,
parsedSamples
].join('\n\n')
},
options: [{
type: 'RADIO',
key: 'f',
value: 'c',
radios: [
{ value: 'c' },
{ value: 'java' }
]
}]
}

View File

@ -1,4 +1,5 @@
import { Base64DecodeTransform, Base64EncodeTransform } from "./Base64Transforms" import { Base64DecodeTransform, Base64EncodeTransform } from "./Base64Transforms"
import { DatetimeTransform } from "./DatetimeTransforms"
import { GzipDecompressTransform } from "./GzipTransform" import { GzipDecompressTransform } from "./GzipTransform"
import { JSONBeautifyTransform, JSONEscapeTransform, JSONSimplifyTransform, JSONUnescapeTransform } from "./JSONTransforms" import { JSONBeautifyTransform, JSONEscapeTransform, JSONSimplifyTransform, JSONUnescapeTransform } from "./JSONTransforms"
import { RegexpTransform } from "./RegexpTransform" import { RegexpTransform } from "./RegexpTransform"
@ -27,17 +28,20 @@ export interface TransformIntboxOption {
value?: number value?: number
} }
export interface TransformRadioOption {
type: 'RADIO',
key: string,
label?: string,
value?: string,
radios: {
label?: string
value: string
}[]
}
export type TransformOption = export type TransformOption =
TransformCheckboxOption | TransformTextboxOption | TransformIntboxOption TransformCheckboxOption | TransformTextboxOption |
TransformIntboxOption | TransformRadioOption
export const isTransformCheckboxOption = (object: any): object is TransformCheckboxOption =>
object.type === 'CHECKBOX'
export const isTransformTextboxOption = (object: any): object is TransformTextboxOption =>
object.type === 'TEXTBOX'
export const isTransformIntboxOption = (object: any): object is TransformIntboxOption =>
object.type === 'INTBOX'
export interface Transform { export interface Transform {
name: string name: string
@ -77,7 +81,7 @@ export const wrapTransform = (transform: Transform): WrappedTransform => ({
export const transforms: Transform[] = [ export const transforms: Transform[] = [
RegexpTransform, RegexpTransform,
GzipDecompressTransform, DatetimeTransform,
Base64DecodeTransform, Base64DecodeTransform,
Base64EncodeTransform, Base64EncodeTransform,
URIDecodeTransform, URIDecodeTransform,
@ -87,5 +91,6 @@ export const transforms: Transform[] = [
JSONEscapeTransform, JSONEscapeTransform,
JSONUnescapeTransform, JSONUnescapeTransform,
JSON2YAMLTransform, JSON2YAMLTransform,
YAML2JSONTransform YAML2JSONTransform,
GzipDecompressTransform
] ]

4
src/vite-env.d.ts vendored
View File

@ -1 +1,5 @@
/// <reference types="vite/client" /> /// <reference types="vite/client" />
module 'strtime' {
function strptime (string, string): Date
}