diff --git a/src/components/TableButton/RuleButton.jsx b/src/components/TableButton/RuleButton.jsx index 5f3e3962..f6eff753 100644 --- a/src/components/TableButton/RuleButton.jsx +++ b/src/components/TableButton/RuleButton.jsx @@ -21,6 +21,10 @@ export default class RuleButton extends Component { return this.isAdminPage ? `${path}${adminStr || '-admin'}` : path; } + getDetailUrl(id) { + return `${this.getUrl('/network/security-group')}/detail/${id}`; + } + render() { const { item: { security_group_rules: datas = [] } = {} } = this.props; const configs = { diff --git a/src/pages/compute/containers/Flavor/Arm/index.jsx b/src/pages/compute/containers/Flavor/Arm/index.jsx index f4241ba4..4fc05ced 100644 --- a/src/pages/compute/containers/Flavor/Arm/index.jsx +++ b/src/pages/compute/containers/Flavor/Arm/index.jsx @@ -68,4 +68,4 @@ export class Flavor extends Base { } } -export default inject('rootStore')(observer(Flavor)); \ No newline at end of file +export default inject('rootStore')(observer(Flavor)); diff --git a/src/pages/compute/containers/Flavor/Detail/index.jsx b/src/pages/compute/containers/Flavor/Detail/index.jsx index 84654bcd..ca174d58 100644 --- a/src/pages/compute/containers/Flavor/Detail/index.jsx +++ b/src/pages/compute/containers/Flavor/Detail/index.jsx @@ -21,9 +21,7 @@ import { emptyActionConfig } from 'utils/constants'; import actionConfigs from '../actions'; import BaseDetail from './BaseDetail'; -@inject('rootStore') -@observer -export default class Detail extends Base { +export class Detail extends Base { get name() { return t('flavor'); } @@ -96,3 +94,5 @@ export default class Detail extends Base { this.store = new FlavorStore(); } } + +export default inject('rootStore')(observer(Detail)); diff --git a/src/pages/compute/containers/Instance/Detail/SecurityGroup/index.jsx b/src/pages/compute/containers/Instance/Detail/SecurityGroup/index.jsx index 5ab5cb92..4ab63dc1 100644 --- a/src/pages/compute/containers/Instance/Detail/SecurityGroup/index.jsx +++ b/src/pages/compute/containers/Instance/Detail/SecurityGroup/index.jsx @@ -68,6 +68,10 @@ export class SecurityGroup extends React.Component { return this.isAdminPage ? `${path}${adminStr || '-admin'}` : path; } + getDetailUrl(id) { + return `${this.getUrl('/network/security-group')}/detail/${id}`; + } + actionCallback = async (first) => { const { match: { diff --git a/src/pages/identity/containers/Project/actions/Create.jsx b/src/pages/identity/containers/Project/actions/Create.jsx index a5c4daa4..ae66e9ed 100644 --- a/src/pages/identity/containers/Project/actions/Create.jsx +++ b/src/pages/identity/containers/Project/actions/Create.jsx @@ -19,7 +19,7 @@ import globalProjectStore from 'stores/keystone/project'; import { regex } from 'utils/validate'; import { statusTypes } from 'utils/constants'; -class CreateForm extends ModalAction { +export class CreateForm extends ModalAction { constructor(props) { super(props); this.state = { diff --git a/src/pages/identity/containers/Project/actions/Edit.jsx b/src/pages/identity/containers/Project/actions/Edit.jsx index 85cf2b06..52609f94 100644 --- a/src/pages/identity/containers/Project/actions/Edit.jsx +++ b/src/pages/identity/containers/Project/actions/Edit.jsx @@ -17,7 +17,7 @@ import { ModalAction } from 'containers/Action'; import globalProjectStore from 'stores/keystone/project'; import { statusTypes } from 'utils/constants'; -class EditForm extends ModalAction { +export class EditForm extends ModalAction { init() { this.store = globalProjectStore; this.store.fetchList(); diff --git a/src/pages/identity/containers/Project/index.jsx b/src/pages/identity/containers/Project/index.jsx index 0fe086a7..aec7d65e 100644 --- a/src/pages/identity/containers/Project/index.jsx +++ b/src/pages/identity/containers/Project/index.jsx @@ -18,13 +18,10 @@ import { Divider, Badge, Tag, Tooltip } from 'antd'; import Base from 'containers/List'; import globalProjectStore from 'stores/keystone/project'; import { yesNoOptions, projectTagsColors } from 'utils/constants'; - import actionConfigs from './actions'; import styles from './index.less'; -@inject('rootStore') -@observer -export default class Projects extends Base { +export class Projects extends Base { init() { this.store = globalProjectStore; } @@ -222,3 +219,5 @@ export default class Projects extends Base { this.list.silent = false; } } + +export default inject('rootStore')(observer(Projects)); diff --git a/src/pages/identity/containers/User/actions/Create.jsx b/src/pages/identity/containers/User/actions/Create.jsx index 88796866..bf08be92 100644 --- a/src/pages/identity/containers/User/actions/Create.jsx +++ b/src/pages/identity/containers/User/actions/Create.jsx @@ -28,7 +28,7 @@ import { } from 'utils/validate'; import { statusTypes } from 'utils/constants'; -class CreateForm extends FormAction { +export class CreateForm extends FormAction { constructor(props) { super(props); diff --git a/src/pages/identity/containers/User/actions/Edit.jsx b/src/pages/identity/containers/User/actions/Edit.jsx index 3e670d3c..6744e7bf 100644 --- a/src/pages/identity/containers/User/actions/Edit.jsx +++ b/src/pages/identity/containers/User/actions/Edit.jsx @@ -18,7 +18,7 @@ import globalUserStore from 'stores/keystone/user'; import globalDomainStore from 'stores/keystone/domain'; import { phoneNumberValidate, emailValidate } from 'utils/validate'; -class EditForm extends ModalAction { +export class EditForm extends ModalAction { init() { this.store = globalUserStore; this.domainStore = globalDomainStore; diff --git a/src/pages/network/containers/FloatingIp/Detail/index.jsx b/src/pages/network/containers/FloatingIp/Detail/index.jsx index 4b9c9fc2..d11af786 100644 --- a/src/pages/network/containers/FloatingIp/Detail/index.jsx +++ b/src/pages/network/containers/FloatingIp/Detail/index.jsx @@ -21,9 +21,7 @@ import actionConfigs from '../actions'; import BaseDetail from './BaseDetail'; import PortForwarding from './PortForwarding'; -@inject('rootStore') -@observer -export default class FloatingIpDetail extends Base { +export class FloatingIpDetail extends Base { get name() { return t('floating ip'); } @@ -92,3 +90,5 @@ export default class FloatingIpDetail extends Base { this.store = new FloatingIpStore(); } } + +export default inject('rootStore')(observer(FloatingIpDetail)); diff --git a/src/pages/network/containers/FloatingIp/actions/Allocate.jsx b/src/pages/network/containers/FloatingIp/actions/Allocate.jsx index e8603daa0..4d7700d8 100644 --- a/src/pages/network/containers/FloatingIp/actions/Allocate.jsx +++ b/src/pages/network/containers/FloatingIp/actions/Allocate.jsx @@ -226,4 +226,4 @@ export class Allocate extends ModalAction { } } -export default inject('rootStore')(observer(Allocate)); \ No newline at end of file +export default inject('rootStore')(observer(Allocate)); diff --git a/src/pages/network/containers/Router/index.jsx b/src/pages/network/containers/Router/index.jsx index c682a2b7..a4361951 100644 --- a/src/pages/network/containers/Router/index.jsx +++ b/src/pages/network/containers/Router/index.jsx @@ -61,4 +61,4 @@ export class Routes extends Base { } } -export default inject('rootStore')(observer(Routes)); \ No newline at end of file +export default inject('rootStore')(observer(Routes)); diff --git a/src/pages/network/containers/SecurityGroup/Detail/Rule/index.jsx b/src/pages/network/containers/SecurityGroup/Detail/Rule/index.jsx index a7527f35..3c140a50 100644 --- a/src/pages/network/containers/SecurityGroup/Detail/Rule/index.jsx +++ b/src/pages/network/containers/SecurityGroup/Detail/Rule/index.jsx @@ -31,6 +31,10 @@ export class Rule extends Base { return t('security group rules'); } + getDetailUrl(id) { + return `${this.getUrl('/network/security-group')}/detail/${id}`; + } + getColumns = () => getSelfColumns(this); get actionConfigs() { diff --git a/src/pages/network/containers/VirtualAdapter/Detail/SecurityGroups/index.jsx b/src/pages/network/containers/VirtualAdapter/Detail/SecurityGroups/index.jsx index d70cce7e..373bb2f8 100644 --- a/src/pages/network/containers/VirtualAdapter/Detail/SecurityGroups/index.jsx +++ b/src/pages/network/containers/VirtualAdapter/Detail/SecurityGroups/index.jsx @@ -30,9 +30,7 @@ import styles from './index.less'; const { Panel } = Collapse; -@inject('rootStore') -@observer -export default class SecurityGroup extends React.Component { +export class SecurityGroup extends React.Component { constructor(props) { super(props); this.store = new VirtualAdapterStore(); @@ -46,6 +44,10 @@ export default class SecurityGroup extends React.Component { return this.isAdminPage ? `${path}${adminStr || '-admin'}` : path; } + getDetailUrl(id) { + return `${this.getUrl('/network/security-group')}/detail/${id}`; + } + get portId() { const { detail: { id }, @@ -66,6 +68,7 @@ export default class SecurityGroup extends React.Component { const { security_groups: { data }, } = this.store; + const detailUrl = this.getDetailUrl(item); return ( @@ -76,10 +79,7 @@ export default class SecurityGroup extends React.Component { {!this.isAdminPage && ( <> - + {t('Edit Rule')} @@ -160,3 +160,5 @@ export default class SecurityGroup extends React.Component { ); } } + +export default inject('rootStore')(observer(SecurityGroup)); diff --git a/src/pages/network/containers/VirtualAdapter/Detail/index.jsx b/src/pages/network/containers/VirtualAdapter/Detail/index.jsx index bac7764d..c8c11755 100644 --- a/src/pages/network/containers/VirtualAdapter/Detail/index.jsx +++ b/src/pages/network/containers/VirtualAdapter/Detail/index.jsx @@ -22,9 +22,7 @@ import AllowedAddressPair from './AllowedAddressPair'; import BaseDetail from './BaseDetail'; import actionConfigs from '../actions'; -@inject('rootStore') -@observer -export default class VirtualAdapterDetail extends Base { +export class VirtualAdapterDetail extends Base { get name() { return t('virtual adapter'); } @@ -123,3 +121,5 @@ export default class VirtualAdapterDetail extends Base { this.store = new VirtualAdapterStore(); } } + +export default inject('rootStore')(observer(VirtualAdapterDetail)); diff --git a/src/pages/storage/containers/Snapshot/Detail/BaseDetail.jsx b/src/pages/storage/containers/Snapshot/Detail/BaseDetail.jsx index 4a26e37c..437b4e2a 100644 --- a/src/pages/storage/containers/Snapshot/Detail/BaseDetail.jsx +++ b/src/pages/storage/containers/Snapshot/Detail/BaseDetail.jsx @@ -17,9 +17,7 @@ import { Link } from 'react-router-dom'; import { inject, observer } from 'mobx-react'; import Base from 'containers/BaseDetail'; -@inject('rootStore') -@observer -export default class BaseDetail extends Base { +export class BaseDetail extends Base { get leftCards() { return [this.volumeCard]; } @@ -50,3 +48,5 @@ export default class BaseDetail extends Base { }; } } + +export default inject('rootStore')(observer(BaseDetail)); diff --git a/src/pages/storage/containers/Snapshot/Detail/index.jsx b/src/pages/storage/containers/Snapshot/Detail/index.jsx index f69e758f..9e577354 100644 --- a/src/pages/storage/containers/Snapshot/Detail/index.jsx +++ b/src/pages/storage/containers/Snapshot/Detail/index.jsx @@ -19,9 +19,7 @@ import { volumeStatus } from 'resources/volume'; import BaseDetail from './BaseDetail'; import actionConfigs from '../actions'; -@inject('rootStore') -@observer -export default class Detail extends Base { +export class Detail extends Base { get name() { return t('snapshot'); } @@ -84,3 +82,5 @@ export default class Detail extends Base { this.store = new SnapshotStore(); } } + +export default inject('rootStore')(observer(Detail)); diff --git a/src/pages/storage/containers/Snapshot/actions/CreateVolume.jsx b/src/pages/storage/containers/Snapshot/actions/CreateVolume.jsx index a38fd77c..01dce20a 100644 --- a/src/pages/storage/containers/Snapshot/actions/CreateVolume.jsx +++ b/src/pages/storage/containers/Snapshot/actions/CreateVolume.jsx @@ -16,9 +16,7 @@ import { inject, observer } from 'mobx-react'; import { ModalAction } from 'containers/Action'; import globalVolumeStore from 'stores/cinder/volume'; -@inject('rootStore') -@observer -export default class CreateVolume extends ModalAction { +export class CreateVolume extends ModalAction { static id = 'create'; static title = t('Create Volume'); @@ -36,11 +34,15 @@ export default class CreateVolume extends ModalAction { static allowed = () => Promise.resolve(true); + get volumeTypeParams() { + return {}; + } + async getVolumeTypes() { const { volume_id: id } = this.item; // eslint-disable-next-line no-unused-vars const [_, volume] = await Promise.all([ - this.volumeStore.fetchVolumeTypes(), + this.volumeStore.fetchVolumeTypes(this.volumeTypeParams), this.volumeStore.fetchDetail({ id }), ]); const { volume_type: volumeType } = volume; @@ -122,3 +124,5 @@ export default class CreateVolume extends ModalAction { return globalVolumeStore.create(body); }; } + +export default inject('rootStore')(observer(CreateVolume)); diff --git a/src/pages/storage/containers/Snapshot/index.jsx b/src/pages/storage/containers/Snapshot/index.jsx index 1b5e260e..452fc0fc 100644 --- a/src/pages/storage/containers/Snapshot/index.jsx +++ b/src/pages/storage/containers/Snapshot/index.jsx @@ -18,9 +18,7 @@ import { volumeStatus, snapshotTransitionStatuses } from 'resources/volume'; import globalSnapshotStore, { SnapshotStore } from 'stores/cinder/snapshot'; import actionConfigs from './actions'; -@inject('rootStore') -@observer -export default class Snapshots extends Base { +export class Snapshots extends Base { init() { if (this.inDetailPage) { this.store = new SnapshotStore(); @@ -150,3 +148,5 @@ export default class Snapshots extends Base { ]; } } + +export default inject('rootStore')(observer(Snapshots)); diff --git a/src/pages/storage/containers/Volume/actions/Create/index.jsx b/src/pages/storage/containers/Volume/actions/Create/index.jsx index 828f7eb5..4e84c0b3 100644 --- a/src/pages/storage/containers/Volume/actions/Create/index.jsx +++ b/src/pages/storage/containers/Volume/actions/Create/index.jsx @@ -476,6 +476,8 @@ export class Create extends FormAction { ]; } + onCountChangeCallback() {} + onCountChange = (value) => { let msg = t('Quota: Project quotas sufficient resources can be created'); let status = 'success'; @@ -487,10 +489,17 @@ export class Create extends FormAction { status = 'error'; } this.msg = msg; - this.setState({ - count: value, - status, - }); + this.setState( + { + count: value, + status, + }, + () => { + if (this.onCountChangeCallback) { + this.onCountChangeCallback(); + } + } + ); }; renderBadge() { @@ -501,6 +510,10 @@ export class Create extends FormAction { return ; } + renderExtra() { + return this.renderBadge(); + } + renderFooterLeft() { const { count = 1 } = this.state; const configs = { @@ -518,7 +531,7 @@ export class Create extends FormAction { value={count} className={classnames(styles.input, 'volume-count')} /> - {this.renderBadge()} + {this.renderExtra()} ); } diff --git a/src/pages/storage/containers/Volume/actions/CreateBackup.jsx b/src/pages/storage/containers/Volume/actions/CreateBackup.jsx index 49bf643e..c9ed0611 100644 --- a/src/pages/storage/containers/Volume/actions/CreateBackup.jsx +++ b/src/pages/storage/containers/Volume/actions/CreateBackup.jsx @@ -74,10 +74,11 @@ export class CreateBackup extends ModalAction { onSubmit = (values) => { const { id } = this.item; - const { volume, ...rest } = values; + const { name, incremental } = values; const force = isInUse(this.item); const body = { - ...rest, + name, + incremental, volume_id: id, force, }; diff --git a/src/pages/storage/containers/Volume/actions/Detach.jsx b/src/pages/storage/containers/Volume/actions/Detach.jsx index 3a3b38f3..ac9a6cef 100644 --- a/src/pages/storage/containers/Volume/actions/Detach.jsx +++ b/src/pages/storage/containers/Volume/actions/Detach.jsx @@ -18,9 +18,7 @@ import { ModalAction } from 'containers/Action'; import globalServerStore from 'stores/nova/instance'; import { isInUse, isOsDisk } from 'resources/volume'; -@inject('rootStore') -@observer -export default class Detach extends ModalAction { +export class Detach extends ModalAction { static id = 'detach'; static title = t('Detach'); @@ -92,10 +90,6 @@ export default class Detach extends ModalAction { label: t('Name'), name: 'name', }, - // { - // label: t('IP'), - // name: 'private_ip', - // }, ], columns: [ { @@ -106,36 +100,6 @@ export default class Detach extends ModalAction { title: t('Attached To'), dataIndex: 'device', }, - // { - // title: t('Image'), - // dataIndex: ['image', 'os_distro'], - // render: value => , - // }, - // { - // title: t('Fixed IP'), - // dataIndex: 'private_ip', - // render: private_ip => (private_ip || []).map(it => {it.ip}
), - // }, - // { - // title: t('Floating IP'), - // dataIndex: 'addresses', - // render: (addresses) => { - // if (!addresses || !addresses['pub-net']) { - // return '-'; - // } - // return addresses['pub-net'].map(it => {it.addr}
); - // }, - // }, - // { - // title: t('Flavor'), - // dataIndex: 'flavor', - // render: flavor => `${flavor.disk}G/${Number.parseInt(flavor.ram / 1024, 10)}G`, - // }, - // { - // title: t('Created At'), - // dataIndex: 'created', - // valueRender: 'sinceTime', - // }, ], }, ]; @@ -151,3 +115,5 @@ export default class Detach extends ModalAction { ); }; } + +export default inject('rootStore')(observer(Detach)); diff --git a/src/pages/storage/containers/Volume/actions/ExtendVolume.jsx b/src/pages/storage/containers/Volume/actions/ExtendVolume.jsx index 4cc7e138..afbc1ec2 100644 --- a/src/pages/storage/containers/Volume/actions/ExtendVolume.jsx +++ b/src/pages/storage/containers/Volume/actions/ExtendVolume.jsx @@ -78,7 +78,7 @@ export class ExtendVolume extends ModalAction { } onSubmit = async (values) => { - const { volume, ...rest } = values; + const { new_size } = values; const { id } = this.item; const instanceId = get(this.item, 'attachments[0].server_id'); @@ -99,7 +99,7 @@ export class ExtendVolume extends ModalAction { return; } } - return this.store.extendSize(id, rest); + return this.store.extendSize(id, { new_size }); }; } diff --git a/src/pages/storage/containers/Volume/index.jsx b/src/pages/storage/containers/Volume/index.jsx index 3401668c..17e4968a 100644 --- a/src/pages/storage/containers/Volume/index.jsx +++ b/src/pages/storage/containers/Volume/index.jsx @@ -12,27 +12,19 @@ // See the License for the specific language governing permissions and // limitations under the License. -import React from 'react'; -import { Link } from 'react-router-dom'; import { observer, inject } from 'mobx-react'; import Base from 'containers/List'; import { - volumeStatus, - diskTag, volumeTransitionStatuses, - bootableType, volumeFilters, - multiTip, + getVolumnColumnsList, } from 'resources/volume'; import globalVolumeStore, { VolumeStore } from 'stores/cinder/volume'; import { InstanceVolumeStore } from 'stores/nova/instance-volume'; -import { toLocalTimeFilter } from 'utils/index'; import { emptyActionConfig } from 'utils/constants'; import actionConfigs from './actions'; -@inject('rootStore') -@observer -export default class Volume extends Base { +export class Volume extends Base { init() { if (this.inDetailPage) { this.store = new InstanceVolumeStore(); @@ -91,113 +83,7 @@ export default class Volume extends Base { } getColumns = () => { - const columns = [ - { - title: t('ID/Name'), - dataIndex: 'name', - linkPrefix: `/storage/${this.getUrl('volume')}/detail`, - stringify: (name, record) => name || record.id, - sortKey: 'name', - }, - { - title: t('Project ID/Name'), - dataIndex: 'project_name', - hidden: !this.isAdminPage, - isHideable: true, - sorter: false, - }, - { - title: t('Host'), - dataIndex: 'host', - isHideable: true, - hidden: !this.isAdminPage, - sorter: false, - }, - { - title: t('Size'), - dataIndex: 'size', - isHideable: true, - render: (value) => `${value}GB`, - }, - { - title: t('Status'), - dataIndex: 'status', - render: (value) => volumeStatus[value] || '-', - }, - { - title: t('Type'), - dataIndex: 'volume_type', - isHideable: true, - width: 100, - sorter: false, - }, - { - title: t('Disk Tag'), - dataIndex: 'disk_tag', - isHideable: true, - render: (value) => diskTag[value] || '-', - sorter: false, - }, - { - title: t('Attached To'), - dataIndex: 'attachments', - isHideable: true, - sorter: false, - render: (value) => { - if (value && value.length > 0) { - return value.map((it) => ( -
- {it.device} on{' '} - - {it.server_name} - -
- )); - } - return '-'; - }, - stringify: (value) => { - if (value && value.length) { - return value - .map((it) => `${it.server_name}(${it.server_id})`) - .join(','); - } - return '-'; - }, - }, - { - title: t('Bootable'), - titleTip: t( - 'When the volume is "bootable" and the status is "available", it can be used as a startup source to create an instance.' - ), - dataIndex: 'bootable', - isHideable: true, - render: (value) => bootableType[value] || '-', - }, - { - title: t('Shared'), - dataIndex: 'multiattach', - valueRender: 'yesNo', - titleTip: multiTip, - width: 80, - sorter: false, - }, - { - title: t('Created At'), - dataIndex: 'created_at', - isHideable: true, - valueRender: 'sinceTime', - stringify: (value) => toLocalTimeFilter(value), - }, - ]; - if (this.inDetailPage) { - return columns.filter((it) => it.dataIndex !== 'attachments'); - } - return columns; + return getVolumnColumnsList(this); }; get searchFilters() { @@ -219,3 +105,5 @@ export default class Volume extends Base { return params; }; } + +export default inject('rootStore')(observer(Volume)); diff --git a/src/resources/security-group-rule.jsx b/src/resources/security-group-rule.jsx index 0d895ff8..e9182b02 100644 --- a/src/resources/security-group-rule.jsx +++ b/src/resources/security-group-rule.jsx @@ -88,19 +88,8 @@ export const getSelfColumns = (self) => [ dataIndex: 'remote_group_id', isHideable: true, render: (value) => { - return ( -
- {value ? ( - - {value} - - ) : ( - '-' - )} -
- ); + const url = self.getDetailUrl(value); + return
{value ? {value} : '-'}
; }, }, { diff --git a/src/resources/volume.jsx b/src/resources/volume.jsx index 69c2cb4d..225848ae 100644 --- a/src/resources/volume.jsx +++ b/src/resources/volume.jsx @@ -14,6 +14,8 @@ import React from 'react'; import { yesNoOptions } from 'utils/constants'; +import { toLocalTimeFilter } from 'utils/index'; +import { Link } from 'react-router-dom'; export const volumeStatus = { available: t('Available'), @@ -221,3 +223,113 @@ export const snapshotTypeTip = (

); + +export const getVolumnColumnsList = (self) => { + const columns = [ + { + title: t('ID/Name'), + dataIndex: 'name', + linkPrefix: `/storage/${self.getUrl('volume')}/detail`, + stringify: (name, record) => name || record.id, + sortKey: 'name', + }, + { + title: t('Project ID/Name'), + dataIndex: 'project_name', + hidden: !self.isAdminPage, + isHideable: true, + sorter: false, + }, + { + title: t('Host'), + dataIndex: 'host', + isHideable: true, + hidden: !self.isAdminPage, + sorter: false, + }, + { + title: t('Size'), + dataIndex: 'size', + isHideable: true, + render: (value) => `${value}GB`, + }, + { + title: t('Status'), + dataIndex: 'status', + render: (value) => volumeStatus[value] || '-', + }, + { + title: t('Type'), + dataIndex: 'volume_type', + isHideable: true, + width: 100, + sorter: false, + }, + { + title: t('Disk Tag'), + dataIndex: 'disk_tag', + isHideable: true, + render: (value) => diskTag[value] || '-', + sorter: false, + }, + { + title: t('Attached To'), + dataIndex: 'attachments', + isHideable: true, + sorter: false, + render: (value) => { + if (value && value.length > 0) { + return value.map((it) => ( +
+ {it.device} on{' '} + + {it.server_name} + +
+ )); + } + return '-'; + }, + stringify: (value) => { + if (value && value.length) { + return value + .map((it) => `${it.server_name}(${it.server_id})`) + .join(','); + } + return '-'; + }, + }, + { + title: t('Bootable'), + titleTip: t( + 'When the volume is "bootable" and the status is "available", it can be used as a startup source to create an instance.' + ), + dataIndex: 'bootable', + isHideable: true, + render: (value) => bootableType[value] || '-', + }, + { + title: t('Shared'), + dataIndex: 'multiattach', + valueRender: 'yesNo', + titleTip: multiTip, + width: 80, + sorter: false, + }, + { + title: t('Created At'), + dataIndex: 'created_at', + isHideable: true, + valueRender: 'sinceTime', + stringify: (value) => toLocalTimeFilter(value), + }, + ]; + if (self.inDetailPage) { + return columns.filter((it) => it.dataIndex !== 'attachments'); + } + return columns; +};