feat: Support client module

1. Add client module to request openstack api
2. Remove window.request, stores use client to request api
3. Remove window.globals, use globalRootStore to deal with user info

Change-Id: I5657cfd8cf142dbacce8716991f805bbbb4a9222
This commit is contained in:
Jingwei.Zhang 2021-08-24 14:26:19 +08:00
parent 0061ce4f15
commit c960f06c1a
140 changed files with 3632 additions and 3181 deletions

View File

@ -127,6 +127,7 @@ module.exports = {
locales: root('src/locales'),
styles: root('src/styles'),
resources: root('src/resources'),
client: root('src/client'),
},
},
plugins: [

View File

@ -81,7 +81,8 @@
"react-highcharts": "^16.0.2",
"react-router": "^4.3.1",
"react-router-dom": "^4.3.1",
"react-sortable-hoc": "1.11.0"
"react-sortable-hoc": "1.11.0",
"uuid": "^8.3.2"
},
"devDependencies": {
"@babel/core": "^7.14.3",

View File

@ -16,7 +16,7 @@
* @param {String} key api url
* @returns {String}
*/
import { cinderBase } from 'utils/constants';
import { cinderBase } from 'client/client/constants';
const getCinderBaseUrl = (key) => `${cinderBase()}/${key}`;

View File

@ -16,7 +16,7 @@
* @param {String} key api url
* @returns {String}
*/
import { glanceBase } from 'utils/constants';
import { glanceBase } from 'client/client/constants';
const getGlanceBaseUrl = (key) => `${glanceBase()}/${key}`;

View File

@ -16,7 +16,7 @@
* @param {String} key api url
* @returns {String}
*/
import { gocronBase } from 'utils/constants';
import { gocronBase } from 'client/client/constants';
const getGocronBaseUrl = (key) => `${gocronBase()}/${key}`;

View File

@ -16,7 +16,7 @@
* @param {String} key api url
* @returns {String}
*/
import { heatBase } from 'utils/constants';
import { heatBase } from 'client/client/constants';
const getHeatBaseUrl = (key) => `${heatBase()}/${key}`;

View File

@ -16,7 +16,7 @@
* @param {String} key api url
* @returns {String}
*/
import { ironicInspectorBase } from 'utils/constants';
import { ironicInspectorBase } from 'client/client/constants';
const getIronicInspectorBaseUrl = (key) => `${ironicInspectorBase()}/${key}`;

View File

@ -16,7 +16,7 @@
* @param {String} key api url
* @returns {String}
*/
import { ironicBase } from 'utils/constants';
import { ironicBase } from 'client/client/constants';
const getIronicBaseUrl = (key) => `${ironicBase()}/${key}`;

View File

@ -16,7 +16,7 @@
* @param {String} key api url
* @returns {String}
*/
import { keystoneBase } from 'utils/constants';
import { keystoneBase } from 'client/client/constants';
const getKeystoneBaseUrl = (key) => `${keystoneBase()}/${key}`;

View File

@ -16,7 +16,7 @@
* @param {String} key api url
* @returns {String}
*/
import { neutronBase } from 'utils/constants';
import { neutronBase } from 'client/client/constants';
const getNeutronBaseUrl = (key) => `${neutronBase()}/${key}`;

View File

@ -16,7 +16,7 @@
* @param {String} key api url
* @returns {String}
*/
import { novaBase } from 'utils/constants';
import { novaBase } from 'client/client/constants';
const getNovaBaseUrl = (key) => `${novaBase()}/${key}`;

View File

@ -16,7 +16,7 @@
* @param {String} key api url
* @returns {String}
*/
import { octaviaBase } from 'utils/constants';
import { octaviaBase } from 'client/client/constants';
const getOctaviaBaseUrl = (key) => `${octaviaBase()}/${key}`;

View File

@ -16,7 +16,7 @@
* @param {String} key api url
* @returns {String}
*/
import { pankoBase } from 'utils/constants';
import { pankoBase } from 'client/client/constants';
const getPankoBaseUrl = (key) => `${pankoBase()}/${key}`;

View File

@ -16,7 +16,7 @@
* @param {String} key api url
* @returns {String}
*/
import { placementBase } from 'utils/constants';
import { placementBase } from 'client/client/constants';
const getPlacementBaseUrl = (key) => `${placementBase()}/${key}`;

View File

@ -16,7 +16,7 @@
* @param {String} key api url
* @returns {String}
*/
import { skylineBase } from 'utils/constants';
import { skylineBase } from 'client/client/constants';
const getSkylineBaseUrl = (key) => `${skylineBase()}/${key}`;

View File

@ -16,7 +16,7 @@
* @param {String} key api url
* @returns {String}
*/
import { swiftBase } from 'utils/constants';
import { swiftBase } from 'client/client/constants';
const getSwiftBaseUrl = (key) => `${swiftBase()}/${key}`;

155
src/client/cinder/index.js Normal file
View File

@ -0,0 +1,155 @@
// Copyright 2021 99cloud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Base from '../client/base';
import { cinderBase } from '../client/constants';
class CinderClient extends Base {
get baseUrl() {
return cinderBase();
}
get projectInUrl() {
return true;
}
get resources() {
return [
{
key: 'volumes',
responseKey: 'volume',
extendOperations: [
{
key: 'action',
method: 'post',
},
],
},
{
key: 'types',
responseKey: 'volume_type',
extendOperations: [
{
key: 'action',
method: 'post',
},
{
name: 'getAccess',
key: 'os-volume-type-access',
},
],
subResources: [
{
name: 'extraSpecs',
key: 'extra_specs',
responseKey: 'extra_spec',
},
{
key: 'encryption',
},
],
},
{
key: 'snapshots',
responseKey: 'snapshot',
},
{
key: 'backups',
responseKey: 'backup',
extendOperations: [
{
key: 'restore',
isDetail: true,
method: 'post',
},
],
},
{
name: 'backupChains',
key: 'backup_chains',
responseKey: 'backup_chain',
extendOperations: [
{
key: 'restore',
isDetail: true,
method: 'post',
},
],
},
{
name: 'pools',
key: 'scheduler-stats/get_pools',
responseKey: 'pool',
},
{
name: 'qosSpecs',
key: 'qos-specs',
responseKey: 'qos_spec',
extendOperations: [
{
name: 'deleteKeys',
key: 'delete_keys',
method: 'put',
},
{
key: 'associate',
},
{
key: 'disassociate',
},
],
},
{
name: 'services',
key: 'os-services',
responseKey: 'service',
extendOperations: [
{
key: 'enable',
isDetail: false,
method: 'put',
},
{
name: 'reason',
key: 'disable-log-reason',
isDetail: false,
method: 'put',
},
],
},
{
name: 'quotaSets',
key: 'os-quota-sets',
responseKey: 'quota_set',
},
{
name: 'azones',
key: 'os-availability-zone',
},
{
name: 'volumeTransfers',
key: 'volume-transfers',
extendOperations: [
{
key: 'accept',
method: 'post',
},
],
},
];
}
}
const cinderClient = new CinderClient();
export default cinderClient;

420
src/client/client/base.js Normal file
View File

@ -0,0 +1,420 @@
// Copyright 2021 99cloud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import globalRootStore from 'stores/root';
import clientRequest from './request';
export default class BaseClient {
constructor() {
this.generateAll();
}
getUrl = (url) => {
if (this.projectInUrl) {
return `${this.baseUrl}/${this.project}/${url}`;
}
return `${this.baseUrl}/${url}`;
};
get request() {
const { request } = clientRequest;
return {
get: (url, params, conf) => request.get(this.getUrl(url), params, conf),
post: (url, data, params, conf) =>
request.post(this.getUrl(url), data, params, conf),
put: (url, data, params, conf) =>
request.put(this.getUrl(url), data, params, conf),
delete: (url, data, params, conf) =>
request.delete(this.getUrl(url), data, params, conf),
patch: (url, data, params, conf) =>
request.patch(this.getUrl(url), data, params, conf),
head: (url, params, conf) => request.head(this.getUrl(url), params, conf),
};
}
get originRequest() {
const { request } = clientRequest;
return request;
}
get params() {
return [];
}
get baseUrl() {
return '';
}
get projectInUrl() {
return false;
}
get project() {
if (!this.projectInUrl) {
return '';
}
const { project: { id } = {} } = globalRootStore.user || {};
return id || '';
}
get enabled() {
return true;
}
get resources() {
return [];
}
getListUrl(resourceName) {
return resourceName;
}
getDetailUrl(resourceName, id) {
if (!id) {
return resourceName;
}
if (resourceName[resourceName.length - 1] === '/') {
return `${resourceName.substr(0, resourceName.length - 1)}/${id}`;
}
return `${resourceName}/${id}`;
}
getSubResourceUrl(resourceName, subResourceName) {
if (!resourceName) {
return subResourceName;
}
if (resourceName[resourceName.length - 1] === '/') {
return `${resourceName.substr(
0,
resourceName.length - 1
)}/${subResourceName}`;
}
return `${resourceName}/${subResourceName}`;
}
getSubResourceUrlById(resourceName, subResourceName, id) {
return `${this.getDetailUrl(resourceName, id)}/${subResourceName}`;
}
getSubResourceUrlBySubId(resourceName, subResourceName, id, subId) {
return `${this.getSubResourceUrlById(
resourceName,
subResourceName,
id
)}/${subId}`;
}
getSubSubResourceListUrl(
resourceName,
subResourceName,
subSubResourceName,
id,
subId
) {
return `${this.getSubResourceUrlBySubId(
resourceName,
subResourceName,
id,
subId
)}/${subSubResourceName}`;
}
getSubSubResourceDetailUrl(
resourceName,
subResourceName,
subSubResourceName,
id,
subId,
subSubId
) {
return `${this.getSubSubResourceListUrl(
resourceName,
subResourceName,
subSubResourceName,
id,
subId
)}/${subSubId}`;
}
generateResource = (resourceName, responseKey, enabled = true) => {
const listUrl = this.getListUrl(resourceName);
return {
list: (params, conf) => this.request.get(listUrl, params, conf),
listDetail: (params, conf) =>
this.request.get(`${listUrl}/detail`, params, conf),
show: (id, params, conf) => {
return this.request.get(
this.getDetailUrl(resourceName, id),
params,
conf
);
},
create: (data, ...args) => this.request.post(listUrl, data, ...args),
update: (id, data, ...args) =>
this.request.put(this.getDetailUrl(resourceName, id), data, ...args),
patch: (id, data, ...args) =>
this.request.patch(this.getDetailUrl(resourceName, id), data, ...args),
delete: (id, ...args) =>
this.request.delete(this.getDetailUrl(resourceName, id), ...args),
responseKey,
enabled,
};
};
generateSubResource = (
resourceName,
subResourceName,
responseKey,
enabled
) => ({
list: (id, params, ...args) =>
this.request.get(
this.getSubResourceUrlById(resourceName, subResourceName, id),
params,
...args
),
listDetail: (id, params, ...args) =>
this.request.get(
`${this.getSubResourceUrlById(
resourceName,
subResourceName,
id
)}/detail`,
params,
...args
),
show: (id, subId, params, ...args) =>
this.request.get(
this.getSubResourceUrlBySubId(resourceName, subResourceName, id, subId),
params,
...args
),
create: (id, data, ...args) =>
this.request.post(
this.getSubResourceUrlById(resourceName, subResourceName, id),
data,
...args
),
update: (id, subId, data, ...args) =>
this.request.put(
this.getSubResourceUrlBySubId(resourceName, subResourceName, id, subId),
data,
...args
),
patch: (id, subId, data, ...args) =>
this.request.patch(
this.getSubResourceUrlBySubId(resourceName, subResourceName, id, subId),
data,
...args
),
delete: (id, subId, ...args) =>
this.request.delete(
this.getSubResourceUrlBySubId(resourceName, subResourceName, id, subId),
...args
),
responseKey,
enabled,
});
generateSubSonResource = (
resourceName,
subResourceName,
subSubResonseName,
responseKey
) => ({
list: (id, subId, params, ...args) =>
this.request.get(
this.getSubSubResourceListUrl(
resourceName,
subResourceName,
subSubResonseName,
id,
subId
),
params,
...args
),
show: (id, subId, subSubId, params, ...args) =>
this.request.get(
this.getSubSubResourceDetailUrl(
resourceName,
subResourceName,
subSubResonseName,
id,
subId,
subSubId
),
params,
...args
),
create: (id, subId, data, ...args) =>
this.request.post(
this.getSubSubResourceListUrl(
resourceName,
subResourceName,
subSubResonseName,
id,
subId
),
data,
...args
),
update: (id, subId, subSubId, data, ...args) =>
this.request.put(
this.getSubSubResourceDetailUrl(
resourceName,
subResourceName,
subSubResonseName,
id,
subId,
subSubId
),
data,
...args
),
patch: (id, subId, subSubId, data, ...args) =>
this.request.patch(
this.getSubSubResourceDetailUrl(
resourceName,
subResourceName,
subSubResonseName,
id,
subId,
subSubId
),
data,
...args
),
delete: (id, subId, subSubId, ...args) =>
this.request.delete(
this.getSubSubResourceDetailUrl(
resourceName,
subResourceName,
subSubResonseName,
id,
subId,
subSubId
),
...args
),
responseKey,
});
setRequest = (url, method, ...restArgs) => {
const lowerMethod = method.toLowerCase();
return this.request[lowerMethod](url, ...restArgs);
};
generateAll = () => {
this.resources.forEach((resource) => {
const {
name,
key,
responseKey,
enabled,
subResources = [],
isResource = true,
extendOperations = [],
} = resource;
const result = isResource
? this.generateResource(key, responseKey, enabled)
: {};
const realName = name || key;
extendOperations.forEach((other) => {
const {
name: otherName,
key: otherKey,
method = 'get',
isDetail,
generate,
url,
} = other;
const otherRealName = otherName || otherKey;
const otherUrl = url && url();
const otherIsDetail = isResource
? isDetail === undefined
? true
: isDetail
: isDetail === undefined
? false
: isDetail;
if (generate) {
result[otherRealName] = generate;
} else if (otherIsDetail) {
result[otherRealName] = (id, ...args) => {
return this.setRequest(
otherUrl || this.getSubResourceUrlById(key, otherKey, id),
method,
...args
);
};
} else {
result[otherRealName] = (...args) => {
return this.setRequest(
otherUrl || this.getSubResourceUrl(key, otherKey),
method,
...args
);
};
}
});
subResources.forEach((sub) => {
let subResult = {};
const {
name: subName,
key: subKey,
responseKey: subResponseKey,
method: subMethod,
enabled: subEnabled,
subResources: subSubResources = [],
} = sub;
const subRealName = subName || subKey;
if (!subMethod) {
subResult = this.generateSubResource(
key,
subKey,
subResponseKey,
subEnabled
);
} else {
subResult = (id, ...args) => {
const url = this.getSubResourceUrlById(key, subKey, id);
return this.setRequest(url, subMethod, ...args);
};
}
subSubResources.forEach((son) => {
const {
key: sonKey,
name: sonName,
responseKey: sonResponseKey,
} = son;
subResult[sonName || sonKey] = this.generateSubSonResource(
key,
subKey,
sonKey,
sonResponseKey
);
});
result[subRealName] = subResult;
});
if (realName) {
this[realName] = result;
} else {
Object.keys(result).forEach((resultKey) => {
this[resultKey] = result[resultKey];
});
}
});
};
}

View File

@ -0,0 +1,125 @@
// Copyright 2021 99cloud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import globalRootStore from 'stores/root';
import { toJS } from 'mobx';
export const groupNameVersionMap = {
core: 'v1',
system: 'v1',
};
const endpointVersionMap = {
keystone: 'v3',
nova: 'v2.1',
cinder: 'v3',
glance: 'v2',
neutron: 'v2.0',
ironic: 'v1',
ironicInspector: 'v1',
heat: 'v1',
swift: 'v1',
octavia: 'v2',
courier: 'v1',
prometheus: 'api/v1',
prometheus_sidecar: 'api/v1',
gocron: 'api',
panko: 'v2',
billing_system: 'api/core.io/v1',
workflow: 'api/core.io/v1',
};
const endpointsDefault = {
ironic: '/api/openstack/ironic',
ironicInspector: '/api/openstack/ironic-inspector',
swift: '/api/openstack/swift/swift',
octavia: '/api/openstack/octavia',
};
export const getOpenstackEndpoint = (key) => {
const { endpoints = {} } = globalRootStore || {};
const version = endpointVersionMap[key];
const endpoint = endpoints[key] || endpointsDefault[key] || '';
return version ? `${endpoint}/${version}` : endpoint;
};
export const getOriginEndpoint = (key) => {
const endpoints = toJS((globalRootStore && globalRootStore.endpoints) || {});
return endpoints[key];
};
export const skylineBase = () => '/api/openstack/skyline/api/v1';
export const keystoneBase = () => getOpenstackEndpoint('keystone');
export const novaBase = () => getOpenstackEndpoint('nova');
export const cinderBase = () => getOpenstackEndpoint('cinder');
export const glanceBase = () => getOpenstackEndpoint('glance');
export const neutronBase = () => getOpenstackEndpoint('neutron');
export const ironicBase = () => getOpenstackEndpoint('ironic');
export const ironicInspectorBase = () =>
getOpenstackEndpoint('ironicInspector');
export const placementBase = () => getOpenstackEndpoint('placement');
export const heatBase = () => getOpenstackEndpoint('heat');
export const swiftBase = () => getOpenstackEndpoint('swift');
export const octaviaBase = () => getOpenstackEndpoint('octavia');
export const alertmanagerBase = () => getOpenstackEndpoint('alertmanager');
export const prometheusBase = () => getOpenstackEndpoint('prometheus');
export const prometheusSidecarBase = () =>
getOpenstackEndpoint('prometheus_sidecar');
export const courierBase = () => getOpenstackEndpoint('courier');
export const gocronBase = () => getOpenstackEndpoint('gocron');
export const pankoBase = () => getOpenstackEndpoint('panko');
export const s3Base = () => getOpenstackEndpoint('s3');
export const billingBase = () => getOpenstackEndpoint('billing_system');
export const workflowBase = () => getOpenstackEndpoint('workflow');
export const ironicOriginEndpoint = () => getOriginEndpoint('ironic');
export const s3OriginEndpoint = () => getOriginEndpoint('s3');
export const billingEndpoint = () => getOriginEndpoint('billing_system');
export const firewallEndpoint = () => getOriginEndpoint('neutron_firewall');
export const vpnEndpoint = () => getOriginEndpoint('neutron_vpn');
export const lbEndpoint = () => getOriginEndpoint('octavia');
export const apiVersionMaps = {
nova: {
key: 'Openstack-Api-Version',
value: 'compute 2.79',
},
placement: {
key: 'Openstack-Api-Version',
value: 'placement 1.28',
},
cinder: {
key: 'Openstack-Api-Version',
value: 'volume 3.59',
},
ironic: {
key: 'X-Openstack-Ironic-Api-Version',
value: '1.58',
},
'ironic-inspect': {
key: 'X-OpenStack-Ironic-Inspector-API-Version',
value: '1.15',
},
};
export const getOpenstackApiVersion = (url) => {
const key = Object.keys(apiVersionMaps).find((it) => url.indexOf(it) > -1);
if (!key) {
return null;
}
return apiVersionMaps[key];
};
export const getK8sTypeEndpoint = (groupName, baseUrl) =>
`${baseUrl}/${groupName}/${groupNameVersionMap[groupName]}`;

View File

@ -0,0 +1,181 @@
// Copyright 2021 99cloud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Axios from 'axios';
import { getLocalStorageItem } from 'utils/local-storage';
import { isEqual } from 'lodash';
import qs from 'qs';
import globalRootStore from 'stores/root';
import { v4 as uuidv4 } from 'uuid';
import { getOpenstackApiVersion } from './constants';
const METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD'];
/**
* @class HttpRequest
* request with axios
*/
export class HttpRequest {
constructor() {
this.request = {};
}
/**
* @param instance instance of axios
* @param url request url
* interceptors includes request & response
* @returns {void}
*/
interceptors(instance, url) {
instance.interceptors.request.use(
(config) => {
const uuid = uuidv4();
config.headers['X-Openstack-Request-Id'] = `req-${uuid}`;
const keystoneToken = getLocalStorageItem('keystone_token') || '';
const apiVersionMap = getOpenstackApiVersion(url);
if (keystoneToken) {
config.headers['X-Auth-Token'] = keystoneToken;
}
if (apiVersionMap) {
config.headers[apiVersionMap.key] = apiVersionMap.value;
}
const { options: { headers, isFormData, ...rest } = {} } = config;
if (!isEqual(headers)) {
config.headers = {
...config.headers,
...headers,
};
}
if (isFormData) {
delete config.headers['Content-Type'];
}
Object.keys(rest).forEach((key) => {
config[key] = rest[key];
});
return config;
},
(err) => Promise.reject(err)
);
instance.interceptors.response.use(
(response) => {
// request is finished
const { data, status } = response;
const disposition = response.headers['content-disposition'] || '';
const contentType = response.headers['content-type'] || '';
if (contentType.includes('application/octet-stream')) {
return response;
}
if (disposition.includes('attachment')) {
return response;
}
if (status < 200 || status >= 300) {
return Promise.reject(data);
}
return data;
},
(error) => {
// request is finished
// eslint-disable-next-line no-console
console.log('error.response', error.response, error);
if (error.response) {
const { status } = error.response;
if (status === 401) {
const currentPath = window.location.pathname;
if (currentPath.indexOf('login') < 0) {
globalRootStore.gotoLoginPage(currentPath);
}
}
}
return Promise.reject(error);
}
);
}
/**
* create a new instance of axios with a custom config
*/
create() {
const conf = {
baseURL: '/',
headers: {
'Content-Type': 'application/json;charset=utf-8',
'cache-control': 'no-cache',
pragma: 'no-cache',
},
};
return Axios.create(conf);
}
/**
* @param {Object} obj translated object
* @returns {Object} trim undefined & null
*/
omitNil(obj) {
if (typeof obj !== 'object') return obj;
return Object.keys(obj).reduce((acc, v) => {
if (obj[v] !== undefined && obj[v] !== null && obj[v] !== '')
acc[v] = obj[v];
return acc;
}, {});
}
/**
* build request
* @param {Object} config requests config
* @returns {Promise} axios instance return promise
*/
buildRequest(config) {
const method = config.method ? config.method.toLowerCase() : 'get';
const options = { ...config };
// Only get and head, we need to use null for some posts requests
if (options.params && ['get', 'head'].includes(method)) {
options.params = this.omitNil(options.params);
options.paramsSerializer = (p) =>
qs.stringify(p, { arrayFormat: 'repeat' });
}
const instance = this.create();
this.interceptors(instance, options.url);
return instance(options);
}
generateRequestMap = () => {
METHODS.forEach((method) => {
const lowerMethod = method.toLowerCase();
if (lowerMethod === 'get' || lowerMethod === 'head') {
this.request[lowerMethod] = (url, params = {}, options) => {
return this.buildRequest({
method: lowerMethod,
url,
params,
options,
});
};
} else {
this.request[lowerMethod] = (url, data, params, options) => {
return this.buildRequest({
method: lowerMethod,
url,
data,
params,
options,
});
};
}
});
};
}
const httpRequest = new HttpRequest();
httpRequest.generateRequestMap();
export default httpRequest;

View File

@ -0,0 +1,87 @@
// Copyright 2021 99cloud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Base from '../client/base';
import { glanceBase } from '../client/constants';
class GlanceClient extends Base {
get baseUrl() {
return glanceBase();
}
get resources() {
return [
{
key: 'images',
responseKey: 'image',
extendOperations: [
{
key: 'count',
isDetail: false,
},
{
key: 'uploadFile',
generate: (id, body, conf = {}) => {
return this.request.put(
`${this.getDetailUrl('images', id)}/file`,
body,
null,
{
headers: {
'content-type': 'application/octet-stream',
},
...conf,
}
);
},
},
{
key: 'patch',
generate: (id, data) =>
this.request.patch(this.getDetailUrl('images', id), data, null, {
headers: {
'content-type':
'application/openstack-images-v2.1-json-patch',
},
}),
},
],
subResources: [
{
key: 'members',
},
],
},
{
name: 'namespaces',
key: 'metadefs/namespaces',
responseKey: 'namespace',
subResources: [
{
name: 'resourceTypes',
key: 'resource_types',
},
],
},
{
name: 'resourceTypes',
key: 'metadefs/resource_types',
responseKey: 'resource_type',
},
];
}
}
const glanceClient = new GlanceClient();
export default glanceClient;

93
src/client/heat/index.js Normal file
View File

@ -0,0 +1,93 @@
// Copyright 2021 99cloud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Base from '../client/base';
import { heatBase } from '../client/constants';
class HeatClient extends Base {
get baseUrl() {
return heatBase();
}
get projectInUrl() {
return true;
}
getDetailUrlForStack = ({ id, name }) => `stacks/${name}/${id}`;
get resources() {
return [
{
key: 'stacks',
responseKey: 'stack',
extendOperations: [
{
key: 'show',
generate: ({ id, name }, params) => {
return this.request.get(
this.getDetailUrlForStack({ id, name }),
params
);
},
},
{
key: 'update',
generate: ({ id, name }, data) =>
this.request.put(this.getDetailUrlForStack({ id, name }), data),
},
{
key: 'delete',
generate: ({ id, name }) =>
this.request.delete(this.getDetailUrlForStack({ id, name })),
},
{
key: 'abandon',
generate: ({ id, name }) =>
this.request.delete(
`${this.getDetailUrlForStack({ id, name })}/abandon`
),
},
{
key: 'template',
generate: ({ id, name }) =>
this.request.get(
`${this.getDetailUrlForStack({ id, name })}/template`
),
},
{
key: 'events',
generate: ({ id, name }) =>
this.request.get(
`${this.getDetailUrlForStack({ id, name })}/events`
),
},
{
key: 'resources',
generate: ({ id, name }) =>
this.request.get(
`${this.getDetailUrlForStack({ id, name })}/resources`
),
},
],
},
{
key: 'services',
responseKey: 'service',
},
];
}
}
const heatClient = new HeatClient();
export default heatClient;

41
src/client/index.js Normal file
View File

@ -0,0 +1,41 @@
// Copyright 2021 99cloud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import skyline from './skyline';
import nova from './nova';
import cinder from './cinder';
import glance from './glance';
import neutron from './neutron';
import keystone from './keystone';
import heat from './heat';
import octavia from './octavia';
import placement from './placement';
import ironic from './ironic';
const client = {
skyline,
nova,
cinder,
glance,
neutron,
keystone,
heat,
octavia,
placement,
ironic,
};
window.client = client;
export default client;

View File

@ -0,0 +1,96 @@
// Copyright 2021 99cloud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Base from '../client/base';
import { ironicBase } from '../client/constants';
class IronicClient extends Base {
get baseUrl() {
return ironicBase();
}
get resources() {
return [
{
key: 'nodes',
responseKey: 'node',
extendOperations: [
{
name: 'updateStatesProvision',
key: 'states/provision',
method: 'put',
},
{
name: 'UpdateStatesPower',
key: 'states/power',
method: 'put',
},
{
name: 'updateMaintenance',
key: 'maintenance',
method: 'put',
},
{
name: 'deleteMaintenance',
key: 'maintenance',
method: 'delete',
},
{
name: 'getManagementBootDevice',
key: 'management/boot_device',
},
{
name: 'updateManagementBootDevice',
key: 'management/boot_device',
method: 'put',
},
{
name: 'getManagementBootDeviceSupported',
key: 'management/boot_device/supported',
},
{
key: 'updateTraits',
method: 'put',
},
],
subResources: [
{
key: 'states',
},
{
key: 'validate',
},
{
key: 'ports',
},
{
key: 'portgroups',
responseKey: 'portgroup',
},
],
},
{
key: 'ports',
responseKey: 'port',
},
{
key: 'portgroups',
responseKey: 'portgroup',
},
];
}
}
const ironicClient = new IronicClient();
export default ironicClient;

View File

@ -0,0 +1,149 @@
// Copyright 2021 99cloud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Base from '../client/base';
import { keystoneBase } from '../client/constants';
class KeystoneClient extends Base {
get baseUrl() {
return keystoneBase();
}
get resources() {
return [
{
name: 'catalog',
key: 'auth/catalog',
responseKey: 'catalog',
},
{
key: 'projects',
responseKey: 'project',
extendOperations: [
{
name: 'updateTags',
key: 'tags',
method: 'put',
},
],
subResources: [
{
key: 'tags',
responseKey: 'tag',
},
{
key: 'groups',
subResources: [
{
key: 'roles',
},
],
},
{
key: 'users',
subResources: [
{
key: 'roles',
},
],
},
],
},
{
key: 'domains',
responseKey: 'domain',
subResources: [
{
key: 'groups',
subResources: [
{
key: 'roles',
},
],
},
{
key: 'users',
subResources: [
{
key: 'roles',
},
],
},
],
},
{
key: 'roles',
responseKey: 'role',
subResources: [
{
key: 'implies',
},
],
},
{
name: 'roleAssignments',
key: 'role_assignments',
},
{
key: 'users',
responseKey: 'user',
subResources: [
{
key: 'projects',
},
{
key: 'groups',
},
],
extendOperations: [
{
name: 'updatePassword',
key: 'password',
method: 'post',
},
],
},
{
key: 'groups',
responseKey: 'group',
subResources: [
{
key: 'users',
},
],
},
{
name: 'systemGroups',
key: 'system/groups',
subResources: [
{
key: 'roles',
},
],
},
{
name: 'systemUsers',
key: 'system/users',
subResources: [
{
key: 'roles',
},
],
},
];
}
}
const keystoneClient = new KeystoneClient();
export default keystoneClient;

201
src/client/neutron/index.js Normal file
View File

@ -0,0 +1,201 @@
// Copyright 2021 99cloud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Base from '../client/base';
import { neutronBase } from '../client/constants';
class NeutronClient extends Base {
get baseUrl() {
return neutronBase();
}
get resources() {
return [
{
key: 'networks',
responseKey: 'network',
subResources: [
{
name: 'dhcpAgents',
key: 'dhcp-agents',
},
],
},
{
key: 'subnets',
responseKey: 'subnet',
},
{
key: 'extensions',
},
{
key: 'ports',
responseKey: 'port',
},
{
key: 'routers',
responseKey: 'router',
extendOperations: [
{
name: 'addRouterInterface',
key: 'add_router_interface',
method: 'put',
},
{
name: 'removeRouterInterface',
key: 'remove_router_interface',
method: 'put',
},
{
name: 'addExtraRoutes',
key: 'add_extraroutes',
method: 'put',
},
{
name: 'removeExtraRoutes',
key: 'remove_extraroutes',
method: 'put',
},
],
},
{
key: 'floatingips',
responseKey: 'floatingip',
subResources: [
{
name: 'portForwardings',
key: 'port_forwardings',
responseKey: 'port_forwarding',
},
],
},
{
key: 'agents',
responseKey: 'agent',
subResources: [
{
name: 'dhcpNetworks',
key: 'dhcp-networks',
responseKey: 'network',
},
{
name: 'l3Routers',
key: 'l3-routers',
responseKey: 'router',
},
],
},
{
name: 'firewalls',
key: 'fwaas/firewall_groups',
responseKey: 'firewall_group',
},
{
name: 'firewallPolicies',
key: 'fwaas/firewall_policies',
responseKey: 'firewall_policy',
extendOperations: [
{
name: 'insertRule',
key: 'insert_rule',
method: 'put',
},
{
name: 'removeRule',
key: 'remove_rule',
method: 'put',
},
],
},
{
name: 'firewallRules',
key: 'fwaas/firewall_rules',
responseKey: 'firewall_rule',
},
{
name: 'networkIpAvailabilities',
key: 'network-ip-availabilities',
},
{
name: 'azones',
key: 'availability_zones',
},
{
name: 'qosPolicies',
key: 'qos/policies',
responseKey: 'policy',
subResources: [
{
name: 'bandwidthLimitRules',
key: 'bandwidth_limit_rules',
},
{
name: 'dscpMarkingRules',
key: 'dscp_marking_rules',
},
],
},
{
name: 'securityGroups',
key: 'security-groups',
responseKey: 'security_group',
},
{
name: 'securityGroupRules',
key: 'security-group-rules',
responseKey: 'security_group_rule',
},
{
key: 'subnets',
responseKey: 'subnet',
},
{
name: 'endpointGroups',
key: 'endpoint-groups',
responseKey: 'endpoint_group',
},
{
name: 'ikePolicies',
key: 'ikepolicies',
responseKey: 'ikepolicy',
},
{
name: 'ipsecPolicies',
key: 'ipsecpolicies',
responseKey: 'ipsecpolicy',
},
{
name: 'ipsecSiteConnections',
key: 'ipsec_site_connections',
responseKey: 'ipsec_site_connection',
},
{
key: 'vpnservices',
responseKey: 'vpnservice',
},
{
key: 'quotas',
responseKey: 'quota',
extendOperations: [
{
key: 'details',
},
],
},
];
}
}
const neutronClient = new NeutronClient();
export default neutronClient;

134
src/client/nova/index.js Normal file
View File

@ -0,0 +1,134 @@
// Copyright 2021 99cloud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Base from '../client/base';
import { novaBase } from '../client/constants';
class NovaClient extends Base {
get baseUrl() {
return novaBase();
}
get resources() {
return [
{
key: 'servers',
responseKey: 'server',
subResources: [
{
name: 'interfaces',
key: 'os-interface',
},
{
name: 'volumeAttachments',
key: 'os-volume_attachments',
responseKey: 'volumeAttachment',
},
{
name: 'instanceActions',
key: 'os-instance-actions',
responseKey: 'instanceAction',
},
],
extendOperations: [
{
name: 'createConsole',
key: 'remote-consoles',
method: 'post',
},
{
key: 'action',
method: 'post',
},
],
},
{
name: 'zone',
key: 'os-availability-zone',
responseKey: 'availabilityZoneInfo',
},
{
key: 'flavors',
responseKey: 'flavor',
extendOperations: [
{
name: 'action',
key: 'action',
method: 'post',
},
],
subResources: [
{
name: 'access',
key: 'os-flavor-access',
},
{
name: 'extraSpecs',
key: 'os-extra_specs',
},
],
},
{
name: 'keypairs',
key: 'os-keypairs',
responseKey: 'keypair',
},
{
name: 'serverGroups',
key: 'os-server-groups',
responseKey: 'server_group',
},
{
name: 'aggregates',
key: 'os-aggregates',
responseKey: 'aggregate',
extendOperations: [
{
name: 'action',
key: 'action',
method: 'post',
},
],
},
{
name: 'services',
key: 'os-services',
responseKey: 'service',
},
{
name: 'quotaSets',
key: 'os-quota-sets',
responseKey: 'quota_set',
extendOperations: [
{
key: 'detail',
},
],
},
{
name: 'hypervisors',
key: 'os-hypervisors',
responseKey: 'hypervisor',
},
{
name: 'pciDevices',
key: 'os-pci-devices',
responseKey: 'pci_device',
},
];
}
}
const novaClient = new NovaClient();
export default novaClient;

View File

@ -0,0 +1,62 @@
// Copyright 2021 99cloud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Base from '../client/base';
import { octaviaBase } from '../client/constants';
class OctaviaClient extends Base {
get baseUrl() {
return octaviaBase();
}
get resources() {
return [
{
name: 'healthMonitors',
key: 'lbaas/healthmonitors',
responseKey: 'healthmonitor',
},
{
name: 'listeners',
key: 'lbaas/listeners',
responseKey: 'listener',
},
{
name: 'loadbalancers',
key: 'lbaas/loadbalancers',
responseKey: 'loadbalancer',
},
{
name: 'pools',
key: 'lbaas/pools',
responseKey: 'pool',
extendOperations: [
{
name: 'batchUpdateMembers',
key: 'members',
method: 'put',
},
],
subResources: [
{
key: 'members',
},
],
},
];
}
}
const octaviaClient = new OctaviaClient();
export default octaviaClient;

View File

@ -0,0 +1,42 @@
// Copyright 2021 99cloud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Base from '../client/base';
import { placementBase } from '../client/constants';
class PlacementClient extends Base {
get baseUrl() {
return placementBase();
}
get resources() {
return [
{
name: 'resourceProviders',
key: 'resource_providers',
subResources: [
{
key: 'inventories',
},
],
},
{
key: 'traits',
},
];
}
}
const placementClient = new PlacementClient();
export default placementClient;

123
src/client/skyline/index.js Normal file
View File

@ -0,0 +1,123 @@
// Copyright 2021 99cloud
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import Base from '../client/base';
import { skylineBase } from '../client/constants';
class SkylineClient extends Base {
get baseUrl() {
return skylineBase();
}
get resources() {
return [
{
key: 'contrib',
isResource: false,
extendOperations: [
{
key: 'domains',
},
{
key: 'regions',
},
{
name: 'keystoneEndpoints',
key: 'keystone_endpoints',
},
],
},
{
key: 'extension',
isResource: false,
extendOperations: [
{
key: 'servers',
},
{
name: 'recycleServers',
key: 'recycle_servers',
},
{
key: 'volumes',
},
{
name: 'volumeSnapshots',
key: 'volume_snapshots',
},
{
key: 'ports',
},
],
},
{
name: 'policies',
key: 'policies',
extendOperations: [
{
name: 'check',
key: 'check',
isDetail: false,
},
],
},
{
name: '',
key: '',
isResource: false,
extendOperations: [
{
key: 'login',
method: 'post',
},
{
key: 'logout',
method: 'post',
},
{
key: 'profile',
},
{
name: 'switchProject',
method: 'post',
generate: (projectId, domainId) => {
const url = `switch_project/${projectId}`;
const data = {
project_id: projectId,
project_domain_id: domainId,
};
const params = {
project_domain_id: domainId,
};
return this.request.post(url, data, params);
},
},
],
},
{
key: 'setting',
responseKey: 'setting',
extendOperations: [
{
key: 'list',
url: () => 'settings',
},
],
},
];
}
}
const skylineClient = new SkylineClient();
export default skylineClient;

View File

@ -104,6 +104,11 @@ export default class BaseForm extends React.Component {
return '';
}
get currentUser() {
const { user } = this.props.rootStore || {};
return user || {};
}
get isAdminPage() {
const { pathname = '' } = this.props.location || {};
return isAdminPage(pathname);
@ -114,11 +119,11 @@ export default class BaseForm extends React.Component {
}
get currentProjectId() {
return globals.user.project.id;
return this.props.rootStore.projectId;
}
get currentProjectName() {
return globals.user.project.name;
return this.props.rootStore.projectName;
}
getUrl(path, adminStr) {
@ -258,7 +263,7 @@ export default class BaseForm extends React.Component {
this.responseError = err;
this.showNotice && Notify.errorWithDetail(err, this.errorText);
// eslint-disable-next-line no-console
console.log(err);
console.log('err', err);
if (callback && isFunction(callback)) {
callback(false, true);
}

View File

@ -44,7 +44,7 @@ export default class NetworkSelectTable extends Component {
}
get currentProjectId() {
return globals.user.project.id;
return this.props.rootStore.projectId;
}
get hasAdminRole() {

View File

@ -34,7 +34,7 @@ export default class VolumeSelectTable extends Component {
}
get currentProjectId() {
return globals.user.project.id;
return this.props.rootStore.projectId;
}
get hasAdminRole() {

View File

@ -126,7 +126,7 @@ class AvatarDropdown extends React.Component {
<ItemActionButtons
actions={{ moreActions: [{ action: Password }] }}
onFinishAction={this.afterChangePassword}
item={globals.user.user}
item={this.user && this.user.user}
isWide
/>
</Menu.Item>

View File

@ -28,7 +28,7 @@ const gotoConsole = (type, props) => {
};
const GlobalHeaderRight = (props) => {
const { isAdminPage = false, rootStore: { hasAdminRole = false } = {} } =
const { isAdminPage = false, rootStore: { hasAdminPageRole = false } = {} } =
props;
let linkRender = null;
if (isAdminPage) {
@ -41,7 +41,7 @@ const GlobalHeaderRight = (props) => {
{t('Console')}
</Button>
);
} else if (hasAdminRole) {
} else if (hasAdminPageRole) {
linkRender = (
<Button
type="link"

View File

@ -107,6 +107,15 @@ export default class BaseStepForm extends React.Component {
return this.checkEndpoint && !this.endpoint;
}
get currentUser() {
const { user } = this.props.rootStore || {};
return user || {};
}
get currentProjectId() {
return this.props.rootStore.projectId;
}
get labelCol() {
return {
xs: { span: 4 },
@ -218,9 +227,10 @@ export default class BaseStepForm extends React.Component {
Notify.success(this.successText);
},
(err) => {
// eslint-disable-next-line no-console
console.log('reject', err);
Notify.errorWithDetail(err, this.errorText);
this.responseError = err;
const { response: { data: responseData } = {} } = err;
console.log('err', err, responseData);
Notify.errorWithDetail(responseData, this.errorText);
}
);
};

View File

@ -243,7 +243,8 @@ class ActionButton extends Component {
const message = submitErrorMsgBatch
? submitErrorMsgBatch(data)
: getDefaultMsg(this.props.action, data).submitErrorMsgBatch;
Notify.errorWithDetail(error, message);
const { data: responseData } = error.response || error || {};
Notify.errorWithDetail(responseData || error, message);
this.onCallback(false, true);
};
@ -260,10 +261,12 @@ class ActionButton extends Component {
return;
}
const { submitErrorMsg } = this.props.action;
const { data: responseData } = error.response || error || {};
const realError = responseData || error;
const message = submitErrorMsg
? submitErrorMsg(data, error)
? submitErrorMsg(data, realError)
: getDefaultMsg(this.props.action, data).submitErrorMsg;
Notify.errorWithDetail(error, message);
Notify.errorWithDetail(realError, message);
this.onCallback(false, true);
};

View File

@ -59,9 +59,16 @@ function DropdownActionButton({
const menuItems = actions.map((it) => {
const key = `table-batch-more-${generateId()}`;
const newConf = updateConf(it, selectedItems);
const { buttonType } = newConf;
const { buttonType, name } = newConf;
newConf.onFinishAction = onFinishAction;
newConf.danger = buttonType === 'danger';
if (!selectedItems.length) {
return (
<Menu.Item key={key} disabled style={{ textAlign: 'center' }}>
{name}
</Menu.Item>
);
}
return (
<Menu.Item key={key}>
<ActionButton

View File

@ -55,8 +55,8 @@ export default class TablePrimaryButtons extends Component {
this.getActionsAllowed();
}
componentDidUpdate(nextProps) {
if (!isEqual(nextProps, this.props)) {
componentDidUpdate(prevProps) {
if (!isEqual(prevProps, this.props)) {
this.getActionsAllowed();
}
}

View File

@ -223,8 +223,12 @@ export default class SimpleTable extends React.Component {
}
return {
onClick: () => {
const { selectedRowKeys, onChange, type, getCheckboxProps } =
rowSelection;
const {
selectedRowKeys = [],
onChange,
type,
getCheckboxProps,
} = rowSelection || {};
if (getCheckboxProps) {
const { disabled } = getCheckboxProps(record);
if (disabled) {

View File

@ -35,8 +35,13 @@ export default class BaseDetail extends React.Component {
return id;
}
get currentProject() {
return globals.user.project.id;
get currentUser() {
const { user } = this.props.rootStore || {};
return user || {};
}
get currentProjectId() {
return this.props.rootStore.projectId;
}
get projectId() {
@ -45,7 +50,7 @@ export default class BaseDetail extends React.Component {
}
get isMyResource() {
return this.projectId === this.currentProject;
return this.projectId === this.currentProjectId;
}
get detailData() {

View File

@ -271,8 +271,13 @@ export default class BaseList extends React.Component {
return true;
}
get currentUser() {
const { user } = this.props.rootStore || {};
return user || {};
}
get currentProjectId() {
return globals.user.project.id;
return this.props.rootStore.projectId;
}
get fetchDataByCurrentProject() {
@ -480,7 +485,7 @@ export default class BaseList extends React.Component {
}
getDataWithPolicy(params) {
if (!globals.user) {
if (!this.currentUser || isEmpty(this.currentUser)) {
return;
}
if (this.endpointError) {
@ -510,7 +515,7 @@ export default class BaseList extends React.Component {
} catch (e) {
// eslint-disable-next-line no-console
console.log('fetch list error', e);
const { message = '', data, status } = e || {};
const { message = '', data, status } = e.response || e || {};
if (status === 500) {
const sysErr = t('System is error, please try again later.');
const title = `${t('Get {name} error.', {
@ -520,7 +525,7 @@ export default class BaseList extends React.Component {
} else {
const error = {
message: data || message || e || '',
status: e.status,
status,
};
Notify.errorWithDetail(
error,

View File

@ -245,12 +245,8 @@ export default class DetailBase extends React.Component {
catch = (e) => {
// eslint-disable-next-line no-console
console.log(e);
if (
e.code === 404 ||
e.status === 404 ||
e.reason === 'NotFound' ||
e.reason === 'Not Found'
) {
const { data, status } = e.response || e || {};
if (status === 404) {
this.setState({ notFound: true });
Notify.warn(
t('{name} {id} could not be found.', {
@ -260,8 +256,8 @@ export default class DetailBase extends React.Component {
);
} else {
const error = {
message: e,
status: e.code || e.status,
message: data,
status,
};
Notify.errorWithDetail(
error,

View File

@ -21,34 +21,13 @@ import { ConfigProvider } from 'antd';
import zhCN from 'antd/es/locale/zh_CN';
import enUS from 'antd/es/locale/en_US';
import globalRootStore from 'stores/root';
import request from 'utils/request';
import PageLoading from 'components/PageLoading';
import i18n from './i18n';
import App from './App';
window.t = i18n.t;
window.request = request;
window.globals = {
user: null,
};
const store = globalRootStore;
// request error handler
window.onunhandledrejection = function (e) {
if (e && (e.status === 'Failure' || e.status >= 400)) {
if (e.status === 401) {
// session timeout handler, except app store page.
/* eslint-disable no-alert */
const currentPath = window.location.pathname;
if (currentPath.indexOf('login') < 0) {
store.gotoLoginPage(currentPath);
// window.location.href = `/user/login?referer=${currentPath}`;
}
}
}
};
const browserHistory = createBrowserHistory();
const history = syncHistoryWithStore(browserHistory, store.routing);
const lang = i18n.getLocale();

View File

@ -61,6 +61,10 @@ class BaseLayout extends Component {
return this.user && this.rootStore.hasAdminRole;
}
get hasAdminPageRole() {
return this.user && this.rootStore.hasAdminPageRole;
}
get originMenu() {
if (this.isAdminPage) {
return renderAdminMenu(i18n.t);

View File

@ -71,7 +71,7 @@ const renderMenu = (t) => {
level: 2,
},
{
path: /^\/compute\/flavor-admin\/detail\/.[^/]+$/,
path: /^\/compute\/flavor-admin\/detail\/[^/]+$/,
name: t('Flavor Detail'),
key: 'flavor-detail',
level: 2,

View File

@ -236,7 +236,6 @@
"Clear Gateway": "Clear Gateway",
"Click here for filters.": "Click here for filters.",
"Click to Upload": "Click to Upload",
"Click to see": "Click to see",
"Click to show detail": "Click to show detail",
"Clone Volume": "Clone Volume",
"Clone volume": "Clone volume",
@ -1159,7 +1158,6 @@
"Please select!": "Please select!",
"Please set CPU && Ram first.": "Please set CPU && Ram first.",
"Please set MUNA": "Please set MUNA",
"Please set expiration time": "Please set expiration time",
"Pleasse input a valid ip!": "Pleasse input a valid ip!",
"Pleasse select a network!": "Pleasse select a network!",
"Pleasse select a subnet!": "Pleasse select a subnet!",
@ -1509,7 +1507,6 @@
"The current operation requires the instance to be shut down:": "The current operation requires the instance to be shut down:",
"The description can be up to 255 characters long.": "The description can be up to 255 characters long.",
"The entire inspection process takes 5 to 10 minutes, so you need to be patient. After the registration is completed, the node configuration status will return to the manageable status.": "The entire inspection process takes 5 to 10 minutes, so you need to be patient. After the registration is completed, the node configuration status will return to the manageable status.",
"The expiration time needs to be greater than the current time.": "The expiration time needs to be greater than the current time.",
"The feasible configuration of cloud-init or cloudbase-init service in the image is not synced to image's properties, so the Login Name is unknown.": "The feasible configuration of cloud-init or cloudbase-init service in the image is not synced to image's properties, so the Login Name is unknown.",
"The instance": "The instance",
"The instance architecture diagram mainly shows the overall architecture composition of the instance. If you need to view the network topology of the instance, please go to: ": "The instance architecture diagram mainly shows the overall architecture composition of the instance. If you need to view the network topology of the instance, please go to: ",
@ -1549,6 +1546,7 @@
"The timeout period of waiting for the return of the health check request, the check timeout will be judged as a check failure": "The timeout period of waiting for the return of the health check request, the check timeout will be judged as a check failure",
"The trait name of the flavor needs to correspond to the trait of the scheduling node; by injecting the necessary traits into the ironic instance, the computing service will only schedule the instance to the bare metal node with all necessary traits (for example: the trait of the scheduling node has HW_CPU_X86_VMX trait, and the flavor adds HW_CPU_X86_VMX, it can be scheduled to this node for necessary traits).": "The trait name of the flavor needs to correspond to the trait of the scheduling node; by injecting the necessary traits into the ironic instance, the computing service will only schedule the instance to the bare metal node with all necessary traits (for example: the trait of the scheduling node has HW_CPU_X86_VMX trait, and the flavor adds HW_CPU_X86_VMX, it can be scheduled to this node for necessary traits).",
"The trait of the scheduled node needs to correspond to the trait of the flavor used by the ironic instance; by injecting the necessary traits into the ironic instance, the computing service will only schedule the instance to the bare metal node with all the necessary traits (for example, the ironic instance which use the flavor that has HW_CPU_X86_VMX as a necessary trait, can be scheduled to the node which has the trait of HW_CPU_X86_VMX).": "The trait of the scheduled node needs to correspond to the trait of the flavor used by the ironic instance; by injecting the necessary traits into the ironic instance, the computing service will only schedule the instance to the bare metal node with all the necessary traits (for example, the ironic instance which use the flavor that has HW_CPU_X86_VMX as a necessary trait, can be scheduled to the node which has the trait of HW_CPU_X86_VMX).",
"The user has been disabled, please contact the administrator": "The user has been disabled, please contact the administrator",
"The user needs to ensure that the input is a shell script that can run completely and normally.": "The user needs to ensure that the input is a shell script that can run completely and normally.",
"The volume associated with the backup is not available, unable to restore.": "The volume associated with the backup is not available, unable to restore.",
"The volume type needs to set \"multiattach\" in the metadata to support shared volume attributes.": "The volume type needs to set \"multiattach\" in the metadata to support shared volume attributes.",

View File

@ -236,7 +236,6 @@
"Clear Gateway": "",
"Click here for filters.": "筛选",
"Click to Upload": "点击上传文件",
"Click to see": "点击查看",
"Click to show detail": "点击查看详情",
"Clone Volume": "克隆云硬盘",
"Clone volume": "克隆云硬盘",
@ -1159,7 +1158,6 @@
"Please select!": "请选择!",
"Please set CPU && Ram first.": "请先设置CPU、内存。",
"Please set MUNA": "请设置NUMA节点",
"Please set expiration time": "请设置到期时间",
"Pleasse input a valid ip!": "请输入正确的IP地址",
"Pleasse select a network!": "请选择网络!",
"Pleasse select a subnet!": "请选择子网!",
@ -1509,7 +1507,6 @@
"The current operation requires the instance to be shut down:": "当前操作需要云主机在关机状态下进行:",
"The description can be up to 255 characters long.": "描述最长为255字符",
"The entire inspection process takes 5 to 10 minutes, so you need to be patient. After the registration is completed, the node configuration status will return to the manageable status.": "检查的整个过程需要耗费 5 到 10 分钟时间,您需要耐心等待。在完成注册后,节点配置状态会重新回到可管理状态。",
"The expiration time needs to be greater than the current time.": "到期时间需要大于当前时间。",
"The feasible configuration of cloud-init or cloudbase-init service in the image is not synced to image's properties, so the Login Name is unknown.": "镜像中的cloud-init或cloudbase-init服务的预制配置未同步至镜像属性, 登录名未知",
"The instance": "云主机",
"The instance architecture diagram mainly shows the overall architecture composition of the instance. If you need to view the network topology of the instance, please go to: ": "云主机架构图主要展示云主机的总体架构组成。如果需要查看云主机的网络拓扑,请转到:",
@ -1549,6 +1546,7 @@
"The timeout period of waiting for the return of the health check request, the check timeout will be judged as a check failure": "等待健康检查请求返回的超时时间,检查超时将会被判定为一次检查失败",
"The trait name of the flavor needs to correspond to the trait of the scheduling node; by injecting the necessary traits into the ironic instance, the computing service will only schedule the instance to the bare metal node with all necessary traits (for example: the trait of the scheduling node has HW_CPU_X86_VMX trait, and the flavor adds HW_CPU_X86_VMX, it can be scheduled to this node for necessary traits).": "云主机类型的特性名称需要与调度节点的特性对应;通过给裸机实例注入必需特性,计算服务将只调度实例到具有所有必需特性的裸金属节点(比如:调度节点的有 HW_CPU_X86_VMX的特性云主机类型添加HW_CPU_X86_VMX为必需特性可以调度到此节点。",
"The trait of the scheduled node needs to correspond to the trait of the flavor used by the ironic instance; by injecting the necessary traits into the ironic instance, the computing service will only schedule the instance to the bare metal node with all the necessary traits (for example, the ironic instance which use the flavor that has HW_CPU_X86_VMX as a necessary trait, can be scheduled to the node which has the trait of HW_CPU_X86_VMX).": "被调度节点的特性需要与裸机实例使用的云主机类型的特性对应;通过给裸机实例注入必需特性,计算服务将只调度实例到具有所有必需特性的裸金属节点(比如:调度节点的有 HW_CPU_X86_VMX的特性 云主机类型添加HW_CPU_X86_VMX为必要特性可以调度到此节点。",
"The user has been disabled, please contact the administrator": "",
"The user needs to ensure that the input is a shell script that can run completely and normally.": "请确保输入的是能完整正常运行的 shell 脚本。",
"The volume associated with the backup is not available, unable to restore.": "云硬盘不处于可用状态,不支持恢复备份操作。",
"The volume type needs to set \"multiattach\" in the metadata to support shared volume attributes.": "云硬盘类型需在元数据中设置\"multiattach\",才可支持共享盘属性。",

View File

@ -20,6 +20,7 @@ import { InfoCircleFilled } from '@ant-design/icons';
import SimpleForm from 'components/SimpleForm';
import globalSkylineStore from 'stores/skyline/skyline';
import i18n from 'core/i18n';
import { isEmpty } from 'lodash';
import styles from './index.less';
@inject('rootStore')
@ -189,13 +190,15 @@ export default class Login extends Component {
this.setState({
loading: true,
});
this.rootStore.login(values).then(
const { domain, password, region, username } = values;
const body = { domain, password, region, username };
this.rootStore.login(body).then(
() => {
this.setState({
loading: false,
error: false,
});
if (globals.user) {
if (this.rootStore.user && !isEmpty(this.rootStore.user)) {
this.rootStore.routing.push(this.nextPage);
}
},
@ -205,7 +208,7 @@ export default class Login extends Component {
});
const {
data: { detail },
} = error;
} = error.response;
if (
detail.indexOf(
'The password is expired and needs to be changed for user'
@ -240,13 +243,16 @@ export default class Login extends Component {
getErrorMessage() {
const { message } = this.state;
if (message.indexOf('The account is locked for user') >= 0) {
if (message.includes('The account is locked for user')) {
return t(
'Frequent login failure will cause the account to be temporarily locked, please operate after 5 minutes'
);
}
if (message.includes('The account is disabled for user')) {
return t('The user has been disabled, please contact the administrator');
}
if (
message.indexOf('You are not authorized for any projects or domains') >= 0
message.includes('You are not authorized for any projects or domains')
) {
return t(
'If you are not authorized to access any project, or if the project you are involved in has been deleted or disabled, contact the platform administrator to reassign the project'

View File

@ -23,7 +23,8 @@ import styles from '../style.less';
@observer
class ResourceStatistic extends Component {
componentDidMount() {
const { project: { id: project_id } = {} } = globals.user || {};
const { user } = this.props.rootStore || {};
const { project: { id: project_id } = {} } = user || {};
this.props.store.getResourceStatisticData(project_id);
}

View File

@ -16,7 +16,7 @@ import { observer, inject } from 'mobx-react';
import Base from 'containers/List';
import globalIronicStore from 'stores/ironic/ironic';
import { powerState, provisioningState } from 'resources/ironic';
import { ironicOriginEndpoint } from 'utils/constants';
import { ironicOriginEndpoint } from 'client/client/constants';
import actionConfigs from './actions';
@inject('rootStore')

View File

@ -16,8 +16,6 @@ import { inject, observer } from 'mobx-react';
import { HypervisorStore } from 'stores/nova/hypervisor';
import Base from 'containers/TabDetail';
import Members from 'pages/compute/containers/Instance';
import Link from 'react-router-dom/Link';
import React from 'react';
@inject('rootStore')
@observer
@ -55,15 +53,6 @@ export default class HypervisorDetail extends Base {
render: (value, record) =>
`${record.memory_mb_used} / ${record.memory_mb}`,
},
{
title: t('Used Local Storage (GB)'),
dataIndex: 'storage_percent',
render: () => (
<Link to="/monitor-center/storage-cluster-admin">
{t('Click to see')}
</Link>
),
},
];
}

View File

@ -33,10 +33,6 @@ export default class SystemStep extends Base {
return 'SystemStep';
}
get hasAdminRole() {
return globals.user.hasAdminRole;
}
get keypairs() {
return (this.keyPairStore.list.data || []).map((it) => ({
...it,

View File

@ -22,7 +22,7 @@ import globalProjectStore from 'stores/keystone/project';
import classnames from 'classnames';
import { isEmpty, isFinite } from 'lodash';
import { getUserData, canCreateIronicByLicense } from 'resources/instance';
import { ironicOriginEndpoint } from 'utils/constants';
import { ironicOriginEndpoint } from 'client/client/constants';
import styles from './index.less';
import ConfirmStep from './ConfirmStep';
import SystemStep from './SystemStep';
@ -68,9 +68,8 @@ export default class CreateIronic extends StepAction {
}
async getQuota() {
const { project: { id: project_id } = {} } = globals.user || {};
await this.projectStore.fetchProjectQuota({
project_id,
project_id: this.currentProjectId,
});
this.onCountChange(1);
}

View File

@ -44,10 +44,6 @@ export default class SystemStep extends Base {
return 'SystemStep';
}
get hasAdminRole() {
return globals.user.hasAdminRole;
}
get keypairs() {
return (this.keyPairStore.list.data || []).map((it) => ({
...it,

View File

@ -63,9 +63,8 @@ class StepCreate extends StepAction {
}
async getQuota() {
const { project: { id: project_id } = {} } = globals.user || {};
await this.projectStore.fetchProjectQuota({
project_id,
project_id: this.currentProjectId,
});
this.onCountChange(1);
}

View File

@ -36,26 +36,15 @@ export default class PortForwarding extends Base {
return true;
}
updateFetchParamsByPage = (params) => {
const { id, ...rest } = params;
updateFetchParams = (params) => {
const { id, all_projects, ...rest } = params;
return {
fipID: id,
fipInfo: this.props.detail,
...rest,
};
};
fetchDataByPage = async (params) => {
await this.store.getFipAlreadyUsedPorts(params);
this.updateList({
data: this.store.list.data.map((i) => {
i.fip = this.props.detail;
i.floating_ip_address = this.props.detail.floating_ip_address;
return i;
}),
});
this.list.silent = false;
};
get actionConfigs() {
return this.isAdminPage
? actionConfigs.actionConfigsAdmin

View File

@ -147,7 +147,11 @@ export default class FloatingIps extends Base {
title: t('Associated Resource'),
dataIndex: 'resource_name',
render: (resource_name, record) => {
if (!resource_name && record.port_forwardings.length !== 0) {
if (
!resource_name &&
record.port_forwardings &&
record.port_forwardings.length !== 0
) {
return (
<>
{t('{number} port forwarding rules', {

View File

@ -15,7 +15,7 @@
import { inject, observer } from 'mobx-react';
import Base from 'containers/List';
import { LbaasStore } from 'stores/octavia/loadbalancer';
import { lbEndpoint } from 'utils/constants';
import { lbEndpoint } from 'client/client/constants';
import { actionConfigs, adminActions } from './actions';
@inject('rootStore')

View File

@ -30,10 +30,6 @@ export default class QoSPolicy extends Base {
return 'get_policy';
}
get module() {
return 'qos_policies';
}
get name() {
return t('QoS policies');
}

View File

@ -35,10 +35,6 @@ export default class QoSPolicy extends Base {
return 'get_policy';
}
get module() {
return 'qos_policies';
}
get name() {
return t('QoS policies');
}

View File

@ -35,10 +35,6 @@ export default class QoSPolicy extends Base {
return 'get_policy';
}
get module() {
return 'qos_policies';
}
get name() {
return t('QoS policies');
}

View File

@ -68,7 +68,7 @@ export default class AssociateFip extends ModalAction {
} = this.item;
this.floatingIpStore.fetchList({
floating_network_id: network_id,
project_id: globals.user.project.id,
project_id: this.currentProjectId,
status: 'DOWN',
});
}

View File

@ -14,7 +14,7 @@
import { observer, inject } from 'mobx-react';
import Base from 'containers/TabList';
import { vpnEndpoint } from 'utils/constants';
import { vpnEndpoint } from 'client/client/constants';
import VPNGateway from './VPNGateway';
import EndPointGroup from './EndpointGroup';
import IKEPolicy from './IKEPolicy';

View File

@ -15,6 +15,7 @@
import React from 'react';
import ImageType from 'components/ImageType';
import { get } from 'lodash';
import globalRootStore from 'stores/root';
export const imageStatus = {
active: t('Active'),
@ -99,21 +100,14 @@ export const imageProperties = {
export const transitionStatusList = ['saving', 'queued', 'pending_delete'];
export const isOwnerOrAdmin = (item) => {
const {
project: { id },
hasAdminRole,
} = globals.user;
if (id === item.owner) {
if (globalRootStore.projectId === item.owner) {
return true;
}
return hasAdminRole;
return globalRootStore.hasAdminRole;
};
export const isOwner = (item) => {
const {
project: { id },
} = globals.user;
if (id === item.owner) {
if (globalRootStore.projectId === item.owner) {
return true;
}
return false;

View File

@ -13,10 +13,8 @@
// limitations under the License.
import React from 'react';
import moment from 'moment';
import ImageType from 'components/ImageType';
import globalRootStore from 'stores/root';
import { getLocalTimeStr, timeFormatStr } from 'utils/time';
import lockSvg from 'src/asset/image/lock.svg';
import unlockSvg from 'src/asset/image/unlock.svg';
@ -263,53 +261,6 @@ export const getUserData = (password, userData) => {
return onlyUserData.replace(/USER_DATA/g, userData);
};
function range(start, end) {
const result = [];
for (let i = start; i < end; i++) {
result.push(i);
}
return result;
}
export const getExpireDateFormItem = (autoRelease) => ({
name: 'expiredTime',
label: t('Expired Time'),
type: 'date-picker',
hidden: !autoRelease,
required: autoRelease,
format: timeFormatStr.YMDHm,
showTime: {
defaultValue: getLocalTimeStr('00:00:00', 'HH:mm'),
// minuteStep: 60,
},
showNow: false,
disabledDate: (current) => current && current < moment().startOf('day'),
disabledTime: (date) => {
const currentDay = moment();
const currentHour = moment().hour();
const currentMinute = moment().minute();
const disabledMap = {};
if (moment(date).isSame(currentDay, 'day')) {
disabledMap.disabledHours = () => range(0, currentHour);
if (moment(date).isSame(currentDay, 'hour')) {
disabledMap.disabledMinutes = () => range(0, currentMinute + 1);
}
}
return disabledMap;
},
validator: (rule, value) => {
if (!value) {
return Promise.reject(t('Please set expiration time'));
}
if (moment(value) < moment()) {
return Promise.reject(
t('The expiration time needs to be greater than the current time.')
);
}
return Promise.resolve();
},
});
export const getIpInitValue = (subnet) => {
if (!subnet) {
return null;

View File

@ -95,3 +95,5 @@ export const getAnchorData = (num, y) => {
}
return result;
};
export const isExternalNetwork = (network) => !!network['router:external'];

View File

@ -13,12 +13,13 @@
// limitations under the License.
import { isArray, isObject, isFunction, isString, has } from 'lodash';
import globalRootStore from 'stores/root';
export const checkPolicyRule = (rule, actionName) => {
if (!rule) {
return true;
}
const item = globals.policies.find((it) => it.rule === rule);
const item = globalRootStore.policies.find((it) => it.rule === rule);
if (!item) {
// eslint-disable-next-line no-console
console.log('policy rule not exit', rule, actionName);
@ -37,7 +38,7 @@ const checkPolicyRules = (rules, every, actionName) => {
};
export const systemRoleIsReader = () => {
const { user: { roles = [] } = {} } = globals || {};
const { roles = [] } = globalRootStore.user || {};
const readerRole = 'system_reader';
const adminRoles = ['system_admin', 'admin'];
const hasReaderRole = roles.some((it) => it.name === readerRole);
@ -55,9 +56,11 @@ const checkItemPolicy = ({
isAdminPage,
enableSystemReader,
}) => {
if (globals.policies.length === 0) {
// TODO: change to false
return true;
if (globalRootStore.policies.length === 0) {
return false;
}
if (isAdminPage && !enableSystemReader && systemRoleIsReader()) {
return false;
}
if (isAdminPage && !enableSystemReader && systemRoleIsReader()) {
return false;

View File

@ -12,11 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { get, isArray } from 'lodash';
import { get } from 'lodash';
import { action, observable } from 'mobx';
import { keystoneBase } from 'utils/constants';
import client from 'client';
import List from './base-list';
import globalProjectMapStore from './project';
import globalRootStore from './root';
export default class BaseStore {
list = new List();
@ -30,16 +31,16 @@ export default class BaseStore {
@observable
isSubmitting = false;
get module() {
return '';
get client() {
return {};
}
get apiVersion() {
return '';
get skylineClient() {
return client.skyline;
}
get responseKey() {
return '';
return this.client.responseKey;
}
get listResponseKey() {
@ -50,6 +51,22 @@ export default class BaseStore {
return true;
}
get currentUser() {
return globalRootStore.user || {};
}
get currentProjectId() {
return globalRootStore.projectId;
}
get hasAdminRole() {
return globalRootStore.hasAdminRole;
}
get enableBilling() {
return globalRootStore.enableBilling;
}
get mapper() {
// update response items;
return (data) => data;
@ -112,7 +129,7 @@ export default class BaseStore {
get paramsFuncPage() {
return (params) => {
const { current, ...rest } = params;
const { current, withPrice, ...rest } = params;
return rest;
};
}
@ -126,14 +143,39 @@ export default class BaseStore {
return false;
}
get currentProject() {
return globals.user.project.id;
}
get markerKey() {
return 'id';
}
get listWithDetail() {
return false;
}
get isSubResource() {
return false;
}
getFatherResourceId = (params) => params.id;
detailFetchByClient(resourceParams, params) {
const { id } = resourceParams;
if (!this.isSubResource) {
return this.client.show(id, params);
}
const fatherId = this.getFatherResourceId(resourceParams);
return this.client.show(fatherId, id, params);
}
listFetchByClient(params, originParams) {
if (!this.isSubResource) {
return this.listWithDetail
? this.client.listDetail(params)
: this.client.list(params);
}
const fatherId = this.getFatherResourceId(originParams);
return this.client.list(fatherId, params);
}
getItemProjectId(item) {
return (
item.project_id ||
@ -153,21 +195,13 @@ export default class BaseStore {
const itemProject = globalProjectMapStore.getItemProjectId(item);
const { shared, visibility, is_public } = item;
return (
itemProject === this.currentProject ||
itemProject === this.currentProjectId ||
is_public ||
shared ||
visibility === 'public'
);
};
getListUrl = () => `${this.apiVersion}/${this.module}`;
getListDetailUrl = () => '';
getListPageUrl = () => '';
getDetailUrl = ({ id }) => `${this.getListUrl()}/${id}`;
@action
setModule(module) {
this.module = module;
@ -188,12 +222,6 @@ export default class BaseStore {
return promise;
};
async fetchProjectDetail({ id }) {
return request.get(`${keystoneBase()}/projects/${id}`, {}, null, () =>
Promise.resolve('error')
);
}
// eslint-disable-next-line no-unused-vars
async listDidFetch(items, allProjects, filters) {
return items;
@ -208,7 +236,7 @@ export default class BaseStore {
if (!this.needGetProject) {
return items;
}
if (!all_projects || !globals.user.hasAdminRole) {
if (!all_projects || !this.hasAdminRole) {
return items;
}
const projectIds = [];
@ -240,28 +268,33 @@ export default class BaseStore {
return items;
}
async requestListByMarker(url, params, limit, marker) {
updateMarkerParams = (limit, marker) => {
return {
limit,
marker,
};
};
async requestListByMarker(params, limit, marker) {
const markerParams = this.updateMarkerParams(limit, marker);
const newParams = {
...params,
limit,
...markerParams,
};
if (marker) {
newParams.marker = marker;
}
return request.get(url, newParams);
return this.listFetchByClient(newParams);
}
async requestListAllByLimit(url, params, limit) {
async requestListAllByLimit(params, limit) {
let marker = '';
let hasNext = true;
let datas = [];
while (hasNext) {
// eslint-disable-next-line no-await-in-loop
const result = await this.requestListByMarker(url, params, limit, marker);
const result = await this.requestListByMarker(params, limit, marker);
const data = this.getListDataFromResult(result);
datas = [...datas, ...data];
if (data.length >= limit) {
marker = this.parseMarker(data);
marker = this.parseMarker(data, result, datas);
if (!marker) {
// eslint-disable-next-line no-console
console.log('parse marker error!');
@ -274,21 +307,21 @@ export default class BaseStore {
return datas;
}
async requestListAll(url, params) {
const result = await request.get(url, params);
async requestListAll(params, originParams) {
const result = await this.listFetchByClient(params, originParams);
return this.getListDataFromResult(result);
}
async requestList(url, params) {
async requestList(params, originParams) {
const datas = !this.fetchListByLimit
? await this.requestListAll(url, params)
: await this.requestListAllByLimit(url, params, 100);
? await this.requestListAll(params, originParams)
: await this.requestListAllByLimit(params, 100);
return datas;
}
// eslint-disable-next-line no-unused-vars
async requestListByPage(url, params, page, filters) {
const datas = await request.get(url, params);
async requestListByPage(params, page, originParams) {
const datas = await this.listFetchByClient(params, originParams);
return datas;
}
@ -319,19 +352,7 @@ export default class BaseStore {
params.all_projects = true;
}
}
let url = `${this.getListDetailUrl() || this.getListUrl()}?`;
let othersStr = '';
Object.keys(params).forEach((item) => {
if (isArray(params[item])) {
params[item].forEach((i) => {
othersStr += `${item}=${i}&`;
});
} else {
othersStr += `${item}=${params[item]}&`;
}
});
url += othersStr.substring(0, othersStr.length - 1);
const allData = await this.requestList(url);
const allData = await this.requestList(params, {});
return allData;
}
@ -355,9 +376,7 @@ export default class BaseStore {
}
}
const newParams = this.paramsFunc(params);
const url = this.getListDetailUrl(filters) || this.getListUrl(filters);
const newUrl = this.updateUrl(url, params);
const allData = await this.requestList(newUrl, newParams, filters);
const allData = await this.requestList(newParams, filters);
const allDataNew = allData.map((it) =>
this.mapperBeforeFetchProject(it, filters)
);
@ -393,15 +412,15 @@ export default class BaseStore {
}
// eslint-disable-next-line no-unused-vars
parseMarker(datas, result) {
parseMarker(datas, result, allDatas) {
return datas.length === 0
? ''
: get(datas[datas.length - 1], this.markerKey);
}
@action
updateMarker(datas, page, result) {
const marker = this.parseMarker(datas, result);
updateMarker(datas, page, result, allDatas) {
const marker = this.parseMarker(datas, result, allDatas);
if (page === 1) {
this.list.markers = [marker];
} else {
@ -423,6 +442,9 @@ export default class BaseStore {
return {};
}
// eslint-disable-next-line no-unused-vars
getOtherInfo = (result) => {};
@action
async fetchListByPage({
limit = 10,
@ -448,20 +470,10 @@ export default class BaseStore {
if (marker) {
params.marker = marker;
}
const url =
this.getListPageUrl(filters) ||
this.getListDetailUrl(filters) ||
this.getListUrl(filters);
const newUrl = this.updateUrl(url, params);
const newParams = this.paramsFuncPage(params, all_projects);
const result = await this.requestListByPage(
newUrl,
newParams,
page,
filters
);
const result = await this.requestListByPage(newParams, page, filters);
const allData = this.getListDataFromResult(result);
this.updateMarker(allData, page, result);
this.updateMarker(allData, page, result, allData);
const allDataNew = allData.map(this.mapperBeforeFetchProject);
let newData = await this.listDidFetchProject(allDataNew, all_projects);
newData = await this.listDidFetch(newData, all_projects, filters);
@ -482,6 +494,7 @@ export default class BaseStore {
count = retCount;
total = retTotal;
}
const others = this.getOtherInfo(result);
this.list.update({
data: newData,
limit: Number(limit) || 10,
@ -493,54 +506,7 @@ export default class BaseStore {
isLoading: false,
total: count || total,
...(this.list.silent ? {} : { selectedRowKeys: [] }),
});
return newData;
}
@action
async fetchListWithoutDetail({
limit,
page,
sortKey,
sortOrder,
conditions,
timeFilter,
...filters
} = {}) {
this.list.isLoading = true;
// todo: no page, no limit, fetch all
const { tab, all_projects, ...rest } = filters;
const params = { ...rest };
if (all_projects) {
if (!this.listFilterByProject) {
params.all_projects = true;
}
}
const newParams = this.paramsFunc(params, all_projects);
const allData = await this.requestList(this.getListUrl(), newParams);
const allDataNew = allData.map(this.mapperBeforeFetchProject);
const data = allDataNew.filter((item) => {
if (!this.listFilterByProject) {
return true;
}
return this.itemInCurrentProject(item, all_projects);
});
// const items = data.map(this.mapper);
let newData = await this.listDidFetchProject(data, all_projects);
newData = await this.listDidFetch(newData, all_projects, filters);
newData = newData.map(this.mapper);
this.list.update({
data: newData,
total: newData.length || 0,
limit: Number(limit) || 10,
page: Number(page) || 1,
sortKey,
sortOrder,
filters,
timeFilter,
isLoading: false,
...(this.list.silent ? {} : { selectedRowKeys: [] }),
...others,
});
return newData;
@ -551,8 +517,8 @@ export default class BaseStore {
if (!silent) {
this.isLoading = true;
}
const result = await request.get(
this.getDetailUrl(rest),
const result = await this.detailFetchByClient(
rest,
this.getDetailParams({ all_projects })
);
const originData = get(result, this.responseKey) || result;
@ -579,37 +545,30 @@ export default class BaseStore {
create(data) {
const body = {};
body[this.responseKey] = data;
return this.submitting(request.post(this.getListUrl(), body));
}
@action
update({ id }, newObject, sleepTime) {
return this.submitting(
request.post(
`${this.getDetailUrl({ id })}/action`,
newObject,
null,
null,
sleepTime
)
);
return this.submitting(this.client.create(body));
}
@action
edit({ id }, newObject) {
const body = {};
body[this.responseKey] = newObject;
return this.submitting(request.put(this.getDetailUrl({ id }), body));
return this.submitting(this.client.update(id, body));
}
@action
update({ id }, newObject) {
const body = {};
body[this.responseKey] = newObject;
return this.submitting(this.client.update(id, body));
}
@action
patch({ id }, newObject) {
return this.submitting(request.patch(this.getDetailUrl({ id }), newObject));
return this.submitting(this.client.patch(id, newObject));
}
@action
delete = ({ id }) =>
this.submitting(request.delete(this.getDetailUrl({ id })));
delete = ({ id }) => this.submitting(this.client.delete(id));
@action
batchDelete(rowKeys) {
@ -617,17 +576,13 @@ export default class BaseStore {
Promise.all(
rowKeys.map((name) => {
const item = this.list.data.find((_item) => _item.name === name);
return request.delete(this.getDetailUrl(item));
const { id } = item;
return this.client.delete(id);
})
)
);
}
reject = (res) => {
this.isSubmitting = false;
window.onunhandledrejection(res);
};
@action
clearData() {
this.list.reset();

View File

@ -13,28 +13,19 @@
// limitations under the License.
import { action } from 'mobx';
import { cinderBase } from 'utils/constants';
import client from 'client';
import Base from '../base';
import { VolumeStore } from './volume';
export class BackupStore extends Base {
get module() {
if (!globals.user) {
return null;
}
return `${globals.user.project.id}/backups`;
get client() {
return client.cinder.backups;
}
get apiVersion() {
return cinderBase();
get listWithDetail() {
return true;
}
get responseKey() {
return 'backup';
}
getListDetailUrl = () => `${this.apiVersion}/${this.module}/detail`;
updateParamsSortPage = (params, sortKey, sortOrder) => {
if (sortKey && sortOrder) {
params.sort = `${sortKey}:${sortOrder === 'descend' ? 'desc' : 'asc'}`;
@ -65,9 +56,7 @@ export class BackupStore extends Base {
@action
restore(id, data) {
const body = { restore: data || {} };
return this.submitting(
request.post(`${this.getDetailUrl({ id })}/restore`, body)
);
return this.submitting(this.client.restore(id, body));
}
}
const globalBackupStore = new BackupStore();

View File

@ -13,43 +13,21 @@
// limitations under the License.
import { action } from 'mobx';
import { cinderBase } from 'utils/constants';
import client from 'client';
import Base from '../base';
export class ExtraSpecStore extends Base {
get module() {
if (!globals.user) {
return null;
}
return `${globals.user.project.id}/types`;
get client() {
return client.cinder.types.extraSpecs;
}
get apiVersion() {
return cinderBase();
get isSubResource() {
return true;
}
get responseKey() {
return 'extra_spec';
}
getFatherResourceId = (params) => params.id;
getExtraSpecsUrl = ({ id }) =>
`${this.apiVersion}/${this.module}/${id}/extra_specs`;
@action
async fetchList({
id,
limit,
page,
sortKey,
sortOrder,
conditions,
...filters
} = {}) {
this.list.isLoading = true;
// todo: no page, no limit, fetch all
const params = { ...filters };
const result = await request.get(this.getExtraSpecsUrl({ id }), params);
getListDataFromResult = (result) => {
const { extra_specs } = result;
const data = [];
Object.keys(extra_specs).forEach((key) => {
@ -60,36 +38,20 @@ export class ExtraSpecStore extends Base {
value: extra_specs[key],
});
});
const items = data.map(this.mapper);
this.list.update({
data,
total: items.length || 0,
limit: Number(limit) || 10,
page: Number(page) || 1,
sortKey,
sortOrder,
filters,
isLoading: false,
...(this.list.silent ? {} : { selectedRowKeys: [] }),
});
this.urlId = id;
return data;
}
};
@action
createOrUpdate(id, data) {
const body = {
extra_specs: data,
};
return this.submitting(request.post(this.getExtraSpecsUrl({ id }), body));
return this.submitting(this.client.create(id, body));
}
@action
delete = ({ id, keyname }) => {
return this.submitting(
request.delete(`${this.getExtraSpecsUrl({ id })}/${keyname}`)
);
return this.submitting(this.client.delete(id, keyname));
};
}
const globalExtraSpecStore = new ExtraSpecStore();

View File

@ -12,27 +12,26 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { cinderBase } from 'utils/constants';
import { isNumber } from 'lodash';
import client from 'client';
import Base from '../base';
export class PoolStore extends Base {
get module() {
return 'scheduler-stats/get_pools';
}
get apiVersion() {
return cinderBase();
}
get responseKey() {
return 'pool';
get client() {
return client.cinder.pools;
}
get listFilterByProject() {
return false;
}
get paramsFunc() {
return (params) => ({
...params,
detail: true,
});
}
get mapper() {
return (data) => {
const { name, capabilities = {} } = data;
@ -46,9 +45,6 @@ export class PoolStore extends Base {
return newItem;
};
}
getListUrl = () =>
`${this.apiVersion}/${globals.user.project.id}/${this.module}?detail=true`;
}
const globalPoolStore = new PoolStore();

View File

@ -13,42 +13,20 @@
// limitations under the License.
import { action } from 'mobx';
import { cinderBase } from 'utils/constants';
import client from 'client';
import Base from '../base';
export class QosSpecKeyStore extends Base {
get module() {
if (!globals.user) {
return null;
}
return `${globals.user.project.id}/qos-specs`;
get client() {
return client.cinder.qosSpecs;
}
get apiVersion() {
return cinderBase();
listFetchByClient(params) {
const { id } = params;
return this.client.show(id);
}
get responseKey() {
return 'qos_specs';
}
getListUrl = ({ id }) => `${this.apiVersion}/${this.module}/${id}`;
@action
async fetchList({
id,
limit,
page,
sortKey,
sortOrder,
conditions,
...filters
} = {}) {
this.list.isLoading = true;
// todo: no page, no limit, fetch all
const params = { ...filters };
const result = await request.get(this.getListUrl({ id }), params);
getListDataFromResult = (result) => {
const { specs = {} } = result.qos_specs || {};
const data = [];
Object.keys(specs).forEach((key) => {
@ -59,35 +37,21 @@ export class QosSpecKeyStore extends Base {
value: specs[key],
});
});
const items = data.map(this.mapper);
this.list.update({
data,
total: items.length || 0,
limit: Number(limit) || 10,
page: Number(page) || 1,
sortKey,
sortOrder,
filters,
isLoading: false,
...(this.list.silent ? {} : { selectedRowKeys: [] }),
});
this.urlId = id;
return data;
}
};
@action
createOrUpdate(id, data) {
const body = {};
body[this.responseKey] = data;
return this.submitting(request.put(this.getListUrl({ id }), body));
body.qos_specs = data;
return this.submitting(this.client.update(id, body));
}
// TODO
@action
delete = ({ id, keyname }) =>
this.submitting(
request.put(`${this.getListUrl({ id })}/delete_keys`, {
this.client.deleteKeys(id, {
keys: [keyname],
})
);

View File

@ -13,25 +13,12 @@
// limitations under the License.
import { action } from 'mobx';
import { cinderBase } from 'utils/constants';
import client from 'client';
import Base from '../base';
const qs = require('qs');
export class QosSpecStore extends Base {
get module() {
if (!globals.user) {
return null;
}
return `${globals.user.project.id}/qos-specs`;
}
get apiVersion() {
return cinderBase();
}
get responseKey() {
return 'qos_spec';
get client() {
return client.cinder.qosSpecs;
}
@action
@ -39,13 +26,13 @@ export class QosSpecStore extends Base {
const body = {};
const { values } = data;
body[`${this.responseKey}s`] = values;
return this.submitting(request.post(this.getListUrl(), body));
return this.submitting(this.client.create(body));
}
@action
editConsumer({ id, consumer }) {
return this.submitting(
request.put(this.getDetailUrl({ id }), {
this.client.update(id, {
qos_specs: {
consumer,
},
@ -66,18 +53,12 @@ export class QosSpecStore extends Base {
@action
associate(id, data) {
const query = qs.stringify(data);
return this.submitting(
request.get(`${this.getDetailUrl({ id })}/associate?${query}`)
);
return this.submitting(this.client.associate(id, data));
}
@action
disassociate(id, data) {
const query = qs.stringify(data);
return this.submitting(
request.get(`${this.getDetailUrl({ id })}/disassociate?${query}`)
);
return this.submitting(this.client.disassociate(id, data));
}
}

View File

@ -12,40 +12,23 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { cinderBase } from 'utils/constants';
import { action } from 'mobx';
import client from 'client';
import Base from '../base';
export class ServiceStore extends Base {
get module() {
return 'os-services';
}
get apiVersion() {
return cinderBase();
}
get responseKey() {
return 'service';
}
getListUrl = () =>
`${this.apiVersion}/${globals.user.project.id}/${this.module}`;
@action
operate(actionName, body) {
const url = `${this.getListUrl()}/${actionName}`;
return this.submitting(request.put(url, body));
get client() {
return client.cinder.services;
}
@action
enable(body) {
return this.operate('enable', body);
return this.submitting(this.client.enable(body));
}
@action
disable(body) {
return this.operate('disable-log-reason', body);
return this.submitting(this.client.reason(body));
}
}

View File

@ -12,44 +12,30 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { action, observable } from 'mobx';
import { cinderBase, skylineBase } from 'utils/constants';
import { action } from 'mobx';
import client from 'client';
import Base from '../base';
export class SnapshotStore extends Base {
@observable
allSnapshotList = [];
get module() {
if (!globals.user) {
return null;
}
return `${globals.user.project.id}/snapshots`;
}
get apiVersion() {
return cinderBase();
}
get responseKey() {
return 'snapshot';
get client() {
return client.cinder.snapshots;
}
get listResponseKey() {
return 'volume_snapshots';
}
listFetchByClient(params) {
return this.skylineClient.extension.volumeSnapshots(params);
}
get paramsFunc() {
return (params) => {
const { id, ...rest } = params;
const { id, withPrice, ...rest } = params;
return rest;
};
}
getListPageUrl = () => `${skylineBase()}/extension/volume_snapshots`;
getListDetailUrl = () => `${skylineBase()}/extension/volume_snapshots`;
async listDidFetch(items, allProjects, filters) {
if (items.length === 0) {
return items;
@ -61,10 +47,7 @@ export class SnapshotStore extends Base {
async detailDidFetch(item) {
const { volume_id } = item;
const volumeUrl = `${cinderBase()}/${
globals.user.project.id
}/volumes/${volume_id}`;
const { volume } = await request.get(volumeUrl);
const { volume } = await client.cinder.volumes.show(volume_id);
item.volume = volume;
return item;
}
@ -76,19 +59,10 @@ export class SnapshotStore extends Base {
}
};
@action
fetchAllList() {
return request.get(this.getListUrl()).then((res) => {
const list = res.snapshots || [];
this.allSnapshotList = list;
return list;
});
}
@action
update(id, data) {
const body = { [this.responseKey]: data };
return this.submitting(request.put(this.getDetailUrl({ id }), body));
return this.submitting(this.client.update(id, body));
}
}
const globalSnapshotStore = new SnapshotStore();

View File

@ -13,26 +13,19 @@
// limitations under the License.
import { action, observable } from 'mobx';
import { cinderBase } from 'utils/constants';
import client from 'client';
import { uniq } from 'lodash';
import Base from '../base';
export class VolumeTypeStore extends Base {
@observable
access = [];
get module() {
if (!globals.user) {
return null;
}
return `${globals.user.project.id}/types`;
}
@observable
projectVolumeTypes = [];
get apiVersion() {
return cinderBase();
}
get responseKey() {
return 'volume_type';
get client() {
return client.cinder.types;
}
get listFilterByProject() {
@ -41,32 +34,58 @@ export class VolumeTypeStore extends Base {
get paramsFuncPage() {
return (params) => {
const { current, showEncryption, ...rest } = params;
const {
current,
showEncryption,
showQoS,
withPrice,
resourceType,
...rest
} = params;
return rest;
};
}
get paramsFunc() {
return this.paramsFuncPage;
}
get mapper() {
return (data) => {
const { extra_specs: { multiattach = 'False' } = {} } = data;
return {
...data,
multiattach: multiattach === '<is> True',
enableBilling: this.enableBilling,
};
};
}
async listDidFetch(items, allProjects, filters) {
const { showEncryption } = filters;
const { showEncryption, showQoS } = filters;
if (items.length === 0) {
return items;
}
if (showQoS) {
const qosIds = uniq(
items.filter((it) => !!it.qos_specs_id).map((it) => it.qos_specs_id)
);
if (qosIds.length) {
const qosReqs = qosIds.map((id) => client.cinder.qosSpecs.show(id));
const qosResults = await Promise.all(qosReqs);
const qosItems = qosResults.map((it) => it.qos_specs);
items.forEach((it) => {
if (it.qos_specs_id) {
it.qos_specs = qosItems.find((qos) => qos.id === it.qos_specs_id);
it.qos_specs_name = (it.qos_specs || {}).name;
}
});
}
}
if (!showEncryption) {
return items;
}
const promiseList = items.map((i) =>
request.get(`${this.getDetailUrl({ id: i.id })}/encryption`)
);
const promiseList = items.map((i) => this.client.encryption.list(i.id));
const encryptionList = await Promise.all(promiseList);
const result = items.map((i) => {
const { id } = i;
@ -81,7 +100,7 @@ export class VolumeTypeStore extends Base {
async detailDidFetch(item) {
const { id } = item || {};
const result = await request.get(`${this.getDetailUrl({ id })}/encryption`);
const result = await this.client.encryption.list(id);
item.encryption = result;
return item;
}
@ -90,7 +109,7 @@ export class VolumeTypeStore extends Base {
update(id, data) {
const body = {};
body[this.responseKey] = data;
return this.submitting(request.put(this.getDetailUrl({ id }), body));
return this.submitting(this.client.update(id, body));
}
@action
@ -98,16 +117,12 @@ export class VolumeTypeStore extends Base {
const body = {
encryption: data,
};
return this.submitting(
request.post(`${this.getDetailUrl({ id })}/encryption`, body)
);
return this.submitting(this.client.encryption.create(id, body));
}
@action
deleteEncryption(id, encryption_id) {
return this.submitting(
request.delete(`${this.getDetailUrl({ id })}/encryption/${encryption_id}`)
);
return this.submitting(this.client.encryption.delete(id, encryption_id));
}
@action
@ -115,17 +130,16 @@ export class VolumeTypeStore extends Base {
const body = {};
body[this.responseKey] = data;
if (projectIds.length === 0) {
return this.submitting(request.post(this.getListUrl(), body));
return this.submitting(this.client.create(body));
}
this.isSubmitting = true;
const result = await request.post(this.getListUrl(), body);
const result = await this.client.create(body);
const { id } = result[this.responseKey];
return this.addProjectAccess(id, projectIds);
}
@action
addProjectAccess(id, projectIds = []) {
const actionUrl = `${this.getDetailUrl({ id })}/action`;
return this.submitting(
Promise.all(
projectIds.map((it) => {
@ -134,7 +148,7 @@ export class VolumeTypeStore extends Base {
project: it,
},
};
return request.post(actionUrl, actionBody);
return this.client.action(id, actionBody);
})
)
);
@ -142,7 +156,6 @@ export class VolumeTypeStore extends Base {
@action
removeProjectAccess(id, projectIds = []) {
const actionUrl = `${this.getDetailUrl({ id })}/action`;
return this.submitting(
Promise.all(
projectIds.map((it) => {
@ -151,7 +164,7 @@ export class VolumeTypeStore extends Base {
project: it,
},
};
return request.post(actionUrl, actionBody);
return this.client.action(id, actionBody);
})
)
);
@ -159,8 +172,7 @@ export class VolumeTypeStore extends Base {
@action
async fetchProjectAccess(id) {
const url = `${this.getDetailUrl({ id })}/os-volume-type-access`;
const result = await request.get(url);
const result = await this.client.getAccess(id);
this.access = result.volume_type_access;
}
@ -176,6 +188,30 @@ export class VolumeTypeStore extends Base {
await this.removeProjectAccess(id, dels);
return this.addProjectAccess(id, adds);
}
@action
async fetchProjectVolumeTypes(projectId) {
const result = await this.client.list({ is_public: 'None' });
const { volume_types: types } = result;
const privateTypes = types.filter((it) => !it.is_public);
if (!privateTypes.length) {
this.projectVolumeTypes = types;
return types;
}
const projectTypes = types.filter((it) => it.public);
const reqs = privateTypes.map((it) => this.client.getAccess(it.id));
const accessResults = await Promise.all(reqs);
accessResults.forEach((it) => {
const { volume_type_access: access } = it;
const item = access.find((a) => a.project_id === projectId);
if (item) {
const type = types.find((t) => t.id === item.volume_type_id);
projectTypes.push(type);
}
});
this.projectVolumeTypes = projectTypes;
return projectTypes;
}
}
const globalVolumeTypeStore = new VolumeTypeStore();
export default globalVolumeTypeStore;

View File

@ -13,8 +13,9 @@
// limitations under the License.
import { action, observable } from 'mobx';
import { cinderBase, skylineBase } from 'utils/constants';
import { isOsDisk } from 'resources/volume';
import { renderFilterMap } from 'utils/index';
import client from 'client';
import Base from '../base';
import globalVolumeTypeStore from './volume-type';
@ -31,32 +32,32 @@ export class VolumeStore extends Base {
@observable
quotaSet = {};
get module() {
if (!globals.user) {
return null;
get client() {
return client.cinder.volumes;
}
get transferClient() {
return client.cinder.volumeTransfers;
}
listFetchByClient(params, originParams) {
const { recycle } = originParams;
if (recycle) {
return this.client.listDetail(params);
}
return `${globals.user.project.id}/volumes`;
return this.skylineClient.extension.volumes(params);
}
get apiVersion() {
return cinderBase();
}
get responseKey() {
return 'volume';
}
getListDetailUrl = () => `${skylineBase()}/extension/volumes`;
getListPageUrl = () => `${skylineBase()}/extension/volumes`;
getListDetailUrlOpenstack = () => `${this.apiVersion}/${this.module}/detail`;
get mapper() {
return (volume) => ({
...volume,
disk_tag: isOsDisk(volume) ? 'os_disk' : 'data_disk',
description: volume.description || (volume.origin_data || {}).description,
delete_interval:
volume.metadata && volume.metadata.delete_interval
? new Date(renderFilterMap.toLocalTime(volume.updated_at)).getTime() +
Number(volume.metadata.delete_interval) * 1000
: null,
});
}
@ -68,16 +69,32 @@ export class VolumeStore extends Base {
}
updateParamsSortPage = (params, sortKey, sortOrder) => {
const { recycle } = params;
if (sortKey && sortOrder) {
params.sort_keys = sortKey;
params.sort_dirs = sortOrder === 'descend' ? 'desc' : 'asc';
const dirs = sortOrder === 'descend' ? 'desc' : 'asc';
if (recycle) {
params.sort = `${sortKey}:${dirs}`;
} else {
params.sort_keys = sortKey;
params.sort_dirs = sortOrder === 'descend' ? 'desc' : 'asc';
}
}
};
async listDidFetch(items, _, filters) {
const { withPrice } = filters;
if (items.length === 0) {
return items;
}
if (withPrice) {
const volumeTypes = await globalVolumeTypeStore.fetchList({ withPrice });
items.forEach((item) => {
const { size, volume_type } = item;
const volumeType = volumeTypes.find((it) => it.name === volume_type);
const cost = volumeType ? (volumeType.priceCost * size).toFixed(2) : 0;
item.cost = cost;
});
}
const { serverId } = filters;
return !serverId
? items
@ -88,54 +105,41 @@ export class VolumeStore extends Base {
);
}
async detailDidFetch(item, all_projects) {
async detailDidFetch(item, all_projects, { withPrice }) {
const { id } = item;
try {
const result = await this.fetchList({ uuid: id, all_projects });
item.itemInList = result[0];
item.attachmentsContrib = result[0].attachments;
} catch (e) {}
if (withPrice) {
const volumeTypes = await globalVolumeTypeStore.fetchList({ withPrice });
const { size, volume_type } = item;
const volumeType = volumeTypes.find((it) => it.name === volume_type);
const cost = volumeType ? (volumeType.priceCost * size).toFixed(2) : 0;
item.cost = cost;
}
return item;
}
@action
async fetchCinderService() {
return this.submitting(
request
.get(
`${this.apiVersion}/${globals.user.project.id}/os-services?binary=cinder-volume`
)
.then((data) => {
this.cinderServiceOptions = (data.services || [])
.filter((item) => item.status === 'enabled')
.map((s) => ({
value: s.host,
lable: s.host,
}));
})
);
}
@action
async fetchQuota() {
const url = `${this.apiVersion}/${this.currentProject}/os-quota-sets/${this.currentProject}?usage=True`;
const result = await request.get(url);
const result = await client.cinder.quotaSets.show(this.currentProjectId, {
usage: 'True',
});
this.quotaSet = result.quota_set;
}
@action
async fetchAvailabilityZoneList() {
const url = `${this.apiVersion}/${globals.user.project.id}/os-availability-zone`;
const result = await request.get(url);
const result = await client.cinder.azones.list();
this.availabilityZones = result.availabilityZoneInfo;
}
@action
async operation(id, data, key) {
const body = { [key]: data };
return this.submitting(
request.post(`${this.getDetailUrl({ id })}/action`, body)
);
return this.submitting(this.client.action(id, body));
}
@action
@ -150,7 +154,7 @@ export class VolumeStore extends Base {
@action
revert(id, data) {
return this.operation(id, data, 'revert');
return this.operation(id, data, 'revert_any');
}
@action
@ -171,45 +175,36 @@ export class VolumeStore extends Base {
@action
update(id, data) {
const body = { [this.responseKey]: data };
return this.submitting(request.put(this.getDetailUrl({ id }), body));
return this.submitting(this.client.update(id, body));
}
@action
softDelete(id, data) {
return this.operation(id, data, 'os-recycle');
}
restore(id) {
return this.operation(id, {}, 'os-restore-recycle');
}
@action
createTransfer(data) {
const body = { transfer: data };
return this.submitting(
request.post(
`${this.apiVersion}/${globals.user.project.id}/volume-transfers`,
body
)
);
return this.submitting(this.transferClient.create(body));
}
@action
cancelTransfer({ id }) {
return this.submitting(
request.get(
`${this.apiVersion}/${globals.user.project.id}/volume-transfers`
)
).then((resData) => {
return this.submitting(this.transferClient.list()).then((resData) => {
const findObj = (resData.transfers || []).find((s) => s.volume_id === id);
return this.submitting(
request.delete(
`${this.apiVersion}/${globals.user.project.id}/volume-transfers/${findObj.id}`
)
);
return this.submitting(this.transferClient.delete(findObj.id));
});
}
@action
acceptVolumeTransfer(transfer_id, data) {
const body = { accept: data };
return this.submitting(
request.post(
`${this.apiVersion}/${globals.user.project.id}/volume-transfers/${transfer_id}/accept`,
body
)
);
return this.submitting(this.transferClient.accept(transfer_id, body));
}
@action
@ -225,3 +220,5 @@ export class VolumeStore extends Base {
const globalVolumeStore = new VolumeStore();
export default globalVolumeStore;
export const globalRecycleVolumeStore = new VolumeStore();

View File

@ -12,32 +12,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { glanceBase } from 'utils/constants';
import { action, observable } from 'mobx';
import client from 'client';
import Base from '../base';
// import { getArrayBuffer } from 'utils/file';
export class ImageStore extends Base {
@observable
members = [];
get module() {
return 'images';
get client() {
return client.glance.images;
}
get apiVersion() {
return glanceBase();
}
get responseKey() {
return 'image';
}
// get listFilterByProject() {
// // use it for nuetron apois
// return true;
// }
get fetchListByLimit() {
return true;
}
@ -46,9 +32,16 @@ export class ImageStore extends Base {
return this.paramsFuncPage;
}
updateParamsSortPage = (params, sortKey, sortOrder) => {
if (sortKey && sortOrder) {
params.sort_key = sortKey;
params.sort_dir = sortOrder === 'descend' ? 'desc' : 'asc';
}
};
get paramsFuncPage() {
return (params) => {
const { current, all_projects, ...rest } = params;
const { current, all_projects, withPrice, ...rest } = params;
return {
...rest,
// image_type: 'image',
@ -73,50 +66,32 @@ export class ImageStore extends Base {
}
@action
async uploadImage(imageId, file) {
const url = `${this.getListUrl()}/${imageId}/file`;
// const body = await getArrayBuffer(file);
const body = file;
const headers = {
'content-type': 'application/octet-stream',
};
const options = {
headers,
};
return request.put(url, body, options);
async uploadImage(imageId, file, conf) {
return this.client.uploadFile(imageId, file, conf);
}
@action
async create(data, file, members) {
async create(data, file, members, conf) {
this.isSubmitting = true;
const image = await request.post(this.getListUrl(), data);
const image = await this.client.create(data);
const { id } = image;
// return this.submitting(this.uploadImage(id, file));
if (members.length > 0) {
await Promise.all(members.map((it) => this.createMember(id, it)));
}
await this.uploadImage(id, file);
await this.uploadImage(id, file, conf);
this.isSubmitting = false;
return Promise.resolve();
}
@action
async update({ id }, newbody) {
const url = this.getDetailUrl({ id });
const headers = {
'content-type': 'application/openstack-images-v2.1-json-patch',
};
const options = {
headers,
};
return request.patch(url, newbody, options);
return this.client.patch(id, newbody);
}
@action
async getMembers(id) {
const url = `${this.getDetailUrl({ id })}/members`;
const result = await request.get(url);
const result = await this.client.members.list(id);
const { members = [] } = result || {};
this.members = members;
return members;
@ -124,27 +99,24 @@ export class ImageStore extends Base {
@action
async createMember(id, member) {
const url = `${this.getDetailUrl({ id })}/members`;
const body = {
member,
};
await request.post(url, body);
await this.client.members.create(id, body);
return this.updateMemberStatus(id, member, 'accepted');
}
@action
async updateMemberStatus(id, member, status) {
const url = `${this.getDetailUrl({ id })}/members/${member}`;
const body = {
status,
};
return request.put(url, body);
return this.client.members.update(id, member, body);
}
@action
async deleteMember(id, member) {
const url = `${this.getDetailUrl({ id })}/members/${member}`;
return request.delete(url);
return this.client.members.delete(id, member);
}
@action

View File

@ -12,20 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { glanceBase, cinderBase, novaBase } from 'utils/constants';
import client from 'client';
import Base from '../base';
export class InstanceSnapshotStore extends Base {
get module() {
return 'images';
}
get apiVersion() {
return glanceBase();
}
get responseKey() {
return 'image';
get client() {
return client.glance.images;
}
get listFilterByProject() {
@ -49,18 +41,26 @@ export class InstanceSnapshotStore extends Base {
get paramsFuncPage() {
return (params, all_projects) => {
const { id, current, ...rest } = params;
const { id, current, owner, ...rest } = params;
const newParams = {
...rest,
// image_type: 'snapshot',
image_type: 'snapshot',
};
if (!all_projects) {
newParams.owner = this.currentProject;
if (owner) {
newParams.owner = owner;
} else if (!all_projects) {
newParams.owner = this.currentProjectId;
}
return newParams;
};
}
async getCountForPage(params) {
const { limit, marker, ...rest } = params;
const result = await this.client.count(rest);
return result;
}
get mapperBeforeFetchProject() {
return (data) => ({
...data,
@ -76,13 +76,11 @@ export class InstanceSnapshotStore extends Base {
if (!id) {
return items;
}
const snapshotsUrl = `${cinderBase()}/${globals.user.project.id}/snapshots`;
const volumesUrl = `${novaBase()}/servers/${id}/os-volume_attachments`;
const volumeParams = {};
const snapshotParams = { all_tenants: allProjects };
const results = await Promise.all([
request.get(snapshotsUrl, snapshotParams),
request.get(volumesUrl, volumeParams),
client.cinder.snapshots.list(snapshotParams),
client.nova.servers.volumeAttachments.list(id, volumeParams),
]);
const snapshotsAll = results[0].snapshots;
const volumesAll = results[1].volumeAttachments;
@ -121,16 +119,11 @@ export class InstanceSnapshotStore extends Base {
if (snapshot) {
const { snapshot_id: snapshotId } = snapshot;
item.snapshotId = snapshotId;
const currentProject = globals.user.project.id;
const snapshotsUrl = `${cinderBase()}/${currentProject}/snapshots/${snapshotId}`;
const snapshotResult = await request.get(snapshotsUrl);
const snapshotResult = await client.cinder.snapshots.show(snapshotId);
const snapshotDetail = snapshotResult.snapshot;
item.snapshotDetail = snapshotDetail;
const { volume_id: volumeId } = snapshotDetail;
const volumeUrl = `${cinderBase()}/${
globals.user.project.id
}/volumes/${volumeId}`;
const volumeResult = await await request.get(volumeUrl);
const volumeResult = await client.cinder.volumes.show(volumeId);
const volumeDetail = volumeResult.volume;
item.volumeDetail = volumeDetail;
instanceId =
@ -142,10 +135,10 @@ export class InstanceSnapshotStore extends Base {
const { instance_uuid } = item;
instanceId = instance_uuid;
}
let instanceResult = {};
try {
if (instanceId) {
const instanceUrl = `${novaBase()}/servers/${instanceId}`;
const instanceResult = await request.get(instanceUrl);
instanceResult = await client.nova.servers.show(instanceId);
const { server: { name } = {} } = instanceResult;
instanceName = name;
}
@ -154,6 +147,7 @@ export class InstanceSnapshotStore extends Base {
server_id: instanceId,
server_name: instanceName,
};
item.instanceDetail = instanceResult.server || {};
return item;
}
}

View File

@ -12,24 +12,23 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { glanceBase } from 'utils/constants';
import { action, observable } from 'mobx';
import client from 'client';
import Base from '../base';
export class MetadataStore extends Base {
@observable
resourceTypes = [];
get module() {
return 'metadefs/namespaces';
@observable
resourceTypeLoading = false;
get client() {
return client.glance.namespaces;
}
get apiVersion() {
return glanceBase();
}
get responseKey() {
return 'namespace';
get resourceTypeClient() {
return client.glance.resourceTypes;
}
get needGetProject() {
@ -44,9 +43,7 @@ export class MetadataStore extends Base {
const results = await Promise.all(
items.map((it) => {
const { namespace } = it;
return request.get(this.getDetailUrl({ id: namespace }), {
resource_type: resource_types,
});
return this.client.show(namespace, { resource_type: resource_types });
})
);
items.forEach((it, index) => {
@ -95,7 +92,7 @@ export class MetadataStore extends Base {
@action
async fetchDetail({ id }) {
this.isLoading = true;
const result = await request.get(this.getDetailUrl({ id }));
const result = await this.client.show(id);
this.detail = result;
this.isLoading = false;
return result;
@ -103,20 +100,18 @@ export class MetadataStore extends Base {
@action
edit({ id }, newObject) {
return this.submitting(
request.put(`${this.getDetailUrl({ id })}`, newObject)
);
return this.submitting(this.client.update(id, newObject));
}
@action
create(newObject) {
return this.submitting(request.post(`${this.getListUrl()}`, newObject));
return this.submitting(this.client.create(newObject));
}
@action
async fetchResourceTypes(item) {
const url = `${this.apiVersion}/metadefs/resource_types`;
const result = await request.get(url);
this.resourceTypeLoading = true;
const result = await this.resourceTypeClient.list();
const { resource_type_associations: associations = [] } = item || {};
const { resource_types: resourceTypes = [] } = result;
const mapper = {};
@ -130,6 +125,7 @@ export class MetadataStore extends Base {
}
});
this.resourceTypes = resourceTypes;
this.resourceTypeLoading = false;
}
@action
@ -137,11 +133,9 @@ export class MetadataStore extends Base {
this.isSubmitting = true;
await Promise.all(
dels.map((it) => {
const delUrl = `${this.apiVersion}/${this.module}/${namespace}/resource_types/${it.name}`;
return request.delete(delUrl);
return this.client.resourceTypes.delete(namespace, it.name);
})
);
const addUrl = `${this.apiVersion}/${this.module}/${namespace}/resource_types`;
return this.submitting(
Promise.all(
adds.map((it) => {
@ -149,7 +143,7 @@ export class MetadataStore extends Base {
name: it.name,
prefix: it.prefix,
};
return request.post(addUrl, body);
return this.client.resourceTypes.create(namespace, body);
})
)
);

View File

@ -12,27 +12,22 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { heatBase } from 'utils/constants';
import client from 'client';
import Base from '../base';
export class StackEventStore extends Base {
get module() {
if (!globals.user) {
return null;
}
return `${globals.user.project.id}/stacks`;
}
get apiVersion() {
return heatBase();
get client() {
return client.heat.stacks;
}
get responseKey() {
return 'event';
}
getListUrl = ({ id, name }) =>
`${this.apiVersion}/${this.module}/${name}/${id}/events`;
listFetchByClient(params, originParams) {
const { id, name } = originParams;
return this.client.events({ id, name }, params);
}
get paramsFunc() {
return () => {};

View File

@ -12,27 +12,22 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { heatBase } from 'utils/constants';
import client from 'client';
import Base from '../base';
export class StackResourceStore extends Base {
get module() {
if (!globals.user) {
return null;
}
return `${globals.user.project.id}/stacks`;
}
get apiVersion() {
return heatBase();
get client() {
return client.heat.stacks;
}
get responseKey() {
return 'resource';
}
getListUrl = ({ id, name }) =>
`${this.apiVersion}/${this.module}/${name}/${id}/resources`;
listFetchByClient(params, originParams) {
const { id, name } = originParams;
return this.client.resources({ id, name }, params);
}
get paramsFunc() {
return () => {};

View File

@ -12,24 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { heatBase } from 'utils/constants';
import client from 'client';
import Base from '../base';
export class HeatServiceStore extends Base {
get module() {
return 'services';
get client() {
return client.heat.services;
}
get apiVersion() {
return heatBase();
}
get responseKey() {
return 'service';
}
getListUrl = () =>
`${this.apiVersion}/${globals.user.project.id}/${this.module}`;
}
const globalHeatServiceStore = new HeatServiceStore();

View File

@ -13,26 +13,20 @@
// limitations under the License.
import { action, observable } from 'mobx';
import { heatBase } from 'utils/constants';
import client from 'client';
import Base from '../base';
export class StackStore extends Base {
@observable
template = {};
template = null;
get module() {
if (!globals.user) {
return null;
}
return `${globals.user.project.id}/stacks`;
get client() {
return client.heat.stacks;
}
get apiVersion() {
return heatBase();
}
get responseKey() {
return 'stack';
detailFetchByClient(resourceParams) {
const { id, name } = resourceParams;
return this.client.show({ id, name });
}
updateParamsSortPage = (params, sortKey, sortOrder) => {
@ -42,8 +36,6 @@ export class StackStore extends Base {
}
};
getDetailUrl = ({ id, name }) => `${this.getListUrl()}/${name}/${id}`;
get paramsFuncPage() {
return (params) => {
const { current, all_projects, ...rest } = params;
@ -54,7 +46,7 @@ export class StackStore extends Base {
if (all_projects) {
newParams.global_tenant = true;
} else {
newParams.tenant = globals.user.project.id;
newParams.tenant = this.currentProjectId;
}
return newParams;
};
@ -76,28 +68,25 @@ export class StackStore extends Base {
@action
create(body) {
return this.submitting(request.post(this.getListUrl(), body));
return this.submitting(this.client.create(body));
}
@action
edit({ id, name }, body) {
return this.submitting(request.put(this.getDetailUrl({ id, name }), body));
return this.submitting(this.client.update({ id, name }, body));
}
@action
delete = ({ id, name }) =>
this.submitting(request.delete(this.getDetailUrl({ id, name })));
delete = ({ id, name }) => this.submitting(this.client.delete({ id, name }));
@action
abandon = ({ id, name }) => {
const url = `${this.getDetailUrl({ id, name })}/abandon`;
return this.submitting(request.delete(url));
return this.submitting(this.client.abandon({ id, name }));
};
@action
getTemplate = async ({ id, name }) => {
const url = `${this.getDetailUrl({ id, name })}/template`;
const result = await request.get(url);
const result = await this.client.template({ id, name });
this.template = result;
};
}

43
src/stores/index.jsx Normal file
View File

@ -0,0 +1,43 @@
import globalFloatingIpsStore from './neutron/floatingIp';
import globalImageStore from './glance/image';
import globalServerStore from './nova/instance';
import globalInstanceSnapshotStore from './glance/instance-snapshot';
import globalKeypairStore from './nova/keypair';
import globalNetworkStore from './neutron/network';
import globalPortForwardingStore from './neutron/port-forwarding';
import globalQoSPolicyStore from './neutron/qos-policy';
import globalRecycleBinStore from './skyline/recycle-server';
import globalSecurityGroupStore from './neutron/security-group';
import globalSecurityGroupRuleStore from './neutron/security-rule';
import globalServerGroupStore from './nova/server-group';
import globalSnapshotStore from './cinder/snapshot';
import globalStaticRouteStore from './neutron/static-route';
import globalSubnetStore from './neutron/subnet';
import globalVirtualAdapterStore from './neutron/virtual-adapter';
import globalVolumeStore from './cinder/volume';
import globalComputeHostStore from './nova/compute-host';
import globalHypervisorStore from './nova/hypervisor';
import globalStackStore from './heat/stack';
export default {
globalFloatingIpsStore,
globalImageStore,
globalServerStore,
globalInstanceSnapshotStore,
globalKeypairStore,
globalNetworkStore,
globalPortForwardingStore,
globalQoSPolicyStore,
globalRecycleBinStore,
globalSecurityGroupStore,
globalSecurityGroupRuleStore,
globalServerGroupStore,
globalSnapshotStore,
globalStaticRouteStore,
globalSubnetStore,
globalVirtualAdapterStore,
globalVolumeStore,
globalComputeHostStore,
globalHypervisorStore,
globalStackStore,
};

View File

@ -13,7 +13,7 @@
// limitations under the License.
import { action, observable } from 'mobx';
import { ironicBase, placementBase } from 'utils/constants';
import client from 'client';
import Base from '../base';
export class IronicStore extends Base {
@ -26,20 +26,18 @@ export class IronicStore extends Base {
@observable
traits = [];
get module() {
return 'nodes';
get client() {
return client.ironic.nodes;
}
get apiVersion() {
return ironicBase();
get portClient() {
return client.ironic.ports;
}
get responseKey() {
return 'node';
get listWithDetail() {
return true;
}
getListDetailUrl = () => `${this.getListUrl()}/detail`;
async detailDidFetch(item, all_projects, params) {
if (params.onlyDetail) {
return item;
@ -48,9 +46,9 @@ export class IronicStore extends Base {
const newItem = { ...item };
const [bootDevice, states, validate, ports] = await Promise.all([
this.getBootDevice(id),
request.get(`${this.getDetailUrl({ id })}/states`),
request.get(`${this.getDetailUrl({ id })}/validate`),
request.get(`${this.getDetailUrl({ id })}/ports`),
this.client.states.list(id),
this.client.validate.list(id),
this.client.ports.list(id),
]);
newItem.bootDevice = bootDevice;
newItem.states = states;
@ -63,8 +61,7 @@ export class IronicStore extends Base {
if (items.length === 0) {
return items;
}
const url = `${this.apiVersion}/ports/detail`;
const result = await request.get(url);
const result = await this.portClient.listDetail();
const { ports } = result;
items.forEach((it) => {
const nodePorts = ports.filter((port) => port.node_uuid === it.uuid);
@ -75,33 +72,30 @@ export class IronicStore extends Base {
@action
changeProvision(id, body) {
const url = `${this.getDetailUrl({ id })}/states/provision`;
return this.submitting(request.put(url, body));
return this.submitting(this.client.updateStatesProvision(id, body));
}
@action
changePower(id, body) {
const url = `${this.getDetailUrl({ id })}/states/power`;
return this.submitting(request.put(url, body));
return this.submitting(this.client.UpdateStatesPower(id, body));
}
@action
setMaintenance(id, body) {
const url = `${this.getDetailUrl({ id })}/maintenance`;
return this.submitting(request.put(url, body));
return this.submitting(this.client.updateMaintenance(id, body));
}
@action
clearMaintenance(id) {
const url = `${this.getDetailUrl({ id })}/maintenance`;
return this.submitting(request.delete(url));
return this.submitting(this.client.deleteMaintenance(id));
}
@action
async getBootDevice(id) {
const url = `${this.getDetailUrl({ id })}/management/boot_device`;
try {
const result = await this.submitting(request.get(url));
const result = await this.submitting(
this.client.getManagementBootDevice(id)
);
this.bootDevice = result;
return result;
} catch (e) {
@ -113,39 +107,38 @@ export class IronicStore extends Base {
@action
async getSupportedBootDevice(id) {
const url = `${this.getDetailUrl({ id })}/management/boot_device/supported`;
const result = await this.submitting(request.get(url));
const result = await this.submitting(
this.client.getManagementBootDeviceSupported(id)
);
this.supportedBootDevices = result.supported_boot_devices || [];
return this.supportedBootDevices;
}
@action
setBootDevice(id, body) {
const url = `${this.getDetailUrl({ id })}/management/boot_device`;
return this.submitting(request.put(url, body));
return this.submitting(this.client.upateManagementBootDevice(id, body));
}
@action
async create(body) {
const { traits = [], ...rest } = body;
if (traits.length === 0) {
return this.submitting(request.post(this.getListUrl(), rest));
return this.submitting(this.client.create(rest));
}
this.isLoading = true;
const result = await request.post(this.getListUrl(), rest);
const result = await this.client.create(rest);
const { uuid } = result;
return this.updateTraits(uuid, traits);
}
@action
edit({ id }, body) {
return this.submitting(request.patch(`${this.getDetailUrl({ id })}`, body));
return this.submitting(this.client.patch(id, body));
}
@action
async getTraits() {
const url = `${placementBase()}/traits`;
const result = await request.get(url);
const result = await client.placement.traits.list();
const { traits = [] } = result;
traits.sort();
this.traits = traits;
@ -153,11 +146,10 @@ export class IronicStore extends Base {
@action
updateTraits(id, traits) {
const url = `${this.getDetailUrl({ id })}/traits`;
const body = {
traits,
};
return this.submitting(request.put(url, body));
return this.submitting(this.client.updateTraits(id, body));
}
}

View File

@ -12,38 +12,32 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { ironicBase } from 'utils/constants';
import { action } from 'mobx';
import client from 'client';
import Base from '../base';
export class IronicPortGroupStore extends Base {
get module() {
return 'portgroups';
get client() {
return client.ironic.nodes.portgroups;
}
get apiVersion() {
return ironicBase();
listFetchByClient(params, originParams) {
const { id } = originParams;
return this.client.listDetail(id, params);
}
get responseKey() {
return 'portgroup';
}
getListDetailUrl = ({ id }) =>
`${this.apiVersion}/nodes/${id}/${this.module}/detail`;
get paramsFunc() {
return () => {};
}
@action
create(data) {
return this.submitting(request.post(this.getListUrl(), data));
return this.submitting(client.ironic.portgroups.create(data));
}
@action
edit({ id }, body) {
return this.submitting(request.patch(`${this.getDetailUrl({ id })}`, body));
return this.submitting(client.ironic.portgroups.patch(id, body));
}
}

View File

@ -12,38 +12,32 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { ironicBase } from 'utils/constants';
import { action } from 'mobx';
import client from 'client';
import Base from '../base';
export class IronicPortStore extends Base {
get module() {
return 'ports';
get client() {
return client.ironic.ports;
}
get apiVersion() {
return ironicBase();
listFetchByClient(params, originParams) {
const { id } = originParams;
return client.ironic.nodes.ports.listDetail(id, params);
}
get responseKey() {
return 'port';
}
getListDetailUrl = ({ id }) =>
`${this.apiVersion}/nodes/${id}/${this.module}/detail`;
get paramsFunc() {
return () => {};
}
@action
create(data) {
return this.submitting(request.post(this.getListUrl(), data));
return this.submitting(this.client.create(data));
}
@action
edit({ id }, body) {
return this.submitting(request.patch(`${this.getDetailUrl({ id })}`, body));
return this.submitting(this.client.patch(id, body));
}
}

View File

@ -12,20 +12,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { keystoneBase } from 'utils/constants';
import client from 'client';
import Base from '../base';
export class AuthCatalogStore extends Base {
get module() {
return 'auth/catalog';
}
get apiVersion() {
return keystoneBase();
get client() {
return client.keystone.catalog;
}
get listResponseKey() {
return 'catalog';
return this.responseKey;
}
get mapper() {

View File

@ -13,9 +13,8 @@
// limitations under the License.
import { action, observable } from 'mobx';
import request from 'utils/request';
import { keystoneBase } from 'utils/constants';
import { get } from 'lodash';
import client from 'client';
import Base from '../base';
export class DomainStore extends Base {
@ -28,20 +27,14 @@ export class DomainStore extends Base {
@observable
adminRoleId = '';
get module() {
return 'domains';
get client() {
return client.keystone.domains;
}
get apiVersion() {
return keystoneBase();
get userClient() {
return client.keystone.users;
}
get responseKey() {
return 'domain';
}
getResourceUrl = () => keystoneBase();
@action
async fetchList({
limit,
@ -55,33 +48,32 @@ export class DomainStore extends Base {
// todo: no page, no limit, fetch all
// const params = { ...filters };
await Promise.all([
request.get(`${this.apiVersion}/domains`),
request.get(`${this.apiVersion}/users`),
]).then(([domainsResult, usersResult]) => {
const { domains } = domainsResult;
// eslint-disable-next-line array-callback-return
domains.map((domain) => {
const domainUsers = usersResult.users.filter(
(it) => it.domain_id === domain.id
);
domain.user_num = domainUsers.length;
});
await Promise.all([this.client.list(), this.userClient.list()]).then(
([domainsResult, usersResult]) => {
const { domains } = domainsResult;
// eslint-disable-next-line array-callback-return
domains.map((domain) => {
const domainUsers = usersResult.users.filter(
(it) => it.domain_id === domain.id
);
domain.user_num = domainUsers.length;
});
// const { domains: items } = domainsResult;
this.list.update({
data: domains,
total: domains.length || 0,
limit: Number(limit) || 10,
page: Number(page) || 1,
sortKey,
sortOrder,
filters,
isLoading: false,
...(this.list.silent ? {} : { selectedRowKeys: [] }),
});
return domains;
});
// const { domains: items } = domainsResult;
this.list.update({
data: domains,
total: domains.length || 0,
limit: Number(limit) || 10,
page: Number(page) || 1,
sortKey,
sortOrder,
filters,
isLoading: false,
...(this.list.silent ? {} : { selectedRowKeys: [] }),
});
return domains;
}
);
}
@action
@ -89,74 +81,67 @@ export class DomainStore extends Base {
if (!silent) {
this.isLoading = true;
}
await Promise.all([
request.get(this.getDetailUrl({ id })),
request.get(`${this.apiVersion}/users`),
]).then(([result, usersResult]) => {
const domain = this.mapper(get(result, this.responseKey) || result);
domain.domain_administrator = [];
const domainUsers = usersResult.users.filter(
(it) => it.domain_id === domain.id
);
domain.user_num = domainUsers.length;
this.domainUsers = domainUsers;
this.detail = domain;
this.isLoading = false;
return domain;
});
await Promise.all([this.client.show(id), this.userClient.list()]).then(
([result, usersResult]) => {
const domain = this.mapper(get(result, this.responseKey) || result);
domain.domain_administrator = [];
const domainUsers = usersResult.users.filter(
(it) => it.domain_id === domain.id
);
domain.user_num = domainUsers.length;
this.domainUsers = domainUsers;
this.detail = domain;
this.isLoading = false;
return domain;
}
);
}
@action
async fetchDomain() {
const doaminsResult = await request.get(`${this.getResourceUrl()}/domains`);
const doaminsResult = await this.client.list();
this.domains = doaminsResult.domains;
}
@action
async update({ id, body }) {
const url = `${this.apiVersion}/${id}`;
this.isSubmitting = true;
const resData = await request.put(url, body, null, (res) => res.data);
const resData = await this.client.update(id, body);
this.isSubmitting = false;
return resData;
}
@action
async edit({ id, description }) {
const url = `${this.apiVersion}/domains/${id}`;
const reqBody = {
domain: { description },
};
return this.submitting(request.patch(url, reqBody));
return this.submitting(this.client.patch(id, reqBody));
}
async setDomainAdmin({ id, user_id, role_id }) {
const url = `${this.apiVersion}/domains/${id}/users/${user_id}/roles/${role_id}`;
return this.submitting(request.put(url));
return this.submitting(this.client.users.roles.put(id, user_id, role_id));
}
async deleteDomainAdmin({ id, user_id, role_id }) {
const url = `${this.apiVersion}/domains/${id}/users/${user_id}/roles/${role_id}`;
const result = await request.delete(url);
const result = await this.client.users.roles.delete(id, user_id, role_id);
return result;
}
@action
async forbidden({ id }) {
const url = `${this.apiVersion}/domains/${id}`;
const reqBody = {
domain: { enabled: false },
};
return this.submitting(request.patch(url, reqBody));
return this.submitting(this.client.patch(id, reqBody));
}
@action
async enable({ id }) {
const url = `${this.apiVersion}/domains/${id}`;
const reqBody = {
domain: { enabled: true },
};
return this.submitting(request.patch(url, reqBody));
return this.submitting(this.client.patch(id, reqBody));
}
}

View File

@ -14,14 +14,8 @@
import { action, observable } from 'mobx';
import { getGBValue } from 'utils/index';
import request from 'utils/request';
import {
keystoneBase,
novaBase,
cinderBase,
neutronBase,
} from 'utils/constants';
import { get } from 'lodash';
import { get, isNil, isEmpty } from 'lodash';
import client from 'client';
import Base from '../base';
export class ProjectStore extends Base {
@ -40,18 +34,20 @@ export class ProjectStore extends Base {
@observable
projectsOnly = [];
getResourceUrl = () => keystoneBase();
get module() {
return 'projects';
get client() {
return client.keystone.projects;
}
get apiVersion() {
return keystoneBase();
get roleAssignmentClient() {
return client.keystone.roleAssignments;
}
get responseKey() {
return 'project';
get roleClient() {
return client.keystone.roles;
}
get userClient() {
return client.keystone.users;
}
@action
@ -66,16 +62,23 @@ export class ProjectStore extends Base {
this.list.isLoading = true;
// todo: no page, no limit, fetch all
// const params = { ...filters };
const { tags } = filters;
const [roleAssignmentsReault, projectsResult, roleResult] =
await Promise.all([
request.get(`${this.apiVersion}/role_assignments`),
request.get(`${this.apiVersion}/projects`),
request.get(`${this.apiVersion}/roles`),
this.roleAssignmentClient.list(),
this.client.list(tags ? { tags } : {}),
this.roleClient.list(),
]);
const { projects } = projectsResult;
const { roles } = roleResult;
const projectRoleId = roles.map((it) => it.id);
const projectRoles = roles.filter(
(it) =>
(it.name.indexOf('project_') !== -1 &&
it.name.indexOf('_project_') === -1) ||
it.name === 'admin'
);
const projectRoleId = projectRoles.map((it) => it.id);
projects.map((project) => {
const userMapRole = {}; // all user include system role and project role: { user_id: [roles_id] }
const projectGroups = {};
@ -169,25 +172,23 @@ export class ProjectStore extends Base {
@action
async enable({ id }) {
const url = `${this.apiVersion}/projects/${id}`;
const reqBody = {
project: { enabled: true },
};
return this.submitting(request.patch(url, reqBody));
return this.submitting(this.client.patch(id, reqBody));
}
@action
async forbidden({ id }) {
const url = `${this.apiVersion}/projects/${id}`;
const reqBody = {
project: { enabled: false },
};
return this.submitting(request.patch(url, reqBody));
return this.submitting(this.client.patch(id, reqBody));
}
@action
async fetchDomain() {
const doaminsResult = await request.get(`${this.getResourceUrl()}/domains`);
const doaminsResult = await this.skylineClient.domains();
this.domains = doaminsResult.domains;
}
@ -196,9 +197,7 @@ export class ProjectStore extends Base {
const reqBody = {
project: data,
};
return this.submitting(
request.post(`${this.getResourceUrl()}/projects`, reqBody)
);
return this.submitting(this.client.create(reqBody));
}
@action
@ -208,12 +207,18 @@ export class ProjectStore extends Base {
}
const [roleAssignmentsReault, projectResult, roleResult] =
await Promise.all([
request.get(`${this.apiVersion}/role_assignments`),
request.get(`${this.apiVersion}/projects/${id}`),
request.get(`${this.apiVersion}/roles`),
this.roleAssignmentClient.list(),
this.client.show(id),
this.roleClient.list(),
]);
const { roles } = roleResult;
const projectRoleId = roles.map((it) => it.id);
const projectRoles = roles.filter(
(it) =>
(it.name.indexOf('project_') !== -1 &&
it.name.indexOf('_project_') === -1) ||
it.name === 'admin'
);
const projectRoleId = projectRoles.map((it) => it.id);
const { project } = projectResult;
const userMapRole = {};
const projectGroups = {};
@ -232,30 +237,26 @@ export class ProjectStore extends Base {
project.groups = projectGroups;
project.user_num = Object.keys(userMapRole).length;
project.group_num = Object.keys(projectGroups).length;
this.detail = project;
const newItem = await this.detailDidFetch(project);
this.detail = newItem;
this.isLoading = false;
return project;
return newItem;
}
@action
async edit({ id, description, name }) {
const url = `${this.apiVersion}/projects/${id}`;
const reqBody = {
project: { description, name },
};
return this.submitting(request.patch(url, reqBody));
return this.submitting(this.client.patch(id, reqBody));
}
@action
async fetchProjectQuota({ project_id }) {
const [novaResult, cinderResult, neutronResult] = await Promise.all([
request.get(`${novaBase()}/os-quota-sets/${project_id}/detail`),
request.get(
`${cinderBase()}/${
globals.user.project.id
}/os-quota-sets/${project_id}?usage=True`
),
request.get(`${neutronBase()}/quotas/${project_id}/details`),
client.nova.quotaSets.detail(project_id),
client.cinder.quotaSets.show(project_id, { usage: 'True' }),
client.neutron.quotas.details(project_id),
]);
this.isSubmitting = false;
const { quota_set: novaQuota } = novaResult;
@ -276,6 +277,15 @@ export class ProjectStore extends Base {
this.quota = quota;
}
omitNil = (obj) => {
return Object.keys(obj).reduce((acc, v) => {
if (!isNil(obj[v])) {
acc[v] = obj[v];
}
return acc;
}, {});
};
@action
async updateProjectQuota({ project_id, data }) {
this.isSubmitting = true;
@ -285,6 +295,7 @@ export class ProjectStore extends Base {
ram,
volumes,
gigabytes,
firewall_group,
security_group_rule,
server_groups,
snapshots,
@ -301,59 +312,61 @@ export class ProjectStore extends Base {
...others
} = data;
let ramGb = ram;
if (ram !== -1) {
if (ram && ram !== -1) {
ramGb = ram * 1024;
}
const novaReqBody = {
quota_set: {
quota_set: this.omitNil({
instances,
cores,
ram: ramGb,
server_groups,
server_group_members,
key_pairs,
},
}),
};
const cinderReqBody = {
quota_set: {
quota_set: this.omitNil({
volumes,
gigabytes,
backup_gigabytes,
snapshots,
backups,
...others,
},
}),
};
const firewallValue = firewall_group ? { firewall_group } : {};
const neutronReqBody = {
quota: {
quota: this.omitNil({
network,
router,
subnet,
floatingip,
security_group,
security_group_rule,
...firewallValue,
port,
},
}),
};
const result = await Promise.all([
request.put(`${novaBase()}/os-quota-sets/${project_id}`, novaReqBody),
request.put(
`${cinderBase()}/${
globals.user.project.id
}/os-quota-sets/${project_id}`,
cinderReqBody
),
request.put(`${neutronBase()}/quotas/${project_id}`, neutronReqBody),
]);
const reqs = [];
if (!isEmpty(novaReqBody.quota_set)) {
reqs.push(client.nova.quotaSets.update(project_id, novaReqBody));
}
if (!isEmpty(cinderReqBody.quota_set)) {
reqs.push(client.cinder.quotaSets.update(project_id, cinderReqBody));
}
if (!isEmpty(neutronReqBody.quota)) {
reqs.push(client.neutron.quotas.update(project_id, neutronReqBody));
}
const result = await Promise.all(reqs);
this.isSubmitting = false;
return result;
}
@action
async getUserRoleList({ id, user_id }) {
const url = `${this.apiVersion}/projects/${id}/users/${user_id}/roles/`;
this.isSubmitting = true;
const result = await request.get(url);
const result = await this.client.users.roles.list(id, user_id);
this.userRoleList = result.roles;
}
@ -362,43 +375,37 @@ export class ProjectStore extends Base {
const body = {};
body[this.responseKey] = data;
this.isSubmitting = true;
const result = await request.post(this.getListUrl(), body);
const result = await this.client.create(body);
this.isSubmitting = false;
return result;
}
@action
async assignUserRole({ id, user_id, role_id }) {
const url = `${this.apiVersion}/projects/${id}/users/${user_id}/roles/${role_id}`;
const result = request.put(url);
const result = await this.client.users.roles.update(id, user_id, role_id);
return result;
}
@action
async removeUserRole({ id, user_id, role_id }) {
const url = `${this.apiVersion}/projects/${id}/users/${user_id}/roles/${role_id}`;
const result = request.delete(url);
const result = await this.client.users.roles.delete(id, user_id, role_id);
return result;
}
@action
async getGroupRoleList({ id, group_id }) {
const url = `${this.apiVersion}/projects/${id}/groups/${group_id}/roles/`;
this.isSubmitting = true;
const result = await request.get(url);
const result = await this.client.groups.roles.list(id, group_id);
this.groupRoleList = result.roles;
}
@action
async assignGroupRole({ id, group_id, role_id }) {
const url = `${this.apiVersion}/projects/${id}/groups/${group_id}/roles/${role_id}`;
const result = request.put(url);
const result = await this.client.groups.roles.update(id, group_id, role_id);
return result;
}
async removeGroupRole({ id, group_id, role_id }) {
const url = `${this.apiVersion}/projects/${id}/groups/${group_id}/roles/${role_id}`;
const result = request.delete(url);
const result = await this.client.groups.roles.delete(id, group_id, role_id);
return result;
}
@ -415,10 +422,10 @@ export class ProjectStore extends Base {
const { userId } = filters;
const [roleAssignmentsReault, projectsResult, roleResult, groupResult] =
await Promise.all([
request.get(`${this.apiVersion}/role_assignments`),
request.get(`${this.apiVersion}/users/${userId}/projects`),
request.get(`${this.apiVersion}/roles`),
request.get(`${this.apiVersion}/users/${userId}/groups`),
this.roleAssignmentClient.list(),
this.userClient.projects.list(userId),
this.roleClient.list(),
this.userClient.groups.list(userId),
]);
const projects = get(projectsResult, this.listResponseKey, []);
projects.map((project) => {
@ -485,9 +492,9 @@ export class ProjectStore extends Base {
const { groupId } = filters;
const [roleAssignmentsReault, projectsResult, roleResult] =
await Promise.all([
request.get(`${this.apiVersion}/role_assignments`),
request.get(`${this.apiVersion}/projects`),
request.get(`${this.apiVersion}/roles`),
this.roleAssignmentClient.list(),
this.client.list(),
this.roleClient.list(),
]);
const projects = get(projectsResult, this.listResponseKey, []);
projects.map((project) => {
@ -534,8 +541,10 @@ export class ProjectStore extends Base {
@action
async fetchProjectListOnly() {
this.list.isLoading = true;
const result = await request.get(`${this.apiVersion}/${this.module}`);
const result = await this.client.list();
this.projectsOnly = get(result, this.listResponseKey, []);
this.list.isLoading = false;
return result;
}
}

View File

@ -12,21 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { keystoneBase } from 'utils/constants';
import { action, observable } from 'mobx';
import client from 'client';
import Base from '../base';
export class RoleStore extends Base {
get module() {
return 'roles';
}
get apiVersion() {
return keystoneBase();
}
get responseKey() {
return 'role';
get client() {
return client.keystone.roles;
}
@observable
@ -34,9 +26,7 @@ export class RoleStore extends Base {
@action
async fetchImpliedRoles({ id }) {
const rolesResult = await request.get(
`${this.getDetailUrl({ id })}/implies/`
);
const rolesResult = await this.client.implies.list(id);
const {
role_inference: { implies },
} = rolesResult;

View File

@ -12,40 +12,28 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { keystoneBase } from 'utils/constants';
import { action } from 'mobx';
import client from 'client';
import Base from '../base';
export class TagStore extends Base {
get module() {
return 'tags';
get client() {
return client.keystone.projects.tags;
}
get apiVersion() {
return keystoneBase();
}
get responseKey() {
return 'tag';
listFetchByClient(params, originParams) {
const { project_id } = originParams;
return this.client.list(project_id, params);
}
get paramsFunc() {
return () => null;
}
getListUrl = ({ project_id }) =>
`${this.apiVersion}/projects/${project_id}/${this.module}`;
@action
update({ project_id }, newObject, sleepTime) {
update({ project_id }, newObject) {
return this.submitting(
request.put(
`${this.getListUrl({ project_id })}`,
newObject,
null,
null,
sleepTime
)
client.keystone.projects.updateTags(project_id, newObject)
);
}
}

View File

@ -13,9 +13,8 @@
// limitations under the License.
import { action, observable } from 'mobx';
import { keystoneBase } from 'utils/constants';
import request from 'utils/request';
import { get } from 'lodash';
import client from 'client';
import Base from '../base';
import globalProjectStore from './project';
@ -32,16 +31,32 @@ export class GroupStore extends Base {
@observable
groupUsers = [];
get module() {
return 'groups';
get client() {
return client.keystone.groups;
}
get apiVersion() {
return keystoneBase();
get domainClient() {
return client.keystone.domains;
}
get responseKey() {
return 'group';
get systemGroupClient() {
return client.keystone.systemGroups;
}
get roleClient() {
return client.keystone.roles;
}
get roleAssignmentClient() {
return client.keystone.roleAssignments;
}
get userClient() {
return client.keystone.users;
}
get projectClient() {
return client.keystone.projects;
}
@action
@ -51,7 +66,7 @@ export class GroupStore extends Base {
body[this.responseKey] = other;
this.isSubmitting = true;
const result = await request.post(this.getListUrl(), body);
const result = await this.client.create(body);
const {
group: { id: group_id },
} = result;
@ -83,7 +98,7 @@ export class GroupStore extends Base {
@action
async fetchDomain() {
const doaminsResult = await request.get(`${this.apiVersion}/domains`);
const doaminsResult = await this.domainClient.list();
this.domains = doaminsResult.domains;
}
@ -99,12 +114,11 @@ export class GroupStore extends Base {
@action
async edit({ id, description, name }) {
const url = `${this.apiVersion}/groups/${id}`;
this.isSubmitting = true;
const reqBody = {
group: { description, name },
};
const result = await request.patch(url, reqBody);
const result = await this.client.patch(id, reqBody);
this.isSubmitting = false;
return result;
}
@ -112,51 +126,38 @@ export class GroupStore extends Base {
@action
async fetchSystemRole({ id }) {
this.systemRoles = [];
const rolesResult = await request.get(
`${this.apiVersion}/system/groups/${id}/roles`
);
const rolesResult = await this.systemGroupClient.roles.list(id);
this.systemRoles = rolesResult.roles;
}
@action
async assignSystemRole({ id, role_id }) {
const result = request.put(
`${this.apiVersion}/system/groups/${id}/roles/${role_id}`
);
return result;
return this.systemGroupClient.roles.update(id, role_id);
}
@action
async deleteSystemRole({ id, role_id }) {
const result = request.delete(
`${this.apiVersion}/system/groups/${id}/roles/${role_id}`
);
return result;
return this.systemGroupClient.roles.delete(id, role_id);
}
@action
async fetchDomainRole({ id, domain_id }) {
this.domainRoles = [];
const rolesResult = await request.get(
`${this.apiVersion}/domains/${domain_id}/groups/${id}/roles`
const rolesResult = await this.domainClient.groups.roles.list(
domain_id,
id
);
this.domainRoles = rolesResult.roles;
}
@action
async assignDomainRole({ id, role_id, domain_id }) {
const result = request.put(
`${this.apiVersion}/domains/${domain_id}/groups/${id}/roles/${role_id}`
);
return result;
return this.domainClient.groups.roles.update(domain_id, id, role_id);
}
@action
async deleteDomainRole({ id, role_id, domain_id }) {
const result = request.delete(
`${this.apiVersion}/domains/${domain_id}/groups/${id}/roles/${role_id}`
);
return result;
return this.domainClient.groups.roles.delete(domain_id, id, role_id);
}
@action
@ -172,8 +173,8 @@ export class GroupStore extends Base {
const { projectId } = filters;
const params = {};
const [roleAssignmentsReault, result] = await Promise.all([
request.get(`${this.apiVersion}/role_assignments`),
request.get(this.getListUrl(), params),
this.roleAssignmentClient.list(),
this.client.list(params),
]);
const projectGroupIds = [];
roleAssignmentsReault.role_assignments.forEach((roleAssignment) => {
@ -191,33 +192,38 @@ export class GroupStore extends Base {
data = data.filter((it) => projectGroupIds.indexOf(it.id) >= 0);
// const items = data.map(this.mapper);
// const newData = await this.listDidFetch(items);
Promise.all(
data.map((it) => request.get(`${this.apiVersion}/groups/${it.id}/users`))
).then((rest) => {
const addUserItem = data.map((it, index) => {
const { users } = rest[index];
const userIds = users.map((user) => user.id);
it.users = userIds;
it.user_num = users.length;
return it;
});
const items = addUserItem.map((item) =>
this.mapperProject(roleAssignmentsReault, item)
);
this.list.update({
data: items,
total: items.length || 0,
limit: Number(limit) || 10,
page: Number(page) || 1,
sortKey,
sortOrder,
filters,
isLoading: false,
...(this.list.silent ? {} : { selectedRowKeys: [] }),
});
Promise.all(data.map((it) => this.client.users.list(it.id))).then(
(rest) => {
const addUserItem = data.map((it, index) => {
const { users } = rest[index];
const userIds = users.map((user) => user.id);
const userInfo = users.map((user) => ({
id: user.id,
name: user.name,
}));
it.users = userIds;
it.user_num = users.length;
it.user_info = userInfo;
return it;
});
const items = addUserItem.map((item) =>
this.mapperProject(roleAssignmentsReault, item)
);
this.list.update({
data: items,
total: items.length || 0,
limit: Number(limit) || 10,
page: Number(page) || 1,
sortKey,
sortOrder,
filters,
isLoading: false,
...(this.list.silent ? {} : { selectedRowKeys: [] }),
});
return items;
});
return items;
}
);
}
@action
@ -233,8 +239,8 @@ export class GroupStore extends Base {
const { userId } = filters;
const params = {};
const [roleAssignmentsReault, result] = await Promise.all([
request.get(`${this.apiVersion}/role_assignments`),
request.get(`${this.apiVersion}/users/${userId}/groups`, params),
this.roleAssignmentClient.list(),
this.userClient.groups.list(userId, params),
]);
const projectGroupIds = [];
roleAssignmentsReault.role_assignments.forEach((roleAssignment) => {
@ -269,9 +275,7 @@ export class GroupStore extends Base {
@action
async fetchGroupUsers({ id }) {
const usersResult = await request.get(
`${this.apiVersion}/groups/${id}/users`
);
const usersResult = await this.client.users.list(id);
const { users: result } = usersResult;
this.groupUsers = result;
return result;
@ -279,18 +283,12 @@ export class GroupStore extends Base {
@action
async deleteGroupUsers({ id, user_id }) {
const result = request.delete(
`${this.apiVersion}/groups/${id}/users/${user_id}`
);
return result;
return this.client.users.delete(id, user_id);
}
@action
async addGroupUsers({ id, user_id }) {
const result = request.put(
`${this.apiVersion}/groups/${id}/users/${user_id}`
);
return result;
return this.client.users.update(id, user_id);
}
mapperProject = (roleAssignmentsReault, item) => {
@ -320,17 +318,12 @@ export class GroupStore extends Base {
// todo: no page, no limit, fetch all
const params = { ...filters };
const result = await request.get(
this.getListDetailUrl() || this.getListUrl(),
params
);
const roleAssignmentsReault = await request.get(
`${this.apiVersion}/role_assignments/`
);
const result = await this.client.list(params);
const roleAssignmentsReault = await this.roleAssignmentClient.list();
const data = get(result, this.listResponseKey, []);
Promise.all(
data.map(
(it) => request.get(`${this.apiVersion}/groups/${it.id}/users`)
(it) => this.client.users.list(it.id)
// const { users } = userResult;
// return { ...it, users };
)
@ -338,8 +331,13 @@ export class GroupStore extends Base {
const addUserItem = data.map((it, index) => {
const { users } = rest[index];
const userIds = users.map((user) => user.id);
const userInfo = users.map((user) => ({
id: user.id,
name: user.name,
}));
it.users = userIds;
it.user_num = users.length;
it.user_info = userInfo;
return it;
});
const items = addUserItem.map((item) =>
@ -369,15 +367,19 @@ export class GroupStore extends Base {
}
const [roleAssignmentsReault, groupResult, usersInGroup] =
await Promise.all([
request.get(`${this.apiVersion}/role_assignments`),
request.get(`${this.apiVersion}/groups/${id}`),
request.get(`${this.apiVersion}/groups/${id}/users`),
this.roleAssignmentClient.list(),
this.client.show(id),
this.client.users.list(id),
]);
const originData = get(groupResult, this.responseKey) || groupResult;
const { users } = usersInGroup;
const userIds = users.map((user) => user.id);
originData.users = userIds;
originData.user_num = users.length;
originData.user_info = users.map((user) => ({
id: user.id,
name: user.name,
}));
const group = this.mapperProject(roleAssignmentsReault, originData);
this.detail = group;
this.isLoading = false;
@ -386,7 +388,7 @@ export class GroupStore extends Base {
@action
async fetchGroupData() {
const result = await request.get(this.getListUrl());
const result = await this.client.list();
const { groups } = result;
return groups;
}
@ -404,9 +406,9 @@ export class GroupStore extends Base {
const { roleId } = filters;
const params = {};
const [roleAssignmentsReault, projectResult, result] = await Promise.all([
request.get(`${this.apiVersion}/role_assignments`),
request.get(`${this.apiVersion}/projects`),
request.get(this.getListUrl(), params),
this.roleAssignmentClient.list(),
this.projectClient.list(),
this.client.list(params),
]);
const projectRoleUsers = {};
const systemRoleUsers = {};
@ -442,30 +444,35 @@ export class GroupStore extends Base {
// const items = data.map(this.mapper);
// const newData = await this.listDidFetch(items);
Promise.all(
data.map((it) => request.get(`${this.apiVersion}/groups/${it.id}/users`))
).then((rest) => {
items.map((it, index) => {
const { users } = rest[index];
const userIds = users.map((user) => user.id);
it.users = userIds;
it.user_num = users.length;
return it;
});
this.list.update({
data: items,
total: items.length || 0,
limit: Number(limit) || 10,
page: Number(page) || 1,
sortKey,
sortOrder,
filters,
isLoading: false,
...(this.list.silent ? {} : { selectedRowKeys: [] }),
});
Promise.all(data.map((it) => this.client.users.list(it.id))).then(
(rest) => {
items.map((it, index) => {
const { users } = rest[index];
const userIds = users.map((user) => user.id);
const userInfo = users.map((user) => ({
id: user.id,
name: user.name,
}));
it.users = userIds;
it.user_num = users.length;
it.user_info = userInfo;
return it;
});
this.list.update({
data: items,
total: items.length || 0,
limit: Number(limit) || 10,
page: Number(page) || 1,
sortKey,
sortOrder,
filters,
isLoading: false,
...(this.list.silent ? {} : { selectedRowKeys: [] }),
});
return items;
});
return items;
}
);
}
}

View File

@ -13,12 +13,13 @@
// limitations under the License.
import { action, observable } from 'mobx';
import request from 'utils/request';
import { keystoneBase } from 'utils/constants';
import { get } from 'lodash';
import Base from '../base';
import List from 'stores/base-list';
import client from 'client';
import globalRootStore from 'stores/root';
import globalProjectStore from './project';
import globalGroupStore from './user-group';
import Base from '../base';
export class UserStore extends Base {
@observable
@ -27,6 +28,12 @@ export class UserStore extends Base {
@observable
roleAssignments = [];
@observable
userProjects = new List();
@observable
userGroups = new List();
@observable
projects = [];
@ -36,16 +43,36 @@ export class UserStore extends Base {
@observable
domainRoles = [];
get module() {
return 'users';
get client() {
return client.keystone.users;
}
get apiVersion() {
return keystoneBase();
get domainClient() {
return client.keystone.domains;
}
get responseKey() {
return 'user';
get systemGroupClient() {
return client.keystone.systemGroups;
}
get roleClient() {
return client.keystone.roles;
}
get roleAssignmentClient() {
return client.keystone.roleAssignments;
}
get projectClient() {
return client.keystone.projects;
}
get systemUserClient() {
return client.keystone.systemUsers;
}
get groupClient() {
return client.keystone.groups;
}
@action
@ -61,14 +88,10 @@ export class UserStore extends Base {
const data = other;
body[this.responseKey] = data;
this.isSubmitting = true;
const result = await request.post(this.getListUrl(), body);
const result = await this.client.create(body);
const {
user: { id: user_id },
} = result;
// if (default_project_id) {
// const url = `${this.apiVersion}/projects/${default_project_id}/users/${user_id}/roles/${adminId}`;
// await request.put(url);
// }
const promiseList = [];
if (select_user_group[0] || select_project[0]) {
const newProjects = Object.keys(newProjectRoles);
@ -99,7 +122,7 @@ export class UserStore extends Base {
@action
async fetchDomain() {
const doaminsResult = await request.get(`${this.apiVersion}/domains`);
const doaminsResult = await this.domainClient.list();
this.domains = doaminsResult.domains;
}
@ -113,6 +136,40 @@ export class UserStore extends Base {
};
}
@action
async getUserProjects() {
this.userProjects.update({
isLoading: true,
});
const {
user: {
user: { id },
},
} = globalRootStore;
const { projects } = await this.client.projects.list(id);
this.userProjects.update({
data: projects,
isLoading: false,
});
}
@action
async getUserGroups() {
this.userGroups.update({
isLoading: true,
});
const {
user: {
user: { id },
},
} = globalRootStore;
const { groups } = await this.client.groups.list(id);
this.userGroups.update({
data: groups,
isLoading: false,
});
}
@action
getUserProjectRole = (user, roleAssignment, projectMapRole) => {
if (roleAssignment.user) {
@ -131,6 +188,17 @@ export class UserStore extends Base {
}
};
getUserProjectWithRole = (projectMapRole, roles, projects) => {
return Object.keys(projectMapRole).map((key) => {
const item = projects.find((it) => it.id === key);
const roleItems = projectMapRole[key].map((roleId) =>
roles.find((it) => it.id === roleId)
);
item.roles = roleItems;
return item;
});
};
@action
async fetchList({
limit,
@ -143,11 +211,13 @@ export class UserStore extends Base {
} = {}) {
this.list.isLoading = true;
// todo: no page, no limit, fetch all
const [roleAssignmentsReault, usersResult, roleResult] = await Promise.all([
request.get(`${this.apiVersion}/role_assignments`),
request.get(`${this.apiVersion}/users`),
request.get(`${this.apiVersion}/roles`),
]);
const [roleAssignmentsReault, usersResult, roleResult, projectResult] =
await Promise.all([
this.roleAssignmentClient.list(),
this.client.list(),
this.roleClient.list(),
this.projectClient.list(),
]);
const { users } = usersResult;
const { roles } = roleResult;
const systemRoles = roles.filter(
@ -167,6 +237,11 @@ export class UserStore extends Base {
systemRoleId,
projectMapSystemRole
);
user.projectItems = this.getUserProjectWithRole(
projectMapRole,
roles,
projectResult.projects
);
user.projects = projectMapRole;
user.projectMapSystemRole = projectMapSystemRole;
user.project_num = Object.keys(projectMapRole).length;
@ -195,9 +270,9 @@ export class UserStore extends Base {
this.isLoading = true;
}
const [roleAssignmentsReault, usersResult, roleResult] = await Promise.all([
request.get(`${this.apiVersion}/role_assignments`),
request.get(`${this.apiVersion}/users/${id}`),
request.get(`${this.apiVersion}/roles`),
this.roleAssignmentClient.list(),
this.client.show(id),
this.roleClient.list(),
]);
const { roles } = roleResult;
const systemRoles = roles.filter(
@ -241,43 +316,39 @@ export class UserStore extends Base {
@action
async enable({ id }) {
const url = `${this.apiVersion}/users/${id}`;
const reqBody = {
user: { enabled: true },
};
return this.submitting(request.patch(url, reqBody));
return this.submitting(this.client.patch(id, reqBody));
}
@action
async forbidden({ id }) {
const url = `${this.apiVersion}/users/${id}`;
const reqBody = {
user: { enabled: false },
};
return this.submitting(request.patch(url, reqBody));
return this.submitting(this.client.patch(id, reqBody));
}
@action
async changePassword({ id, password }) {
const url = `${this.apiVersion}/users/${id}`;
const reqBody = {
user: { password },
};
return this.submitting(request.patch(url, reqBody));
return this.submitting(this.client.patch(id, reqBody));
}
@action
async changePasswordUser({ id, password, original_password }) {
const url = `${this.apiVersion}/users/${id}/password`;
const reqBody = {
user: { password, original_password },
};
return this.submitting(request.post(url, reqBody));
return this.submitting(this.client.updatePassword(id, reqBody));
}
@action
async fetchProject() {
const projectsResult = await request.get(`${this.apiVersion}/projects`);
const projectsResult = await this.projectClient.list();
this.projects = projectsResult.projects;
}
@ -285,9 +356,9 @@ export class UserStore extends Base {
async fetchSystemRole({ id, projects }) {
this.systemRoles = [];
const project_id = projects[0].id;
// const rolesResult = await request.get(`${this.apiVersion}/system/users/${id}/roles`);
const projectResult = await request.get(
`${this.apiVersion}/projects/${project_id}/users/${id}/roles/`
const projectResult = await this.projectClient.users.roles.list(
project_id,
id
);
const systemRole = projectResult.roles.filter(
(it) => it.name.includes('system_') && !it.name.includes('_system_')
@ -297,48 +368,33 @@ export class UserStore extends Base {
@action
async assignSystemRole({ id, role_id }) {
const result = request.put(
`${this.apiVersion}/system/users/${id}/roles/${role_id}`
);
return result;
return this.systemUserClient.roles.update(id, role_id);
}
@action
async deleteSystemRole({ id, role_id }) {
const result = request.delete(
`${this.apiVersion}/system/users/${id}/roles/${role_id}`
);
return result;
return this.systemUserClient.delete(id, role_id);
}
@action
async fetchDomainRole({ id, domain_id }) {
this.domainRoles = [];
const rolesResult = await request.get(
`${this.apiVersion}/domains/${domain_id}/users/${id}/roles`
);
const rolesResult = await this.domainClient.users.roles.list(id, domain_id);
this.domainRoles = rolesResult.roles;
}
@action
async assignDomainRole({ id, role_id, domain_id }) {
const result = request.put(
`${this.apiVersion}/domains/${domain_id}/users/${id}/roles/${role_id}`
);
return result;
return this.domainClient.users.roles.update(domain_id, id, role_id);
}
@action
async deleteDomainRole({ id, role_id, domain_id }) {
const result = request.delete(
`${this.apiVersion}/domains/${domain_id}/users/${id}/roles/${role_id}`
);
return result;
return this.domainClient.users.roles.delete(domain_id, id, role_id);
}
@action
async edit(id, { email, phone, real_name, description, name }) {
const url = `${this.apiVersion}/users/${id}`;
const reqBody = {
user: {
email,
@ -348,7 +404,7 @@ export class UserStore extends Base {
name,
},
};
return this.submitting(request.patch(url, reqBody));
return this.submitting(this.client.patch(id, reqBody));
}
@action
@ -363,36 +419,34 @@ export class UserStore extends Base {
this.list.isLoading = true;
const { domainId } = filters;
const params = {};
const result = await request.get(this.getListUrl(), params);
const result = await this.client.list(params);
let data = get(result, this.listResponseKey, []);
data = data.filter((it) => it.domain_id === domainId);
const items = data.map(this.mapper);
const newData = await this.listDidFetch(items);
Promise.all(
newData.map((it) =>
request.get(`${this.apiVersion}/users/${it.id}/projects`)
)
).then((projectResult) => {
newData.map((it, index) => {
const { projects } = projectResult[index];
it.projects = projects;
it.project_num = projects.length;
return it;
});
this.list.update({
data: newData,
total: items.length || 0,
limit: Number(limit) || 10,
page: Number(page) || 1,
sortKey,
sortOrder,
filters,
isLoading: false,
...(this.list.silent ? {} : { selectedRowKeys: [] }),
});
Promise.all(newData.map((it) => this.client.projects.list(it.id))).then(
(projectResult) => {
newData.map((it, index) => {
const { projects } = projectResult[index];
it.projects = projects;
it.project_num = projects.length;
return it;
});
this.list.update({
data: newData,
total: items.length || 0,
limit: Number(limit) || 10,
page: Number(page) || 1,
sortKey,
sortOrder,
filters,
isLoading: false,
...(this.list.silent ? {} : { selectedRowKeys: [] }),
});
return items;
});
return items;
}
);
}
@action
@ -408,9 +462,9 @@ export class UserStore extends Base {
const { projectId } = filters;
const params = {};
const [roleAssignmentsReault, roleResult, result] = await Promise.all([
request.get(`${this.apiVersion}/role_assignments`),
request.get(`${this.apiVersion}/roles`),
request.get(this.getListUrl(), params),
this.roleAssignmentClient.list(),
this.roleClient.list(),
this.client.list(params),
]);
const projectUserIds = [];
const userMapRole = {};
@ -435,34 +489,32 @@ export class UserStore extends Base {
data = data.filter((it) => projectUserIds.includes(it.id));
const items = data.map(this.mapper);
const newData = await this.listDidFetch(items);
Promise.all(
newData.map((it) =>
request.get(`${this.apiVersion}/users/${it.id}/projects`)
)
).then((projectResult) => {
newData.map((it, index) => {
const { projects } = projectResult[index];
it.projects = projects;
it.project_num = projects.length;
it.project_roles = userMapRole[it.id].map(
(r) => roleResult.roles.filter((role) => role.id === r)[0].name
);
return it;
});
this.list.update({
data: newData,
total: items.length || 0,
limit: Number(limit) || 10,
page: Number(page) || 1,
sortKey,
sortOrder,
filters,
isLoading: false,
...(this.list.silent ? {} : { selectedRowKeys: [] }),
});
Promise.all(newData.map((it) => this.client.projects.list(it.id))).then(
(projectResult) => {
newData.map((it, index) => {
const { projects } = projectResult[index];
it.projects = projects;
it.project_num = projects.length;
it.project_roles = userMapRole[it.id].map(
(r) => roleResult.roles.filter((role) => role.id === r)[0].name
);
return it;
});
this.list.update({
data: newData,
total: items.length || 0,
limit: Number(limit) || 10,
page: Number(page) || 1,
sortKey,
sortOrder,
filters,
isLoading: false,
...(this.list.silent ? {} : { selectedRowKeys: [] }),
});
return items;
});
return items;
}
);
}
@action
@ -477,38 +529,33 @@ export class UserStore extends Base {
this.list.isLoading = true;
const { groupId } = filters;
const params = {};
const result = await request.get(
`${this.apiVersion}/groups/${groupId}/users`,
params
);
const result = await this.groupClient.users.list(groupId, params);
const data = get(result, this.listResponseKey, []);
const items = data.map(this.mapper);
const newData = await this.listDidFetch(items);
Promise.all(
newData.map((it) =>
request.get(`${this.apiVersion}/users/${it.id}/projects`)
)
).then((projectResult) => {
newData.map((it, index) => {
const { projects } = projectResult[index];
it.projects = projects;
it.project_num = projects.length;
return it;
});
this.list.update({
data: newData,
total: items.length || 0,
limit: Number(limit) || 10,
page: Number(page) || 1,
sortKey,
sortOrder,
filters,
isLoading: false,
...(this.list.silent ? {} : { selectedRowKeys: [] }),
});
Promise.all(newData.map((it) => this.client.projects.list(it.id))).then(
(projectResult) => {
newData.map((it, index) => {
const { projects } = projectResult[index];
it.projects = projects;
it.project_num = projects.length;
return it;
});
this.list.update({
data: newData,
total: items.length || 0,
limit: Number(limit) || 10,
page: Number(page) || 1,
sortKey,
sortOrder,
filters,
isLoading: false,
...(this.list.silent ? {} : { selectedRowKeys: [] }),
});
return items;
});
return items;
}
);
}
@action
@ -524,9 +571,9 @@ export class UserStore extends Base {
const { roleId } = filters;
const params = {};
const [roleAssignmentsReault, projectResult, result] = await Promise.all([
request.get(`${this.apiVersion}/role_assignments`),
request.get(`${this.apiVersion}/projects`),
request.get(this.getListUrl(), params),
this.roleAssignmentClient.list(),
this.projectClient.list(),
this.client.list(params),
]);
const projectRoleUsers = {};
const systemRoleUsers = {};
@ -542,9 +589,9 @@ export class UserStore extends Base {
(it) => it.id === project.id
);
if (projectRoleUsers[user_id]) {
projectRoleUsers[user_id].push(projectData.name);
projectRoleUsers[user_id].push(projectData);
} else {
projectRoleUsers[user_id] = [projectData.name];
projectRoleUsers[user_id] = [projectData];
}
} else if (role_id === roleId && system) {
systemRoleUsers[user_id] = system.all;
@ -555,7 +602,7 @@ export class UserStore extends Base {
const items = data
.filter((it) => projectRoleUsers[it.id] || systemRoleUsers[it.id])
.map((it) => ({
projectScope: projectRoleUsers[it.id] || [],
projects: projectRoleUsers[it.id] || [],
systemScope: systemRoleUsers[it.id] || [],
...it,
}));

View File

@ -13,30 +13,34 @@
// limitations under the License.
import { action } from 'mobx';
import { neutronBase } from 'utils/constants';
import client from 'client';
import { isArray } from 'lodash';
import Base from '../base';
export class NeutronAgentNetworkStore extends Base {
get module() {
return 'networks';
get client() {
return client.neutron.agents.dhcpNetworks;
}
get apiVersion() {
return neutronBase();
get isSubResource() {
return true;
}
get responseKey() {
return 'network';
}
getFatherResourceId = (params) => params.agentId;
get listFilterByProject() {
return true;
}
getListUrl = ({ agentId }) =>
`${this.apiVersion}/agents/${agentId}/dhcp-networks`;
getDetailUrl = ({ agentId, id }) => `${this.getListUrl({ agentId })}/${id}`;
get mapper() {
return (data) => {
const { created_at } = data;
return {
...data,
standard_attr_id: created_at,
};
};
}
async listDidFetch(items, allProjects, filters) {
const { agentId } = filters;
@ -48,11 +52,16 @@ export class NeutronAgentNetworkStore extends Base {
@action
remove = ({ agentId, id }) =>
this.submitting(request.delete(this.getDetailUrl({ agentId, id })));
this.submitting(this.client.delete(agentId, id));
@action
add = ({ agentId }, body) =>
this.submitting(request.post(this.getListUrl({ agentId }), body));
add = ({ agentId }, body) => {
if (!isArray(body)) {
return this.submitting(this.client.create(agentId, body));
}
const reqs = body.map((it) => this.client.create(agentId, it));
return this.submitting(Promise.allSettled(reqs));
};
}
const globalNeutronAgentNetworkStore = new NeutronAgentNetworkStore();

View File

@ -13,34 +13,28 @@
// limitations under the License.
import { action } from 'mobx';
import { neutronBase } from 'utils/constants';
import client from 'client';
import { isArray } from 'lodash';
import Base from '../base';
export class NeutronAgentRouterStore extends Base {
get module() {
return 'routers';
}
get apiVersion() {
return neutronBase();
}
get responseKey() {
return 'router';
get client() {
return client.neutron.agents.l3Routers;
}
get listFilterByProject() {
return true;
}
getListUrl = ({ agentId }) =>
`${this.apiVersion}/agents/${agentId}/l3-routers`;
get isSubResource() {
return true;
}
getDetailUrl = ({ agentId, id }) => `${this.getListUrl({ agentId })}/${id}`;
getFatherResourceId = (params) => params.agentId;
get mapper() {
return (data) => {
const externalGateway = data.external_gateway_info;
const { external_gateway_info: externalGateway, created_at } = data || {};
return {
...data,
hasExternalGateway: !!externalGateway,
@ -50,6 +44,7 @@ export class NeutronAgentRouterStore extends Base {
(externalGateway && externalGateway.network_name) || '',
externalFixedIps:
(externalGateway && externalGateway.external_fixed_ips) || [],
standard_attr_id: created_at,
};
};
}
@ -64,11 +59,16 @@ export class NeutronAgentRouterStore extends Base {
@action
remove = ({ agentId, id }) =>
this.submitting(request.delete(this.getDetailUrl({ agentId, id })));
this.submitting(this.client.delete(agentId, id));
@action
add = ({ agentId }, body) =>
this.submitting(request.post(this.getListUrl({ agentId }), body));
add = ({ agentId }, body) => {
if (!isArray(body)) {
return this.submitting(this.client.create(agentId, body));
}
const reqs = body.map((it) => this.client.create(agentId, it));
return this.submitting(Promise.allSettled(reqs));
};
}
const globalNeutronAgentRouterStore = new NeutronAgentRouterStore();

View File

@ -12,20 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { neutronBase } from 'utils/constants';
import client from 'client';
import Base from '../base';
export class NeutronAgentStore extends Base {
get module() {
return 'agents';
}
get apiVersion() {
return neutronBase();
}
get responseKey() {
return 'agent';
get client() {
return client.neutron.agents;
}
get listFilterByProject() {

View File

@ -12,26 +12,25 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { neutronBase } from 'utils/constants';
import globalNetworkStore from 'stores/neutron/network';
import globalFloatingIpsStore from 'stores/neutron/floatingIp';
import client from 'client';
import Base from '../base';
export class FixedIpStore extends Base {
get module() {
return 'ports';
get client() {
return client.neutron.ports;
}
get apiVersion() {
return neutronBase();
get paramsFunc() {
return ({ all_projects, ...rest }) => rest;
}
get listResponseKey() {
return 'ports';
}
async getItemFloatingIPs(fixed_ip) {
return globalFloatingIpsStore.pureFetchList({ fixed_ip_address: fixed_ip });
async getItemFloatingIPs(fixed_ip, portId) {
return globalFloatingIpsStore.pureFetchList({
fixed_ip_address: fixed_ip,
port_id: portId,
});
}
async listDidFetch(items) {
@ -39,7 +38,7 @@ export class FixedIpStore extends Base {
return [];
}
const port = items[0];
const { fixed_ips: fixedIPs = [] } = port;
const { fixed_ips: fixedIPs = [], id } = port;
const subnets = Array.from(new Set(fixedIPs.map((it) => it.subnet_id)));
const subnetResults = await Promise.all(
subnets.map((item) => globalNetworkStore.fetchSubnetDetail({ id: item }))
@ -49,7 +48,7 @@ export class FixedIpStore extends Base {
subnetMap[result.id] = result;
});
const fipResults = await Promise.all(
fixedIPs.map((item) => this.getItemFloatingIPs(item.ip_address))
fixedIPs.map((item) => this.getItemFloatingIPs(item.ip_address, id))
);
return fixedIPs.map((it, index) => ({
...it,

Some files were not shown because too many files have changed in this diff Show More