diff --git a/src/client/client/constants.js b/src/client/client/constants.js
index de36d96b..c62888b4 100644
--- a/src/client/client/constants.js
+++ b/src/client/client/constants.js
@@ -33,6 +33,7 @@ export const endpointVersionMap = {
trove: 'v1.0',
manilav2: 'v2',
barbican: 'v1',
+ zun: 'v1',
magnum : 'v1',
};
@@ -72,6 +73,7 @@ export const swiftBase = () => getOpenstackEndpoint('swift');
export const troveBase = () => getOpenstackEndpoint('trove');
export const manilaBase = () => getOpenstackEndpoint('manilav2');
export const barbicanBase = () => getOpenstackEndpoint('barbican');
+export const zunBase = () => getOpenstackEndpoint('zun');
export const magnumBase = () => getOpenstackEndpoint('magnum');
export const ironicOriginEndpoint = () => getOriginEndpoint('ironic');
diff --git a/src/client/index.js b/src/client/index.js
index a161cf61..260ba416 100644
--- a/src/client/index.js
+++ b/src/client/index.js
@@ -26,6 +26,7 @@ import swift from './swift';
import trove from './trove';
import manila from './manila';
import barbican from './barbican';
+import zun from './zun';
import magnum from './magnum';
const client = {
@@ -43,6 +44,7 @@ const client = {
trove,
manila,
barbican,
+ zun,
magnum
};
diff --git a/src/client/zun/index.js b/src/client/zun/index.js
new file mode 100644
index 00000000..902629eb
--- /dev/null
+++ b/src/client/zun/index.js
@@ -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 { zunBase } from 'client/client/constants';
+import Base from '../client/base';
+
+class ZunClient extends Base {
+ get baseUrl() {
+ return zunBase();
+ }
+
+ get resources() {
+ return [
+ {
+ name: 'capsules',
+ key: 'capsules',
+ responseKey: 'capsule',
+ },
+ {
+ name: 'containers',
+ key: 'containers',
+ responseKey: 'container',
+ extendOperations: [
+ {
+ key: 'start',
+ method: 'post',
+ },
+ {
+ key: 'stop',
+ method: 'post',
+ },
+ {
+ key: 'pause',
+ method: 'post',
+ },
+ {
+ key: 'reboot',
+ method: 'post',
+ },
+ {
+ key: 'unpause',
+ method: 'post',
+ },
+ ],
+ },
+ ];
+ }
+}
+
+const zunClient = new ZunClient();
+export default zunClient;
\ No newline at end of file
diff --git a/src/components/FormItem/ZunVolume/index.jsx b/src/components/FormItem/ZunVolume/index.jsx
new file mode 100644
index 00000000..20033eed
--- /dev/null
+++ b/src/components/FormItem/ZunVolume/index.jsx
@@ -0,0 +1,169 @@
+// 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 { Select, Row, Col, Form, Input } from 'antd';
+import PropTypes from 'prop-types';
+import styles from './index.less';
+import InputInt from '../InputInt';
+
+export default class ZunVolume extends React.Component {
+ static propTypes = {
+ onChange: PropTypes.func,
+ value: PropTypes.any,
+ };
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ type: [],
+ source: [],
+ destination: "",
+ cinderVolumeSize: 0,
+ isCinderVolume: false
+ };
+ }
+
+ static getDerivedStateFromProps(nextProps, prevState) {
+ const { type, source, cinderVolumeSize, destination } = nextProps.value || {};
+ if (type !== prevState.type || source !== prevState.source || cinderVolumeSize !== prevState.cinderVolumeSize || destination !== prevState.destination) {
+ return {
+ type,
+ source,
+ cinderVolumeSize,
+ destination,
+ };
+ }
+ return null;
+ }
+
+ onChange = (value) => {
+ const { onChange } = this.props;
+ if (onChange) {
+ onChange(value);
+ }
+ };
+
+ onTypeChange = (value) => {
+ if (value === "cinder-new") {
+ this.setState(
+ {
+ isCinderVolume: true,
+ },
+ );
+ }
+ if (value === "cinder-available") {
+ this.setState(
+ {
+ isCinderVolume: false,
+ },
+ );
+ }
+ this.onChange({
+ ...this.state,
+ type: value,
+ });
+ };
+
+ onSourceChange = (value) => {
+ this.onChange({
+ ...this.state,
+ source: value,
+ });
+ };
+
+ onCinderVolumeSizeChange = (e) => {
+ this.onChange({
+ ...this.state,
+ cinderVolumeSize: e
+ });
+ };
+
+ onDestinationChange = (e) => {
+ this.onChange({
+ ...this.state,
+ destination: e.target.value
+ });
+ };
+
+ render() {
+ const {
+ type,
+ source,
+ destination,
+ cinderVolumeSize,
+ isCinderVolume
+ } = this.state;
+ const { name } = this.props;
+ const selectType = (
+
+ );
+ const selectSource = (
+
+ );
+ const inputSize = (
+
+ );
+ const inputDestination = (
+
+ );
+
+ return (
+
+
+
+ {t('Type')}
+ {selectType}
+
+
+ {t('Source')}
+ {selectSource}
+
+
+ {t('Size(GB)')}
+ {inputSize}
+
+
+ {t('Destination')}
+ {inputDestination}
+
+
+
+ );
+ }
+}
diff --git a/src/components/FormItem/ZunVolume/index.less b/src/components/FormItem/ZunVolume/index.less
new file mode 100644
index 00000000..da5ea000
--- /dev/null
+++ b/src/components/FormItem/ZunVolume/index.less
@@ -0,0 +1,13 @@
+.zun-volume {
+ display: block;
+ margin-bottom: 8px;
+}
+
+.label {
+ margin-right: 10px;
+ max-width: 20%;
+}
+
+.select {
+ max-width: 80%;
+}
\ No newline at end of file
diff --git a/src/layouts/menu.jsx b/src/layouts/menu.jsx
index d4779b5c..44ee09e4 100644
--- a/src/layouts/menu.jsx
+++ b/src/layouts/menu.jsx
@@ -582,11 +582,47 @@ const renderMenu = (t) => {
],
},
{
- path: '/container-infra',
- name: t('Container Infra'),
- key: 'containerInfra',
+ path: '/container',
+ name: t('Container'),
+ key: 'container',
icon: ,
children: [
+ {
+ path: '/container/containers',
+ name: t('Containers'),
+ key: 'containers',
+ level: 1,
+ children: [
+ {
+ path: '/container/containers/create',
+ name: t('Create Container'),
+ key: 'containersCreateContainer',
+ level: 2,
+ },
+ {
+ path: /^\/container\/containers\/detail\/.[^/]+$/,
+ name: t('Containers Detail'),
+ key: 'containersDetail',
+ level: 2,
+ routePath: '/container/containers/detail/:id',
+ },
+ ],
+ },
+ {
+ path: '/container/capsules',
+ name: t('Capsules'),
+ key: 'capsules',
+ level: 1,
+ children: [
+ {
+ path: /^\/container\/capsules\/detail\/.[^/]+$/,
+ name: t('Capsules Detail'),
+ key: 'capsulesDetail',
+ level: 2,
+ routePath: '/container/capsules/detail/:id',
+ },
+ ],
+ },
{
path: '/container-infra/clusters',
name: t('Clusters'),
diff --git a/src/pages/basic/routes/index.js b/src/pages/basic/routes/index.js
index 32bc811d..01e6c2db 100644
--- a/src/pages/basic/routes/index.js
+++ b/src/pages/basic/routes/index.js
@@ -53,6 +53,9 @@ const Share = lazy(() =>
const ContainerInfra = lazy(() =>
import(/* webpackChunkName: "container-infra" */ 'pages/container-infra/App')
);
+const Containers = lazy(() =>
+ import(/* webpackChunkName: "Container" */ 'pages/container-service/App')
+);
const E404 = lazy(() =>
import(/* webpackChunkName: "E404" */ 'pages/base/containers/404')
);
@@ -109,6 +112,10 @@ export default [
path: `/container-infra`,
component: ContainerInfra,
},
+ {
+ path: `/container`,
+ component: Containers,
+ },
{ path: '*', component: E404 },
],
},
diff --git a/src/pages/container-service/App.jsx b/src/pages/container-service/App.jsx
new file mode 100644
index 00000000..014bcad1
--- /dev/null
+++ b/src/pages/container-service/App.jsx
@@ -0,0 +1,21 @@
+// 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 renderRoutes from 'utils/RouterConfig';
+
+import routes from './routes';
+
+const App = (props) => renderRoutes(routes, props);
+
+export default App;
diff --git a/src/pages/container-service/containers/Capsules/Detail/BaseDetail.jsx b/src/pages/container-service/containers/Capsules/Detail/BaseDetail.jsx
new file mode 100644
index 00000000..e7d64587
--- /dev/null
+++ b/src/pages/container-service/containers/Capsules/Detail/BaseDetail.jsx
@@ -0,0 +1,136 @@
+// 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/BaseDetail';
+import React from 'react';
+import { inject, observer } from 'mobx-react';
+
+export class BaseDetail extends Base {
+ get leftCards() {
+ const cards = [this.baseInfoCard, this.containersCard];
+ return cards;
+ }
+
+ get rightCards() {
+ return [this.specCard];
+ }
+
+ get baseInfoCard() {
+ const options = [
+ {
+ label: t('ID'),
+ dataIndex: 'uuid',
+ },
+ {
+ label: t('Name'),
+ dataIndex: 'meta_name',
+ },
+ {
+ label: t('Status'),
+ dataIndex: 'status',
+ },
+ {
+ label: t('Status Reason'),
+ dataIndex: 'status_reason',
+ },
+ {
+ label: t('Created'),
+ dataIndex: 'created_at',
+ },
+ {
+ label: t('Updated'),
+ dataIndex: 'updated_at',
+ },
+ {
+ label: t('Project ID'),
+ dataIndex: 'project_id',
+ },
+ {
+ label: t('User ID'),
+ dataIndex: 'user_id',
+ },
+ ];
+
+ return {
+ title: t('Cluster Type'),
+ options,
+ };
+ }
+
+ get containersCard() {
+ const options = [
+ {
+ label: t('Containers'),
+ dataIndex: 'containers',
+ render: (value) =>
+ value.map((it) => {
+ return (
+
+ Name : {it.name} Container ID : {it.uuid}
+
+ );
+ }),
+ },
+ ];
+
+ return {
+ title: t('Containers'),
+ options,
+ };
+ }
+
+ get specCard() {
+ const options = [
+ {
+ label: t('CPU'),
+ dataIndex: 'cpu',
+ },
+ {
+ label: t('Memory'),
+ dataIndex: 'memory',
+ },
+ {
+ label: t('Restart Policy'),
+ dataIndex: 'restart_policy',
+ },
+ {
+ label: t('Labels'),
+ dataIndex: 'labels',
+ render: (value) => value || ' - ',
+ },
+ {
+ label: t('Links'),
+ dataIndex: 'links',
+ render: (value) =>
+ value.map((it) => {
+ return (
+
+ {it.href} : {it.rel}
+
+ );
+ }),
+ },
+ {
+ label: t('Addresses'),
+ dataIndex: 'addresses',
+ render: (value) => (value.length != null ? value : '-'),
+ },
+ ];
+
+ return {
+ title: t('Spec'),
+ options,
+ };
+ }
+}
+
+export default inject("rootStore")(observer(BaseDetail))
\ No newline at end of file
diff --git a/src/pages/container-service/containers/Capsules/Detail/index.jsx b/src/pages/container-service/containers/Capsules/Detail/index.jsx
new file mode 100644
index 00000000..3fad79a0
--- /dev/null
+++ b/src/pages/container-service/containers/Capsules/Detail/index.jsx
@@ -0,0 +1,57 @@
+// 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 Base from 'containers/TabDetail';
+import BaseDetail from './BaseDetail';
+import globalCapsulesStore from 'src/stores/zun/capsules';
+
+export class CapsulesDetail extends Base {
+ init() {
+ this.store = globalCapsulesStore;
+ }
+
+ get name() {
+ return t('Cluster Template Detail');
+ }
+
+ get listUrl() {
+ return this.getRoutePath('capsules');
+ }
+
+ get policy() {
+ return 'container:capsule:get_one_all_projects';
+ }
+
+ get detailInfos() {
+ return [
+ {
+ title: t('Name'),
+ dataIndex: 'name',
+ },
+ ];
+ }
+
+ get tabs() {
+ return [
+ {
+ title: t('General Info'),
+ key: 'general_info',
+ component: BaseDetail,
+ },
+ ];
+ }
+}
+
+export default inject("rootStore")(observer(CapsulesDetail))
\ No newline at end of file
diff --git a/src/pages/container-service/containers/Capsules/actions/Create.jsx b/src/pages/container-service/containers/Capsules/actions/Create.jsx
new file mode 100644
index 00000000..44fc8663
--- /dev/null
+++ b/src/pages/container-service/containers/Capsules/actions/Create.jsx
@@ -0,0 +1,79 @@
+// 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
+//
+// Unles //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 'src/containers/Action';
+import { getYaml } from 'src/resources/heat/stack';
+import globalCapsulesStore from 'src/stores/zun/capsules';
+
+export class Create extends ModalAction {
+ static id = 'create-capsules';
+
+ static title = t('Create Capsule');
+
+ init() {
+ this.store = globalCapsulesStore;
+ this.maxSize = 1;
+ }
+
+ static allowed = () => Promise.resolve(true);
+
+ static buttonText = t('Create Capsule');
+
+ static get modalSize() {
+ return 'middle';
+ }
+
+ get name() {
+ return t('Create Capsules');
+ }
+
+ static policy = 'container:capsule:create';
+
+ sizeValidate = (rule, value) => {
+ if (!value) {
+ return Promise.reject(t('Please select a file'));
+ }
+ const { size } = value;
+ if (size <= this.maxSize * 1024 * 1024 * 1024) {
+ return Promise.resolve();
+ }
+ return Promise.reject(
+ t(
+ 'Please upload files smaller than { size }G on the page. It is recommended to upload files over { size }G using API.',
+ { size: this.maxSize }
+ )
+ );
+ };
+
+ get formItems() {
+ return [
+ {
+ name: 'template_file',
+ label: t('Load Template from a file'),
+ type: 'textarea-from-file',
+ },
+ ];
+ }
+
+ onSubmit = (values) => {
+ const y = getYaml(values.template_file);
+
+ return this.store.create({
+ template: y,
+ });
+ };
+}
+
+export default inject("rootStore")(observer(Create))
\ No newline at end of file
diff --git a/src/pages/container-service/containers/Capsules/actions/Delete.jsx b/src/pages/container-service/containers/Capsules/actions/Delete.jsx
new file mode 100644
index 00000000..bf5019b1
--- /dev/null
+++ b/src/pages/container-service/containers/Capsules/actions/Delete.jsx
@@ -0,0 +1,41 @@
+// 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 { ConfirmAction } from 'containers/Action';
+import globalCapsulesStore from 'src/stores/zun/capsules';
+
+export class DeleteCapsules extends ConfirmAction {
+ get id() {
+ return 'delete';
+ }
+
+ get title() {
+ return t('Delete Capsules');
+ }
+
+ get actionName() {
+ return t('Delete Capsules');
+ }
+
+ get buttonType() {
+ return 'danger';
+ }
+
+ policy = 'container:capsule:delete';
+
+ allowedCheckFunc = () => true;
+
+ onSubmit = (data) => globalCapsulesStore.delete({ id: data.uuid });
+}
+
+export default inject("rootStore")(observer(DeleteCapsules))
\ No newline at end of file
diff --git a/src/pages/container-service/containers/Capsules/actions/index.jsx b/src/pages/container-service/containers/Capsules/actions/index.jsx
new file mode 100644
index 00000000..4e5e9dc2
--- /dev/null
+++ b/src/pages/container-service/containers/Capsules/actions/index.jsx
@@ -0,0 +1,25 @@
+// 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 Create from './Create';
+import DeleteCapsules from './Delete';
+
+const actionConfigs = {
+ rowActions: {
+ firstAction: DeleteCapsules,
+ },
+ batchActions: [DeleteCapsules],
+ primaryActions: [Create],
+};
+
+export default actionConfigs;
diff --git a/src/pages/container-service/containers/Capsules/index.jsx b/src/pages/container-service/containers/Capsules/index.jsx
new file mode 100644
index 00000000..c6fa6fba
--- /dev/null
+++ b/src/pages/container-service/containers/Capsules/index.jsx
@@ -0,0 +1,64 @@
+// 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 actionConfigs from './actions';
+import globalCapsulesStore from 'src/stores/zun/capsules';
+
+export class Capsules extends Base {
+ init() {
+ this.store = globalCapsulesStore;
+ this.downloadStore = globalCapsulesStore;
+ }
+
+ get name() {
+ return t('capsules');
+ }
+
+ get policy() {
+ return 'container:capsule:get_all';
+ }
+
+ get actionConfigs() {
+ return actionConfigs;
+ }
+
+ getColumns = () => [
+ {
+ title: t('ID/Name'),
+ dataIndex: 'meta_name',
+ isLink: true,
+ routeName: this.getRouteName('capsulesDetail'),
+ idKey: 'uuid',
+ },
+ {
+ title: t('Status'),
+ isHideable: true,
+ dataIndex: 'status',
+ },
+ {
+ title: t('CPU'),
+ isHideable: true,
+ dataIndex: 'cpu',
+ },
+ {
+ title: t('Memory'),
+ isHideable: true,
+ dataIndex: 'memory',
+ },
+ ];
+}
+
+export default inject("rootStore")(observer(Capsules))
\ No newline at end of file
diff --git a/src/pages/container-service/containers/Containers/Detail/BaseDetail.jsx b/src/pages/container-service/containers/Containers/Detail/BaseDetail.jsx
new file mode 100644
index 00000000..7750b530
--- /dev/null
+++ b/src/pages/container-service/containers/Containers/Detail/BaseDetail.jsx
@@ -0,0 +1,183 @@
+// 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/BaseDetail';
+import React from 'react';
+import { inject, observer } from 'mobx-react';
+
+export class BaseDetail extends Base {
+ get leftCards() {
+ const cards = [this.baseInfoCard, this.miscellaneousCard];
+ return cards;
+ }
+
+ get rightCards() {
+ return [this.specCard];
+ }
+
+ get baseInfoCard() {
+ const options = [
+ {
+ label: t('ID'),
+ dataIndex: 'uuid',
+ },
+ {
+ label: t('Name'),
+ dataIndex: 'name',
+ },
+ {
+ label: t('Status'),
+ dataIndex: 'status',
+ },
+ {
+ label: t('Status Detail'),
+ dataIndex: 'status_detail',
+ },
+ {
+ label: t('Status Reason'),
+ dataIndex: 'status_reason',
+ },
+ {
+ label: t('Task State'),
+ dataIndex: 'task_state',
+ },
+ {
+ label: t('Command'),
+ dataIndex: 'command',
+ },
+ ];
+
+ return {
+ title: t('Base Info'),
+ options,
+ };
+ }
+
+ get miscellaneousCard() {
+ const content = (
+
+ },
+ ];
+
+ return {
+ title: t('Spec'),
+ labelCol: 4,
+ options,
+ };
+ }
+}
+
+export default inject("rootStore")(observer(BaseDetail))
\ No newline at end of file
diff --git a/src/pages/container-service/containers/Containers/Detail/index.jsx b/src/pages/container-service/containers/Containers/Detail/index.jsx
new file mode 100644
index 00000000..fffc4370
--- /dev/null
+++ b/src/pages/container-service/containers/Containers/Detail/index.jsx
@@ -0,0 +1,55 @@
+// 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 Base from 'containers/TabDetail';
+import BaseDetail from './BaseDetail';
+import globalContainersStore from 'src/stores/zun/containers';
+
+export class ContainersDetail extends Base {
+ init() {
+ this.store = globalContainersStore;
+ }
+
+ get name() {
+ return t('Containers Detail');
+ }
+
+ get listUrl() {
+ return this.getRoutePath('containers');
+ }
+
+ get policy() {
+ return 'container:container:get_one';
+ }
+
+ get detailInfos() {
+ return [
+ {
+ title: t('Name'),
+ dataIndex: 'name',
+ },
+ ];
+ }
+
+ get tabs() {
+ return [
+ {
+ title: t('General Info'),
+ key: 'general_info',
+ component: BaseDetail,
+ },
+ ];
+ }
+}
+
+export default inject("rootStore")(observer(ContainersDetail))
\ No newline at end of file
diff --git a/src/pages/container-service/containers/Containers/actions/Delete.jsx b/src/pages/container-service/containers/Containers/actions/Delete.jsx
new file mode 100644
index 00000000..1c143bd7
--- /dev/null
+++ b/src/pages/container-service/containers/Containers/actions/Delete.jsx
@@ -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 { ConfirmAction } from 'containers/Action';
+import globalContainersStore from 'src/stores/zun/containers';
+
+export default class DeleteContainers extends ConfirmAction {
+ get id() {
+ return 'delete';
+ }
+
+ get title() {
+ return t('Delete Container')
+ }
+
+ get actionName() {
+ return t('Delete Container');
+ }
+
+ get buttonType() {
+ return 'danger';
+ }
+
+ get buttonText() {
+ return t('Delete');
+ }
+
+ policy = 'container:container:delete';
+
+ allowedCheckFunc = () => true;
+
+ onSubmit = (data) =>
+ globalContainersStore.delete({ id: data.uuid });
+}
diff --git a/src/pages/container-service/containers/Containers/actions/Pause.jsx b/src/pages/container-service/containers/Containers/actions/Pause.jsx
new file mode 100644
index 00000000..6c2bd7dd
--- /dev/null
+++ b/src/pages/container-service/containers/Containers/actions/Pause.jsx
@@ -0,0 +1,34 @@
+// 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 { ConfirmAction } from 'containers/Action';
+import globalContainersStore from 'src/stores/zun/containers';
+
+export default class PauseContainers extends ConfirmAction {
+ get id() {
+ return 'pause';
+ }
+
+ get title() {
+ return t('Pause Container')
+ }
+
+ get actionName() {
+ return t('Pause Container');
+ }
+
+ policy = 'container:container:pause';
+
+ allowedCheckFunc = () => true;
+
+ onSubmit = (data) => globalContainersStore.pause({ id: data.uuid });
+}
diff --git a/src/pages/container-service/containers/Containers/actions/Reboot.jsx b/src/pages/container-service/containers/Containers/actions/Reboot.jsx
new file mode 100644
index 00000000..f3bb8771
--- /dev/null
+++ b/src/pages/container-service/containers/Containers/actions/Reboot.jsx
@@ -0,0 +1,34 @@
+// 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 { ConfirmAction } from 'containers/Action';
+import globalContainersStore from 'src/stores/zun/containers';
+
+export default class RebootContainers extends ConfirmAction {
+ get id() {
+ return 'reboot';
+ }
+
+ get title() {
+ return t('Reboot Container')
+ }
+
+ get actionName() {
+ return t('Reboot Container');
+ }
+
+ policy = 'container:container:reboot';
+
+ allowedCheckFunc = () => true;
+
+ onSubmit = (data) => globalContainersStore.reboot({ id: data.uuid });
+}
diff --git a/src/pages/container-service/containers/Containers/actions/Start.jsx b/src/pages/container-service/containers/Containers/actions/Start.jsx
new file mode 100644
index 00000000..d15365ce
--- /dev/null
+++ b/src/pages/container-service/containers/Containers/actions/Start.jsx
@@ -0,0 +1,34 @@
+// 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 { ConfirmAction } from 'containers/Action';
+import globalContainersStore from 'src/stores/zun/containers';
+
+export default class StartContainers extends ConfirmAction {
+ get id() {
+ return 'start';
+ }
+
+ get title() {
+ return t('Start Container')
+ }
+
+ get actionName() {
+ return t('Start Container');
+ }
+
+ policy = 'container:container:start';
+
+ allowedCheckFunc = () => true;
+
+ onSubmit = (data) => globalContainersStore.start({ id: data.uuid });
+}
diff --git a/src/pages/container-service/containers/Containers/actions/StepCreate/StepInfo/index.jsx b/src/pages/container-service/containers/Containers/actions/StepCreate/StepInfo/index.jsx
new file mode 100644
index 00000000..5ff841da
--- /dev/null
+++ b/src/pages/container-service/containers/Containers/actions/StepCreate/StepInfo/index.jsx
@@ -0,0 +1,68 @@
+// 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 "components/Form";
+import { inject, observer } from "mobx-react";
+
+export class StepInfo extends Base {
+ get title() {
+ return t("Info")
+ }
+
+ get name() {
+ return t("Info")
+ }
+
+ get formItems() {
+ return [
+ {
+ name: "clusterName",
+ label: t("Cluster Name"),
+ type: "input",
+ placeholder: t("Cluster Name"),
+ required: true
+ },
+ {
+ name: "image",
+ label: t("Image"),
+ type: "input",
+ placeholder: t("Name or ID og the container image"),
+ required: true
+ },
+ {
+ name: "imageDriver",
+ label: t("Image Driver"),
+ placeholder: t("Image Driver"),
+ type: "select",
+ options: [
+ {
+ label: t("Docker"),
+ value: "docker"
+ },
+ {
+ label: t("Glance"),
+ value: "glance"
+ }
+ ],
+ allowClear: true
+ },
+ {
+ name: "command",
+ label: t("Command"),
+ type: "input",
+ placeholder: t("A command that will be sent to the container"),
+ },
+ ]
+ }
+}
+
+export default inject('rootStore')(observer(StepInfo));
\ No newline at end of file
diff --git a/src/pages/container-service/containers/Containers/actions/StepCreate/StepMiscellaneous/index.jsx b/src/pages/container-service/containers/Containers/actions/StepCreate/StepMiscellaneous/index.jsx
new file mode 100644
index 00000000..07b21866
--- /dev/null
+++ b/src/pages/container-service/containers/Containers/actions/StepCreate/StepMiscellaneous/index.jsx
@@ -0,0 +1,71 @@
+// 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 "components/Form";
+import { inject, observer } from "mobx-react";
+import KeyValueInput from 'components/FormItem/KeyValueInput';
+
+export class StepMiscellaneous extends Base {
+
+ get title() {
+ return t("Miscellaneous")
+ }
+
+ get name() {
+ return t("Miscellaneous")
+ }
+
+ get formItems() {
+ return [
+ {
+ name: "workingDirectory",
+ label: t("Working Directory"),
+ type: "input",
+ placeholder: t("The working directory for commands to run in")
+ },
+ {
+ name: "environmentVariables",
+ label: t("Environment Variables"),
+ type: 'add-select',
+ itemComponent: KeyValueInput,
+ addText: t('Add Environment Variable'),
+ },
+ {
+ name: "enableInteractiveMode",
+ label: t("Enable interactive mode"),
+ type: "check"
+ },
+ {
+ type: "divider"
+ },
+ {
+ name: "labels",
+ label: t("Labels"),
+ type: 'add-select',
+ itemComponent: KeyValueInput,
+ addText: t('Add Label'),
+ },
+ {
+ type: "divider"
+ },
+ {
+ name: "hints",
+ label: t("Scheduler Hints"),
+ type: "select",
+ mode: "tags",
+ placeholder: t("Type to Scheduler Hints and press enter")
+ }
+ ]
+ }
+}
+
+export default inject('rootStore')(observer(StepMiscellaneous));
\ No newline at end of file
diff --git a/src/pages/container-service/containers/Containers/actions/StepCreate/StepNetworks/index.jsx b/src/pages/container-service/containers/Containers/actions/StepCreate/StepNetworks/index.jsx
new file mode 100644
index 00000000..9560b6d4
--- /dev/null
+++ b/src/pages/container-service/containers/Containers/actions/StepCreate/StepNetworks/index.jsx
@@ -0,0 +1,80 @@
+// 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 { SecurityGroupStore } from 'stores/neutron/security-group';
+import { VirtualAdapterStore } from 'stores/neutron/virtual-adapter';
+import Base from "components/Form";
+import { inject, observer } from "mobx-react";
+import globalNetworkStore from 'src/stores/neutron/network';
+import { portColumns, portFilters } from 'src/resources/neutron/port';
+import { securityGroupColumns, securityGroupFilter } from 'src/resources/neutron/security-group';
+
+export class StepNetworks extends Base {
+
+ init() {
+ this.getNetworkStore();
+ this.portStore = new VirtualAdapterStore();
+ this.securityGroupStore = new SecurityGroupStore();
+ }
+
+ get title() {
+ return t("Networks")
+ }
+
+ get name() {
+ return t("Networks")
+ }
+
+ async getNetworkStore() {
+ await globalNetworkStore.fetchList({ project_id: this.currentProjectId });
+ }
+
+ get networking() {
+ return (globalNetworkStore.list.data || []).map((it) => ({
+ label: it.name,
+ value: it.id,
+ }));
+ }
+
+ get formItems() {
+ return [
+ {
+ name: 'networkSelect',
+ label: t('Networks'),
+ type: 'network-select-table',
+ isMulti: true,
+ },
+ {
+ name: 'ports',
+ type: 'select-table',
+ label: t('Ports'),
+ isMulti: true,
+ columns: portColumns,
+ filterParams: portFilters,
+ backendPageStore: this.portStore,
+ extraParams: { project_id: this.currentProjectId, device_owner: [''], admin_state_up: [true] }
+ },
+ {
+ name: 'securityGroup',
+ label: t('Security Group'),
+ type: 'select-table',
+ backendPageStore: this.securityGroupStore,
+ extraParams: { project_id: this.currentProjectId },
+ columns: securityGroupColumns,
+ filterParams: securityGroupFilter,
+ isMulti: true
+ }
+ ]
+ }
+}
+
+export default inject('rootStore')(observer(StepNetworks));
\ No newline at end of file
diff --git a/src/pages/container-service/containers/Containers/actions/StepCreate/StepSpec/index.jsx b/src/pages/container-service/containers/Containers/actions/StepCreate/StepSpec/index.jsx
new file mode 100644
index 00000000..3a2578a1
--- /dev/null
+++ b/src/pages/container-service/containers/Containers/actions/StepCreate/StepSpec/index.jsx
@@ -0,0 +1,136 @@
+// 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 "components/Form";
+import { inject, observer } from "mobx-react";
+import globalAvailabilityZoneStore from "src/stores/nova/zone";
+
+export class StepSpec extends Base {
+ init() {
+ this.getAvailabilityZones();
+ this.state.isMaxRetry = true;
+ }
+
+ get title() {
+ return t("Spec");
+ }
+
+ get name() {
+ return t("Spec");
+ }
+
+ async getAvailabilityZones() {
+ await globalAvailabilityZoneStore.fetchListWithoutDetail();
+ }
+
+ get getAvailabilityZoneList() {
+ return (globalAvailabilityZoneStore.list.data || []).filter((it) => it.zoneState.available)
+ .map((it) => ({
+ value: it.zoneName,
+ label: it.zoneName,
+ }));
+ }
+
+ onExitPolicyChange(value) {
+ this.setState({ isMaxRetry: value === "on-failure" ? false : true })
+ }
+
+ get formItems() {
+ return [
+ {
+ name: "hostname",
+ label: t("Hostname"),
+ type: "input",
+ placeholder: t("The host name of this container"),
+ },
+ {
+ name: "runtime",
+ label: t("Runtime"),
+ type: "input",
+ placeholder: t("The runtime to create container with"),
+ },
+ {
+ name: "cpu",
+ label: t("CPU"),
+ type: "input-number",
+ placeholder: t("The number of virtual cpu for this container"),
+ min: 1,
+ width: 300
+ },
+ {
+ name: "memory",
+ label: t("Memory"),
+ type: "input-number",
+ placeholder: t("The container memory size in MiB"),
+ min: 4,
+ width: 300
+ },
+ {
+ name: "disk",
+ label: t("Disk"),
+ type: "input-number",
+ placeholder: t("The disk size in GİB for per container"),
+ min: 1,
+ width: 300
+ },
+ {
+ name: "availableZone",
+ label: t("Availability Zone"),
+ type: "select",
+ options: this.getAvailabilityZoneList,
+ allowClear: true,
+ showSearch: true
+ },
+ {
+ name: "exitPolicy",
+ label: t("Exit Policy"),
+ type: "select",
+ options: [
+ {
+ label: t("No"),
+ value: "no"
+ },
+ {
+ label: t("On failure"),
+ value: "on-failure"
+ },
+ {
+ label: t("Always"),
+ value: "always"
+ },
+ {
+ label: t("Unless Stopped"),
+ value: "unless-stopped"
+ },
+ ],
+ onChange: (val) => this.onExitPolicyChange(val),
+ allowClear: true,
+ showSearch: true
+ },
+ {
+ name: "maxRetry",
+ label: t("Max Retry"),
+ type: "input-number",
+ placeholder: t("Retry times for 'Restart on failure' policy"),
+ min: 1,
+ disabled: this.state.isMaxRetry
+ },
+ {
+ name: "enableAutoHeal",
+ label: t("Enable auto heal"),
+ type: "check"
+ }
+ ]
+ }
+}
+
+export default inject('rootStore')(observer(StepSpec));
\ No newline at end of file
diff --git a/src/pages/container-service/containers/Containers/actions/StepCreate/StepVolumes/index.jsx b/src/pages/container-service/containers/Containers/actions/StepCreate/StepVolumes/index.jsx
new file mode 100644
index 00000000..6605acaf
--- /dev/null
+++ b/src/pages/container-service/containers/Containers/actions/StepCreate/StepVolumes/index.jsx
@@ -0,0 +1,52 @@
+// 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 "components/Form";
+import { inject, observer } from "mobx-react";
+import ZunVolume from "src/components/FormItem/ZunVolume";
+import globalVolumeStore from "src/stores/cinder/volume";
+
+export class StepVolumes extends Base {
+
+ init() {
+ this.globalVolumeStore = globalVolumeStore;
+ this.getVolumeStore();
+ }
+
+ get cinderVolume() {
+ return (this.globalVolumeStore.list.data || [])
+ .filter((it) => it.status === 'available')
+ .map((it) => ({
+ value: it.id,
+ label: it.name === '' ? it.id : it.name,
+ }));
+ }
+
+ getVolumeStore() {
+ this.globalVolumeStore.fetchList();
+ }
+
+ get formItems() {
+ return [
+ {
+ name: "mounts",
+ label: t("Type"),
+ type: 'add-select',
+ optionsType: [{ label: "Existing Cinder Volume", value: "cinder-available" }, { label: "New Cinder Volume", value: "cinder-new" }],
+ optionsSource: this.cinderVolume,
+ itemComponent: ZunVolume,
+ },
+ ]
+ }
+}
+
+export default inject('rootStore')(observer(StepVolumes));
\ No newline at end of file
diff --git a/src/pages/container-service/containers/Containers/actions/StepCreate/index.jsx b/src/pages/container-service/containers/Containers/actions/StepCreate/index.jsx
new file mode 100644
index 00000000..b7e073cb
--- /dev/null
+++ b/src/pages/container-service/containers/Containers/actions/StepCreate/index.jsx
@@ -0,0 +1,153 @@
+// 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 StepInfo from './StepInfo';
+import StepSpec from './StepSpec';
+import StepVolumes from './StepVolumes';
+import StepNetworks from './StepNetworks';
+import { inject, observer } from 'mobx-react';
+import StepMiscellaneous from './StepMiscellaneous';
+import { StepAction } from 'src/containers/Action';
+import globalContainersStore from 'src/stores/zun/containers';
+
+export class StepCreate extends StepAction {
+ init() {
+ this.store = globalContainersStore;
+ }
+
+ static id = "create-container";
+
+ static title = t("Create Container (Step)");
+
+ static path = "/container/containers/create";
+
+ static policy = "container:container:create";
+
+ static allowed() {
+ return Promise.resolve(true);
+ }
+
+ get name() {
+ return t("Create Container");
+ }
+
+ get listUrl() {
+ return this.getRoutePath("containers");
+ }
+
+ get hasConfirmStep() {
+ return false;
+ }
+
+ get steps() {
+ return [
+ {
+ title: t("Info"),
+ component: StepInfo
+ },
+ {
+ title: t("Spec"),
+ component: StepSpec
+ },
+ {
+ title: t("Volumes"),
+ component: StepVolumes
+ },
+ {
+ title: t("Network Config"),
+ component: StepNetworks
+ },
+ {
+ title: t("Miscellaneous"),
+ component: StepMiscellaneous
+ }
+ ]
+ }
+
+ onSubmit = (values) => {
+ const { environmentVariables, labels, mounts } = values
+
+ const requestEnviranment = {};
+ const requestLabels = {};
+ const requestValumes = [];
+
+ environmentVariables !== null ? environmentVariables.forEach((item) => {
+ const labelKey = item.value.key.toLowerCase().trim();
+ const labelValue = item.value.value.toLowerCase().trim();
+ requestEnviranment[labelKey] = labelValue;
+ }) : null;
+
+ labels !== null ? labels.forEach((item) => {
+ const key = item.value.key.toLowerCase().trim();
+ const value = item.value.value.toLowerCase().trim();
+ requestLabels[key] = value;
+ }) : null;
+
+ mounts !== null ? mounts.forEach((item) => {
+ const destination = item.value.destination;
+ const source = item.value.source;
+ const type = item.value.type;
+ const cinderVolumeSize = item.value.cinderVolumeSize;
+ item.value.isCinderVolume !== true ? requestValumes.push({
+ destination: destination,
+ source: source,
+ type: type
+ }) : requestValumes.push({
+ destination: destination,
+ cinderVolumeSize: cinderVolumeSize,
+ type: type
+ })
+ }) : null;
+
+ const networks = [];
+ const securityGroups = [];
+
+ values.networkSelect.selectedRowKeys.forEach((item) => {
+ networks.push({ network: item })
+ })
+
+ values.ports.selectedRowKeys.forEach((item) => {
+ networks.push({ port: item })
+ })
+
+ values.securityGroup.selectedRowKeys.forEach((item) => {
+ securityGroups.push(item)
+ })
+
+ return this.store.create({
+ name: values.clusterName,
+ image: values.image,
+ command: values.command,
+ cpu: values.cpu,
+ memory: values.memory,
+ workdir: values.workingDirectory,
+ labels: requestLabels,
+ environment: requestEnviranment,
+ restart_policy: {
+ Name: values.exitPolicy === null ? 'no' : values.exitPolicy,
+ MaximumRetryCount: values.maxRetry === null ? 0 : values.maxRetry,
+ },
+ interactive: values.enableInteractiveMode,
+ image_driver: values.imageDriver,
+ security_groups: securityGroups,
+ nets: networks,
+ runtime: values.runtime,
+ hostname: values.hostname,
+ auto_heal: values.enableAutoHeal,
+ availability_zone: values.availableZone,
+ hints: values.hints,
+ mounts: values.mounts,
+ })
+ }
+}
+
+export default inject('rootStore')(observer(StepCreate));
\ No newline at end of file
diff --git a/src/pages/container-service/containers/Containers/actions/Stop.jsx b/src/pages/container-service/containers/Containers/actions/Stop.jsx
new file mode 100644
index 00000000..a51126e7
--- /dev/null
+++ b/src/pages/container-service/containers/Containers/actions/Stop.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 { ConfirmAction } from 'containers/Action';
+import globalContainersStore from 'src/stores/zun/containers';
+
+export default class StopContainers extends ConfirmAction {
+ get id() {
+ return 'start';
+ }
+
+ get title() {
+ return t('Stop Container')
+ }
+
+ get actionName() {
+ return t('Stop Container');
+ }
+
+ policy = 'container:container:stop';
+
+ allowedCheckFunc = () => true;
+
+ onSubmit = (data) => globalContainersStore.stop({ id: data.uuid });
+}
diff --git a/src/pages/container-service/containers/Containers/actions/Unpause.jsx b/src/pages/container-service/containers/Containers/actions/Unpause.jsx
new file mode 100644
index 00000000..7c73a120
--- /dev/null
+++ b/src/pages/container-service/containers/Containers/actions/Unpause.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 { ConfirmAction } from 'containers/Action';
+import globalContainersStore from 'src/stores/zun/containers';
+
+export default class UnpauseContainers extends ConfirmAction {
+ get id() {
+ return 'Unpause';
+ }
+
+ get title() {
+ return t('Unpause Container')
+ }
+
+ get actionName() {
+ return t('Unpause Container');
+ }
+
+ policy = 'container:container:unpause';
+
+ allowedCheckFunc = () => true;
+
+ onSubmit = (data) => globalContainersStore.unpause({ id: data.uuid });
+}
diff --git a/src/pages/container-service/containers/Containers/actions/index.jsx b/src/pages/container-service/containers/Containers/actions/index.jsx
new file mode 100644
index 00000000..356a2e29
--- /dev/null
+++ b/src/pages/container-service/containers/Containers/actions/index.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 CreateStep from './StepCreate';
+import DeleteContainer from './Delete';
+import PauseContainer from './Pause';
+import RebootContainer from './Reboot';
+import StartContainer from './Start';
+import StopContainer from './Stop';
+import UnpauseContainer from './Unpause';
+
+const actionConfigs = {
+ rowActions: {
+ moreActions: [
+ { action: StartContainer },
+ { action: DeleteContainer },
+ { action: StopContainer },
+ { action: PauseContainer },
+ { action: RebootContainer },
+ { action: UnpauseContainer },
+ ],
+ },
+ batchActions: [DeleteContainer],
+ primaryActions: [CreateStep],
+};
+export default actionConfigs;
diff --git a/src/pages/container-service/containers/Containers/index.jsx b/src/pages/container-service/containers/Containers/index.jsx
new file mode 100644
index 00000000..c9bace7b
--- /dev/null
+++ b/src/pages/container-service/containers/Containers/index.jsx
@@ -0,0 +1,68 @@
+// 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 actionConfigs from './actions';
+import globalContainersStore from 'src/stores/zun/containers';
+
+export class Containers extends Base {
+ init() {
+ this.store = globalContainersStore;
+ this.downloadStore = globalContainersStore;
+ }
+
+ get name() {
+ return t('containers');
+ }
+
+ get policy() {
+ return 'container:container:get_all';
+ }
+
+ get actionConfigs() {
+ return actionConfigs;
+ }
+
+ get rowKey() {
+ return 'uuid';
+ }
+
+ getColumns = () => [
+ {
+ title: t('ID/Name'),
+ dataIndex: 'name',
+ isLink: true,
+ routeName: this.getRouteName('containerDetail'),
+ idKey: 'uuid',
+ },
+ {
+ title: t('Status'),
+ isHideable: true,
+ dataIndex: 'status',
+ },
+ {
+ title: t('Image'),
+ isHideable: true,
+ dataIndex: 'image',
+ },
+ {
+ title: t('Task State'),
+ isHideable: true,
+ dataIndex: 'task_state',
+ },
+ ];
+}
+
+export default inject("rootStore")(observer(Containers))
\ No newline at end of file
diff --git a/src/pages/container-service/routes/index.js b/src/pages/container-service/routes/index.js
new file mode 100644
index 00000000..5b46458d
--- /dev/null
+++ b/src/pages/container-service/routes/index.js
@@ -0,0 +1,51 @@
+// 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 BaseLayout from 'layouts/Basic';
+import E404 from 'pages/base/containers/404';
+import Containers from '../containers/Containers';
+import Capsules from '../containers/Capsules';
+import ContainersDetail from '../containers/Containers/Detail';
+import CapsulesDetail from '../containers/Capsules/Detail';
+import StepCreateContainer from '../containers/Containers/actions/StepCreate';
+
+const PATH = '/container';
+export default [
+ {
+ path: PATH,
+ component: BaseLayout,
+ routes: [
+ // Containers
+ { path: `${PATH}/containers`, component: Containers, exact: true },
+ { path: `${PATH}/containers/create`, component: StepCreateContainer, exact: true },
+ {
+ path: `${PATH}/containers/detail/:id`,
+ component: ContainersDetail,
+ exact: true,
+ },
+ {
+ path: `${PATH}/capsules`,
+ component: Capsules,
+ exact: true,
+ },
+ {
+ path: `${PATH}/capsules/detail/:id`,
+ component: CapsulesDetail,
+ exact: true,
+ },
+ // All
+ { path: '*', component: E404 },
+ ],
+ },
+];
diff --git a/src/stores/zun/capsules.js b/src/stores/zun/capsules.js
new file mode 100644
index 00000000..b787ce65
--- /dev/null
+++ b/src/stores/zun/capsules.js
@@ -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 'stores/base';
+import client from 'client';
+import { action } from 'mobx';
+
+export class CapsulesStore extends Base {
+ get client() {
+ return client.zun.capsules;
+ }
+
+ @action
+ async create(newbody) {
+ return this.client.create(newbody);
+ }
+
+ @action
+ async delete({ id }) {
+ return this.client.delete(id);
+ }
+}
+
+const globalCapsulesStore = new CapsulesStore();
+export default globalCapsulesStore;
diff --git a/src/stores/zun/containers.js b/src/stores/zun/containers.js
new file mode 100644
index 00000000..3ad667ac
--- /dev/null
+++ b/src/stores/zun/containers.js
@@ -0,0 +1,61 @@
+// 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';
+import { action } from 'mobx';
+
+export class ContainersStore extends Base {
+ get client() {
+ return client.zun.containers;
+ }
+
+ @action
+ async create(newbody) {
+ return this.submitting(this.client.create(newbody));
+ }
+
+ @action
+ async delete({ id }) {
+ return this.client.delete(id);
+ }
+
+ @action
+ async start({ id }) {
+ return this.client.start(id);
+ }
+
+ @action
+ async stop({ id }) {
+ return this.client.stop(id);
+ }
+
+ @action
+ async pause({ id }) {
+ return this.client.pause(id);
+ }
+
+ @action
+ async reboot({ id }) {
+ return this.client.reboot(id);
+ }
+
+ @action
+ async unpause({ id }) {
+ return this.client.unpause(id);
+ }
+}
+
+const globalContainersStore = new ContainersStore();
+export default globalContainersStore;
\ No newline at end of file