fix: Update link generate for security group rule
1. Update link generate for security group rule 2. Update export Change-Id: I12ea81aab8ff697e1b0764ae9592d0de4ee00bc4
This commit is contained in:
parent
ca4f999c7f
commit
f21c5a6daa
@ -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 = {
|
||||
|
@ -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));
|
||||
|
@ -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: {
|
||||
|
@ -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 = {
|
||||
|
@ -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();
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
|
@ -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() {
|
||||
|
@ -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 (
|
||||
<Row>
|
||||
<Col span={18}>
|
||||
@ -76,10 +79,7 @@ export default class SecurityGroup extends React.Component {
|
||||
<Col span={6}>
|
||||
{!this.isAdminPage && (
|
||||
<>
|
||||
<Link
|
||||
style={{ fontSize: 12, marginRight: 16 }}
|
||||
to={`/network/security-group/detail/${item.id}`}
|
||||
>
|
||||
<Link style={{ fontSize: 12, marginRight: 16 }} to={detailUrl}>
|
||||
{t('Edit Rule')}
|
||||
</Link>
|
||||
</>
|
||||
@ -160,3 +160,5 @@ export default class SecurityGroup extends React.Component {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default inject('rootStore')(observer(SecurityGroup));
|
||||
|
@ -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));
|
||||
|
@ -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));
|
||||
|
@ -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));
|
||||
|
@ -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));
|
||||
|
@ -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));
|
||||
|
@ -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({
|
||||
this.setState(
|
||||
{
|
||||
count: value,
|
||||
status,
|
||||
});
|
||||
},
|
||||
() => {
|
||||
if (this.onCountChangeCallback) {
|
||||
this.onCountChangeCallback();
|
||||
}
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
renderBadge() {
|
||||
@ -501,6 +510,10 @@ export class Create extends FormAction {
|
||||
return <Badge status={status} text={this.msg} />;
|
||||
}
|
||||
|
||||
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()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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 => <ImageType type={value} />,
|
||||
// },
|
||||
// {
|
||||
// title: t('Fixed IP'),
|
||||
// dataIndex: 'private_ip',
|
||||
// render: private_ip => (private_ip || []).map(it => <span key={it.ip}>{it.ip}<br /></span>),
|
||||
// },
|
||||
// {
|
||||
// title: t('Floating IP'),
|
||||
// dataIndex: 'addresses',
|
||||
// render: (addresses) => {
|
||||
// if (!addresses || !addresses['pub-net']) {
|
||||
// return '-';
|
||||
// }
|
||||
// return addresses['pub-net'].map(it => <span key={it.addr}>{it.addr}<br /></span>);
|
||||
// },
|
||||
// },
|
||||
// {
|
||||
// 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));
|
||||
|
@ -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 });
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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) => (
|
||||
<div key={it.server_id}>
|
||||
{it.device} on{' '}
|
||||
<Link
|
||||
to={`${this.getUrl('/compute/instance')}/detail/${
|
||||
it.server_id
|
||||
}?tab=volumes`}
|
||||
>
|
||||
{it.server_name}
|
||||
</Link>
|
||||
</div>
|
||||
));
|
||||
}
|
||||
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));
|
||||
|
@ -88,19 +88,8 @@ export const getSelfColumns = (self) => [
|
||||
dataIndex: 'remote_group_id',
|
||||
isHideable: true,
|
||||
render: (value) => {
|
||||
return (
|
||||
<div>
|
||||
{value ? (
|
||||
<Link
|
||||
to={`/network/${self.getUrl('security-group')}/detail/${value}`}
|
||||
>
|
||||
{value}
|
||||
</Link>
|
||||
) : (
|
||||
'-'
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
const url = self.getDetailUrl(value);
|
||||
return <div>{value ? <Link to={url}>{value}</Link> : '-'}</div>;
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -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 = (
|
||||
</p>
|
||||
</>
|
||||
);
|
||||
|
||||
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) => (
|
||||
<div key={it.server_id}>
|
||||
{it.device} on{' '}
|
||||
<Link
|
||||
to={`${self.getUrl('/compute/instance')}/detail/${
|
||||
it.server_id
|
||||
}?tab=volumes`}
|
||||
>
|
||||
{it.server_name}
|
||||
</Link>
|
||||
</div>
|
||||
));
|
||||
}
|
||||
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;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user