feat: support refresh button for SelectTable component

1. Support refresh button to refresh data for the SelectTable component.
2. When creating an instance/ironic/container, you can click to create a network/security group, then create a new resource in a new window, refresh the data in the previous window and select the newly created resource.

Closes-Bug: 2042928
Change-Id: I66bdbf848d375e45f0ab8941b0989165ad86a137
This commit is contained in:
zhangjingwei 2024-01-31 14:21:55 +08:00
parent 8a1d7ab034
commit 5fcc3b053e
9 changed files with 101 additions and 4 deletions

View File

@ -0,0 +1,13 @@
---
features:
- |
`Feature #2042928 <https://bugs.launchpad.net/skyline-console/+bug/2042928>`_:
Support refresh button for SelectTable component:
* Support refresh button to refresh data for the SelectTable component
* When creating an instance/ironic/container, you can click to create
a network/security group, then create a new resource in a new window,
refresh the data in the previous window and select the newly created
resource.

View File

@ -14,7 +14,7 @@
import React from 'react'; import React from 'react';
import { Radio, Tag, Button, Tooltip } from 'antd'; import { Radio, Tag, Button, Tooltip } from 'antd';
import { ClearOutlined } from '@ant-design/icons'; import { ClearOutlined, SyncOutlined } from '@ant-design/icons';
import { observer } from 'mobx-react'; import { observer } from 'mobx-react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import MagicInput from 'components/MagicInput'; import MagicInput from 'components/MagicInput';
@ -102,6 +102,8 @@ export default class SelectTable extends React.Component {
onRow: PropTypes.func, onRow: PropTypes.func,
childrenColumnName: PropTypes.string, childrenColumnName: PropTypes.string,
imageTabAuto: PropTypes.bool, imageTabAuto: PropTypes.bool,
refreshFunc: PropTypes.func,
hideRefresh: PropTypes.bool,
}; };
static defaultProps = { static defaultProps = {
@ -127,6 +129,8 @@ export default class SelectTable extends React.Component {
defaultSortOrder: '', defaultSortOrder: '',
childrenColumnName: 'children', childrenColumnName: 'children',
imageTabAuto: false, imageTabAuto: false,
refreshFunc: null,
hideRefresh: false,
}; };
constructor(props) { constructor(props) {
@ -388,6 +392,7 @@ export default class SelectTable extends React.Component {
}; };
handleFilterInput = (tags) => { handleFilterInput = (tags) => {
this.setState({ tags });
const { backendPageStore } = this.props; const { backendPageStore } = this.props;
const filters = {}; const filters = {};
tags.forEach((n) => { tags.forEach((n) => {
@ -606,6 +611,19 @@ export default class SelectTable extends React.Component {
}); });
}; };
handleRefresh = () => {
console.log('handleRefresh');
const { backendPageStore, refreshFunc } = this.props;
const { tags = [] } = this.state;
if (refreshFunc) {
refreshFunc();
return;
}
if (backendPageStore) {
this.handleFilterInput(tags);
}
};
initTabChange() { initTabChange() {
const { defaultTabValue, onTabChange, value } = this.props; const { defaultTabValue, onTabChange, value } = this.props;
if (defaultTabValue !== undefined && onTabChange !== undefined) { if (defaultTabValue !== undefined && onTabChange !== undefined) {
@ -615,6 +633,28 @@ export default class SelectTable extends React.Component {
} }
} }
renderRefresh() {
const { hideRefresh, backendPageStore, refreshFunc } = this.props;
let showButton = false;
if (!hideRefresh) {
if (backendPageStore) {
showButton = true;
} else if (refreshFunc) {
showButton = true;
}
}
if (!showButton) {
return null;
}
return (
<Button
type="default"
icon={<SyncOutlined />}
onClick={this.handleRefresh}
/>
);
}
renderSearch() { renderSearch() {
const { canSearch } = this.props; const { canSearch } = this.props;
if (!canSearch) { if (!canSearch) {
@ -639,6 +679,15 @@ export default class SelectTable extends React.Component {
); );
} }
renderSearchLine() {
return (
<div className={styles['search-line']}>
{this.renderSearch()}
{this.renderRefresh()}
</div>
);
}
renderHeader() { renderHeader() {
const { header } = this.props; const { header } = this.props;
return header || null; return header || null;
@ -849,7 +898,8 @@ export default class SelectTable extends React.Component {
<div className={styles['select-table']}> <div className={styles['select-table']}>
{this.renderHeader()} {this.renderHeader()}
{this.renderTabs()} {this.renderTabs()}
{this.renderSearch()}
{this.renderSearchLine()}
{this.renderTableHeader()} {this.renderTableHeader()}
{this.renderTable()} {this.renderTable()}
{this.renderSelected()} {this.renderSelected()}

View File

@ -76,3 +76,21 @@
} }
} }
} }
.search-line {
display: flex;
gap: 8px;
:global {
.ant-btn-default {
color: @table-header-default-button-color;
background-color: @table-header-default-button-background-gray;
border-color: @table-header-default-button-border;
}
.ant-btn-default:hover {
color: @primary-color;
border-color: @primary-color;
}
}
}

View File

@ -212,6 +212,7 @@ export class NetworkStep extends Base {
{getLinkRender({ {getLinkRender({
key: 'network', key: 'network',
value: `${t('create a new network/subnet')} > `, value: `${t('create a new network/subnet')} > `,
extra: { target: '_blank' },
})} })}
</div> </div>
), ),
@ -285,6 +286,7 @@ export class NetworkStep extends Base {
{getLinkRender({ {getLinkRender({
key: 'securityGroup', key: 'securityGroup',
value: `${t('create a new security group')}> `, value: `${t('create a new security group')}> `,
extra: { target: '_blank' },
})} })}
{t( {t(
'Note: The security group you use will act on all virtual adapters of the instance.' 'Note: The security group you use will act on all virtual adapters of the instance.'

View File

@ -155,6 +155,7 @@ export class StepNetworks extends Base {
{getLinkRender({ {getLinkRender({
key: 'network', key: 'network',
value: `${t('create a new network/subnet')} > `, value: `${t('create a new network/subnet')} > `,
extra: { target: '_blank' },
})} })}
</div> </div>
), ),

View File

@ -97,6 +97,7 @@ export class StepNetworks extends Base {
{getLinkRender({ {getLinkRender({
key: 'securityGroup', key: 'securityGroup',
value: `${t('create a new security group')}> `, value: `${t('create a new security group')}> `,
extra: { target: '_blank' },
})} })}
</div> </div>
), ),

View File

@ -332,6 +332,7 @@
// @table-header-search-input-background: @background-color; // @table-header-search-input-background: @background-color;
// @table-header-search-input-border-color: @primary-color; // @table-header-search-input-border-color: @primary-color;
@table-header-default-button-background: #fff; @table-header-default-button-background: #fff;
@table-header-default-button-background-gray: #f6f7fb;
@table-header-default-button-border: #fff; @table-header-default-button-border: #fff;
@table-header-default-button-color: #1d2129; @table-header-default-button-color: #1d2129;
@table-header-search-input-background: #fff; @table-header-search-input-background: #fff;

View File

@ -225,6 +225,7 @@
// table // table
@table-header-default-button-background: #fff; @table-header-default-button-background: #fff;
@table-header-default-button-background-gray: #f6f7fb;
@table-header-default-button-border: @primary-color; @table-header-default-button-border: @primary-color;
@table-header-default-button-color: @primary-color; @table-header-default-button-color: @primary-color;
@table-header-search-input-background: #fff; @table-header-search-input-background: #fff;

View File

@ -54,10 +54,20 @@ export const getPath = ({ key, params, query = {} }) => {
return str ? `${path}?${str}` : path; return str ? `${path}?${str}` : path;
}; };
export const getLinkRender = ({ key, params, query = {}, value }) => { export const getLinkRender = ({
key,
params,
query = {},
value,
extra = {},
}) => {
if (!value) { if (!value) {
return null; return null;
} }
const path = getPath({ key, params, query }); const path = getPath({ key, params, query });
return <Link to={path}>{value}</Link>; return (
<Link to={path} {...extra}>
{value}
</Link>
);
}; };