diff --git a/src/client/zun/index.js b/src/client/zun/index.js index 960ae98a..1cd2a76e 100644 --- a/src/client/zun/index.js +++ b/src/client/zun/index.js @@ -71,6 +71,11 @@ export class ZunClient extends Base { { key: 'stats', }, + { + name: 'actions', + key: 'container_actions', + responseKey: 'containerAction', + }, ], }, { diff --git a/src/components/Popover/PopActionEvent.jsx b/src/components/Popover/PopActionEvent.jsx new file mode 100644 index 00000000..e86b6138 --- /dev/null +++ b/src/components/Popover/PopActionEvent.jsx @@ -0,0 +1,52 @@ +// 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 React from 'react'; +import { getLocalTimeStr } from 'utils/time'; +import IPopover from './Popover'; + +export default function PopActionEvent({ id, requestId, store, actionEvent }) { + const columns = [ + { + title: t('Operation Name'), + dataIndex: 'event', + key: 'event', + render: (value) => actionEvent[value] || value, + }, + { + title: t('Start Time'), + dataIndex: 'start_time', + key: 'start_time', + render: (value) => getLocalTimeStr(value), + }, + { + title: t('End Time'), + dataIndex: 'finish_time', + key: 'finish_time', + render: (value) => (value ? getLocalTimeStr(value) : '-'), + }, + { + title: t('Execution Result'), + dataIndex: 'result', + key: 'result', + render: (value) => (value === 'Success' ? t('Success') : '-'), + }, + ]; + const getData = async () => { + const detail = (await store.fetchDetail({ id, requestId })) || {}; + const { events = [] } = detail; + return events.slice().reverse(); + }; + return ; +} diff --git a/src/pages/container-service/containers/Containers/Detail/ActionLogs.jsx b/src/pages/container-service/containers/Containers/Detail/ActionLogs.jsx new file mode 100644 index 00000000..b1176172 --- /dev/null +++ b/src/pages/container-service/containers/Containers/Detail/ActionLogs.jsx @@ -0,0 +1,36 @@ +// 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 'containers/List'; +import { inject, observer } from 'mobx-react'; +import { ActionsLogStore } from 'src/stores/zun/action-log'; +import { actionColumn } from 'resources/zun/actions'; + +export class ActionLogs extends Base { + init() { + this.store = new ActionsLogStore(); + } + + get name() { + return t('Action Logs'); + } + + get policy() { + return 'container:actions'; + } + + getColumns = () => actionColumn(this); +} + +export default inject('rootStore')(observer(ActionLogs)); diff --git a/src/pages/container-service/containers/Containers/Detail/index.jsx b/src/pages/container-service/containers/Containers/Detail/index.jsx index 87c03179..28fbc781 100644 --- a/src/pages/container-service/containers/Containers/Detail/index.jsx +++ b/src/pages/container-service/containers/Containers/Detail/index.jsx @@ -16,6 +16,7 @@ import globalContainersStore from 'src/stores/zun/containers'; import { containerStatus } from 'resources/zun/container'; import actionConfigs from '../actions'; import BaseDetail from './BaseDetail'; +import ActionLogs from './ActionLogs'; export class ContainerDetail extends Base { init() { @@ -62,6 +63,11 @@ export class ContainerDetail extends Base { key: 'general_info', component: BaseDetail, }, + { + title: t('Action Logs'), + key: 'action_logs', + component: ActionLogs, + }, ]; } } diff --git a/src/resources/nova/instance.jsx b/src/resources/nova/instance.jsx index a6d53dc7..0ad19037 100644 --- a/src/resources/nova/instance.jsx +++ b/src/resources/nova/instance.jsx @@ -12,14 +12,13 @@ // See the License for the specific language governing permissions and // limitations under the License. -import React, { useEffect, useState } from 'react'; +import React from 'react'; import ImageType from 'components/ImageType'; -import { getLocalTimeStr } from 'utils/time'; -import { Table, Popover, Tag, Tooltip } from 'antd'; -import globalActionLogStore from 'stores/nova/action-log'; +import { Tag, Tooltip } from 'antd'; +import { ActionLogStore } from 'stores/nova/action-log'; import { ironicOriginEndpoint } from 'client/client/constants'; import { projectTagsColors } from 'src/utils/constants'; - +import PopActionEvent from 'src/components/Popover/PopActionEvent'; import lockSvg from 'asset/image/lock.svg'; import unlockSvg from 'asset/image/unlock.svg'; import { isEmpty } from 'lodash'; @@ -506,64 +505,6 @@ export const actionEvent = { compute_reboot_instance: t('Compute Reboot Instance'), }; -function PopUpContent({ id, requestId }) { - const [event, setEvent] = useState([]); - const [loading, setLoading] = useState(false); - - useEffect(() => { - let timeout = null; - (async function () { - setLoading(true); - const cb = await globalActionLogStore.fetchDetail({ id, requestId }); - const { events = [] } = cb; - timeout = setTimeout(() => { - setLoading(false); - setEvent(events.slice().reverse()); - }, 200); - })(); - return () => { - clearTimeout(timeout); - }; - }, []); - const columns = [ - { - title: t('Operation Name'), - dataIndex: 'event', - key: 'event', - render: (value) => actionEvent[value], - }, - { - title: t('Start Time'), - dataIndex: 'start_time', - key: 'start_time', - render: (value) => getLocalTimeStr(value), - }, - { - title: t('End Time'), - dataIndex: 'finish_time', - key: 'finish_time', - render: (value) => (value ? getLocalTimeStr(value) : '-'), - }, - { - title: t('Execution Result'), - dataIndex: 'result', - key: 'result', - render: (value) => (value === 'Success' ? t('Success') : '-'), - }, - ]; - const table = ( - - ); - return table; -} - export const actionColumn = (self) => { return [ { @@ -586,20 +527,17 @@ export const actionColumn = (self) => { title: t('Request ID'), dataIndex: 'request_id', isHideable: true, - render: (value, record) => { - const content = ( - - ); - return ( - <> - {value && ( - - {value} - - )} - - ); - }, + render: (value, record) => ( + <> + {value} + + + ), }, { title: t('User ID'), diff --git a/src/resources/zun/actions.jsx b/src/resources/zun/actions.jsx new file mode 100644 index 00000000..ed5632a2 --- /dev/null +++ b/src/resources/zun/actions.jsx @@ -0,0 +1,90 @@ +// 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 React from 'react'; +import { ActionsLogStore } from 'src/stores/zun/action-log'; +import PopActionEvent from 'src/components/Popover/PopActionEvent'; + +export const actionEvent = { + compute__do_container_start: t('Start Container'), + compute__do_container_create: t('Create Container'), + compute__do_container_stop: t('Stop Container'), + compute__do_container_reboot: t('Reboot Container'), + compute__do_container_restart: t('Restart Container'), + compute__do_container_pause: t('Pause Container'), + compute__do_container_unpause: t('Unpause Container'), + compute__do_container_resize: t('Resize Container'), + compute__do_container_rebuild: t('Rebuild Container'), + compute__do_container_kill: t('Kill Container'), + compute__do_container_delete: t('Delete Container'), +}; + +export const actionMap = { + create: t('Create'), + stop: t('Stop'), + reboot: t('Reboot'), + start: t('Start'), + restart: t('Restart'), + pause: t('Pause'), + unpause: t('Unpause'), + resize: t('Resize'), + rebuild: t('Rebuild'), + kill: t('Kill'), + delete: t('Delete'), +}; + +export const actionColumn = (self) => { + return [ + { + title: t('Operation Name'), + dataIndex: 'action', + render: (value) => actionMap[value] || value, + }, + { + title: t('Project ID/Name'), + dataIndex: 'project_name', + isHideable: true, + hidden: !self.isAdminPage, + }, + { + title: t('Operation Time'), + dataIndex: 'start_time', + valueRender: 'toLocalTimeMoment', + }, + { + title: t('Request ID'), + dataIndex: 'request_id', + isHideable: true, + render: (value, record) => ( + <> + {value} + + + ), + }, + { + title: t('User ID'), + dataIndex: 'user_id', + isHideable: true, + hidden: !self.isAdminPage, + render: (value) => + self.getLinkRender('userDetail', value, { id: value }, null), + }, + ]; +}; diff --git a/src/stores/zun/action-log.js b/src/stores/zun/action-log.js new file mode 100644 index 00000000..990a0782 --- /dev/null +++ b/src/stores/zun/action-log.js @@ -0,0 +1,45 @@ +// 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 'stores/base'; +import client from 'client'; + +export class ActionsLogStore extends Base { + get client() { + return client.zun.containers.actions; + } + + get isSubResource() { + return true; + } + + get paramsFunc() { + return () => {}; + } + + get mapper() { + return (data) => ({ + ...data, + id: data.request_id, + }); + } + + detailFetchByClient(resourceParams) { + const { id, requestId } = resourceParams; + return this.client.show(id, requestId); + } +} + +const globalActionsLogStore = new ActionsLogStore(); +export default globalActionsLogStore;