Skip to content

Commit

Permalink
add Validate
Browse files Browse the repository at this point in the history
  • Loading branch information
satoshi7190 committed Jun 11, 2024
1 parent a375897 commit 6d20865
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 98 deletions.
44 changes: 29 additions & 15 deletions app/src/lib/parameters.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,33 @@
export type ParameterType = 'Integer' | 'String' | 'Boolean';
interface IntegerParameter {
Integer: {
value: number;
min?: number;
max?: number;
};
}

export type ParameterOption<T extends ParameterType> = T extends 'Integer'
? { Integer: { value: number; min: number; max: number } }
: T extends 'String'
? { String: { value: string } }
: T extends 'Boolean'
? { Boolean: { value: boolean } }
: never;
interface StringParameter {
String: {
value: string;
};
}

export type ParameterEntry<T extends ParameterType> = {
interface BooleanParameter {
Boolean: {
value: boolean;
};
}

// TODO - In practice, use as IntegerParameter | StringParameter | BooleanParameter
type Parameter = IntegerParameter & StringParameter & BooleanParameter;

interface ParamsOptionItem {
parameter: Parameter;
description: string;
required: string;
parameter: ParameterOption<T>;
};
}

export type Parameters = {
items: { [key: string]: ParameterEntry<ParameterType> };
};
export interface ParamsOption {
items: {
[key: string]: ParamsOptionItem;
};
}
9 changes: 3 additions & 6 deletions app/src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { invoke } from '@tauri-apps/api/tauri';
import { attachConsole } from 'tauri-plugin-log-api';
import { message } from '@tauri-apps/api/dialog';
import type { Parameters } from '$lib/parameters';
import type { ParamsOption } from '$lib/parameters';
import Icon from '@iconify/svelte';
import InputSelector from './InputSelector.svelte';
Expand All @@ -12,15 +12,12 @@
attachConsole(); // For Tauri log in the webview console
let paramsOption = {} as Parameters;
let inputPaths: string[] = [];
let filetype: string;
let epsg: number;
let rulesPath = '';
let outputPath = '';
let paramsOption = {} as ParamsOption;
let isRunning = false;
async function convertAndSave() {
Expand All @@ -43,7 +40,7 @@
filetype,
epsg,
rulesPath,
paramsOption
paramsOption
});
isRunning = false;
await message(`変換が完了しました。\n'${outputPath}' に出力しました。`, { type: 'info' });
Expand Down
171 changes: 94 additions & 77 deletions app/src/routes/SettingSelector.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@
import { dialog } from '@tauri-apps/api';
import Icon from '@iconify/svelte';
import { filetypeOptions } from '$lib/settings';
import { invoke } from '@tauri-apps/api/tauri';
import type { Parameters, ParameterType } from '$lib/parameters';
import { invoke } from '@tauri-apps/api/tauri';
import type { ParamsOption } from '$lib/parameters';
export let filetype: string;
export let epsg: number = 4979;
export let rulesPath: string;
export let paramsOption: Parameters;
export let paramsOption: ParamsOption;
let debug: any;
let optionParameter: string[] = [];
let debug: any; // NOTE debug
let optionParameter: string[] = [];
$: epsgOptions = filetypeOptions[filetype]?.epsg || [];
$: disableEpsgOptions = epsgOptions.length < 2;
Expand All @@ -23,24 +23,17 @@
}
}
async function setOptionParameter(filetype: string) {
const parameters = await invoke('get_parameter', { filetype }) as Parameters;
// '@output'を除外
// delete parameters.items["@output"];
const keys = Object.keys(parameters.items).filter(item => item !== '@output');
// Get the parameter options for the selected filetype
async function setOptionParameter(filetype: string) {
const parameters = (await invoke('get_parameter', { filetype })) as ParamsOption;
// if (keys.length === 0) {
// optionParameter = [];
// return;
// }
optionParameter = keys;
paramsOption = parameters
debug = parameters
}
// Exclude '@output'
optionParameter = Object.keys(parameters.items).filter((item) => item !== '@output');
paramsOption = parameters;
debug = parameters;
}
$:setOptionParameter(filetype);
$: setOptionParameter(filetype);
async function openRulesPathDialog() {
const res = await dialog.open({
Expand All @@ -59,36 +52,46 @@
rulesPath = '';
}
// 型ガード関数
function isIntegerParameter(parameter: any): parameter is { Integer: { value: number; min: number; max: number; } } {
return (parameter as { Integer?: unknown }).Integer !== undefined;
}
function isStringParameter(parameter: any): parameter is { String: { value: string; } } {
return (parameter as { String?: unknown }).String !== undefined;
}
function isBooleanParameter(parameter: any): parameter is { Boolean: { value: boolean; } } {
return (parameter as { Boolean?: unknown }).Boolean !== undefined;
}
// ParameterTypeの型を取得
function getParameterType(key: string): ParameterType {
const parameter = paramsOption.items[key].parameter;
if (isIntegerParameter(parameter)) return "Integer";
if (isStringParameter(parameter)) return "String";
if (isBooleanParameter(parameter)) return "Boolean";
throw new Error("Unknown parameter type");
}
// async function test() {
// await invoke ('set_parameter', {paramsOption});
// }
// Check the parameter type
function isIntegerParameter(
parameter: any
): parameter is { Integer: { value: number; min: number; max: number } } {
return (parameter as { Integer?: unknown }).Integer !== undefined;
}
function isStringParameter(parameter: any): parameter is { String: { value: string } } {
return (parameter as { String?: unknown }).String !== undefined;
}
function isBooleanParameter(parameter: any): parameter is { Boolean: { value: boolean } } {
return (parameter as { Boolean?: unknown }).Boolean !== undefined;
}
// Validate the input value
function validateInput(event: any) {
const input = event.target.value;
const validInput = input.replace(/[^0-9]/g, '');
const param = paramsOption.items[event.target.id].parameter.Integer;
if (validInput === '') {
paramsOption.items[event.target.id].parameter.Integer.value = validInput;
return;
}
const numValue = Number(validInput);
if (
(param.min === undefined || numValue >= param.min) &&
(param.max === undefined || numValue <= param.max)
) {
paramsOption.items[event.target.id].parameter.Integer.value = validInput;
} else {
event.target.value = paramsOption.items[event.target.id].parameter.Integer.value;
}
}
</script>

{#if debug}
<p>{JSON.stringify(debug)}</p>
<p>{JSON.stringify(debug)}</p>
{/if}
<!-- <button on:click={test}>test</button> -->

<div>
<div class="flex items-center gap-1.5">
<Icon class="text-xl" icon="material-symbols:settings" />
Expand All @@ -106,35 +109,49 @@
</select>
</div>

{#if optionParameter.length > 0}
<div class="flex flex-col gap-1.5">
<label for="epsg-select" class="font-bold">出力オプション</label>
<div>
{#each optionParameter as key}
<!-- Integerの場合 -->
{#if getParameterType(key) === 'Integer'}
<div class="flex gap-2 w-80">
<label for={key} class="w-3/4">{paramsOption.items[key].description}</label>
<input type="number" id={key} min={paramsOption.items[key].parameter.Integer.min} max={paramsOption.items[key].parameter.Integer.max} bind:value={paramsOption.items[key].parameter.Integer.value} class="w-1/4"/>
</div>
{:else if getParameterType(key) === 'String'}
<!-- Stringの場合 -->
<div class="flex gap-2 w-80">
<label for={key} class="w-3/4">{paramsOption.items[key].description}</label>
<input type="text" id={key} bind:value={paramsOption.items[key].parameter.String.value} class="w-1/4"/>
</div>
{:else if getParameterType(key) === 'Boolean'}
<!-- Booleanの場合 -->
<div class="flex gap-2 w-80">
<label for={key} class="w-3/4">{paramsOption.items[key].description}</label>
<input type="checkbox" id={key} bind:checked={paramsOption.items[key].parameter.Boolean.value} class="w-1/4"/>
</div>
{/if}
{/each}

</div>
</div>
{/if}
{#if optionParameter.length > 0}
<div class="flex flex-col gap-1.5">
<label for="epsg-select" class="font-bold">出力オプション</label>
<div>
{#each optionParameter as key}
{#if isIntegerParameter(paramsOption.items[key].parameter)}
<div class="flex gap-2 w-80">
<label for={key} class="w-3/4">{paramsOption.items[key].description}</label>
<input
type="number"
id={key}
on:input={validateInput}
min={paramsOption.items[key].parameter.Integer.min ?? undefined}
max={paramsOption.items[key].parameter.Integer.max ?? undefined}
bind:value={paramsOption.items[key].parameter.Integer.value}
class="w-1/4"
/>
</div>
{:else if isStringParameter(paramsOption.items[key].parameter)}
<div class="flex gap-2 w-80">
<label for={key} class="w-3/4">{paramsOption.items[key].description}</label>
<input
type="text"
id={key}
bind:value={paramsOption.items[key].parameter.String.value}
class="w-1/4"
/>
</div>
{:else if isBooleanParameter(paramsOption.items[key].parameter)}
<div class="flex gap-2 w-80">
<label for={key} class="w-3/4">{paramsOption.items[key].description}</label>
<input
type="checkbox"
id={key}
bind:checked={paramsOption.items[key].parameter.Boolean.value}
class="w-1/4"
/>
</div>
{/if}
{/each}
</div>
</div>
{/if}

<div class="flex flex-col gap-1.5">
<label for="epsg-select" class="font-bold">座標参照系</label>
Expand Down

0 comments on commit 6d20865

Please sign in to comment.