diff --git a/docs/en/develop/3-6-FormAction-introduction.md b/docs/en/develop/3-6-FormAction-introduction.md index 6045b7bd..b7e8fcca 100644 --- a/docs/en/develop/3-6-FormAction-introduction.md +++ b/docs/en/develop/3-6-FormAction-introduction.md @@ -110,7 +110,7 @@ English | [Chinese](../../zh/develop/3-6-FormAction-introduction.md) ``` - `allowed` - - Static functions + - Static functions - Determine whether the operation needs to be disabled - Return `Promise` - Write directly without using disabled buttons diff --git a/src/client/trove/index.js b/src/client/trove/index.js index 25d573ec..f0758d52 100644 --- a/src/client/trove/index.js +++ b/src/client/trove/index.js @@ -48,6 +48,20 @@ export class TroveClient extends Base { responseKey: 'log', }, ], + extendOperations: [ + { + name: 'grantDatabase', + generate: (id, subId, body) => { + return this.request.put( + `${this.getDetailUrl( + 'instances', + id + )}/users/${subId}/databases`, + body + ); + }, + }, + ], }, { name: 'datastores', diff --git a/src/locales/en.json b/src/locales/en.json index 171b4db0..3268729e 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -988,6 +988,7 @@ "Glance": "Glance", "Global Setting": "Global Setting", "GlusterFS": "GlusterFS", + "Grant Databases Access": "Grant Databases Access", "Greece": "Greece", "Greenland": "Greenland", "Grenada": "Grenada", @@ -2660,6 +2661,7 @@ "flavor": "flavor", "floating ip": "floating ip", "floating ips": "floating ips", + "gigabytes": "gigabytes", "heat services": "heat services", "host aggregates": "host aggregates", "hosts": "hosts", diff --git a/src/locales/zh.json b/src/locales/zh.json index 68c56160..b5ce339e 100644 --- a/src/locales/zh.json +++ b/src/locales/zh.json @@ -988,6 +988,7 @@ "Glance": "", "Global Setting": "平台配置", "GlusterFS": "", + "Grant Databases Access": "设置数据库访问", "Greece": "希腊", "Greenland": "格陵兰", "Grenada": "格林纳达", @@ -2660,6 +2661,7 @@ "flavor": "云主机类型", "floating ip": "浮动IP", "floating ips": "浮动IP", + "gigabytes": "容量", "heat services": "编排服务", "host aggregates": "主机集合", "hosts": "主机", diff --git a/src/pages/database/containers/Instances/Detail/BaseDetail.jsx b/src/pages/database/containers/Instances/Detail/BaseDetail.jsx index 076e30e0..ee4cde4d 100644 --- a/src/pages/database/containers/Instances/Detail/BaseDetail.jsx +++ b/src/pages/database/containers/Instances/Detail/BaseDetail.jsx @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import React from 'react'; import { inject, observer } from 'mobx-react'; import Base from 'containers/BaseDetail'; import { InstanceStatus, policyType } from 'resources/trove/database'; @@ -104,7 +105,17 @@ export class BaseDetail extends Base { { label: t('Host'), dataIndex: 'ip', - render: (value) => (value ? value.map((it) => it) : '-'), + render: (value) => { + return value && value.length ? ( + + {value.map((it) => ( +
{it}
+ ))} +
+ ) : ( + '-' + ); + }, }, { label: t('Database Port'), diff --git a/src/pages/database/containers/Instances/Detail/UserAction.jsx b/src/pages/database/containers/Instances/Detail/UserAction.jsx index a81fba7c..d30c3b33 100644 --- a/src/pages/database/containers/Instances/Detail/UserAction.jsx +++ b/src/pages/database/containers/Instances/Detail/UserAction.jsx @@ -14,10 +14,16 @@ import DeleteUser from './UserDelete'; import CreateUser from './UserCreate'; +import UserDatabase from './UserDatabase'; const actionConfigs = { rowActions: { firstAction: DeleteUser, + moreActions: [ + { + action: UserDatabase, + }, + ], }, batchActions: [DeleteUser], primaryActions: [CreateUser], diff --git a/src/pages/database/containers/Instances/Detail/UserDatabase.jsx b/src/pages/database/containers/Instances/Detail/UserDatabase.jsx new file mode 100644 index 00000000..479c21cf --- /dev/null +++ b/src/pages/database/containers/Instances/Detail/UserDatabase.jsx @@ -0,0 +1,94 @@ +// 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 { inject, observer } from 'mobx-react'; +import ModalAction from 'containers/Action/ModalAction'; +import globalInstancesUsersStore from 'stores/trove/instances-user'; +import { InstancesDatabasesStore } from 'stores/trove/instances-database'; + +export class UserDatabase extends ModalAction { + init() { + this.store = globalInstancesUsersStore; + this.databaseStore = new InstancesDatabasesStore(); + this.fetchDatabase(); + } + + static id = 'grant-databases-access'; + + static title = t('Grant Databases Access'); + + get name() { + return t('Grant Databases Access'); + } + + static policy = 'instance:extension:user_access:update'; + + static allowed() { + return Promise.resolve(true); + } + + async fetchDatabase() { + const { containerProps: { detail: { id } = {} } = {} } = this.props; + await this.databaseStore.fetchList({ id }); + this.updateDefaultValue(); + } + + get database() { + return (this.databaseStore.list.data || []).map((it) => ({ + label: it.name, + value: it.name, + key: it.name, + })); + } + + get defaultValue() { + const { name, databases } = this.item; + return { + name, + database: databases, + }; + } + + get formItems() { + return [ + { + name: 'name', + label: t('Name'), + type: 'input-name', + required: true, + disabled: true, + }, + { + name: 'database', + label: t('Database'), + type: 'select', + options: this.database, + mode: 'multiple', + required: true, + loading: this.databaseStore.list.isLoading, + disabled: this.databaseStore.list.isLoading, + }, + ]; + } + + onSubmit = (values, containerProps) => { + const { detail: { id } = {} } = containerProps; + const data = { + databases: values.database.map((it) => ({ name: it })), + }; + return this.store.grantDatabaseAccess({ id, name: values.name, data }); + }; +} + +export default inject('rootStore')(observer(UserDatabase)); diff --git a/src/pages/database/containers/Instances/Detail/Users.jsx b/src/pages/database/containers/Instances/Detail/Users.jsx index 9ae02005..dcfeef37 100644 --- a/src/pages/database/containers/Instances/Detail/Users.jsx +++ b/src/pages/database/containers/Instances/Detail/Users.jsx @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import React from 'react'; import Base from 'containers/List'; import { inject, observer } from 'mobx-react'; import { InstancesUsersStore } from 'stores/trove/instances-user'; @@ -58,6 +59,17 @@ export class Users extends Base { { title: t('Databases'), dataIndex: 'databases', + render: (value) => { + return value.length ? ( + + {value.map((it) => ( +
{it}
+ ))} +
+ ) : ( + '-' + ); + }, }, ]; }; diff --git a/src/pages/database/containers/Instances/index.jsx b/src/pages/database/containers/Instances/index.jsx index ffd616a0..98249dbe 100644 --- a/src/pages/database/containers/Instances/index.jsx +++ b/src/pages/database/containers/Instances/index.jsx @@ -12,6 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +import React from 'react'; import { observer, inject } from 'mobx-react'; import Base from 'containers/List'; import globalInstancesStore from 'stores/trove/instances'; @@ -69,6 +70,17 @@ export class Instances extends Base { { title: t('Host'), dataIndex: 'ip', + render: (value) => { + return value && value.length ? ( + <> + {value.map((it) => ( +
{it}
+ ))} + + ) : ( + '-' + ); + }, isHideable: true, }, { diff --git a/src/stores/trove/instances-user.js b/src/stores/trove/instances-user.js index ea5d0129..976ac78b 100644 --- a/src/stores/trove/instances-user.js +++ b/src/stores/trove/instances-user.js @@ -25,6 +25,10 @@ export class InstancesUsersStore extends Base { return client.trove.instances.databases; } + get instanceClient() { + return client.trove.instances; + } + get isSubResource() { return true; } @@ -46,11 +50,9 @@ export class InstancesUsersStore extends Base { const { databases = [] } = await this.databaseClient.list(id); return items.map((it) => ({ ...it, - databases: - (it.databases || []) - .filter((l1) => databases.find((l2) => l2.name === l1.name)) - .map((db) => db.name) - .join(' , ') || '-', + databases: (it.databases || []) + .filter((l1) => databases.find((l2) => l2.name === l1.name)) + .map((db) => db.name), })); } @@ -63,6 +65,11 @@ export class InstancesUsersStore extends Base { async deleteUser({ id, name }) { return this.submitting(this.client.delete(id, name)); } + + @action + async grantDatabaseAccess({ id, name, data }) { + return this.submitting(this.instanceClient.grantDatabase(id, name, data)); + } } const globalInstancesUsersStore = new InstancesUsersStore();