UI - Fixes UI bugs (#6162)

* fixes

* remove console

* fix hidden clear notification button

* fixes

* fixes

* fixes navigation to ssh from comments
This commit is contained in:
Hoang Nguyen 2022-03-30 17:05:36 +07:00 committed by GitHub
parent 1c238e101d
commit 1a304ccf68
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 172 additions and 141 deletions

View File

@ -68,11 +68,9 @@
<script> <script>
import store from '@/store' import store from '@/store'
import RenderIcon from '@/utils/renderIcon'
export default { export default {
name: 'HeaderNotice', name: 'HeaderNotice',
components: { RenderIcon },
data () { data () {
return { return {
loading: false, loading: false,

View File

@ -61,11 +61,9 @@
</template> </template>
<script> <script>
import RenderIcon from '@/utils/renderIcon'
export default { export default {
name: 'SMenu', name: 'SMenu',
components: { RenderIcon },
props: { props: {
menu: { menu: {
type: Array, type: Array,

View File

@ -209,6 +209,11 @@ export default {
}, 16) }, 16)
}) })
} }
const countNotify = this.$store.getters.countNotify
this.showClear = false
if (countNotify && countNotify > 0) {
this.showClear = true
}
}, },
beforeUnmount () { beforeUnmount () {
document.body.classList.remove('dark') document.body.classList.remove('dark')

View File

@ -51,13 +51,9 @@
</template> </template>
<script> <script>
import RenderIcon from '@/utils/renderIcon'
export default { export default {
name: 'PageHeader', name: 'PageHeader',
components: {
RenderIcon
},
props: { props: {
title: { title: {
type: String, type: String,

View File

@ -54,14 +54,11 @@
</template> </template>
<script> <script>
import RenderIcon from '@/utils/renderIcon'
import PageHeader from './PageHeader' import PageHeader from './PageHeader'
export default { export default {
name: 'LayoutContent', name: 'LayoutContent',
components: { components: {
RenderIcon,
PageHeader PageHeader
}, },
// ['desc', 'logo', 'title', 'avatar', 'linkList', 'extraImage'] // ['desc', 'logo', 'title', 'avatar', 'linkList', 'extraImage']

View File

@ -80,13 +80,11 @@
<script> <script>
import { api } from '@/api' import { api } from '@/api'
import RenderIcon from '@/utils/renderIcon'
import Console from '@/components/widgets/Console' import Console from '@/components/widgets/Console'
export default { export default {
name: 'ActionButton', name: 'ActionButton',
components: { components: {
RenderIcon,
Console Console
}, },
data () { data () {
@ -94,7 +92,7 @@ export default {
actionBadge: {} actionBadge: {}
} }
}, },
mounted () { created () {
this.handleShowBadge() this.handleShowBadge()
}, },
props: { props: {

View File

@ -697,7 +697,6 @@
<script> <script>
import { api } from '@/api' import { api } from '@/api'
import RenderIcon from '@/utils/renderIcon'
import Console from '@/components/widgets/Console' import Console from '@/components/widgets/Console'
import OsLogo from '@/components/widgets/OsLogo' import OsLogo from '@/components/widgets/OsLogo'
import Status from '@/components/widgets/Status' import Status from '@/components/widgets/Status'
@ -714,8 +713,7 @@ export default {
Status, Status,
TooltipButton, TooltipButton,
UploadResourceIcon, UploadResourceIcon,
ResourceIcon, ResourceIcon
RenderIcon
}, },
props: { props: {
resource: { resource: {

View File

@ -98,7 +98,7 @@
</span> </span>
<span v-if="record.hasannotations"> <span v-if="record.hasannotations">
<span v-if="record.id"> <span v-if="record.id && $route.path !== '/ssh'">
<router-link :to="{ path: $route.path + '/' + record.id }">{{ text }}</router-link> <router-link :to="{ path: $route.path + '/' + record.id }">{{ text }}</router-link>
<router-link :to="{ path: $route.path + '/' + record.id, query: { tab: 'comments' } }"><message-filled style="padding-left: 10px" size="small"/></router-link> <router-link :to="{ path: $route.path + '/' + record.id, query: { tab: 'comments' } }"><message-filled style="padding-left: 10px" size="small"/></router-link>
</span> </span>
@ -398,7 +398,6 @@ import Status from '@/components/widgets/Status'
import QuickView from '@/components/view/QuickView' import QuickView from '@/components/view/QuickView'
import TooltipButton from '@/components/widgets/TooltipButton' import TooltipButton from '@/components/widgets/TooltipButton'
import ResourceIcon from '@/components/view/ResourceIcon' import ResourceIcon from '@/components/view/ResourceIcon'
import RenderIcon from '@/utils/renderIcon'
export default { export default {
name: 'ListView', name: 'ListView',
@ -407,8 +406,7 @@ export default {
Status, Status,
QuickView, QuickView,
TooltipButton, TooltipButton,
ResourceIcon, ResourceIcon
RenderIcon
}, },
props: { props: {
columns: { columns: {
@ -682,6 +680,9 @@ export default {
return record.nic.filter(e => { return e.ip6address }).map(e => { return e.ip6address }).join(', ') || text return record.nic.filter(e => { return e.ip6address }).map(e => { return e.ip6address }).join(', ') || text
}, },
generateCommentsPath (record) { generateCommentsPath (record) {
if (this.entityTypeToPath(record.entitytype) === 'ssh') {
return '/' + this.entityTypeToPath(record.entitytype) + '/' + record.entityname
}
return '/' + this.entityTypeToPath(record.entitytype) + '/' + record.entityid return '/' + this.entityTypeToPath(record.entitytype) + '/' + record.entityid
}, },
generateHumanReadableEntityType (record) { generateHumanReadableEntityType (record) {

View File

@ -61,11 +61,9 @@
</template> </template>
<script> <script>
import RenderIcon from '@/utils/renderIcon'
export default { export default {
name: 'Breadcrumb', name: 'Breadcrumb',
components: { RenderIcon },
props: { props: {
resource: { resource: {
type: Object, type: Object,

View File

@ -20,47 +20,46 @@
<template #title v-if="tooltip"> <template #title v-if="tooltip">
{{ tooltip }} {{ tooltip }}
</template> </template>
<a-button <span style="margin-right: 5px">
style="margin-left: -5px" <a-button
v-if="copyResource" v-if="copyResource"
shape="circle" shape="circle"
:size="size" :size="size"
:type="type" :type="type"
:danger="danger" :danger="danger"
:disabled="disabled" :disabled="disabled"
:class="buttonClass" :class="buttonClass"
:loading="loading" :loading="loading"
@click="handleClicked()" @click="handleClicked()"
v-clipboard:copy="copyResource" > v-clipboard:copy="copyResource" >
<template #icon v-if="icon"><render-icon :icon="icon" /></template> <template #icon v-if="icon"><render-icon :icon="icon" /></template>
<template v-if="iconType && iconTwoToneColor"> <template v-if="iconType && iconTwoToneColor">
<render-icon :icon="iconType" :props="{ theme: 'twoTone', twoToneColor: iconTwoToneColor }" /> <render-icon :icon="iconType" :props="{ theme: 'twoTone', twoToneColor: iconTwoToneColor }" />
</template> </template>
</a-button> </a-button>
<a-button <a-button
v-else v-else
shape="circle" shape="circle"
:size="size" :size="size"
:type="type" :type="type"
:danger="danger" :danger="danger"
:disabled="disabled" :disabled="disabled"
:class="buttonClass" :class="buttonClass"
:loading="loading" :loading="loading"
@click="handleClicked()" > @click="handleClicked()" >
<template #icon v-if="icon"><render-icon :icon="icon" /></template> <template #icon v-if="icon"><render-icon :icon="icon" /></template>
<template v-if="iconType && iconTwoToneColor"> <template v-if="iconType && iconTwoToneColor">
<render-icon :icon="iconType" :props="{ theme: 'twoTone', twoToneColor: iconTwoToneColor }" /> <render-icon :icon="iconType" :props="{ theme: 'twoTone', twoToneColor: iconTwoToneColor }" />
</template> </template>
</a-button> </a-button>
</span>
</a-tooltip> </a-tooltip>
</template> </template>
<script> <script>
import RenderIcon from '@/utils/renderIcon'
export default { export default {
name: 'TooltipButton', name: 'TooltipButton',
components: { RenderIcon },
props: { props: {
tooltip: { tooltip: {
type: String, type: String,

View File

@ -152,6 +152,7 @@ import {
UploadOutlined, UploadOutlined,
WifiOutlined WifiOutlined
} from '@ant-design/icons-vue' } from '@ant-design/icons-vue'
import renderIcon from '@/utils/renderIcon'
export default { export default {
install: (app) => { install: (app) => {
@ -290,5 +291,6 @@ export default {
app.component('UserOutlined', UserOutlined) app.component('UserOutlined', UserOutlined)
app.component('UploadOutlined', UploadOutlined) app.component('UploadOutlined', UploadOutlined)
app.component('WifiOutlined', WifiOutlined) app.component('WifiOutlined', WifiOutlined)
app.component('renderIcon', renderIcon)
} }
} }

View File

@ -78,6 +78,11 @@ export default {
if (layoutMode === 'dark') { if (layoutMode === 'dark') {
document.body.classList.add('dark-mode') document.body.classList.add('dark-mode')
} }
const countNotify = this.$store.getters.countNotify
this.showClear = false
if (countNotify && countNotify > 0) {
this.showClear = true
}
}, },
beforeUnmount () { beforeUnmount () {
document.body.classList.remove('userLayout') document.body.classList.remove('userLayout')

View File

@ -47,7 +47,7 @@
@box-shadow-base: 0 2px 8px rgba(0, 0, 0, 0.15); @box-shadow-base: 0 2px 8px rgba(0, 0, 0, 0.15);
@loading-color: @primary-color; @loading-color: @primary-color;
.ant-layout.ant-layout-has-sider>.ant-layout, // .ant-layout.ant-layout-has-sider>.ant-layout,
.ant-layout.ant-layout-has-sider>.ant-layout-content { .ant-layout.ant-layout-has-sider>.ant-layout-content {
width: auto; width: auto;
} }
@ -171,6 +171,18 @@ a {
fill: @navigation-text-color; fill: @navigation-text-color;
} }
.ant-menu-dark .ant-menu-item {
.anticon .custom-icon {
fill: @project-nav-text-color;
}
&.ant-menu-item-selected {
.anticon .custom-icon {
fill: #fff;
}
}
}
.ant-menu-item a { .ant-menu-item a {
.anticon .custom-icon { .anticon .custom-icon {
transition: fill 0.3s ease-out; transition: fill 0.3s ease-out;
@ -180,6 +192,10 @@ a {
} }
} }
.ant-menu-dark .ant-menu-item:hover .anticon .custom-icon {
fill: #fff;
}
.ant-menu-item:hover, .ant-menu-item:hover,
.ant-menu-item-active, .ant-menu-item-active,
.ant-menu:not(.ant-menu-inline) .ant-menu-submenu-open, .ant-menu:not(.ant-menu-inline) .ant-menu-submenu-open,

View File

@ -1190,6 +1190,9 @@ export default {
}) })
} }
} }
if ('successMethod' in action) {
action.successMethod(this, result)
}
resolve(true) resolve(true)
}, },
errorMethod: () => { errorMethod: () => {

View File

@ -282,6 +282,8 @@ export default {
}) })
}, },
loginSuccess (res) { loginSuccess (res) {
this.$notification.destroy()
this.$store.commit('SET_COUNT_NOTIFY', 0)
this.$router.push({ path: '/dashboard' }).catch(() => {}) this.$router.push({ path: '/dashboard' }).catch(() => {})
}, },
requestFailed (err) { requestFailed (err) {

View File

@ -1648,7 +1648,6 @@ export default {
handleSubmitAndStay (e) { handleSubmitAndStay (e) {
this.form.stayonpage = true this.form.stayonpage = true
this.handleSubmit(e.domEvent) this.handleSubmit(e.domEvent)
this.form.stayonpage = false
}, },
handleSubmit (e) { handleSubmit (e) {
console.log('wizard submit') console.log('wizard submit')
@ -1884,6 +1883,9 @@ export default {
}).catch(error => { }).catch(error => {
this.$notifyError(error) this.$notifyError(error)
this.loading.deploy = false this.loading.deploy = false
}).finally(() => {
this.form.stayonpage = false
this.loading.deploy = false
}) })
}).catch(err => { }).catch(err => {
this.formRef.value.scrollToField(err.errorFields[0].name) this.formRef.value.scrollToField(err.errorFields[0].name)

View File

@ -83,43 +83,45 @@
</div> </div>
<div v-if="selectedRowKeys.length > 0" class="row-keys"> <div v-if="selectedRowKeys.length > 0" class="row-keys">
<a-divider /> <a-divider />
<a-table <a-form layout="vertical">
v-if="selectedRowKeys.length > 0" <a-table
size="middle" v-if="selectedRowKeys.length > 0"
:columns="chosenColumns" size="middle"
:dataSource="selectedItems" :columns="chosenColumns"
:rowKey="(record, idx) => record.id || record.name || record.usageType || idx + '-' + Math.random()" :dataSource="selectedItems"
:pagination="true" :rowKey="(record, idx) => record.id || record.name || record.usageType || idx + '-' + Math.random()"
style="overflow-y: auto" :pagination="true"
> style="overflow-y: auto"
<template >
#expandedRowRender="record" <template
style="margin: 0"> #expandedRowRender="{ record } "
<a-form-item :label="$t('label.delete.volumes')" v-if="listVolumes[record.id].opts.length > 0"> style="margin: 0">
<a-select <a-form-item :label="$t('label.delete.volumes')" v-if="listVolumes[record.id].opts.length > 0">
mode="multiple" <a-select
showSearch mode="multiple"
optionFilterProp="label" showSearch
:filterOption="(input, option) => { optionFilterProp="label"
return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0 :filterOption="(input, option) => {
}" return option.children[0].children.toLowerCase().indexOf(input.toLowerCase()) >= 0
:loading="listVolumes[record.id].loading" }"
:placeholder="$t('label.delete.volumes')" :loading="listVolumes[record.id].loading"
@change="(value) => onChangeVolume(record.id, value)"> :placeholder="$t('label.delete.volumes')"
<a-select-option v-for="item in listVolumes[record.id].opts" :key="item.id"> @change="(value) => onChangeVolume(record.id, value)">
{{ item.name || item.description }} <a-select-option v-for="item in listVolumes[record.id].opts" :key="item.id">
</a-select-option> {{ item.name || item.description }}
</a-select> </a-select-option>
</a-form-item> </a-select>
<span v-else v-html="$t('label.volume.empty')" /> </a-form-item>
</template> <span v-else v-html="$t('label.volume.empty')" />
</a-table> </template>
<a-form-item v-if="$store.getters.userInfo.roletype === 'Admin' || $store.getters.features.allowuserexpungerecovervm"> </a-table>
<template #label> <a-form-item v-if="$store.getters.userInfo.roletype === 'Admin' || $store.getters.features.allowuserexpungerecovervm">
<tooltip-label :title="$t('label.expunge')" :tooltip="apiParams.expunge.description"/> <template #label>
</template> <tooltip-label :title="$t('label.expunge')" :tooltip="apiParams.expunge.description"/>
<a-switch v-model:checked="expunge" v-focus="true" /> </template>
</a-form-item> <a-switch v-model:checked="expunge" v-focus="true" />
</a-form-item>
</a-form>
</div> </div>
<div :span="24" class="action-button"> <div :span="24" class="action-button">
@ -214,7 +216,6 @@ export default {
this.listVolumes[item.id].loading = false this.listVolumes[item.id].loading = false
this.listVolumes[item.id].opts = item.volumes || [] this.listVolumes[item.id].opts = item.volumes || []
}) })
this.$forceUpdate()
}) })
} }
}, },

View File

@ -52,7 +52,7 @@
:bordered="false" :bordered="false"
:loading="loading" :loading="loading"
:style="stat.bgcolor ? { 'background': stat.bgcolor } : {}"> :style="stat.bgcolor ? { 'background': stat.bgcolor } : {}">
<router-link :to="{ path: stat.path, query: stat.query }"> <router-link v-if="stat.path" :to="{ path: stat.path, query: stat.query }">
<div <div
class="usage-dashboard-chart-card-inner"> class="usage-dashboard-chart-card-inner">
<h3>{{ stat.name }}</h3> <h3>{{ stat.name }}</h3>
@ -68,8 +68,7 @@
</a-card> </a-card>
</a-row> </a-row>
</a-col> </a-col>
<a-col <a-col :xl="8">
:xl="8">
<chart-card :loading="loading" > <chart-card :loading="loading" >
<div class="usage-dashboard-chart-card-inner"> <div class="usage-dashboard-chart-card-inner">
<a-button> <a-button>
@ -100,7 +99,6 @@
<script> <script>
import { api } from '@/api' import { api } from '@/api'
import store from '@/store' import store from '@/store'
import RenderIcon from '@/utils/renderIcon'
import ChartCard from '@/components/widgets/ChartCard' import ChartCard from '@/components/widgets/ChartCard'
import UsageDashboardChart from '@/views/dashboard/UsageDashboardChart' import UsageDashboardChart from '@/views/dashboard/UsageDashboardChart'
@ -109,8 +107,7 @@ export default {
name: 'UsageDashboard', name: 'UsageDashboard',
components: { components: {
ChartCard, ChartCard,
UsageDashboardChart, UsageDashboardChart
RenderIcon
}, },
props: { props: {
resource: { resource: {
@ -142,6 +139,8 @@ export default {
(newValue, oldValue) => { (newValue, oldValue) => {
if (newValue && newValue.id && (!oldValue || newValue.id !== oldValue.id)) { if (newValue && newValue.id && (!oldValue || newValue.id !== oldValue.id)) {
this.fetchData() this.fetchData()
} else if (store.getters.userInfo.roletype !== 'Admin') {
this.fetchData()
} }
} }
) )
@ -273,4 +272,10 @@ export default {
white-space: normal; white-space: normal;
} }
} }
@media (max-width: 1200px) {
.ant-col-xl-8 {
width: 100%;
}
}
</style> </style>

View File

@ -44,11 +44,9 @@
</template> </template>
<script> <script>
import RenderIcon from '@/utils/renderIcon'
export default { export default {
name: 'UsageDashboardChart', name: 'UsageDashboardChart',
components: { RenderIcon },
props: { props: {
stats: { stats: {
type: Array, type: Array,

View File

@ -169,7 +169,6 @@
import { ref, reactive, toRaw } from 'vue' import { ref, reactive, toRaw } from 'vue'
import { api } from '@/api' import { api } from '@/api'
import router from '@/router' import router from '@/router'
import RenderIcon from '@/utils/renderIcon'
import Breadcrumb from '@/components/widgets/Breadcrumb' import Breadcrumb from '@/components/widgets/Breadcrumb'
import ChartCard from '@/components/widgets/ChartCard' import ChartCard from '@/components/widgets/ChartCard'
@ -180,8 +179,7 @@ export default {
components: { components: {
Breadcrumb, Breadcrumb,
ChartCard, ChartCard,
TooltipLabel, TooltipLabel
RenderIcon
}, },
data () { data () {
return { return {

View File

@ -35,32 +35,32 @@
<template #action="{ record }"> <template #action="{ record }">
<div v-if="record.projectroleid"> <div v-if="record.projectroleid">
<span v-if="imProjectAdmin && dataSource.length > 1" class="account-button-action"> <span v-if="imProjectAdmin && dataSource.length > 1" class="account-button-action">
<tooltip-button <tooltip-button
tooltipPlacement="top" tooltipPlacement="top"
:tooltip="record.userid ? $t('label.make.user.project.owner') : $t('label.make.project.owner')" :tooltip="record.userid ? $t('label.make.user.project.owner') : $t('label.make.project.owner')"
v-if="record.role !== owner" v-if="record.role !== owner"
type="default" type="default"
icon="arrow-up-outlined" icon="arrow-up-outlined"
size="small" size="small"
@onClick="promoteAccount(record)" /> @onClick="promoteAccount(record)" />
<tooltip-button <tooltip-button
tooltipPlacement="top" tooltipPlacement="top"
:tooltip="record.userid ? $t('label.demote.project.owner.user') : $t('label.demote.project.owner')" :tooltip="record.userid ? $t('label.demote.project.owner.user') : $t('label.demote.project.owner')"
v-if="updateProjectApi.params.filter(x => x.name === 'swapowner').length > 0 && record.role === owner" v-if="updateProjectApi.params.filter(x => x.name === 'swapowner').length > 0 && record.role === owner"
type="default" type="default"
icon="arrow-down-outlined" icon="arrow-down-outlined"
size="small" size="small"
@onClick="demoteAccount(record)" /> @onClick="demoteAccount(record)" />
<tooltip-button <tooltip-button
tooltipPlacement="top" tooltipPlacement="top"
:tooltip="record.userid ? $t('label.remove.project.user') : $t('label.remove.project.account')" :tooltip="record.userid ? $t('label.remove.project.user') : $t('label.remove.project.account')"
type="primary" type="primary"
:danger="true" :danger="true"
icon="delete-outlined" icon="delete-outlined"
size="small" size="small"
:disabled="!('deleteAccountFromProject' in $store.getters.apis)" :disabled="!('deleteAccountFromProject' in $store.getters.apis)"
@onClick="onShowConfirmDelete(record)" /> @onClick="onShowConfirmDelete(record)" />
</span> </span>
</div> </div>
</template> </template>
</a-table> </a-table>

View File

@ -44,7 +44,6 @@
<tooltip-button <tooltip-button
tooltipPlacement="top" tooltipPlacement="top"
:tooltip="$t('label.accept.project.invitation')" :tooltip="$t('label.accept.project.invitation')"
type="success"
icon="check-outlined" icon="check-outlined"
size="small" size="small"
@onClick="onShowConfirmAcceptInvitation(record)"/> @onClick="onShowConfirmAcceptInvitation(record)"/>
@ -247,12 +246,24 @@ export default {
params.accept = state params.accept = state
api('updateProjectInvitation', params).then(json => { api('updateProjectInvitation', params).then(json => {
const hasJobId = this.checkForAddAsyncJob(json, title, record.project) this.$pollJob({
jobId: json.updateprojectinvitationresponse.jobid,
if (hasJobId) { title,
this.fetchData() description: record.project,
this.$emit('refresh-data') successMethod: () => {
} this.fetchData()
this.$emit('refresh-data')
},
errorMethod: () => {
this.fetchData()
this.$emit('refresh-data')
},
catchMessage: this.$t('error.fetching.async.job.result'),
catchMethod: () => {
this.fetchData()
this.$emit('refresh-data')
}
})
}).catch(error => { }).catch(error => {
// show error // show error
this.$notifyError(error) this.$notifyError(error)