skyline-console/src/stores/base.js

592 lines
14 KiB
JavaScript

// 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 { get } from 'lodash';
import { action, observable } from 'mobx';
import client from 'client';
import List from './base-list';
import globalProjectMapStore from './project';
import globalRootStore from './root';
export default class BaseStore {
list = new List();
@observable
detail = {};
@observable
isLoading = true;
@observable
isSubmitting = false;
get client() {
return {};
}
get skylineClient() {
return client.skyline;
}
get responseKey() {
return this.client.responseKey;
}
get listResponseKey() {
return `${this.responseKey}s`;
}
get needGetProject() {
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;
// return ObjectMapper[this.module] || (data => data);
}
get mapperBeforeFetchProject() {
return (data) => data;
}
get filterByApi() {
return false;
}
get paramsFunc() {
if (this.filterByApi) {
return (params) => params;
}
return (params) => {
const reservedKeys = [
'all_data',
'all_projects',
'device_id',
'network_id',
'floating_network_id',
'start_at_gt',
'start_at_lt',
'binary',
'fixed_ip_address',
'device_owner',
'project_id',
'type',
'sort',
'security_group_id',
'id',
'security_group_id',
'owner_id',
'status',
'fingerprint',
'resource_types',
'floating_ip_address',
'uuid',
'loadbalancer_id',
'ikepolicy_id',
'ipsecpolicy_id',
'endpoint_id',
'peer_ep_group_id',
'local_ep_group_id',
'vpnservice_id',
];
const newParams = {};
Object.keys(params).forEach((key) => {
if (reservedKeys.indexOf(key) >= 0) {
newParams[key] = params[key];
}
});
return newParams;
};
}
get paramsFuncPage() {
return (params) => {
const { current, withPrice, ...rest } = params;
return rest;
};
}
get listFilterByProject() {
// use it for nuetron apois
return false;
}
get fetchListByLimit() {
return false;
}
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 ||
item.tenant_id ||
item.owner ||
item.owner_id ||
item.tenant ||
item.fingerprint
);
}
itemInCurrentProject = (item, all_projects) => {
// use for neutron resource in admin project
if (all_projects) {
return true;
}
const itemProject = globalProjectMapStore.getItemProjectId(item);
const { shared, visibility, is_public } = item;
return (
itemProject === this.currentProjectId ||
is_public ||
shared ||
visibility === 'public'
);
};
@action
setModule(module) {
this.module = module;
}
@action
submitting = (promise) => {
this.isSubmitting = true;
setTimeout(() => {
promise
.catch(() => {})
.finally(() => {
this.isSubmitting = false;
});
}, 500);
return promise;
};
// eslint-disable-next-line no-unused-vars
async listDidFetch(items, allProjects, filters) {
return items;
}
// eslint-disable-next-line no-unused-vars
async detailDidFetch(item, all_projects, params) {
return item;
}
async listDidFetchProject(items, all_projects) {
if (!this.needGetProject) {
return items;
}
if (!all_projects || !this.hasAdminRole) {
return items;
}
const projectIds = [];
items.forEach((item) => {
const projectId = globalProjectMapStore.getItemProjectId(item);
const projectName = globalProjectMapStore.getItemProjectName(item);
if (!projectName && projectId && projectIds.indexOf(projectId) < 0) {
projectIds.push(projectId);
}
});
if (projectIds.length === 0) {
return items;
}
try {
const results = await Promise.all(
projectIds.map((id) => globalProjectMapStore.fetchProjectDetail({ id }))
);
items.forEach((item) => {
const projectId = globalProjectMapStore.getItemProjectId(item);
if (projectId && projectIds.indexOf(projectId) >= 0) {
const project = results.find((it) => it.id === projectId);
item.project_name = project ? project.name || '-' : '-';
}
});
} catch (e) {
return items;
}
return items;
}
updateMarkerParams = (limit, marker) => {
return {
limit,
marker,
};
};
async requestListByMarker(params, limit, marker) {
const markerParams = this.updateMarkerParams(limit, marker);
const newParams = {
...params,
...markerParams,
};
return this.listFetchByClient(newParams);
}
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(params, limit, marker);
const data = this.getListDataFromResult(result);
datas = [...datas, ...data];
if (data.length >= limit) {
marker = this.parseMarker(data, result, datas);
if (!marker) {
// eslint-disable-next-line no-console
console.log('parse marker error!');
hasNext = false;
}
} else {
hasNext = false;
}
}
return datas;
}
async requestListAll(params, originParams) {
const result = await this.listFetchByClient(params, originParams);
return this.getListDataFromResult(result);
}
async requestList(params, originParams) {
const datas = !this.fetchListByLimit
? await this.requestListAll(params, originParams)
: await this.requestListAllByLimit(params, 100);
return datas;
}
// eslint-disable-next-line no-unused-vars
async requestListByPage(params, page, originParams) {
const datas = await this.listFetchByClient(params, originParams);
return datas;
}
// eslint-disable-next-line no-unused-vars
updateUrl = (url, params) => url;
// eslint-disable-next-line no-unused-vars
updateParamsSortPage = (params, sortKey, sortOrder) => {};
// eslint-disable-next-line no-unused-vars
updateParamsSort = (params, sortKey, sortOrder) => {};
@action
async pureFetchList({
limit,
page,
sortKey,
sortOrder,
conditions,
timeFilter,
...filters
} = {}) {
// 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 allData = await this.requestList(params, {});
return allData;
}
@action
async fetchList({
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);
const allData = await this.requestList(newParams, filters);
const allDataNew = allData.map((it) =>
this.mapperBeforeFetchProject(it, filters)
);
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);
try {
newData = await this.listDidFetch(newData, all_projects, filters);
} catch (e) {
// eslint-disable-next-line no-console
console.log(e);
}
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: [] }),
});
return newData;
}
// eslint-disable-next-line no-unused-vars
parseMarker(datas, result, allDatas) {
return datas.length === 0
? ''
: get(datas[datas.length - 1], this.markerKey);
}
@action
updateMarker(datas, page, result, allDatas) {
const marker = this.parseMarker(datas, result, allDatas);
if (page === 1) {
this.list.markers = [marker];
} else {
this.list.markers[page - 1] = marker;
}
}
getMarker(page) {
return page === 1 ? '' : this.list.markers[page - 2];
}
getDetailParams = () => undefined;
getListDataFromResult = (result) =>
this.listResponseKey ? get(result, this.listResponseKey, []) : result;
// eslint-disable-next-line no-unused-vars
async getCountForPage(newParams, all_projects, newDatas) {
return {};
}
// eslint-disable-next-line no-unused-vars
getOtherInfo = (result) => {};
@action
async fetchListByPage({
limit = 10,
page = 1,
sortKey,
sortOrder,
conditions,
timeFilter,
...filters
} = {}) {
this.list.isLoading = true;
// todo: no page, no limit, fetch all
const { tab, all_projects, ...rest } = filters;
const params = { limit, ...rest };
this.updateParamsSortPage(params, sortKey, sortOrder);
if (all_projects) {
if (!this.listFilterByProject) {
params.all_projects = true;
}
}
const marker = this.getMarker(page);
if (marker) {
params.marker = marker;
}
const newParams = this.paramsFuncPage(params, all_projects);
const result = await this.requestListByPage(newParams, page, filters);
const allData = this.getListDataFromResult(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);
newData = newData.map(this.mapper);
let count;
let total;
if (result.count || result.total) {
count = result.count || result.total;
} else {
const totalResult = await this.getCountForPage(
newParams,
newData,
all_projects,
result,
params
);
const { count: retCount, total: retTotal } = totalResult;
count = retCount;
total = retTotal;
}
const others = this.getOtherInfo(result);
this.list.update({
data: newData,
limit: Number(limit) || 10,
page: Number(page) || 1,
sortKey,
sortOrder,
filters,
timeFilter,
isLoading: false,
total: count || total,
...(this.list.silent ? {} : { selectedRowKeys: [] }),
...others,
});
return newData;
}
@action
async fetchDetail({ all_projects, silent, ...rest }) {
if (!silent) {
this.isLoading = true;
}
const result = await this.detailFetchByClient(
rest,
this.getDetailParams({ all_projects })
);
const originData = get(result, this.responseKey) || result;
const item = this.mapperBeforeFetchProject(originData, rest, true);
try {
const newItem = await this.detailDidFetch(item, all_projects, rest);
const detail = this.mapper(newItem);
this.detail = detail;
} catch (e) {
// eslint-disable-next-line no-console
console.log(e);
this.detail = item;
}
this.isLoading = false;
return this.detail;
}
@action
setSelectRowKeys(key, selectedRowKeys) {
this[key] && this[key].selectedRowKeys.replace(selectedRowKeys);
}
@action
create(data) {
const body = {};
body[this.responseKey] = data;
return this.submitting(this.client.create(body));
}
@action
edit({ id }, newObject) {
const body = {};
body[this.responseKey] = newObject;
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(this.client.patch(id, newObject));
}
@action
delete = ({ id }) => this.submitting(this.client.delete(id));
@action
batchDelete(rowKeys) {
return this.submitting(
Promise.all(
rowKeys.map((name) => {
const item = this.list.data.find((_item) => _item.name === name);
const { id } = item;
return this.client.delete(id);
})
)
);
}
@action
clearData() {
this.list.reset();
this.detail = {};
}
}