Compare commits
2 Commits
dev2
...
dev3-versi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd9d590be2 | ||
|
|
eaedab505c |
@@ -1,24 +1,19 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="q-px-xs">
|
<detail-field-table
|
||||||
<div v-if="!isLoaded" class="spinner flex flex-center">
|
detailField="description"
|
||||||
<q-spinner color="primary" size="3em" />
|
:name="name"
|
||||||
</div>
|
:type="type"
|
||||||
<q-table v-else class="app-table" :selection="type" row-key="id" v-model:selected="selected" flat bordered
|
:filter="filter"
|
||||||
virtual-scroll :columns="columns" :rows="rows" :pagination="pagination" :rows-per-page-options="[0]"
|
:columns="columns"
|
||||||
:filter="filter" style="max-height: 65vh;">
|
:fetchData="fetchApps"
|
||||||
<template v-slot:body-cell-description="props">
|
@update:selected="(item) => { selected = item }"
|
||||||
<q-td :props="props">
|
/>
|
||||||
<q-scroll-area class="description-cell">
|
|
||||||
<div v-html="props.row.description"></div>
|
|
||||||
</q-scroll-area>
|
|
||||||
</q-td>
|
|
||||||
</template>
|
|
||||||
</q-table>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { ref, onMounted, reactive, watchEffect, PropType } from 'vue'
|
import { ref, PropType } from 'vue';
|
||||||
import { api } from 'boot/axios';
|
import { api } from 'boot/axios';
|
||||||
|
import DetailFieldTable from './dialog/DetailFieldTable.vue';
|
||||||
|
|
||||||
interface IAppDisplay {
|
interface IAppDisplay {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -29,50 +24,35 @@ interface IAppDisplay {
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'AppSelectBox',
|
name: 'AppSelectBox',
|
||||||
|
components: {
|
||||||
|
DetailFieldTable
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
name: String,
|
name: String,
|
||||||
type: String,
|
type: String,
|
||||||
filter: String,
|
filter: String,
|
||||||
filterInitRowsFunc: {
|
filterInitRowsFunc: {
|
||||||
type: Function as PropType<(app: IAppDisplay) => boolean>,
|
type: Function as PropType<(app: IAppDisplay) => boolean>,
|
||||||
},
|
|
||||||
updateSelectApp: {
|
|
||||||
type: Function
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setup(props) {
|
setup(props) {
|
||||||
|
const selected = ref<IAppDisplay[]>([]);
|
||||||
const columns = [
|
const columns = [
|
||||||
{ name: 'id', required: true, label: 'ID', align: 'left', field: 'id', sortable: true, sort: (a: string, b: string) => parseInt(a, 10) - parseInt(b, 10) },
|
{ name: 'id', required: true, label: 'ID', align: 'left', field: 'id', sortable: true, sort: (a: string, b: string) => parseInt(a, 10) - parseInt(b, 10) },
|
||||||
{ name: 'name', label: 'アプリ名', field: 'name', sortable: true, align: 'left' },
|
{ name: 'name', label: 'アプリ名', field: 'name', sortable: true, align: 'left' },
|
||||||
{ name: 'description', label: '概要', field: 'description', align: 'left', sortable: false },
|
{ name: 'description', label: '概要', field: 'description', align: 'left', sortable: false },
|
||||||
{ name: 'createdate', label: '作成日時', field: 'createdate', align: 'left' }
|
{ name: 'createdate', label: '作成日時', field: 'createdate', align: 'left' }
|
||||||
]
|
];
|
||||||
const isLoaded = ref(false);
|
|
||||||
const rows = reactive<IAppDisplay[]>([]);
|
|
||||||
const selected = ref([])
|
|
||||||
|
|
||||||
watchEffect(()=>{
|
const fetchApps = async () => {
|
||||||
if (selected.value && selected.value[0] && props.updateSelectApp) {
|
const res = await api.get('api/v1/allapps');
|
||||||
props.updateSelectApp(selected.value[0])
|
return res.data.apps.map((item: any) => ({
|
||||||
}
|
id: item.appId,
|
||||||
});
|
name: item.name,
|
||||||
onMounted(() => {
|
description: item.description,
|
||||||
api.get('api/v1/allapps').then(res => {
|
createdate: dateFormat(item.createdAt)
|
||||||
res.data.apps.forEach((item: any) => {
|
})).filter(app => !props.filterInitRowsFunc || props.filterInitRowsFunc(app));
|
||||||
const row : IAppDisplay = {
|
};
|
||||||
id: item.appId,
|
|
||||||
name: item.name,
|
|
||||||
description: item.description,
|
|
||||||
createdate: dateFormat(item.createdAt)
|
|
||||||
}
|
|
||||||
if (props.filterInitRowsFunc && !props.filterInitRowsFunc(row)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
rows.push(row);
|
|
||||||
});
|
|
||||||
isLoaded.value = true;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const dateFormat = (dateStr: string) => {
|
const dateFormat = (dateStr: string) => {
|
||||||
const date = new Date(dateStr);
|
const date = new Date(dateStr);
|
||||||
@@ -84,31 +64,13 @@ export default {
|
|||||||
const minutes = pad(date.getMinutes());
|
const minutes = pad(date.getMinutes());
|
||||||
const seconds = pad(date.getSeconds());
|
const seconds = pad(date.getSeconds());
|
||||||
return `${year}/${month}/${day} ${hours}:${minutes}:${seconds}`;
|
return `${year}/${month}/${day} ${hours}:${minutes}:${seconds}`;
|
||||||
}
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
columns,
|
columns,
|
||||||
rows,
|
fetchApps,
|
||||||
selected,
|
selected
|
||||||
isLoaded,
|
};
|
||||||
pagination: ref({
|
}
|
||||||
rowsPerPage: 10
|
};
|
||||||
})
|
</script>
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style lang="scss">
|
|
||||||
.description-cell {
|
|
||||||
height: 60px;
|
|
||||||
width: 300px;
|
|
||||||
max-height: 60px;
|
|
||||||
max-width: 300px;
|
|
||||||
white-space: break-spaces;
|
|
||||||
}
|
|
||||||
|
|
||||||
.spinner {
|
|
||||||
min-height: 300px;
|
|
||||||
min-width: 400px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
<q-card class="" style="min-width: 40vw; max-width: 80vw; max-height: 95vh;" :style="cardStyle">
|
<q-card class="" style="min-width: 40vw; max-width: 80vw; max-height: 95vh;" :style="cardStyle">
|
||||||
<q-toolbar class="bg-grey-4">
|
<q-toolbar class="bg-grey-4">
|
||||||
<q-toolbar-title>{{ name }}</q-toolbar-title>
|
<q-toolbar-title>{{ name }}</q-toolbar-title>
|
||||||
<q-space></q-space>
|
<q-space v-if="$slots.toolbar"></q-space>
|
||||||
<slot name="toolbar"></slot>
|
<slot name="toolbar"></slot>
|
||||||
<q-btn flat round dense icon="close" @click="CloseDialogue('Cancel')" />
|
<q-btn flat round dense icon="close" @click="CloseDialogue('Cancel')" />
|
||||||
</q-toolbar>
|
</q-toolbar>
|
||||||
@@ -41,7 +41,8 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
emits: [
|
emits: [
|
||||||
'close'
|
'close',
|
||||||
|
'update:visible'
|
||||||
],
|
],
|
||||||
setup(props, context) {
|
setup(props, context) {
|
||||||
const CloseDialogue = (val) => {
|
const CloseDialogue = (val) => {
|
||||||
|
|||||||
88
frontend/src/components/dialog/DetailFieldTable.vue
Normal file
88
frontend/src/components/dialog/DetailFieldTable.vue
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
<template>
|
||||||
|
<div class="q-px-xs">
|
||||||
|
<div v-if="!isLoaded" class="spinner flex flex-center">
|
||||||
|
<q-spinner color="primary" size="3em" />
|
||||||
|
</div>
|
||||||
|
<q-table v-else class="app-table" :selection="type" row-key="id" v-model:selected="selected" flat bordered
|
||||||
|
virtual-scroll :columns="columns" :rows="rows" :pagination="pagination" :rows-per-page-options="[0]"
|
||||||
|
:filter="filter" style="max-height: 65vh;" @update:selected="emitSelected">
|
||||||
|
<template v-slot:[`body-cell-${detailField}`]="props">
|
||||||
|
<q-td :props="props">
|
||||||
|
<q-scroll-area class="description-cell">
|
||||||
|
<div v-html="props.row[detailField]"></div>
|
||||||
|
</q-scroll-area>
|
||||||
|
</q-td>
|
||||||
|
</template>
|
||||||
|
</q-table>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { ref, onMounted, reactive, PropType } from 'vue'
|
||||||
|
|
||||||
|
interface IRow {
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'DetailFieldTable',
|
||||||
|
props: {
|
||||||
|
name: String,
|
||||||
|
type: String,
|
||||||
|
filter: String,
|
||||||
|
detailField: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
columns: {
|
||||||
|
type: Array as PropType<any[]>,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
fetchData: {
|
||||||
|
type: Function as PropType<() => Promise<IRow[]>>,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emits: ['update:selected'],
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const isLoaded = ref(false);
|
||||||
|
const rows = reactive<IRow[]>([]);
|
||||||
|
const selected = ref([]);
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
const data = await props.fetchData();
|
||||||
|
rows.push(...data);
|
||||||
|
isLoaded.value = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
const emitSelected = (selectedItems: any[]) => {
|
||||||
|
emit('update:selected', selectedItems);
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
rows,
|
||||||
|
selected,
|
||||||
|
isLoaded,
|
||||||
|
pagination: ref({
|
||||||
|
rowsPerPage: 10
|
||||||
|
}),
|
||||||
|
emitSelected
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.description-cell {
|
||||||
|
height: 60px;
|
||||||
|
width: 300px;
|
||||||
|
max-height: 60px;
|
||||||
|
max-width: 300px;
|
||||||
|
white-space: break-spaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spinner {
|
||||||
|
min-height: 300px;
|
||||||
|
min-width: 400px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
82
frontend/src/components/dialog/VersionHistory.vue
Normal file
82
frontend/src/components/dialog/VersionHistory.vue
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
<template>
|
||||||
|
<detail-field-table
|
||||||
|
detailField="comment"
|
||||||
|
type="single"
|
||||||
|
:columns="columns"
|
||||||
|
:fetchData="fetchVersionHistory"
|
||||||
|
@update:selected="(item) => { selected = item }"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, PropType, ref, watch } from 'vue';
|
||||||
|
import { IAppDisplay, IAppVersion } from 'src/types/AppTypes';
|
||||||
|
import { date } from 'quasar';
|
||||||
|
import { api } from 'boot/axios';
|
||||||
|
import DetailFieldTable from './DetailFieldTable.vue';
|
||||||
|
import { IUser, IUserDisplay } from 'src/types/UserTypes';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
name: 'VersionHistory',
|
||||||
|
components: {
|
||||||
|
DetailFieldTable
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
app: {
|
||||||
|
type: Object as PropType<IAppDisplay>,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setup(props, { emit }) {
|
||||||
|
const selected = ref<IAppVersion[]>([]);
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{ name: 'version', label: 'ID', field: 'version', align: 'left', sortable: true },
|
||||||
|
{ name: 'name', label: 'バージョン名', field: 'name', align: 'left', sortable: true },
|
||||||
|
{ name: 'comment', label: 'コメント', field: 'comment', align: 'left', sortable: true },
|
||||||
|
{ name: 'creator', label: '作成者', field: (row: IAppVersion) => row.creator.fullName, align: 'left', sortable: true },
|
||||||
|
{ name: 'createTime', label: '作成日時', field: 'createTime', align: 'left', sortable: true },
|
||||||
|
{ name: 'updater', label: '更新者', field: (row: IAppVersion) => row.updater.fullName, align: 'left', sortable: true },
|
||||||
|
{ name: 'updateTime', label: '更新日時', field: 'updateTime', align: 'left', sortable: true },
|
||||||
|
];
|
||||||
|
|
||||||
|
const formatDate = (dateStr: string) => {
|
||||||
|
return date.formatDate(dateStr, 'YYYY/MM/DD HH:mm:ss');
|
||||||
|
};
|
||||||
|
|
||||||
|
const toUserDisaplay = (user: IUser) => {
|
||||||
|
return {
|
||||||
|
id: user.id,
|
||||||
|
firstName: user.first_name,
|
||||||
|
lastName: user.last_name,
|
||||||
|
fullNameSearch: (user.last_name + user.first_name).toLowerCase(),
|
||||||
|
fullName: user.last_name + ' ' + user.first_name,
|
||||||
|
email: user.email,
|
||||||
|
isActive: user.is_active,
|
||||||
|
isSuperuser: user.is_superuser,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchVersionHistory = async () => {
|
||||||
|
const { data } = await api.get(`api/apps/${props.app.id}/versions`);
|
||||||
|
return data.data.map((item: any) => ({
|
||||||
|
id: item.id,
|
||||||
|
version: item.version,
|
||||||
|
appid: item.appid,
|
||||||
|
name: item.name,
|
||||||
|
comment: item.comment,
|
||||||
|
updater: toUserDisaplay(item.updateuser),
|
||||||
|
updateTime: formatDate(item.updatetime),
|
||||||
|
creator: toUserDisaplay(item.createuser),
|
||||||
|
createTime: formatDate(item.createtime),
|
||||||
|
} as IAppVersion));
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
fetchVersionHistory,
|
||||||
|
columns,
|
||||||
|
selected
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
42
frontend/src/components/dialog/VersionInput.vue
Normal file
42
frontend/src/components/dialog/VersionInput.vue
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<template>
|
||||||
|
<q-input
|
||||||
|
v-model="versionInfo.name"
|
||||||
|
filled
|
||||||
|
autofocus
|
||||||
|
label="バージョン名"
|
||||||
|
:rules="[(val) => !val || val.length <= 30 || '30字以内で入力ください']"
|
||||||
|
/>
|
||||||
|
<q-input
|
||||||
|
v-model="versionInfo.desc"
|
||||||
|
filled
|
||||||
|
type="textarea"
|
||||||
|
:rules="[(val) => !val || val.length <= 80 || '80字以内で入力ください']"
|
||||||
|
label="説明"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, watch, defineProps, defineEmits } from 'vue';
|
||||||
|
import { QInput } from 'quasar';
|
||||||
|
import { IVersionInfo } from 'src/types/AppTypes';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
modelValue: IVersionInfo;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const defaultTitle = `${new Date().toLocaleString()}`;
|
||||||
|
|
||||||
|
const versionInfo = ref({
|
||||||
|
...props.modelValue,
|
||||||
|
name: props.modelValue.name || defaultTitle,
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:modelValue']);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
versionInfo,
|
||||||
|
() => {
|
||||||
|
emit('update:modelValue', { ...versionInfo.value });
|
||||||
|
},
|
||||||
|
{ immediate: true, deep: true }
|
||||||
|
);
|
||||||
|
</script>
|
||||||
@@ -38,8 +38,10 @@ import { computed, onMounted, reactive } from 'vue';
|
|||||||
import EssentialLink, { EssentialLinkProps } from 'components/EssentialLink.vue';
|
import EssentialLink, { EssentialLinkProps } from 'components/EssentialLink.vue';
|
||||||
import DomainSelector from 'components/DomainSelector.vue';
|
import DomainSelector from 'components/DomainSelector.vue';
|
||||||
import { useAuthStore } from 'stores/useAuthStore';
|
import { useAuthStore } from 'stores/useAuthStore';
|
||||||
|
import { useRoute } from 'vue-router';
|
||||||
|
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
|
const route = useRoute()
|
||||||
const noDomain = computed(() => !authStore.hasDomain);
|
const noDomain = computed(() => !authStore.hasDomain);
|
||||||
|
|
||||||
const essentialLinks: EssentialLinkProps[] = reactive([
|
const essentialLinks: EssentialLinkProps[] = reactive([
|
||||||
@@ -128,7 +130,7 @@ const version = process.env.version;
|
|||||||
const productName = process.env.productName;
|
const productName = process.env.productName;
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
authStore.setLeftMenu(true);
|
authStore.setLeftMenu(!route.path.startsWith('/FlowChart/'));
|
||||||
});
|
});
|
||||||
|
|
||||||
function toggleLeftDrawer() {
|
function toggleLeftDrawer() {
|
||||||
|
|||||||
@@ -37,13 +37,18 @@
|
|||||||
|
|
||||||
<show-dialog v-model:visible="showSelectApp" name="アプリ選択" @close="closeSelectAppDialog" min-width="50vw" min-height="50vh" :ok-btn-auto-close="false" :ok-btn-loading="isAdding">
|
<show-dialog v-model:visible="showSelectApp" name="アプリ選択" @close="closeSelectAppDialog" min-width="50vw" min-height="50vh" :ok-btn-auto-close="false" :ok-btn-loading="isAdding">
|
||||||
<template v-slot:toolbar>
|
<template v-slot:toolbar>
|
||||||
<q-input dense debounce="300" v-model="filter" placeholder="検索" clearable>
|
<q-input dense debounce="300" v-model="dgFilter" placeholder="検索" clearable>
|
||||||
<template v-slot:before>
|
<template v-slot:before>
|
||||||
<q-icon name="search" />
|
<q-icon name="search" />
|
||||||
</template>
|
</template>
|
||||||
</q-input>
|
</q-input>
|
||||||
</template>
|
</template>
|
||||||
<app-select-box ref="appDialog" name="アプリ" type="single" :filter="filter" :filterInitRowsFunc="filterInitRows" />
|
<app-select-box ref="appDialog" name="アプリ" type="single" :filter="dgFilter" :filterInitRowsFunc="filterInitRows" />
|
||||||
|
</show-dialog>
|
||||||
|
|
||||||
|
|
||||||
|
<show-dialog v-model:visible="showVersionHistory" :name="targetRow?.name + 'のバージョン履歴'" @close="closeHistoryDg" min-width="50vw" min-height="50vh" :ok-btn-auto-close="false" :ok-btn-loading="isAdding">
|
||||||
|
<version-history ref="versionDialog" :app="targetRow as IAppDisplay" />
|
||||||
</show-dialog>
|
</show-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -56,20 +61,11 @@ import { useAuthStore } from 'stores/useAuthStore';
|
|||||||
import { useFlowEditorStore } from 'stores/flowEditor';
|
import { useFlowEditorStore } from 'stores/flowEditor';
|
||||||
import { router } from 'src/router';
|
import { router } from 'src/router';
|
||||||
import { date } from 'quasar'
|
import { date } from 'quasar'
|
||||||
import { IManagedApp } from 'src/types/AppTypes';
|
import { IManagedApp, IAppDisplay, IAppVersion } from 'src/types/AppTypes';
|
||||||
import ShowDialog from 'src/components/ShowDialog.vue';
|
import ShowDialog from 'src/components/ShowDialog.vue';
|
||||||
import AppSelectBox from 'src/components/AppSelectBox.vue';
|
import AppSelectBox from 'src/components/AppSelectBox.vue';
|
||||||
import TableActionMenu from 'components/TableActionMenu.vue';
|
import TableActionMenu from 'components/TableActionMenu.vue';
|
||||||
|
import VersionHistory from 'components/dialog/VersionHistory.vue';
|
||||||
interface IAppDisplay{
|
|
||||||
id:string;
|
|
||||||
sortId: number;
|
|
||||||
name:string;
|
|
||||||
url:string;
|
|
||||||
user:string;
|
|
||||||
version:string;
|
|
||||||
updatetime:string;
|
|
||||||
}
|
|
||||||
|
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
const numberStringSorting = (a: string, b: string) => parseInt(a, 10) - parseInt(b, 10);
|
const numberStringSorting = (a: string, b: string) => parseInt(a, 10) - parseInt(b, 10);
|
||||||
@@ -78,8 +74,8 @@ const columns = [
|
|||||||
{ name: 'id', label: 'アプリID', field: 'id', align: 'left', sortable: true, sort: numberStringSorting },
|
{ name: 'id', label: 'アプリID', field: 'id', align: 'left', sortable: true, sort: numberStringSorting },
|
||||||
{ name: 'name', label: 'アプリ名', field: 'name', align: 'left', sortable: true },
|
{ name: 'name', label: 'アプリ名', field: 'name', align: 'left', sortable: true },
|
||||||
{ name: 'url', label: 'URL', field: 'url', align: 'left', sortable: true },
|
{ name: 'url', label: 'URL', field: 'url', align: 'left', sortable: true },
|
||||||
{ name: 'user', label: '最後更新者', field: 'user', align: 'left', sortable: true},
|
{ name: 'updateUser', label: '最後更新者', field: (row: IAppDisplay) => row.updateUser.fullName, align: 'left', sortable: true},
|
||||||
{ name: 'updatetime', label: '最後更新日', field: 'updatetime', align: 'left', sortable: true},
|
{ name: 'updateTime', label: '最後更新日', field: 'updateTime', align: 'left', sortable: true},
|
||||||
{ name: 'version', label: 'バージョン', field: 'version', align: 'left', sortable: true, sort: numberStringSorting },
|
{ name: 'version', label: 'バージョン', field: 'version', align: 'left', sortable: true, sort: numberStringSorting },
|
||||||
{ name: 'actions', label: '', field: 'actions' }
|
{ name: 'actions', label: '', field: 'actions' }
|
||||||
];
|
];
|
||||||
@@ -87,13 +83,16 @@ const columns = [
|
|||||||
const pagination = ref({ sortBy: 'id', descending: true, rowsPerPage: 20 });
|
const pagination = ref({ sortBy: 'id', descending: true, rowsPerPage: 20 });
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const filter = ref('');
|
const filter = ref('');
|
||||||
|
const dgFilter = ref('');
|
||||||
const rows = ref<IAppDisplay[]>([]);
|
const rows = ref<IAppDisplay[]>([]);
|
||||||
|
const targetRow = ref<IAppDisplay>();
|
||||||
const rowIds = new Set<string>();
|
const rowIds = new Set<string>();
|
||||||
|
|
||||||
const $q = useQuasar()
|
const $q = useQuasar()
|
||||||
const store = useFlowEditorStore();
|
const store = useFlowEditorStore();
|
||||||
const appDialog = ref();
|
const appDialog = ref();
|
||||||
const showSelectApp=ref(false);
|
const showSelectApp=ref(false);
|
||||||
|
const showVersionHistory=ref(false);
|
||||||
const isAdding = ref(false);
|
const isAdding = ref(false);
|
||||||
|
|
||||||
const actionList = [
|
const actionList = [
|
||||||
@@ -137,6 +136,7 @@ const filterInitRows = (row: {id: string}) => {
|
|||||||
|
|
||||||
const showAddAppDialog = () => {
|
const showAddAppDialog = () => {
|
||||||
showSelectApp.value = true;
|
showSelectApp.value = true;
|
||||||
|
dgFilter.value = ''
|
||||||
}
|
}
|
||||||
|
|
||||||
const closeSelectAppDialog = async (val: 'OK'|'Cancel') => {
|
const closeSelectAppDialog = async (val: 'OK'|'Cancel') => {
|
||||||
@@ -150,31 +150,54 @@ const closeSelectAppDialog = async (val: 'OK'|'Cancel') => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function removeRow(app:IAppDisplay) {
|
function removeRow(app:IAppDisplay) {
|
||||||
|
targetRow.value = app;
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
function showHistory(app:IAppDisplay) {
|
function showHistory(app:IAppDisplay) {
|
||||||
return
|
targetRow.value = app;
|
||||||
|
showVersionHistory.value = true;
|
||||||
|
dgFilter.value = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
const closeHistoryDg = async (val: 'OK'|'Cancel') => {
|
||||||
|
showSelectApp.value = true;
|
||||||
|
if (val == 'OK' && appDialog.value.selected[0]) {
|
||||||
|
isAdding.value = true;
|
||||||
|
await getApps();
|
||||||
|
}
|
||||||
|
showSelectApp.value = false;
|
||||||
|
isAdding.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const appToAppDisplay = (app: IManagedApp) => {
|
const appToAppDisplay = (app: IManagedApp) => {
|
||||||
|
const user = app.updateuser;
|
||||||
return {
|
return {
|
||||||
id: app.appid,
|
id: app.appid,
|
||||||
sortId: parseInt(app.appid, 10),
|
sortId: parseInt(app.appid, 10),
|
||||||
name: app.appname,
|
name: app.appname,
|
||||||
url: `${app.domainurl}/k/${app.appid}`,
|
url: `${app.domainurl}/k/${app.appid}`,
|
||||||
user: `${app.updateuser.first_name} ${app.updateuser.last_name}` ,
|
version: app.version,
|
||||||
updatetime:date.formatDate(app.update_time, 'YYYY/MM/DD HH:mm'),
|
updateTime:date.formatDate(app.update_time, 'YYYY/MM/DD HH:mm'),
|
||||||
version: app.version
|
updateUser: {
|
||||||
}
|
id: user.id,
|
||||||
|
firstName: user.first_name,
|
||||||
|
lastName: user.last_name,
|
||||||
|
fullNameSearch: (user.last_name + user.first_name).toLowerCase(),
|
||||||
|
fullName: user.last_name + ' ' + user.first_name,
|
||||||
|
email: user.email,
|
||||||
|
isSuperuser: user.is_superuser,
|
||||||
|
isActive: user.is_active,
|
||||||
|
}
|
||||||
|
} as IAppDisplay
|
||||||
}
|
}
|
||||||
|
|
||||||
function toEditFlowPage(app:IAppDisplay) {
|
async function toEditFlowPage(app:IAppDisplay) {
|
||||||
store.setApp({
|
store.setApp({
|
||||||
appId: app.id,
|
appId: app.id,
|
||||||
name: app.name
|
name: app.name
|
||||||
});
|
});
|
||||||
store.selectFlow(undefined);
|
store.selectFlow(undefined);
|
||||||
router.push('/FlowChart/' + app.id);
|
await router.push('/FlowChart/' + app.id);
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -14,6 +14,15 @@
|
|||||||
<q-space></q-space>
|
<q-space></q-space>
|
||||||
<q-btn-dropdown color="primary" label="保存" icon="save" :loading="saveLoading" >
|
<q-btn-dropdown color="primary" label="保存" icon="save" :loading="saveLoading" >
|
||||||
<q-list>
|
<q-list>
|
||||||
|
<q-item clickable v-close-popup @click="onSaveVersion">
|
||||||
|
<q-item-section avatar >
|
||||||
|
<q-icon name="bookmark_border"></q-icon>
|
||||||
|
</q-item-section>
|
||||||
|
<q-item-section>
|
||||||
|
<q-item-label>新バージョン保存</q-item-label>
|
||||||
|
</q-item-section>
|
||||||
|
</q-item>
|
||||||
|
|
||||||
<q-item clickable v-close-popup @click="onSaveFlow">
|
<q-item clickable v-close-popup @click="onSaveFlow">
|
||||||
<q-item-section avatar >
|
<q-item-section avatar >
|
||||||
<q-icon name="save" color="primary"></q-icon>
|
<q-icon name="save" color="primary"></q-icon>
|
||||||
@@ -75,6 +84,10 @@
|
|||||||
</template>
|
</template>
|
||||||
<action-select ref="appDg" name="model" :filter="filter" type="single" @clearFilter="onClearFilter" ></action-select>
|
<action-select ref="appDg" name="model" :filter="filter" type="single" @clearFilter="onClearFilter" ></action-select>
|
||||||
</ShowDialog>
|
</ShowDialog>
|
||||||
|
<!-- save version dialog -->
|
||||||
|
<ShowDialog v-model:visible="saveVersionAction" name="新バージョン保存" @close="closeSaveVersionDg" min-width="500px">
|
||||||
|
<version-input v-model="versionInfo" />
|
||||||
|
</ShowDialog>
|
||||||
<q-inner-loading
|
<q-inner-loading
|
||||||
:showing="initLoading"
|
:showing="initLoading"
|
||||||
color="primary"
|
color="primary"
|
||||||
@@ -87,7 +100,7 @@
|
|||||||
import { ref, reactive, computed, onMounted } from 'vue';
|
import { ref, reactive, computed, onMounted } from 'vue';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { IActionNode, ActionNode, IActionFlow, ActionFlow, RootAction, IActionProperty } from 'src/types/ActionTypes';
|
import { IActionNode, ActionNode, IActionFlow, ActionFlow, RootAction, IActionProperty } from 'src/types/ActionTypes';
|
||||||
import { IManagedApp } from 'src/types/AppTypes';
|
import { IAppDisplay, IManagedApp, IVersionInfo } from 'src/types/AppTypes';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import { useFlowEditorStore } from 'stores/flowEditor';
|
import { useFlowEditorStore } from 'stores/flowEditor';
|
||||||
import { useAuthStore } from 'stores/useAuthStore';
|
import { useAuthStore } from 'stores/useAuthStore';
|
||||||
@@ -98,6 +111,7 @@ import ShowDialog from 'components/ShowDialog.vue';
|
|||||||
import ActionSelect from 'components/ActionSelect.vue';
|
import ActionSelect from 'components/ActionSelect.vue';
|
||||||
import PropertyPanel from 'components/right/PropertyPanel.vue';
|
import PropertyPanel from 'components/right/PropertyPanel.vue';
|
||||||
import EventTree from 'components/left/EventTree.vue';
|
import EventTree from 'components/left/EventTree.vue';
|
||||||
|
import VersionInput from 'components/dialog/VersionInput.vue';
|
||||||
import { FlowCtrl } from '../control/flowctrl';
|
import { FlowCtrl } from '../control/flowctrl';
|
||||||
import { useQuasar } from 'quasar';
|
import { useQuasar } from 'quasar';
|
||||||
|
|
||||||
@@ -105,6 +119,7 @@ const deployLoading = ref(false);
|
|||||||
const saveLoading = ref(false);
|
const saveLoading = ref(false);
|
||||||
const initLoading = ref(true);
|
const initLoading = ref(true);
|
||||||
const drawerLeft = ref(false);
|
const drawerLeft = ref(false);
|
||||||
|
const versionInfo = ref<IVersionInfo>();
|
||||||
const $q = useQuasar();
|
const $q = useQuasar();
|
||||||
const store = useFlowEditorStore();
|
const store = useFlowEditorStore();
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
@@ -117,6 +132,7 @@ const prevNodeIfo = ref({
|
|||||||
});
|
});
|
||||||
// const refFlow = ref<ActionFlow|null>(null);
|
// const refFlow = ref<ActionFlow|null>(null);
|
||||||
const showAddAction = ref(false);
|
const showAddAction = ref(false);
|
||||||
|
const saveVersionAction = ref(false);
|
||||||
const drawerRight = ref(false);
|
const drawerRight = ref(false);
|
||||||
const filter=ref("");
|
const filter=ref("");
|
||||||
const model = ref("");
|
const model = ref("");
|
||||||
@@ -177,7 +193,7 @@ const onDeleteAllNextNodes = (node: IActionNode) => {
|
|||||||
}
|
}
|
||||||
const closeDg = (val: any) => {
|
const closeDg = (val: any) => {
|
||||||
console.log("Dialog closed->", val);
|
console.log("Dialog closed->", val);
|
||||||
if (val == 'OK') {
|
if (val == 'OK' && appDg?.value?.selected?.length > 0) {
|
||||||
const data = appDg.value.selected[0];
|
const data = appDg.value.selected[0];
|
||||||
const actionProps = JSON.parse(data.property);
|
const actionProps = JSON.parse(data.property);
|
||||||
const outputPoint = JSON.parse(data.outputPoints);
|
const outputPoint = JSON.parse(data.outputPoints);
|
||||||
@@ -245,6 +261,20 @@ const onSaveActionProps=(props:IActionProperty[])=>{
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onSaveVersion = async () => {
|
||||||
|
versionInfo.value = {
|
||||||
|
id: '1' // TODO
|
||||||
|
}
|
||||||
|
saveVersionAction.value = true;
|
||||||
|
// await onSaveAllFlow();
|
||||||
|
}
|
||||||
|
|
||||||
|
const closeSaveVersionDg = (val: 'OK'|'CANCEL') => {
|
||||||
|
if (val == 'OK') {
|
||||||
|
console.log(versionInfo.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const onSaveFlow = async () => {
|
const onSaveFlow = async () => {
|
||||||
const targetFlow = store.selectedFlow;
|
const targetFlow = store.selectedFlow;
|
||||||
if (targetFlow === undefined) {
|
if (targetFlow === undefined) {
|
||||||
@@ -316,11 +346,9 @@ const onSaveAllFlow= async ()=>{
|
|||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
initLoading.value = true;
|
initLoading.value = true;
|
||||||
if (store.appInfo === undefined && route?.params?.id !== undefined) {
|
if (store.appInfo === undefined && route?.params?.id !== undefined) {
|
||||||
const { appid, appname } = await fetchAppById(route.params.id as string);
|
// only for page refreshed
|
||||||
store.setApp({
|
const app = await fetchAppById(route.params.id as string);
|
||||||
appId: appid,
|
store.setApp(app);
|
||||||
name: appname
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
await store.loadFlow();
|
await store.loadFlow();
|
||||||
initLoading.value = false
|
initLoading.value = false
|
||||||
@@ -328,24 +356,39 @@ const fetchData = async () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const fetchAppById = async(id: string) => {
|
const fetchAppById = async(id: string) => {
|
||||||
try {
|
let result = await api.get('api/apps');
|
||||||
const result = await api.get('api/apps');
|
const app = result.data?.data?.find((item: IManagedApp) => item.appid === id ) as IManagedApp;
|
||||||
return result.data.find((item: IManagedApp) => item.appid === id ) as IManagedApp;
|
if (app) {
|
||||||
} catch (e) {
|
return convertManagedAppToAppInfo(app);
|
||||||
console.error(e);
|
|
||||||
const result = await api.get(`api/v1/app?app=${id}`);
|
|
||||||
const data = result?.data;
|
|
||||||
if (data?.message) {
|
|
||||||
$q.notify({
|
|
||||||
type: 'negative',
|
|
||||||
caption: "エラー",
|
|
||||||
message: data.message
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return { appid: data.appId, appname: data.name };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
result = await api.get(`api/v1/app?app=${id}`);
|
||||||
|
const kApp = result?.data as IAppDisplay | KErrorMsg;
|
||||||
|
if (isErrorMsg(kApp)) {
|
||||||
|
$q.notify({
|
||||||
|
type: 'negative',
|
||||||
|
caption: 'エラー',
|
||||||
|
message: kApp.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return kApp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type KErrorMsg = {
|
||||||
|
message: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isErrorMsg = (e: IAppDisplay | KErrorMsg): e is KErrorMsg => {
|
||||||
|
return 'message' in e;
|
||||||
|
};
|
||||||
|
|
||||||
|
const convertManagedAppToAppInfo = (app: IManagedApp): AppInfo => {
|
||||||
|
return {
|
||||||
|
appId: app.appid,
|
||||||
|
name: app.appname
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const onClearFilter=()=>{
|
const onClearFilter=()=>{
|
||||||
filter.value='';
|
filter.value='';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ import { useAuthStore } from 'stores/useAuthStore';
|
|||||||
import { useDomainStore } from 'stores/useDomainStore';
|
import { useDomainStore } from 'stores/useDomainStore';
|
||||||
import ShareDomainDialog from 'components/ShareDomain/ShareDomainDialog.vue';
|
import ShareDomainDialog from 'components/ShareDomain/ShareDomainDialog.vue';
|
||||||
import TableActionMenu from 'components/TableActionMenu.vue';
|
import TableActionMenu from 'components/TableActionMenu.vue';
|
||||||
import { IDomain, IDomainOwnerDisplay, IDomainSubmit } from '../types/DomainTypes';
|
import { IDomain, IDomainDisplay, IDomainOwnerDisplay, IDomainSubmit } from '../types/DomainTypes';
|
||||||
|
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
const domainStore = useDomainStore();
|
const domainStore = useDomainStore();
|
||||||
@@ -166,7 +166,7 @@ const columns = [
|
|||||||
{ name: 'active', label: 'x', align: 'left', field: 'domainActive', classes: inactiveRowClass },
|
{ name: 'active', label: 'x', align: 'left', field: 'domainActive', classes: inactiveRowClass },
|
||||||
{ name: 'url', label: 'URL', field: 'url', align: 'left', sortable: true, classes: inactiveRowClass },
|
{ name: 'url', label: 'URL', field: 'url', align: 'left', sortable: true, classes: inactiveRowClass },
|
||||||
{ name: 'user', label: 'ログイン名', field: 'user', align: 'left', classes: inactiveRowClass },
|
{ name: 'user', label: 'ログイン名', field: 'user', align: 'left', classes: inactiveRowClass },
|
||||||
{ name: 'owner', label: '所有者', field: row => row.owner.fullName, align: 'left', classes: inactiveRowClass },
|
{ name: 'owner', label: '所有者', field: (row: IDomainOwnerDisplay) => row.owner.fullName, align: 'left', classes: inactiveRowClass },
|
||||||
{ name: 'actions', label: '', field: 'actions', classes: inactiveRowClass }
|
{ name: 'actions', label: '', field: 'actions', classes: inactiveRowClass }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,51 @@
|
|||||||
import { IUser } from './UserTypes';
|
import { IUser, IUserDisplay } from './UserTypes';
|
||||||
|
|
||||||
export interface IManagedApp {
|
export interface IManagedApp {
|
||||||
appid: string;
|
appid: string;
|
||||||
appname: string;
|
appname: string;
|
||||||
domainurl: string;
|
domainurl: string;
|
||||||
version: string;
|
version: string;
|
||||||
updateuser: IUser;
|
user: IUser;
|
||||||
update_time: string;
|
updateuser: IUser;
|
||||||
}
|
create_time: string;
|
||||||
|
update_time: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IManagedApp {
|
||||||
|
appid: string;
|
||||||
|
appname: string;
|
||||||
|
domainurl: string;
|
||||||
|
version: string;
|
||||||
|
user: IUser;
|
||||||
|
updateuser: IUser;
|
||||||
|
create_time: string;
|
||||||
|
update_time: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IAppDisplay{
|
||||||
|
id:string;
|
||||||
|
sortId: number;
|
||||||
|
name:string;
|
||||||
|
url:string;
|
||||||
|
updateUser: IUserDisplay;
|
||||||
|
updateTime:string;
|
||||||
|
version:string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IVersionInfo {
|
||||||
|
id: string;
|
||||||
|
name?: string;
|
||||||
|
desc?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IAppVersion {
|
||||||
|
id: number;
|
||||||
|
version: number;
|
||||||
|
appid: string;
|
||||||
|
name: string
|
||||||
|
comment: string;
|
||||||
|
updater: IUserDisplay;
|
||||||
|
updateTime: string;
|
||||||
|
creator: IUserDisplay;
|
||||||
|
createTime: string;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user