Create run dialog

This commit is contained in:
Takeshi Kimata
2024-05-26 22:02:14 +09:00
parent 1bab870239
commit 5ae4417c23
8 changed files with 219 additions and 40 deletions

View File

@@ -200,15 +200,22 @@
},
"Runs": {
"run_list": "Test Run List",
"run": "Run",
"new_run": "New Run",
"edit_run": "Edit Run",
"delete_run": "Delete Run",
"id": "ID",
"name": "Name",
"description": "Description",
"last_update": "Last update",
"actions": "Actions",
"new_run": "New Run",
"delete_run": "Delete Run",
"run_name": "Run name",
"run_description": "Run description",
"no_runs_found": "No runs found",
"close": "Close",
"create": "Create",
"update": "Update",
"please_enter": "Please enter run name",
"are_you_sure": "Are you sure you want to delete the run?",
"delete": "Delete"
},

View File

@@ -199,15 +199,22 @@
},
"Runs": {
"run_list": "テストラン一覧",
"run": "テストラン",
"new_run": "新規テストラン",
"edit_run": "テストランを編集",
"delete_run": "テストランを削除",
"id": "ID",
"name": "名前",
"description": "詳細",
"last_update": "最終更新",
"actions": "アクション",
"new_run": "新規テストラン",
"delete_run": "テストランを削除",
"run_name": "テストラン",
"run_description": "テストラン詳細",
"no_runs_found": "テストランがありません",
"close": "閉じる",
"create": "作成",
"update": "更新",
"please_enter": "テストラン名を入力してください",
"are_you_sure": "テストランを削除してもよろしいですか?",
"delete": "削除"
},

View File

