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:
Jingwei.Zhang 2021-09-06 16:18:06 +08:00
parent ca4f999c7f
commit f21c5a6daa
26 changed files with 202 additions and 216 deletions

View File

@ -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 = {

View File

@ -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));

View File

@ -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: {

View File

@ -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 = {

View File

@ -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();

View File

@ -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));

View File

@ -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);

View File

@ -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;

View File

@ -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));

View File

@ -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() {

View File

@ -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));

View File

@ -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));

View File

@ -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));

View File

@ -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));

View File

@ -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));

View File

@ -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));

View File

@ -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 <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>
);
}

View File

@ -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,
};

View File

@ -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));

View File

@ -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 });
};
}

View File

@ -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));

View File

@ -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>;
},
},
{

View File

@ -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;
};