diff --git a/-t b/-t new file mode 100644 index 0000000..e69de29 diff --git a/components.d.ts b/components.d.ts index de754fc..ae69cfe 100644 --- a/components.d.ts +++ b/components.d.ts @@ -9,18 +9,28 @@ export {} declare module 'vue' { export interface GlobalComponents { AppFooter: typeof import('./src/components/AppFooter.vue')['default'] + CompareComponent: typeof import('./src/components/run/executions/CompareComponent.vue')['default'] + DeploymentDialog: typeof import('./src/components/atoms/organisms/DeploymentDialog.vue')['default'] DrawerComponent: typeof import('./src/components/common/DrawerComponent.vue')['default'] - FormComponent: typeof import('./src/components/run/experiment/FormComponent.vue')['default'] + ExecutionBaseDialog: typeof import('./src/components/atoms/organisms/ExecutionBaseDialog.vue')['default'] + ExperimentCreateDialog: typeof import('./src/components/atoms/organisms/ExperimentCreateDialog.vue')['default'] HelloWorld: typeof import('./src/components/HelloWorld.vue')['default'] + IconArrowDown: typeof import('./src/components/button/IconArrowDown.vue')['default'] + IconArrowUp: typeof import('./src/components/button/IconArrowUp.vue')['default'] IconDeleteBtn: typeof import('./src/components/button/IconDeleteBtn.vue')['default'] + IconDeployment: typeof import('./src/components/button/IconDeployment.vue')['default'] IconDownloadBtn: typeof import('./src/components/button/IconDownloadBtn.vue')['default'] IconInfoBtn: typeof import('./src/components/button/IconInfoBtn.vue')['default'] IconModifyBtn: typeof import('./src/components/button/IconModifyBtn.vue')['default'] IconSettingBtn: typeof import('./src/components/button/IconSettingBtn.vue')['default'] LayoutComponent: typeof import('./src/components/common/LayoutComponent.vue')['default'] - ListComponent: typeof import('./src/components/home/ListComponent.vue')['default'] + ListComponent: typeof import('./src/components/deployment/ListComponent.vue')['default'] RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] - ViewComponent: typeof import('./src/components/run/executions/ViewComponent.vue')['default'] + StapComfigDialog: typeof import('./src/components/atoms/organisms/StapComfigDialog.vue')['default'] + ViewComponent: typeof import('./src/components/deployment/ViewComponent.vue')['default'] + WorkflowDialog: typeof import('./src/components/atoms/organisms/WorkflowDialog.vue')['default'] + WorkflowsCreateDialog: typeof import('./src/components/atoms/organisms/WorkflowsCreateDialog.vue')['default'] + WorkflowsUploadDialog: typeof import('./src/components/atoms/organisms/WorkflowsUploadDialog.vue')['default'] } } diff --git a/index.html b/index.html index 0a84a1c..fe35a37 100644 --- a/index.html +++ b/index.html @@ -1,9 +1,9 @@ - + - - - + + + Welcome to Vuetify 3 diff --git a/src/components/atoms/organisms/DeploymentDialog.vue b/src/components/atoms/organisms/DeploymentDialog.vue new file mode 100644 index 0000000..319220d --- /dev/null +++ b/src/components/atoms/organisms/DeploymentDialog.vue @@ -0,0 +1,168 @@ + + + diff --git a/src/components/atoms/organisms/ExecutionBaseDialog.vue b/src/components/atoms/organisms/ExecutionBaseDialog.vue new file mode 100644 index 0000000..d2c93c5 --- /dev/null +++ b/src/components/atoms/organisms/ExecutionBaseDialog.vue @@ -0,0 +1,161 @@ + + + diff --git a/src/components/atoms/organisms/ExperimentCreateDialog.vue b/src/components/atoms/organisms/ExperimentCreateDialog.vue new file mode 100644 index 0000000..53e3c9a --- /dev/null +++ b/src/components/atoms/organisms/ExperimentCreateDialog.vue @@ -0,0 +1,71 @@ + + + diff --git a/src/components/atoms/organisms/StapComfigDialog.vue b/src/components/atoms/organisms/StapComfigDialog.vue new file mode 100644 index 0000000..aefed39 --- /dev/null +++ b/src/components/atoms/organisms/StapComfigDialog.vue @@ -0,0 +1,100 @@ + + + diff --git a/src/components/atoms/organisms/WorkflowDialog.vue b/src/components/atoms/organisms/WorkflowDialog.vue new file mode 100644 index 0000000..5d58c02 --- /dev/null +++ b/src/components/atoms/organisms/WorkflowDialog.vue @@ -0,0 +1,100 @@ + + + diff --git a/src/components/atoms/organisms/WorkflowsCreateDialog.vue b/src/components/atoms/organisms/WorkflowsCreateDialog.vue new file mode 100644 index 0000000..21395c8 --- /dev/null +++ b/src/components/atoms/organisms/WorkflowsCreateDialog.vue @@ -0,0 +1,152 @@ + + + diff --git a/src/components/atoms/organisms/WorkflowsUploadDialog.vue b/src/components/atoms/organisms/WorkflowsUploadDialog.vue new file mode 100644 index 0000000..9068924 --- /dev/null +++ b/src/components/atoms/organisms/WorkflowsUploadDialog.vue @@ -0,0 +1,89 @@ + + + diff --git a/src/components/button/IconArrowDown.vue b/src/components/button/IconArrowDown.vue new file mode 100644 index 0000000..9b766fc --- /dev/null +++ b/src/components/button/IconArrowDown.vue @@ -0,0 +1,26 @@ + + + diff --git a/src/components/button/IconArrowUp.vue b/src/components/button/IconArrowUp.vue new file mode 100644 index 0000000..70abe44 --- /dev/null +++ b/src/components/button/IconArrowUp.vue @@ -0,0 +1,26 @@ + + + diff --git a/src/components/button/IconDeployment.vue b/src/components/button/IconDeployment.vue new file mode 100644 index 0000000..e9aa00f --- /dev/null +++ b/src/components/button/IconDeployment.vue @@ -0,0 +1,26 @@ + + + diff --git a/src/components/button/IconSettingBtn.vue b/src/components/button/IconSettingBtn.vue index 858592f..3512465 100644 --- a/src/components/button/IconSettingBtn.vue +++ b/src/components/button/IconSettingBtn.vue @@ -15,7 +15,7 @@ const onClick = () => { @click="onClick" class="ma-1" icon="mdi-cog-play-outline" - color="info" + color="success" density="comfortable" elevation="0" size="small" diff --git a/src/components/deployment/ListComponent.vue b/src/components/deployment/ListComponent.vue new file mode 100644 index 0000000..a25e235 --- /dev/null +++ b/src/components/deployment/ListComponent.vue @@ -0,0 +1,551 @@ + + + + + diff --git a/src/components/deployment/ViewComponent.vue b/src/components/deployment/ViewComponent.vue new file mode 100644 index 0000000..8095b72 --- /dev/null +++ b/src/components/deployment/ViewComponent.vue @@ -0,0 +1,397 @@ + + + + + diff --git a/src/components/home/ListComponent.vue b/src/components/home/ListComponent.vue index de25302..800484a 100644 --- a/src/components/home/ListComponent.vue +++ b/src/components/home/ListComponent.vue @@ -97,7 +97,9 @@ const data = ref({ allSelected: false, selected: [], }); - +const handleRefresh = () => { + alert("Refresh 작업 진행중..."); +}; const getSelectedAllData = () => { data.value.selected = data.value.allSelected ? data.value.results.map(({ deviceKey }) => ({ deviceKey })) @@ -109,7 +111,9 @@ const getSelectedAllData = () => {

배터리 상태 예측 모델 프로젝트

- Refresh + Refresh
diff --git a/src/components/run/executions/CompareComponent.vue b/src/components/run/executions/CompareComponent.vue new file mode 100644 index 0000000..b41ad54 --- /dev/null +++ b/src/components/run/executions/CompareComponent.vue @@ -0,0 +1,526 @@ + + + + + diff --git a/src/components/run/executions/ListComponent.vue b/src/components/run/executions/ListComponent.vue index c0702d1..109122b 100644 --- a/src/components/run/executions/ListComponent.vue +++ b/src/components/run/executions/ListComponent.vue @@ -1,11 +1,13 @@ diff --git a/src/components/run/experiment/FormComponent.vue b/src/components/run/experiment/FormComponent.vue deleted file mode 100644 index 4b3d387..0000000 --- a/src/components/run/experiment/FormComponent.vue +++ /dev/null @@ -1,73 +0,0 @@ - - - diff --git a/src/components/run/experiment/ListComponent.vue b/src/components/run/experiment/ListComponent.vue index 7eed1b7..ca57368 100644 --- a/src/components/run/experiment/ListComponent.vue +++ b/src/components/run/experiment/ListComponent.vue @@ -2,8 +2,9 @@ import IconDeleteBtn from "@/components/button/IconDeleteBtn.vue"; import IconInfoBtn from "@/components/button/IconInfoBtn.vue"; import { onMounted, ref, watch } from "vue"; -import FormComponent from "@/components/run/experiment/FormComponent.vue"; + import ViewComponent from "@/components/run/experiment/ViewComponent.vue"; +import ExperimentCreateDialog from "@/components/atoms/organisms/ExperimentCreateDialog.vue"; // const store = commonStore(); const detailDialog = ref(false); @@ -471,7 +472,7 @@ onMounted(() => {
- +import IconDeleteBtn from "@/components/button/IconDeleteBtn.vue"; +import IconModifyBtn from "@/components/button/IconModifyBtn.vue"; +import IconInfoBtn from "@/components/button/IconInfoBtn.vue"; +// import FormComponent from "@/components/device/FormComponent.vue"; +import { onMounted, ref, watch } from "vue"; +import ViewComponent from "@/components/stepconfig/ViewComponent.vue"; +import StapComfigDialog from "@/components/atoms/organisms/StapComfigDialog.vue"; +// const store = commonStore(); + +const openView = ref(false); +const openModify = ref(false); +const tableHeader = [ + { label: "No", width: "5%", style: "word-break: keep-all;" }, + { label: "Step Name", width: "15%", style: "word-break: keep-all;" }, + { label: "Type", width: "10%", style: "word-break: keep-all;" }, + { label: "Dataset", width: "10%", style: "word-break: keep-all;" }, + { label: "Script", width: "10%", style: "word-break: keep-all;" }, + { label: "Hyper Parameters", width: "15%", style: "word-break: keep-all;" }, + { label: "Resource", width: "15%", style: "word-break: keep-all;" }, + { label: "Status", width: "5%", style: "word-break: keep-all;" }, + { label: "Workflow", width: "10%", style: "word-break: keep-all;" }, + { label: "Action", width: "5%", style: "word-break: keep-all;" }, +]; + +const searchOptions = [ + { searchType: "전체", searchText: "" }, + { searchType: "디바이스 별칭", searchText: "deviceAlias" }, + { searchType: "디바이스 키", searchText: "deviceKey" }, + { searchType: "사용자", searchText: "userId" }, + { searchType: "디바이스 이름", searchText: "deviceName" }, + { searchType: "디바이스 모델", searchText: "deviceModel" }, + { searchType: "디바이스 OS", searchText: "deviceOs" }, +]; + +const pageSizeOptions = [ + { text: "10 페이지", value: 10 }, + { text: "50 페이지", value: 50 }, + { text: "100 페이지", value: 100 }, +]; + +const workflowList = ["pipeline-a", "pipeline-b", "pipeline-c"]; + +const data = ref({ + params: { + pageNum: 1, + pageSize: 10, + searchType: "", + searchText: "", + }, + results: [], + totalDataLength: 0, + pageLength: 0, + modalMode: "", + selectedData: null, + allSelected: false, + selected: [], + isModalVisible: false, + isConfirmDialogVisible: false, + userOption: [], +}); + +const getCodeList = () => { + // UserService.search(data.value.params).then((d) => { + // if (d.status === 200) { + // data.value.userOption = d.data.userList; + // } + // }); +}; + +const getData = () => { + // 더미 데이터: No 7 → 1 + data.value.results = [ + { + no: 7, + stepName: "Data Ingest", + type: "Preprocessing", + dataset: "raw_data", + script: "ingest.py", + hyperParameters: "-", + resource: "CPU:1, MEM:2Gi", + status: "success", + workflow: "pipeline-a", + deviceKey: 7, + }, + { + no: 6, + stepName: "Data Preprocess", + type: "Preprocessing", + dataset: "raw_data", + script: "preprocess.py", + hyperParameters: "normalize=True", + resource: "CPU:2, MEM:4Gi", + status: "success", + workflow: "pipeline-a", + deviceKey: 6, + }, + { + no: 5, + stepName: "Model Training", + type: "Training", + dataset: "processed_data", + script: "train.py", + hyperParameters: "lr=0.01, epochs=10", + resource: "GPU:1, MEM:8Gi", + status: "warning", + workflow: "pipeline-a", + deviceKey: 5, + }, + { + no: 4, + stepName: "Model Evaluation", + type: "Evaluation", + dataset: "test_data", + script: "evaluate.py", + hyperParameters: "-", + resource: "CPU:1, MEM:4Gi", + status: "success", + workflow: "pipeline-a", + deviceKey: 4, + }, + { + no: 3, + stepName: "Model Validation", + type: "Validation", + dataset: "test_data", + script: "validate.py", + hyperParameters: "metrics=['accuracy']", + resource: "CPU:1, MEM:4Gi", + status: "success", + workflow: "pipeline-a", + deviceKey: 3, + }, + { + no: 2, + stepName: "Package Model", + type: "Packaging", + dataset: "trained_model", + script: "package.py", + hyperParameters: "format='tar.gz'", + resource: "CPU:1, MEM:2Gi", + status: "success", + workflow: "pipeline-a", + deviceKey: 2, + }, + { + no: 1, + stepName: "Deploy", + type: "Deployment", + dataset: "package", + script: "deploy.py", + hyperParameters: "env='prod'", + resource: "CPU:1, MEM:2Gi", + status: "success", + workflow: "pipeline-a", + deviceKey: 1, + }, + ]; + data.value.totalDataLength = data.value.results.length; + // 페이지 길이 재계산 + if (data.value.totalDataLength % data.value.params.pageSize === 0) { + data.value.pageLength = + data.value.totalDataLength / data.value.params.pageSize; + } else { + data.value.pageLength = Math.ceil( + data.value.totalDataLength / data.value.params.pageSize, + ); + } +}; + +const setPaginationLength = () => { + if (data.value.totalDataLength % data.value.params.pageSize === 0) { + data.value.pageLength = + data.value.totalDataLength / data.value.params.pageSize; + } else { + data.value.pageLength = Math.ceil( + data.value.totalDataLength / data.value.params.pageSize, + ); + } +}; + +const saveData = (formData) => { + if (data.value.modalMode === "create") { + // DeviceService.add(formData).then((d) => { + // if (d.status === 200) { + // data.value.isModalVisible = false; + // store.setSnackbarMsg({ + // text: "등록 되었습니다.", + // result: 200, + // }); + // changePageNum(1); + // } else { + // store.setSnackbarMsg({ + // text: d, + // result: 500, + // }); + // } + // }); + } else { + // DeviceService.update(formData.deviceKey, formData).then((d) => { + // if (d.status === 200) { + // data.value.isModalVisible = false; + // store.setSnackbarMsg({ + // text: "수정 되었습니다.", + // result: 200, + // }); + // changePageNum(); + // } else { + // store.setSnackbarMsg({ + // text: d, + // result: 500, + // }); + // } + // }); + } +}; + +const removeData = (value) => { + let removeList = value ? value : data.value.selected; + const remove = (code) => { + // return DeviceService.delete(code).then((d) => { + // if (d.status !== 200) { + // store.setSnackbarMsg({ + // text: d, + // result: 500, + // }); + // } + // }); + }; + + if (removeList.length === 1) { + remove(removeList[0].deviceKey).then(() => { + // store.setSnackbarMsg({ + // text: "삭제되었습니다.", + // result: 200, + // }); + changePageNum(); + data.value.isConfirmDialogVisible = false; + data.value.selected = []; + data.value.allSelected = false; + }); + } else { + Promise.all(removeList.map((item) => remove(item.deviceKey))).finally( + () => { + // store.setSnackbarMsg({ + // text: "모두 삭제되었습니다.", + // result: 200, + // }); + changePageNum(); + data.value.isConfirmDialogVisible = false; + data.value.selected = []; + data.value.allSelected = false; + }, + ); + } +}; + +const handleRemoveData = () => { + if (data.value.selected.length === 0) { + // store.setSnackbarMsg({ + // text: "삭제 할 데이터를 선택해주세요. ", + // result: 500, + // }); + return; + } + if (data.value.allSelected || data.value.selected.length !== 1) { + data.value.isConfirmDialogVisible = true; + return; + } + //리스트로 삭제 할때 + removeData(undefined); +}; +const closeDetail = () => { + openView.value = false; +}; +const changePageNum = (page) => { + data.value.params.pageNum = page; + getData(); +}; +const openDetailModal = (selectedItem) => { + data.value.selectedData = selectedItem; + openView.value = true; +}; + +const handleSave = ({ + workflow, + stepName, +}: { + workflow: string; + stepName: string; +}) => { + if (data.value.selectedData) { + data.value.selectedData.workflow = workflow; + data.value.selectedData.stepName = stepName; + } +}; +const openModifyModal = (item: { workflow: string; stepName: string }) => { + data.value.selectedData = { + workflow: item.workflow, + stepName: item.stepName, + }; + openModify.value = true; +}; + +const openCreateModal = () => { + data.value.selectedData = null; + data.value.modalMode = "create"; + data.value.isModalVisible = true; +}; + +const closeModal = () => { + data.value.isModalVisible = false; + data.value.selectedData = null; +}; + +const getSelectedAllData = () => { + data.value.selected = data.value.allSelected + ? data.value.results.map((item) => { + return { + deviceKey: item.deviceKey, + }; + }) + : []; +}; + +// Save 버튼 클릭 +// const saveStep = () => { +// if (!data.value.selectedData) return; + +// // 원본에 덮어쓰기 +// data.value.selectedData.workflow = selectedWorkflow.value; +// data.value.selectedData.stepName = stepName.value; + +// // TODO: API 호출 or saveData(data.value.selectedData) 등 +// // saveData(data.value.selectedData) + +// openModify.value = false; +// }; + +onMounted(() => { + getData(); + getCodeList(); +}); + + + + + diff --git a/src/components/stepconfig/ViewComponent.vue b/src/components/stepconfig/ViewComponent.vue new file mode 100644 index 0000000..325c40d --- /dev/null +++ b/src/components/stepconfig/ViewComponent.vue @@ -0,0 +1,135 @@ + + + + + diff --git a/src/components/workflow/ListComponent.vue b/src/components/workflow/ListComponent.vue index 2fd6d9c..a0beba8 100644 --- a/src/components/workflow/ListComponent.vue +++ b/src/components/workflow/ListComponent.vue @@ -5,9 +5,12 @@ import IconSettingBtn from "@/components/button/IconSettingBtn.vue"; // import FormComponent from "@/components/device/FormComponent.vue"; import { onMounted, ref, watch } from "vue"; import ViewComponent from "@/components/workflow/ViewComponent.vue"; +import WorkflowsCreateDialog from "@/components/atoms/organisms/WorkflowsCreateDialog.vue"; +import WorkflowsUploadDialog from "@/components/atoms/organisms/WorkflowsUploadDialog.vue"; // const store = commonStore(); const openView = ref(false); +const openModify = ref(false); const tableHeader = [ { label: "No", @@ -102,6 +105,8 @@ const data = ref({ selectedData: null, allSelected: false, selected: [], + isCreateVisible: false, + isUploadVisible: false, isModalVisible: false, isConfirmDialogVisible: false, userOption: [], @@ -305,21 +310,32 @@ const openSettingModal = (selectedItem) => { data.value.modalMode = "setting"; openView.value = true; }; -const openModifyModal = (selectedItem) => { - data.value.selectedData = selectedItem; - data.value.modalMode = "modify"; - data.value.isModalVisible = true; +const openModifyModal = (item: { workflow: string; stepName: string }) => { + data.value.selectedData = { + workflow: item.workflow, + stepName: item.stepName, + }; + openModify.value = true; }; const openCreateModal = () => { data.value.selectedData = null; data.value.modalMode = "create"; - data.value.isModalVisible = true; + data.value.isCreateVisible = true; }; -const closeModal = () => { - data.value.isModalVisible = false; +const openUploadModal = () => { data.value.selectedData = null; + data.value.modalMode = "upload"; + data.value.isUploadVisible = true; +}; +const closeCreateModal = () => { + data.value.isModalVisible = false; + data.value.isCreateVisible = null; +}; +const closeUploadModal = () => { + data.value.isModalVisible = false; + data.value.isUploadVisible = null; }; const getSelectedAllData = () => { @@ -440,10 +456,12 @@ onMounted(() => { - 선택 삭제 + Upload Workflow + + Create Workflow - 등록 @@ -537,7 +555,32 @@ onMounted(() => { + + + + + + + + + +
diff --git a/src/pages/DeploymentView.vue b/src/pages/DeploymentView.vue index 52dbf2f..eef311f 100644 --- a/src/pages/DeploymentView.vue +++ b/src/pages/DeploymentView.vue @@ -1,10 +1,9 @@ - + diff --git a/src/pages/WorkflowStepConfigView.vue b/src/pages/WorkflowStepConfigView.vue index 52dbf2f..b9e17dd 100644 --- a/src/pages/WorkflowStepConfigView.vue +++ b/src/pages/WorkflowStepConfigView.vue @@ -1,10 +1,9 @@ - +