@@ -25,13 +25,13 @@ type Props = {
export default function ProjectDialog({ isOpen, editingProject, onCancel, onSubmit, messages }: Props) {
const [projectName, setProjectName] = useState({
text: editingProject ? editingProject.name : '',
isValid: false,
isInvalid: false,
errorMessage: '',
});
const [projectDetail, setProjectDetail] = useState({
text: editingProject ? editingProject.detail : '',
isValid: false,
isInvalid: false,
errorMessage: '',
});
@@ -67,12 +67,12 @@ export default function ProjectDialog({ isOpen, editingProject, onCancel, onSubm
const clear = () => {
setProjectName({
isValid: false,
isInvalid: false,
text: '',
errorMessage: '',
});
setProjectDetail({
isValid: false,
isInvalid: false,
text: '',
errorMessage: '',
});
@@ -82,7 +82,7 @@ export default function ProjectDialog({ isOpen, editingProject, onCancel, onSubm
if (!projectName.text) {
setProjectName({
text: '',
isValid: false,
isInvalid: true,
errorMessage: messages.pleaseEnter,
});
@@ -107,7 +107,7 @@ export default function ProjectDialog({ isOpen, editingProject, onCancel, onSubm
type="text"
label={messages.projectName}
value={projectName.text}
isInvalid={projectName.isValid}
isInvalid={projectName.isInvalid}
errorMessage={projectName.errorMessage}
onChange={(e) => {
setProjectName({
@@ -119,7 +119,7 @@ export default function ProjectDialog({ isOpen, editingProject, onCancel, onSubm
<Textarea
label={messages.projectDetail}
value={projectDetail.text}
isInvalid={projectDetail.isValid}
isInvalid={projectDetail.isInvalid}
errorMessage={projectDetail.errorMessage}
onChange={(e) => {
setProjectDetail({

View File

@@ -0,0 +1,127 @@
'use client';
import React from 'react';
import { useState, useEffect } from 'react';
import { Button, Input, Textarea, Modal, ModalContent, ModalHeader, ModalBody, ModalFooter } from '@nextui-org/react';
import { RunType, RunsMessages } from '@/types/run';
type Props = {
isOpen: boolean;
editingRun: RunType | null;
onCancel: () => void;
onSubmit: (name: string, description: string) => void;
messages: RunsMessages;
};
export default function RunDialog({ isOpen, editingRun, onCancel, onSubmit, messages }: Props) {
const [runName, setRunName] = useState({
text: editingRun ? editingRun.name : '',
isInvalid: false,
errorMessage: '',
});
const [runDescription, setRunDescription] = useState({
text: editingRun ? editingRun.description : '',
isInvalid: false,
errorMessage: '',
});
useEffect(() => {
if (editingRun) {
setRunName({
...runName,
text: editingRun.name,
});
setRunDescription({
...runDescription,
text: editingRun.description ? editingRun.description : '',
});
} else {
setRunName({
...runName,
text: '',
});
setRunDescription({
...runDescription,
text: '',
});
}
}, [editingRun]);
const clear = () => {
setRunName({
isInvalid: false,
text: '',
errorMessage: '',
});
setRunDescription({
isInvalid: false,
text: '',
errorMessage: '',
});
};
const validate = () => {
if (!runName.text) {
setRunName({
text: '',
isInvalid: true,
errorMessage: messages.pleaseEnter,
});
return;
}
onSubmit(runName.text, runDescription.text);
clear();
};
return (
<Modal
isOpen={isOpen}
onOpenChange={() => {
onCancel();
}}
>
<ModalContent>
<ModalHeader className="flex flex-col gap-1">{messages.run}</ModalHeader>
<ModalBody>
<Input
type="text"
label={messages.runName}
value={runName.text}
isInvalid={runName.isInvalid}
errorMessage={runName.errorMessage}
onChange={(e) => {
setRunName({
...runName,
text: e.target.value,
});
}}
/>
<Textarea
label={messages.runDescription}
value={runDescription.text}
isInvalid={runDescription.isInvalid}
errorMessage={runDescription.errorMessage}
onChange={(e) => {
setRunDescription({
...runDescription,
text: e.target.value,
});
}}
/>
</ModalBody>
<ModalFooter>
<Button variant="light" onPress={onCancel}>
{messages.close}
</Button>
<Button color="primary" onPress={validate}>
{editingRun && editingRun.createdAt ? messages.update : messages.create}
</Button>
</ModalFooter>
</ModalContent>
</Modal>
);
}

View File

@@ -3,8 +3,9 @@ import { useEffect, useState } from 'react';
import { Button } from '@nextui-org/react';
import { Plus } from 'lucide-react';
import RunsTable from './RunsTable';
import { fetchRuns, createRun, deleteRun } from './runsControl';
import { RunsMessages } from '@/types/run';
import { fetchRuns, createRun, updateRun, deleteRun } from './runsControl';
import { RunType, RunsMessages } from '@/types/run';
import RunDialog from './RunDialog';
import DeleteConfirmDialog from '@/components/DeleteConfirmDialog';
type Props = {
@@ -13,9 +14,33 @@ type Props = {
messages: RunsMessages;
};
const defaultRun = {
id: null,
name: 'Untitled Run',
configurations: null,
description: null,
state: null,
projectId: null,
createdAt: null,
updatedAt: null,
};
export default function RunsPage({ projectId, locale, messages }: Props) {
const [runs, setRuns] = useState([]);
// run dialog
const [isRunDialogOpen, setIsRunDialogOpen] = useState(false);
const [editingRun, setEditingRun] = useState<RunType | null>(null);
const openDialogForCreate = () => {
setIsRunDialogOpen(true);
setEditingRun(defaultRun);
};
const closeDialog = () => {
setIsRunDialogOpen(false);
setEditingRun(null);
};
// delete confirm dialog
const [isDeleteConfirmDialogOpen, setIsDeleteConfirmDialogOpen] = useState(false);
const [deleteRunId, setDeleteRunId] = useState<number | null>(null);
@@ -37,27 +62,18 @@ export default function RunsPage({ projectId, locale, messages }: Props) {
fetchDataEffect();
}, []);
const onCreateClick = async () => {
try {
const newRun = await createRun(projectId);
const updateRuns = [...runs];
updateRuns.push(newRun);
setRuns(updateRuns);
} catch (error: any) {
console.error('Error deleting run:', error);
const onSubmit = async (name: string, description: string) => {
if (editingRun && editingRun.createdAt) {
const updatedRun = await updateRun(editingRun);
const updatedRuns = runs.map((run) => (run.id === updatedRun.id ? updatedRun : run));
setRuns(updatedRuns);
} else {
const newRun = await createRun(projectId, name, description);
setRuns([...runs, newRun]);
}
closeDialog();
};
// const onDeleteClick = async (runId: number) => {
// try {
// await deleteRun(runId);
// const data = await fetchRuns(projectId);
// setRuns(data);
// } catch (error: any) {
// console.error('Error deleting run:', error);
// }
// };
const onDeleteClick = (runId: number) => {
setDeleteRunId(runId);
setIsDeleteConfirmDialogOpen(true);
@@ -76,7 +92,7 @@ export default function RunsPage({ projectId, locale, messages }: Props) {
<div className="w-full p-3 flex items-center justify-between">
<h3 className="font-bold">{messages.runList}</h3>
<div>
<Button startContent={<Plus size={16} />} size="sm" color="primary" onClick={onCreateClick}>
<Button startContent={<Plus size={16} />} size="sm" color="primary" onClick={openDialogForCreate}>
{messages.newRun}
</Button>
</div>
@@ -84,6 +100,14 @@ export default function RunsPage({ projectId, locale, messages }: Props) {
<RunsTable projectId={projectId} runs={runs} onDeleteRun={onDeleteClick} messages={messages} locale={locale} />
<RunDialog
isOpen={isRunDialogOpen}
editingRun={editingRun}
onCancel={closeDialog}
onSubmit={onSubmit}
messages={messages}
/>
<DeleteConfirmDialog
isOpen={isDeleteConfirmDialogOpen}
onCancel={closeDeleteConfirmDialog}

View File

@@ -5,15 +5,22 @@ export default function Page({ params }: { params: { projectId: string; locale:
const t = useTranslations('Runs');
const messages = {
runList: t('run_list'),
run: t('run'),
editRun: t('edit_run'),
newRun: t('new_run'),
deleteRun: t('delete_run'),
id: t('id'),
name: t('name'),
description: t('description'),
lastUpdate: t('last_update'),
actions: t('actions'),
newRun: t('new_run'),
deleteRun: t('delete_run'),
runName: t('run_name'),
runDescription: t('run_description'),
noRunsFound: t('no_runs_found'),
close: t('close'),
create: t('create'),
update: t('update'),
pleaseEnter: t('please_enter'),
areYouSure: t('are_you_sure'),
delete: t('delete'),
};

View File

@@ -46,11 +46,11 @@ async function fetchRuns(projectId: string) {
}
}
async function createRun(projectId: string) {
async function createRun(projectId: string, name: string, description: string) {
const newTestRun = {
name: 'untitled run',
name,
configurations: 0,
description: '',
description,
state: 0,
projectId: projectId,
};

View File

@@ -33,15 +33,22 @@ type ProgressSeriesType = {
type RunsMessages = {
runList: string;
run: string;
newRun: string;
editRun: string;
deleteRun: string;
id: string;
name: string;
description: string;
lastUpdate: string;
actions: string;
newRun: string;
deleteRun: string;
noRunsFound: string;
runName: string;
runDescription: string;
close: string;
create: string;
update: string;
pleaseEnter: string;
noRunsFound: string;
areYouSure: string;
delete: string;
};