mirror of https://github.com/kubevela/velaux.git
Compare commits
7 Commits
Author | SHA1 | Date |
---|---|---|
|
2e0b738321 | |
|
8dfeae2cc6 | |
|
171c490d7c | |
|
328a212da8 | |
|
c9006c5faf | |
|
44facaa92a | |
|
0275634270 |
|
@ -40,6 +40,7 @@ jobs:
|
||||||
push: true
|
push: true
|
||||||
build-args: |
|
build-args: |
|
||||||
GITVERSION=git-${{ steps.vars.outputs.git_revision }}
|
GITVERSION=git-${{ steps.vars.outputs.git_revision }}
|
||||||
|
VERSION=${{ steps.get_version.outputs.VERSION }}
|
||||||
tags: |-
|
tags: |-
|
||||||
acr.kubevela.net/oamdev/velaux:${{ steps.get_version.outputs.VERSION }}
|
acr.kubevela.net/oamdev/velaux:${{ steps.get_version.outputs.VERSION }}
|
||||||
oamdev/velaux:${{ steps.get_version.outputs.VERSION }}
|
oamdev/velaux:${{ steps.get_version.outputs.VERSION }}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
FROM node:16-alpine as builder
|
FROM node:16-alpine as builder
|
||||||
|
ARG VERSION
|
||||||
WORKDIR /app/velaux
|
WORKDIR /app/velaux
|
||||||
ADD . .
|
ADD . .
|
||||||
|
ENV VERSION=${VERSION}
|
||||||
RUN apk add --no-cache git && yarn install && yarn build
|
RUN apk add --no-cache git && yarn install && yarn build
|
||||||
RUN rm -rf /app/velaux/build/mock
|
RUN rm -rf /app/velaux/build/mock
|
||||||
|
|
||||||
|
|
|
@ -89,6 +89,9 @@ function getClientEnvironment(publicUrl) {
|
||||||
// which is why it's disabled by default.
|
// which is why it's disabled by default.
|
||||||
// It is defined here so it is available in the webpackHotDevClient.
|
// It is defined here so it is available in the webpackHotDevClient.
|
||||||
FAST_REFRESH: process.env.FAST_REFRESH !== 'false',
|
FAST_REFRESH: process.env.FAST_REFRESH !== 'false',
|
||||||
|
|
||||||
|
// The release version
|
||||||
|
VERSION: process.env.VERSION,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
// Stringify all values so we can feed into webpack DefinePlugin
|
// Stringify all values so we can feed into webpack DefinePlugin
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "valaux",
|
"name": "valaux",
|
||||||
"version": "1.4.0-beta.2",
|
"version": "1.4.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node scripts/start.js",
|
"start": "node scripts/start.js",
|
||||||
|
|
|
@ -116,6 +116,11 @@ export function getPolicyDetail(params: { appName: string; policyName: string })
|
||||||
return get(gurl, params).then((res) => res);
|
return get(gurl, params).then((res) => res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function deletePolicy(params: { appName: string; policyName: string }) {
|
||||||
|
const gurl = `${application}/${params.appName}/policies/${params.policyName}`;
|
||||||
|
return rdelete(gurl, params).then((res) => res);
|
||||||
|
}
|
||||||
|
|
||||||
export function createApplicationTemplate(params: any) {
|
export function createApplicationTemplate(params: any) {
|
||||||
const gurl = isMock
|
const gurl = isMock
|
||||||
? `${createApplicationTemplate_mock}`
|
? `${createApplicationTemplate_mock}`
|
||||||
|
|
|
@ -15,7 +15,6 @@ const Permission = (props: Props) => {
|
||||||
if (!props.userInfo) {
|
if (!props.userInfo) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
console.log(props.request);
|
|
||||||
if (!checkPermission(props.request, props.project, props.userInfo)) {
|
if (!checkPermission(props.request, props.project, props.userInfo)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,4 +127,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.line {
|
||||||
|
line-height: 16px;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ import pod from '../../assets/resources/pod.svg';
|
||||||
import kubevela from '../../assets/KubeVela-01.svg';
|
import kubevela from '../../assets/KubeVela-01.svg';
|
||||||
|
|
||||||
import { Link } from 'dva/router';
|
import { Link } from 'dva/router';
|
||||||
import { Dropdown, Icon, Menu, Tag } from '@b-design/ui';
|
import { Dropdown, Icon, Menu, Tag, Balloon } from '@b-design/ui';
|
||||||
import i18n from '../../i18n';
|
import i18n from '../../i18n';
|
||||||
import { If } from 'tsx-control-statements/components';
|
import { If } from 'tsx-control-statements/components';
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ export interface TreeNode {
|
||||||
|
|
||||||
function renderResourceNode(props: TreeGraphProps, id: string, node: GraphNode) {
|
function renderResourceNode(props: TreeGraphProps, id: string, node: GraphNode) {
|
||||||
const fullName = nodeKey(node);
|
const fullName = nodeKey(node);
|
||||||
return (
|
const graphNode = (
|
||||||
<div
|
<div
|
||||||
key={id}
|
key={id}
|
||||||
onClick={() => props.onNodeClick && props.onNodeClick(fullName)}
|
onClick={() => props.onNodeClick && props.onNodeClick(fullName)}
|
||||||
|
@ -68,7 +68,6 @@ function renderResourceNode(props: TreeGraphProps, id: string, node: GraphNode)
|
||||||
'error-status': node.resource.healthStatus?.statusCode == 'UnHealthy',
|
'error-status': node.resource.healthStatus?.statusCode == 'UnHealthy',
|
||||||
'warning-status': node.resource.healthStatus?.statusCode == 'Progressing',
|
'warning-status': node.resource.healthStatus?.statusCode == 'Progressing',
|
||||||
})}
|
})}
|
||||||
title={describeNode(node)}
|
|
||||||
style={{
|
style={{
|
||||||
left: node.x,
|
left: node.x,
|
||||||
top: node.y,
|
top: node.y,
|
||||||
|
@ -99,17 +98,25 @@ function renderResourceNode(props: TreeGraphProps, id: string, node: GraphNode)
|
||||||
</If>
|
</If>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
return (
|
||||||
|
<Balloon trigger={graphNode}>
|
||||||
|
<div>
|
||||||
|
{describeNode(node).map((line) => {
|
||||||
|
return <p className="line">{line}</p>;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</Balloon>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderAppNode(props: TreeGraphProps, id: string, node: GraphNode) {
|
function renderAppNode(props: TreeGraphProps, id: string, node: GraphNode) {
|
||||||
const fullName = nodeKey(node);
|
const fullName = nodeKey(node);
|
||||||
|
|
||||||
return (
|
const graphNode = (
|
||||||
<div
|
<div
|
||||||
key={id}
|
key={id}
|
||||||
onClick={() => props.onNodeClick && props.onNodeClick(fullName)}
|
onClick={() => props.onNodeClick && props.onNodeClick(fullName)}
|
||||||
className={classNames('graph-node', 'graph-node-app')}
|
className={classNames('graph-node', 'graph-node-app')}
|
||||||
title={describeNode(node)}
|
|
||||||
style={{
|
style={{
|
||||||
left: node.x,
|
left: node.x,
|
||||||
top: node.y,
|
top: node.y,
|
||||||
|
@ -126,12 +133,21 @@ function renderAppNode(props: TreeGraphProps, id: string, node: GraphNode) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
return (
|
||||||
|
<Balloon trigger={graphNode}>
|
||||||
|
<div>
|
||||||
|
{describeNode(node).map((line) => {
|
||||||
|
return <p className="line">{line}</p>;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</Balloon>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderPodNode(props: TreeGraphProps, id: string, node: GraphNode) {
|
function renderPodNode(props: TreeGraphProps, id: string, node: GraphNode) {
|
||||||
const fullName = nodeKey(node);
|
const fullName = nodeKey(node);
|
||||||
const { appName, envName } = props;
|
const { appName, envName } = props;
|
||||||
return (
|
const graphNode = (
|
||||||
<div
|
<div
|
||||||
key={id}
|
key={id}
|
||||||
onClick={() => props.onNodeClick && props.onNodeClick(fullName)}
|
onClick={() => props.onNodeClick && props.onNodeClick(fullName)}
|
||||||
|
@ -139,7 +155,6 @@ function renderPodNode(props: TreeGraphProps, id: string, node: GraphNode) {
|
||||||
'error-status': node.resource.healthStatus?.statusCode == 'UnHealthy',
|
'error-status': node.resource.healthStatus?.statusCode == 'UnHealthy',
|
||||||
'warning-status': node.resource.healthStatus?.statusCode == 'Progressing',
|
'warning-status': node.resource.healthStatus?.statusCode == 'Progressing',
|
||||||
})}
|
})}
|
||||||
title={describeNode(node)}
|
|
||||||
style={{
|
style={{
|
||||||
left: node.x,
|
left: node.x,
|
||||||
top: node.y,
|
top: node.y,
|
||||||
|
@ -172,16 +187,24 @@ function renderPodNode(props: TreeGraphProps, id: string, node: GraphNode) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
return (
|
||||||
|
<Balloon trigger={graphNode}>
|
||||||
|
<div>
|
||||||
|
{describeNode(node).map((line) => {
|
||||||
|
return <p className="line">{line}</p>;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</Balloon>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderClusterNode(props: TreeGraphProps, id: string, node: GraphNode) {
|
function renderClusterNode(props: TreeGraphProps, id: string, node: GraphNode) {
|
||||||
const fullName = nodeKey(node);
|
const fullName = nodeKey(node);
|
||||||
|
|
||||||
return (
|
const graphNode = (
|
||||||
<div
|
<div
|
||||||
onClick={() => props.onNodeClick && props.onNodeClick(fullName)}
|
onClick={() => props.onNodeClick && props.onNodeClick(fullName)}
|
||||||
className={classNames('graph-node', 'graph-node-cluster')}
|
className={classNames('graph-node', 'graph-node-cluster')}
|
||||||
title={describeCluster(node)}
|
|
||||||
style={{
|
style={{
|
||||||
left: node.x,
|
left: node.x,
|
||||||
top: node.y,
|
top: node.y,
|
||||||
|
@ -198,6 +221,15 @@ function renderClusterNode(props: TreeGraphProps, id: string, node: GraphNode) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
return (
|
||||||
|
<Balloon trigger={graphNode}>
|
||||||
|
<div>
|
||||||
|
{describeCluster(node).map((line) => {
|
||||||
|
return <p className="line">{line}</p>;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</Balloon>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setNode(graph: dagre.graphlib.Graph<GraphNode, GraphEdge>, node: TreeNode) {
|
function setNode(graph: dagre.graphlib.Graph<GraphNode, GraphEdge>, node: TreeNode) {
|
||||||
|
|
|
@ -50,7 +50,7 @@ export function describeNode(node: GraphNode) {
|
||||||
if (node.resource.healthStatus?.reason) {
|
if (node.resource.healthStatus?.reason) {
|
||||||
lines.push(`Reason: ${node.resource.healthStatus?.reason}`);
|
lines.push(`Reason: ${node.resource.healthStatus?.reason}`);
|
||||||
}
|
}
|
||||||
if (node.resource.kind === 'Service') {
|
if (node.resource.kind === 'Service' && node.resource.additionalInfo?.EIP) {
|
||||||
lines.push(`EIP: ${node.resource.additionalInfo?.EIP}`);
|
lines.push(`EIP: ${node.resource.additionalInfo?.EIP}`);
|
||||||
}
|
}
|
||||||
if (node.resource.kind === 'Pod') {
|
if (node.resource.kind === 'Pod') {
|
||||||
|
@ -58,12 +58,12 @@ export function describeNode(node: GraphNode) {
|
||||||
lines.push(`Ready: ${node.resource.additionalInfo?.Ready}`);
|
lines.push(`Ready: ${node.resource.additionalInfo?.Ready}`);
|
||||||
lines.push(`Restarts: ${node.resource.additionalInfo?.Restarts}`);
|
lines.push(`Restarts: ${node.resource.additionalInfo?.Restarts}`);
|
||||||
}
|
}
|
||||||
return lines.join('\n');
|
return lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function describeCluster(node: GraphNode) {
|
export function describeCluster(node: GraphNode) {
|
||||||
const lines = [`Cluster: ${node.resource.name}`];
|
const lines = [`Cluster: ${node.resource.name}`];
|
||||||
return lines.join('\n');
|
return lines;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function treeNodeKey(node: TreeNode & { uid?: string }) {
|
export function treeNodeKey(node: TreeNode & { uid?: string }) {
|
||||||
|
|
|
@ -4,7 +4,9 @@ import { Upload, Button, Icon, Message } from '@b-design/ui';
|
||||||
import DefinitionCode from '../../components/DefinitionCode';
|
import DefinitionCode from '../../components/DefinitionCode';
|
||||||
import Translation from '../../components/Translation';
|
import Translation from '../../components/Translation';
|
||||||
import * as yaml from 'js-yaml';
|
import * as yaml from 'js-yaml';
|
||||||
|
import { v4 as uuid } from 'uuid';
|
||||||
import { If } from 'tsx-control-statements/components';
|
import { If } from 'tsx-control-statements/components';
|
||||||
|
import type { KubernetesObject } from './objects';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
value: any;
|
value: any;
|
||||||
|
@ -15,6 +17,7 @@ type Props = {
|
||||||
type State = {
|
type State = {
|
||||||
message: string;
|
message: string;
|
||||||
containerId: string;
|
containerId: string;
|
||||||
|
showButton: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
class K8sObjectsCode extends React.Component<Props, State> {
|
class K8sObjectsCode extends React.Component<Props, State> {
|
||||||
|
@ -23,7 +26,8 @@ class K8sObjectsCode extends React.Component<Props, State> {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
message: '',
|
message: '',
|
||||||
containerId: Date.now().toString(),
|
containerId: uuid(),
|
||||||
|
showButton: false,
|
||||||
};
|
};
|
||||||
this.form = new Field(this, {
|
this.form = new Field(this, {
|
||||||
onChange: () => {
|
onChange: () => {
|
||||||
|
@ -37,17 +41,20 @@ class K8sObjectsCode extends React.Component<Props, State> {
|
||||||
const { value } = this.props;
|
const { value } = this.props;
|
||||||
this.setValues(value);
|
this.setValues(value);
|
||||||
};
|
};
|
||||||
componentWillReceiveProps(nextProps: Props) {
|
|
||||||
const { value } = nextProps;
|
|
||||||
if (value !== this.props.value) {
|
|
||||||
this.setValues(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setValues = (value: any) => {
|
setValues = (value: KubernetesObject[]) => {
|
||||||
if (value) {
|
if (value) {
|
||||||
try {
|
try {
|
||||||
const code = yaml.dump(value);
|
let code = '---\n';
|
||||||
|
if (value instanceof Array) {
|
||||||
|
value.map((res) => {
|
||||||
|
if (res) {
|
||||||
|
code = code + yaml.dump(res) + '---\n';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
code = yaml.dump(value) + '---\n';
|
||||||
|
}
|
||||||
this.form.setValues({ code: code });
|
this.form.setValues({ code: code });
|
||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
|
@ -57,10 +64,11 @@ class K8sObjectsCode extends React.Component<Props, State> {
|
||||||
const { onChange, value } = this.props;
|
const { onChange, value } = this.props;
|
||||||
if (onChange) {
|
if (onChange) {
|
||||||
try {
|
try {
|
||||||
let object = yaml.load(v);
|
let object: any = yaml.load(v);
|
||||||
if (!(object instanceof Array)) {
|
if (!(object instanceof Array)) {
|
||||||
object = [object];
|
object = [object];
|
||||||
}
|
}
|
||||||
|
object = object.filter((ob: any) => ob != null);
|
||||||
if (yaml.dump(value) != v) {
|
if (yaml.dump(value) != v) {
|
||||||
onChange(object);
|
onChange(object);
|
||||||
}
|
}
|
||||||
|
@ -68,11 +76,14 @@ class K8sObjectsCode extends React.Component<Props, State> {
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
if ((error.message = 'expected a single document in the stream, but found more')) {
|
if ((error.message = 'expected a single document in the stream, but found more')) {
|
||||||
try {
|
try {
|
||||||
const objects = yaml.loadAll(v);
|
let objects = yaml.loadAll(v);
|
||||||
if (yaml.dump(value) != v) {
|
if (yaml.dump(value) != v) {
|
||||||
|
objects = objects.filter((ob: any) => ob != null);
|
||||||
onChange(objects);
|
onChange(objects);
|
||||||
}
|
}
|
||||||
this.setState({ message: '' });
|
this.setState({
|
||||||
|
message: '',
|
||||||
|
});
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
this.setState({ message: err.message });
|
this.setState({ message: err.message });
|
||||||
}
|
}
|
||||||
|
@ -96,15 +107,25 @@ class K8sObjectsCode extends React.Component<Props, State> {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onConvert2WebService = () => {};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { id } = this.props;
|
const { id } = this.props;
|
||||||
const { init } = this.form;
|
const { init } = this.form;
|
||||||
const { message, containerId } = this.state;
|
const { message, containerId, showButton } = this.state;
|
||||||
return (
|
return (
|
||||||
<div id={id}>
|
<div id={id}>
|
||||||
<If condition={message}>
|
<If condition={message}>
|
||||||
<span style={{ color: 'red' }}>{message}</span>
|
<span style={{ color: 'red' }}>{message}</span>
|
||||||
</If>
|
</If>
|
||||||
|
|
||||||
|
<Message type="notice" style={{ marginTop: '16px' }}>
|
||||||
|
<Translation>
|
||||||
|
The input data will be automatically formatted. Ensure that the input data is a valid
|
||||||
|
k8s resource YAML.
|
||||||
|
</Translation>
|
||||||
|
</Message>
|
||||||
|
|
||||||
<Upload request={this.customRequest}>
|
<Upload request={this.customRequest}>
|
||||||
<Button text type="normal" className="padding-left-0">
|
<Button text type="normal" className="padding-left-0">
|
||||||
<Icon type="cloudupload" />
|
<Icon type="cloudupload" />
|
||||||
|
@ -120,12 +141,19 @@ class K8sObjectsCode extends React.Component<Props, State> {
|
||||||
{...init('code')}
|
{...init('code')}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Message type="notice" style={{ marginTop: '16px' }}>
|
|
||||||
|
<If condition={showButton}>
|
||||||
|
<div style={{ marginTop: '16px' }}>
|
||||||
|
<span style={{ fontSize: '14px', color: '#000', marginRight: '16px' }}>
|
||||||
<Translation>
|
<Translation>
|
||||||
The input data will be automatically formatted. Ensure that the input data is a valid
|
Convert the kubernetes resource component to the webservice component?
|
||||||
k8s resource YAML.
|
|
||||||
</Translation>
|
</Translation>
|
||||||
</Message>
|
</span>
|
||||||
|
<Button type="secondary" onClick={this.onConvert2WebService}>
|
||||||
|
Yes
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</If>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
import type { ResourceObject } from '../../interface/observation';
|
||||||
|
|
||||||
|
export interface KubernetesObject extends ResourceObject {
|
||||||
|
apiVersion: string;
|
||||||
|
kind: string;
|
||||||
|
spec?: Record<string, any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isDeployment(object: KubernetesObject): boolean {
|
||||||
|
return object.kind === 'Deployment';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isShowConvertButton(objects: KubernetesObject[]): boolean {
|
||||||
|
return objects.filter((ob) => isDeployment(ob)).length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildWebServiceBaseDeployment(object: KubernetesObject): Record<string, any> {
|
||||||
|
return {
|
||||||
|
image: object.spec?.containers[0].image,
|
||||||
|
ports: [],
|
||||||
|
readinessProbe: {},
|
||||||
|
livenessProbe: {},
|
||||||
|
env: [],
|
||||||
|
memory: '',
|
||||||
|
cpu: '',
|
||||||
|
};
|
||||||
|
}
|
|
@ -42,9 +42,12 @@ class PolicySelect extends React.Component<Props, State> {
|
||||||
})
|
})
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res && res.policies) {
|
if (res && res.policies) {
|
||||||
const policyListData = (res.policies || []).map(
|
const policyListData = (res.policies || []).map((item: ApplicationPolicyBase) => {
|
||||||
(item: ApplicationPolicyBase) => `${item.name}(${item.type})`,
|
return {
|
||||||
);
|
label: `${item.name}(${item.type})`,
|
||||||
|
value: item.name,
|
||||||
|
};
|
||||||
|
});
|
||||||
this.setState({
|
this.setState({
|
||||||
policySelectDataSource: policyListData,
|
policySelectDataSource: policyListData,
|
||||||
});
|
});
|
||||||
|
|
|
@ -93,6 +93,8 @@ export interface Metadata {
|
||||||
resourceVersion: string;
|
resourceVersion: string;
|
||||||
selfLink: string;
|
selfLink: string;
|
||||||
uid: string;
|
uid: string;
|
||||||
|
annotations?: Record<string, string>;
|
||||||
|
labels?: Record<string, string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ManagedFields {
|
export interface ManagedFields {
|
||||||
|
@ -111,28 +113,22 @@ export interface CloudResource {
|
||||||
status: string;
|
status: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Configuration {
|
export interface Configuration extends ResourceObject {
|
||||||
apiVersion: string;
|
apiVersion: string;
|
||||||
kind: string;
|
kind: string;
|
||||||
metadata: {
|
|
||||||
name: string;
|
|
||||||
namespace: string;
|
|
||||||
creationTimestamp: string;
|
|
||||||
annotations: any;
|
|
||||||
labels: any;
|
|
||||||
};
|
|
||||||
spec: {
|
spec: {
|
||||||
region: string;
|
|
||||||
providerRef: {
|
providerRef: {
|
||||||
name: string;
|
name: string;
|
||||||
namespace: string;
|
namespace: string;
|
||||||
};
|
};
|
||||||
|
region?: string;
|
||||||
};
|
};
|
||||||
status?: {
|
status?: {
|
||||||
apply?: {
|
apply?: {
|
||||||
outputs?: any;
|
outputs?: any;
|
||||||
state?: string;
|
state?: string;
|
||||||
message?: string;
|
message?: string;
|
||||||
|
region?: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,13 @@ class TabsContent extends Component<Props, State> {
|
||||||
payload: { appName: appName },
|
payload: { appName: appName },
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
loadApplicationPolicies = async () => {
|
||||||
|
const { appName } = this.props;
|
||||||
|
this.props.dispatch({
|
||||||
|
type: 'application/getApplicationPolicies',
|
||||||
|
payload: { appName: appName },
|
||||||
|
});
|
||||||
|
};
|
||||||
render() {
|
render() {
|
||||||
const { activeKey, applicationDetail, envbinding } = this.props;
|
const { activeKey, applicationDetail, envbinding } = this.props;
|
||||||
const { visibleEnvPlan } = this.state;
|
const { visibleEnvPlan } = this.state;
|
||||||
|
@ -128,6 +135,7 @@ class TabsContent extends Component<Props, State> {
|
||||||
onOK={() => {
|
onOK={() => {
|
||||||
this.loadEnvbinding();
|
this.loadEnvbinding();
|
||||||
this.loadApplicationWorkflows();
|
this.loadApplicationWorkflows();
|
||||||
|
this.loadApplicationPolicies();
|
||||||
this.setState({ visibleEnvPlan: false });
|
this.setState({ visibleEnvPlan: false });
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -65,6 +65,8 @@ const LeftMenu = (props: Props) => {
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const releaseVersion = process.env.VERSION || version;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ position: 'relative', height: '100%' }}>
|
<div style={{ position: 'relative', height: '100%' }}>
|
||||||
<div className="slide-wrapper">
|
<div className="slide-wrapper">
|
||||||
|
@ -74,7 +76,7 @@ const LeftMenu = (props: Props) => {
|
||||||
align="t"
|
align="t"
|
||||||
trigger={
|
trigger={
|
||||||
<div className="nav-container">
|
<div className="nav-container">
|
||||||
{version}-{__COMMIT_HASH__}
|
{releaseVersion}-{__COMMIT_HASH__}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|
|
@ -75,7 +75,7 @@ export function getLeftSlider(pathname) {
|
||||||
link: '/definitions',
|
link: '/definitions',
|
||||||
iconType: 'database-set',
|
iconType: 'database-set',
|
||||||
navName: 'Definitions',
|
navName: 'Definitions',
|
||||||
permission: { resource: 'definition:*', action: 'update' },
|
permission: { resource: 'definition:*', action: 'list' },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
@ -552,5 +552,6 @@
|
||||||
"Your component type does not support the image field, and the image update cannot be performed": "选择的组件不存在 image 字段,无法进行镜像更新",
|
"Your component type does not support the image field, and the image update cannot be performed": "选择的组件不存在 image 字段,无法进行镜像更新",
|
||||||
"Please select a component": "请选择一个组件",
|
"Please select a component": "请选择一个组件",
|
||||||
"Please select a workflow": "请选择一个工作流",
|
"Please select a workflow": "请选择一个工作流",
|
||||||
"Please select a payloadType": "请选择请求体类型,不同的外部系统请求参数类型具有差异"
|
"Please select a payloadType": "请选择请求体类型,不同的外部系统请求参数类型具有差异",
|
||||||
|
"Resource Graph": "资源拓扑图"
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { Card, Dialog, Grid } from '@b-design/ui';
|
import { Card, Dialog, Grid, Icon } from '@b-design/ui';
|
||||||
import type {
|
import type {
|
||||||
ApplicationDetail,
|
ApplicationDetail,
|
||||||
ApplicationPolicyBase,
|
ApplicationPolicyBase,
|
||||||
|
@ -12,6 +12,7 @@ import Empty from '../../../../components/Empty';
|
||||||
import Translation from '../../../../components/Translation';
|
import Translation from '../../../../components/Translation';
|
||||||
import locale from '../../../../utils/locale';
|
import locale from '../../../../utils/locale';
|
||||||
import Item from '../../../../components/Item';
|
import Item from '../../../../components/Item';
|
||||||
|
import Permission from '../../../../components/Permission';
|
||||||
// import Permission from '../../../../components/Permission';
|
// import Permission from '../../../../components/Permission';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -43,13 +44,13 @@ class PolicyList extends Component<Props, State> {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { Row, Col } = Grid;
|
const { Row, Col } = Grid;
|
||||||
const { policies, envbinding } = this.props;
|
const { policies, envbinding, applicationDetail } = this.props;
|
||||||
const envNameAlias: any = {};
|
const envNameAlias: any = {};
|
||||||
envNameAlias[''] = '-';
|
envNameAlias[''] = '-';
|
||||||
envbinding?.map((item) => {
|
envbinding?.map((item) => {
|
||||||
envNameAlias[item.name] = item.alias;
|
envNameAlias[item.name] = item.alias;
|
||||||
});
|
});
|
||||||
//const projectName = applicationDetail && applicationDetail.project?.name;
|
const projectName = applicationDetail && applicationDetail.project?.name;
|
||||||
return (
|
return (
|
||||||
<div className="list-warper">
|
<div className="list-warper">
|
||||||
<div className="box">
|
<div className="box">
|
||||||
|
@ -63,7 +64,7 @@ class PolicyList extends Component<Props, State> {
|
||||||
{item.alias ? `${item.alias}(${item.name})` : item.name}
|
{item.alias ? `${item.alias}(${item.name})` : item.name}
|
||||||
{/* </a> */}
|
{/* </a> */}
|
||||||
</div>
|
</div>
|
||||||
{/* <div className="trigger-list-operation">
|
<div className="trigger-list-operation">
|
||||||
<Permission
|
<Permission
|
||||||
request={{
|
request={{
|
||||||
resource: `project:${projectName}/application/policy:${item.name}`,
|
resource: `project:${projectName}/application/policy:${item.name}`,
|
||||||
|
@ -80,7 +81,7 @@ class PolicyList extends Component<Props, State> {
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Permission>
|
</Permission>
|
||||||
</div> */}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="policy-list-content">
|
<div className="policy-list-content">
|
||||||
<Row wrap={true}>
|
<Row wrap={true}>
|
||||||
|
|
|
@ -10,6 +10,7 @@ import {
|
||||||
deleteComponent,
|
deleteComponent,
|
||||||
getComponentDefinitions,
|
getComponentDefinitions,
|
||||||
deleteApplicationPlan,
|
deleteApplicationPlan,
|
||||||
|
deletePolicy,
|
||||||
} from '../../api/application';
|
} from '../../api/application';
|
||||||
import Translation from '../../components/Translation';
|
import Translation from '../../components/Translation';
|
||||||
import Title from '../../components/Title';
|
import Title from '../../components/Title';
|
||||||
|
@ -370,6 +371,26 @@ class ApplicationConfig extends Component<Props, State> {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onDeletePolicy = (policyName: string) => {
|
||||||
|
const { appName } = this.state;
|
||||||
|
deletePolicy({ appName: appName, policyName: policyName }).then((re) => {
|
||||||
|
if (re) {
|
||||||
|
Message.success('Application policy deleted successfully');
|
||||||
|
this.loadApplicationPolicies();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
loadApplicationPolicies = async () => {
|
||||||
|
const {
|
||||||
|
params: { appName },
|
||||||
|
} = this.props.match;
|
||||||
|
this.props.dispatch({
|
||||||
|
type: 'application/getApplicationPolicies',
|
||||||
|
payload: { appName: appName },
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { applicationDetail, workflows, components, policies, envbinding } = this.props;
|
const { applicationDetail, workflows, components, policies, envbinding } = this.props;
|
||||||
const {
|
const {
|
||||||
|
@ -555,7 +576,7 @@ class ApplicationConfig extends Component<Props, State> {
|
||||||
policies={policies}
|
policies={policies}
|
||||||
envbinding={envbinding}
|
envbinding={envbinding}
|
||||||
onDeletePolicy={(name: string) => {
|
onDeletePolicy={(name: string) => {
|
||||||
console.log(name);
|
this.onDeletePolicy(name);
|
||||||
}}
|
}}
|
||||||
onShowPolicy={(name: string) => {
|
onShowPolicy={(name: string) => {
|
||||||
console.log(name);
|
console.log(name);
|
||||||
|
|
|
@ -15,7 +15,7 @@ import type {
|
||||||
} from '../../../../interface/application';
|
} from '../../../../interface/application';
|
||||||
import { If } from 'tsx-control-statements/components';
|
import { If } from 'tsx-control-statements/components';
|
||||||
import locale from '../../../../utils/locale';
|
import locale from '../../../../utils/locale';
|
||||||
import { Link } from 'dva/router';
|
import { Link, routerRedux } from 'dva/router';
|
||||||
import i18n from 'i18next';
|
import i18n from 'i18next';
|
||||||
import Permission from '../../../../components/Permission';
|
import Permission from '../../../../components/Permission';
|
||||||
|
|
||||||
|
@ -113,13 +113,14 @@ class Header extends Component<Props, State> {
|
||||||
Dialog.confirm({
|
Dialog.confirm({
|
||||||
content: i18n.t('Are you sure you want to delete the current environment binding?'),
|
content: i18n.t('Are you sure you want to delete the current environment binding?'),
|
||||||
onOk: () => {
|
onOk: () => {
|
||||||
const { applicationDetail, envName, updateEnvs } = this.props;
|
const { applicationDetail, envName, updateEnvs, dispatch } = this.props;
|
||||||
if (applicationDetail) {
|
if (applicationDetail) {
|
||||||
deleteApplicationEnvbinding({ appName: applicationDetail.name, envName: envName }).then(
|
deleteApplicationEnvbinding({ appName: applicationDetail.name, envName: envName }).then(
|
||||||
(re) => {
|
(re) => {
|
||||||
if (re) {
|
if (re) {
|
||||||
Message.success(i18n.t('Environment binding deleted successfully'));
|
Message.success(i18n.t('Environment binding deleted successfully'));
|
||||||
updateEnvs();
|
updateEnvs();
|
||||||
|
dispatch(routerRedux.push(`/applications/${applicationDetail.name}/config`));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -99,7 +99,7 @@ class PodDetail extends React.Component<Props, State> {
|
||||||
this.setState({ showContainerLog: true, containerName: containerName });
|
this.setState({ showContainerLog: true, containerName: containerName });
|
||||||
};
|
};
|
||||||
|
|
||||||
getContainerCloumns = () => {
|
getContainerColumns = () => {
|
||||||
const { observability } = this.state;
|
const { observability } = this.state;
|
||||||
const { clusterName, env, pod, application } = this.props;
|
const { clusterName, env, pod, application } = this.props;
|
||||||
let domain = '';
|
let domain = '';
|
||||||
|
@ -244,7 +244,7 @@ class PodDetail extends React.Component<Props, State> {
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
getEventCloumns = () => {
|
getEventColumns = () => {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
key: 'type',
|
key: 'type',
|
||||||
|
@ -282,15 +282,15 @@ class PodDetail extends React.Component<Props, State> {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { Column } = Table;
|
const { Column } = Table;
|
||||||
const containerColumns = this.getContainerCloumns();
|
const containerColumns = this.getContainerColumns();
|
||||||
const eventCloumns = this.getEventCloumns();
|
const eventColumns = this.getEventColumns();
|
||||||
const { events, containers, loading, showContainerLog, containerName } = this.state;
|
const { events, containers, loading, showContainerLog, containerName } = this.state;
|
||||||
const { pod, clusterName } = this.props;
|
const { pod, clusterName } = this.props;
|
||||||
return (
|
return (
|
||||||
<div className="table-podDetails-list margin-top-20">
|
<div className="table-podDetails-list margin-top-20">
|
||||||
<Table
|
<Table
|
||||||
className="container-table-wraper margin-top-20"
|
className="container-table-wrapper margin-top-20"
|
||||||
dataSource={containers}
|
dataSource={containers || []}
|
||||||
hasBorder={false}
|
hasBorder={false}
|
||||||
primaryKey="name"
|
primaryKey="name"
|
||||||
loading={loading}
|
loading={loading}
|
||||||
|
@ -301,15 +301,15 @@ class PodDetail extends React.Component<Props, State> {
|
||||||
</Table>
|
</Table>
|
||||||
|
|
||||||
<Table
|
<Table
|
||||||
className="event-table-wraper margin-top-20"
|
className="event-table-wrapper margin-top-20"
|
||||||
dataSource={events}
|
dataSource={events || []}
|
||||||
hasBorder={false}
|
hasBorder={false}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
primaryKey="time"
|
primaryKey="time"
|
||||||
locale={locale().Table}
|
locale={locale().Table}
|
||||||
>
|
>
|
||||||
{eventCloumns &&
|
{eventColumns &&
|
||||||
eventCloumns.map((col, key) => <Column {...col} key={key} align={'left'} />)}
|
eventColumns.map((col, key) => <Column {...col} key={key} align={'left'} />)}
|
||||||
</Table>
|
</Table>
|
||||||
|
|
||||||
<If condition={showContainerLog}>
|
<If condition={showContainerLog}>
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
.podlist-table-wraper {
|
.podlist-table-wrapper {
|
||||||
.next-table-cell.last .next-table-cell-wrapper {
|
.next-table-cell.last .next-table-cell-wrapper {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.container-table-wraper {
|
.container-table-wrapper {
|
||||||
.next-table-cell.last .next-table-cell-wrapper {
|
.next-table-cell.last .next-table-cell-wrapper {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.event-table-wraper {
|
.event-table-wrapper {
|
||||||
.next-table-cell.last .next-table-cell-wrapper {
|
.next-table-cell.last .next-table-cell-wrapper {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
|
@ -184,10 +184,15 @@ class ApplicationInstanceList extends React.Component<Props, State> {
|
||||||
const instances: CloudInstance[] = [];
|
const instances: CloudInstance[] = [];
|
||||||
if (Array.isArray(configurations) && configurations.length > 0) {
|
if (Array.isArray(configurations) && configurations.length > 0) {
|
||||||
configurations.map((configuration) => {
|
configurations.map((configuration) => {
|
||||||
let url = configuration.metadata.annotations['cloud-resource/console-url'];
|
let url = '';
|
||||||
const identifierKey = configuration.metadata.annotations['cloud-resource/identifier'];
|
let identifierKey = '';
|
||||||
|
if (configuration.metadata.annotations) {
|
||||||
|
url = configuration.metadata.annotations['cloud-resource/console-url'];
|
||||||
|
identifierKey = configuration.metadata.annotations['cloud-resource/identifier'];
|
||||||
|
}
|
||||||
const outputs = configuration.status?.apply?.outputs;
|
const outputs = configuration.status?.apply?.outputs;
|
||||||
let instanceName = '';
|
let instanceName = '';
|
||||||
|
const region = configuration.status?.apply?.region || configuration.spec.region || '';
|
||||||
if (outputs) {
|
if (outputs) {
|
||||||
if (outputs[identifierKey]) {
|
if (outputs[identifierKey]) {
|
||||||
instanceName = outputs[identifierKey].value;
|
instanceName = outputs[identifierKey].value;
|
||||||
|
@ -197,8 +202,8 @@ class ApplicationInstanceList extends React.Component<Props, State> {
|
||||||
if (Array.isArray(params) && params.length > 0) {
|
if (Array.isArray(params) && params.length > 0) {
|
||||||
params.map((param) => {
|
params.map((param) => {
|
||||||
const paramKey = param.replace('{', '').replace('}', '');
|
const paramKey = param.replace('{', '').replace('}', '');
|
||||||
if (paramKey.toLowerCase() == 'region' && configuration.spec.region) {
|
if (paramKey.toLowerCase() == 'region' && region) {
|
||||||
url = url.replace(param, configuration.spec.region);
|
url = url.replace(param, region);
|
||||||
}
|
}
|
||||||
if (outputs[paramKey]) {
|
if (outputs[paramKey]) {
|
||||||
url = url.replace(param, outputs[paramKey].value);
|
url = url.replace(param, outputs[paramKey].value);
|
||||||
|
@ -209,12 +214,13 @@ class ApplicationInstanceList extends React.Component<Props, State> {
|
||||||
}
|
}
|
||||||
instances.push({
|
instances.push({
|
||||||
instanceName: instanceName,
|
instanceName: instanceName,
|
||||||
status: configuration.status?.apply?.state || 'Initing',
|
status: configuration.status?.apply?.state || '-',
|
||||||
url: url,
|
url: url,
|
||||||
createTime: configuration.metadata.creationTimestamp,
|
createTime: configuration.metadata.creationTimestamp || '',
|
||||||
region: configuration.spec.region,
|
region: region,
|
||||||
message: configuration.status?.apply?.message,
|
message: configuration.status?.apply?.message,
|
||||||
type: configuration.metadata.labels['workload.oam.dev/type'],
|
type:
|
||||||
|
configuration.metadata.labels && configuration.metadata.labels['workload.oam.dev/type'],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -549,11 +555,11 @@ class ApplicationInstanceList extends React.Component<Props, State> {
|
||||||
<Table
|
<Table
|
||||||
style={{ marginBottom: '32px' }}
|
style={{ marginBottom: '32px' }}
|
||||||
locale={locale().Table}
|
locale={locale().Table}
|
||||||
className="podlist-table-wraper"
|
className="podlist-table-wrapper"
|
||||||
size="medium"
|
size="medium"
|
||||||
primaryKey={'primaryKey'}
|
primaryKey={'primaryKey'}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
dataSource={podList}
|
dataSource={podList || []}
|
||||||
expandedIndexSimulate
|
expandedIndexSimulate
|
||||||
expandedRowRender={expandedRowRender}
|
expandedRowRender={expandedRowRender}
|
||||||
openRowKeys={this.state.openRowKeys}
|
openRowKeys={this.state.openRowKeys}
|
||||||
|
|
|
@ -3,12 +3,17 @@ import React from 'react';
|
||||||
import { If } from 'tsx-control-statements/components';
|
import { If } from 'tsx-control-statements/components';
|
||||||
import type { TreeNode } from '../../../../components/TreeGraph';
|
import type { TreeNode } from '../../../../components/TreeGraph';
|
||||||
import { TreeGraph } from '../../../../components/TreeGraph';
|
import { TreeGraph } from '../../../../components/TreeGraph';
|
||||||
import type { ApplicationDetail, EnvBinding } from '../../../../interface/application';
|
import type {
|
||||||
|
ApplicationDetail,
|
||||||
|
ApplicationStatus,
|
||||||
|
EnvBinding,
|
||||||
|
} from '../../../../interface/application';
|
||||||
import type { AppliedResource, ResourceTreeNode } from '../../../../interface/observation';
|
import type { AppliedResource, ResourceTreeNode } from '../../../../interface/observation';
|
||||||
import { ShowResource } from './resource-show';
|
import { ShowResource } from './resource-show';
|
||||||
import './index.less';
|
import './index.less';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
applicationStatus?: ApplicationStatus;
|
||||||
application?: ApplicationDetail;
|
application?: ApplicationDetail;
|
||||||
env?: EnvBinding;
|
env?: EnvBinding;
|
||||||
resources: AppliedResource[];
|
resources: AppliedResource[];
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {
|
||||||
Message,
|
Message,
|
||||||
Dialog,
|
Dialog,
|
||||||
Tag,
|
Tag,
|
||||||
Switch,
|
Tab,
|
||||||
} from '@b-design/ui';
|
} from '@b-design/ui';
|
||||||
import type {
|
import type {
|
||||||
ApplicationComponent,
|
ApplicationComponent,
|
||||||
|
@ -42,6 +42,7 @@ import { checkPermission } from '../../utils/permission';
|
||||||
import type { LoginUserInfo } from '../../interface/user';
|
import type { LoginUserInfo } from '../../interface/user';
|
||||||
import './index.less';
|
import './index.less';
|
||||||
import ApplicationGraph from './components/ApplicationGraph';
|
import ApplicationGraph from './components/ApplicationGraph';
|
||||||
|
import i18n from '../../i18n';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
dispatch: ({}) => {};
|
dispatch: ({}) => {};
|
||||||
|
@ -69,7 +70,7 @@ type State = {
|
||||||
resourceLoading: boolean;
|
resourceLoading: boolean;
|
||||||
endpointLoading: boolean;
|
endpointLoading: boolean;
|
||||||
envName: string;
|
envName: string;
|
||||||
mode: 'table' | 'graph';
|
mode: 'overview' | 'resource-graph' | 'application-graph';
|
||||||
};
|
};
|
||||||
|
|
||||||
@connect((store: any) => {
|
@connect((store: any) => {
|
||||||
|
@ -84,7 +85,7 @@ class ApplicationStatusPage extends React.Component<Props, State> {
|
||||||
resourceLoading: false,
|
resourceLoading: false,
|
||||||
endpointLoading: false,
|
endpointLoading: false,
|
||||||
envName: '',
|
envName: '',
|
||||||
mode: 'graph',
|
mode: 'overview',
|
||||||
resources: [],
|
resources: [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -114,9 +115,11 @@ class ApplicationStatusPage extends React.Component<Props, State> {
|
||||||
this.props.dispatch({
|
this.props.dispatch({
|
||||||
type: 'application/getApplicationStatus',
|
type: 'application/getApplicationStatus',
|
||||||
payload: { appName: appName, envName: envName },
|
payload: { appName: appName, envName: envName },
|
||||||
callback: () => {
|
callback: (res: any) => {
|
||||||
|
if (res.status) {
|
||||||
this.loadApplicationEndpoints();
|
this.loadApplicationEndpoints();
|
||||||
this.loadApplicationAppliedResources();
|
this.loadApplicationAppliedResources();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -175,7 +178,7 @@ class ApplicationStatusPage extends React.Component<Props, State> {
|
||||||
|
|
||||||
loadApplicationAppliedResources = async () => {
|
loadApplicationAppliedResources = async () => {
|
||||||
const { mode } = this.state;
|
const { mode } = this.state;
|
||||||
if (mode == 'graph') {
|
if (mode === 'resource-graph') {
|
||||||
await this.loadResourceTree();
|
await this.loadResourceTree();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -256,6 +259,16 @@ class ApplicationStatusPage extends React.Component<Props, State> {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
loadApplicationPolicies = async () => {
|
||||||
|
const {
|
||||||
|
params: { appName },
|
||||||
|
} = this.props.match;
|
||||||
|
this.props.dispatch({
|
||||||
|
type: 'application/getApplicationPolicies',
|
||||||
|
payload: { appName: appName },
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
loadApplicationEnvbinding = async () => {
|
loadApplicationEnvbinding = async () => {
|
||||||
const {
|
const {
|
||||||
params: { appName },
|
params: { appName },
|
||||||
|
@ -325,14 +338,13 @@ class ApplicationStatusPage extends React.Component<Props, State> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onChangeMode = () => {
|
onChangeMode = (mode: string | number) => {
|
||||||
const { mode } = this.state;
|
if (mode == 'overview') {
|
||||||
if (mode == 'graph') {
|
this.setState({ mode: mode }, () => {
|
||||||
this.setState({ mode: 'table' }, () => {
|
|
||||||
this.loadApplicationAppliedResources();
|
this.loadApplicationAppliedResources();
|
||||||
});
|
});
|
||||||
} else {
|
} else if (mode == 'resource-graph') {
|
||||||
this.setState({ mode: 'graph' }, () => {
|
this.setState({ mode: mode }, () => {
|
||||||
this.loadApplicationAppliedResources();
|
this.loadApplicationAppliedResources();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -351,7 +363,6 @@ class ApplicationStatusPage extends React.Component<Props, State> {
|
||||||
resources,
|
resources,
|
||||||
componentName,
|
componentName,
|
||||||
deployLoading,
|
deployLoading,
|
||||||
mode,
|
|
||||||
} = this.state;
|
} = this.state;
|
||||||
const gatewayIPs: any = [];
|
const gatewayIPs: any = [];
|
||||||
endpoints?.map((endpointObj) => {
|
endpoints?.map((endpointObj) => {
|
||||||
|
@ -381,6 +392,7 @@ class ApplicationStatusPage extends React.Component<Props, State> {
|
||||||
updateEnvs={() => {
|
updateEnvs={() => {
|
||||||
this.loadApplicationEnvbinding();
|
this.loadApplicationEnvbinding();
|
||||||
this.loadApplicationWorkflows();
|
this.loadApplicationWorkflows();
|
||||||
|
this.loadApplicationPolicies();
|
||||||
}}
|
}}
|
||||||
updateQuery={(params: { target?: string; component?: string }) => {
|
updateQuery={(params: { target?: string; component?: string }) => {
|
||||||
this.updateQuery(params);
|
this.updateQuery(params);
|
||||||
|
@ -391,25 +403,28 @@ class ApplicationStatusPage extends React.Component<Props, State> {
|
||||||
dispatch={this.props.dispatch}
|
dispatch={this.props.dispatch}
|
||||||
/>
|
/>
|
||||||
</Loading>
|
</Loading>
|
||||||
<If condition={applicationStatus}>
|
<Tab onChange={this.onChangeMode} shape="capsule">
|
||||||
<Switch
|
<Tab.Item title={i18n.t('Overview')} key="overview">
|
||||||
unCheckedChildren="Table"
|
|
||||||
checkedChildren="Graph"
|
|
||||||
defaultChecked={true}
|
|
||||||
onChange={this.onChangeMode}
|
|
||||||
/>
|
|
||||||
</If>
|
|
||||||
<Loading visible={loading && resourceLoading} style={{ width: '100%' }}>
|
<Loading visible={loading && resourceLoading} style={{ width: '100%' }}>
|
||||||
<If condition={applicationStatus && mode === 'graph'}>
|
<If condition={applicationStatus}>
|
||||||
<ApplicationGraph application={applicationDetail} env={env} resources={resources} />
|
<If condition={componentStatus}>
|
||||||
</If>
|
|
||||||
<If condition={applicationStatus && mode === 'table'}>
|
|
||||||
<Card
|
<Card
|
||||||
locale={locale().Card}
|
locale={locale().Card}
|
||||||
contentHeight="200px"
|
style={{ marginTop: '8px', marginBottom: '16px' }}
|
||||||
title={<Translation>Applied Resources</Translation>}
|
contentHeight="auto"
|
||||||
|
title={<Translation>Component Status</Translation>}
|
||||||
>
|
>
|
||||||
<Table locale={locale().Table} dataSource={resources}>
|
<Table
|
||||||
|
locale={locale().Table}
|
||||||
|
className="customTable"
|
||||||
|
dataSource={componentStatus}
|
||||||
|
>
|
||||||
|
<Table.Column
|
||||||
|
align="left"
|
||||||
|
dataIndex="name"
|
||||||
|
style={{ width: '17%' }}
|
||||||
|
title={<Translation>Name</Translation>}
|
||||||
|
/>
|
||||||
<Table.Column
|
<Table.Column
|
||||||
dataIndex="cluster"
|
dataIndex="cluster"
|
||||||
title={<Translation>Cluster</Translation>}
|
title={<Translation>Cluster</Translation>}
|
||||||
|
@ -431,61 +446,6 @@ class ApplicationStatusPage extends React.Component<Props, State> {
|
||||||
return <span>{clusterName}</span>;
|
return <span>{clusterName}</span>;
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Table.Column
|
|
||||||
dataIndex="name"
|
|
||||||
width="240px"
|
|
||||||
title={<Translation>Namespace/Name</Translation>}
|
|
||||||
cell={(v: string, i: number, row: AppliedResource) => {
|
|
||||||
return `${row.namespace}/${row.name}`;
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Table.Column
|
|
||||||
width="200px"
|
|
||||||
dataIndex="kind"
|
|
||||||
title={<Translation>Kind</Translation>}
|
|
||||||
/>
|
|
||||||
<Table.Column
|
|
||||||
dataIndex="apiVersion"
|
|
||||||
title={<Translation>APIVersion</Translation>}
|
|
||||||
/>
|
|
||||||
<Table.Column dataIndex="component" title={<Translation>Component</Translation>} />
|
|
||||||
<Table.Column
|
|
||||||
dataIndex="deployVersion"
|
|
||||||
title={<Translation>Revision</Translation>}
|
|
||||||
cell={(v: string, i: number, row: AppliedResource) => {
|
|
||||||
if (row.latest) {
|
|
||||||
return (
|
|
||||||
<span>
|
|
||||||
<Icon
|
|
||||||
style={{ color: 'green', marginRight: '8px' }}
|
|
||||||
type="NEW"
|
|
||||||
title="latest version resource"
|
|
||||||
/>
|
|
||||||
<Link to={`/applications/${applicationDetail?.name}/revisions`}>{v}</Link>
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<Link to={`/applications/${applicationDetail?.name}/revisions`}>{v}</Link>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Table>
|
|
||||||
</Card>
|
|
||||||
<If condition={componentStatus}>
|
|
||||||
<Card
|
|
||||||
locale={locale().Card}
|
|
||||||
style={{ marginTop: '8px', marginBottom: '16px' }}
|
|
||||||
contentHeight="auto"
|
|
||||||
title={<Translation>Component Status</Translation>}
|
|
||||||
>
|
|
||||||
<Table locale={locale().Table} className="customTable" dataSource={componentStatus}>
|
|
||||||
<Table.Column
|
|
||||||
align="left"
|
|
||||||
dataIndex="name"
|
|
||||||
style={{ width: '17%' }}
|
|
||||||
title={<Translation>Name</Translation>}
|
|
||||||
/>
|
|
||||||
<Table.Column
|
<Table.Column
|
||||||
align="left"
|
align="left"
|
||||||
dataIndex="healthy"
|
dataIndex="healthy"
|
||||||
|
@ -541,7 +501,6 @@ class ApplicationStatusPage extends React.Component<Props, State> {
|
||||||
<Table.Column
|
<Table.Column
|
||||||
align="center"
|
align="center"
|
||||||
dataIndex="message"
|
dataIndex="message"
|
||||||
style={{ width: '50%' }}
|
|
||||||
title={<Translation>Message</Translation>}
|
title={<Translation>Message</Translation>}
|
||||||
cell={(v: string, i: number, record: ComponentStatus) => {
|
cell={(v: string, i: number, record: ComponentStatus) => {
|
||||||
const { message = '', traits } = record;
|
const { message = '', traits } = record;
|
||||||
|
@ -566,6 +525,80 @@ class ApplicationStatusPage extends React.Component<Props, State> {
|
||||||
</Table>
|
</Table>
|
||||||
</Card>
|
</Card>
|
||||||
</If>
|
</If>
|
||||||
|
<Card
|
||||||
|
locale={locale().Card}
|
||||||
|
contentHeight="200px"
|
||||||
|
title={<Translation>Applied Resources</Translation>}
|
||||||
|
>
|
||||||
|
<Table locale={locale().Table} dataSource={resources}>
|
||||||
|
<Table.Column
|
||||||
|
dataIndex="name"
|
||||||
|
width="240px"
|
||||||
|
title={<Translation>Namespace/Name</Translation>}
|
||||||
|
cell={(v: string, i: number, row: AppliedResource) => {
|
||||||
|
return `${row.namespace}/${row.name}`;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Table.Column
|
||||||
|
dataIndex="cluster"
|
||||||
|
title={<Translation>Cluster</Translation>}
|
||||||
|
width="200px"
|
||||||
|
cell={(v: string) => {
|
||||||
|
let clusterName = v;
|
||||||
|
if (!clusterName) {
|
||||||
|
clusterName = 'Local';
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
checkPermission(
|
||||||
|
{ resource: 'cluster:*', action: 'list' },
|
||||||
|
applicationDetail?.project?.name,
|
||||||
|
userInfo,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return <Link to="/clusters">{clusterName}</Link>;
|
||||||
|
}
|
||||||
|
return <span>{clusterName}</span>;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Table.Column
|
||||||
|
width="200px"
|
||||||
|
dataIndex="kind"
|
||||||
|
title={<Translation>Kind</Translation>}
|
||||||
|
/>
|
||||||
|
<Table.Column
|
||||||
|
dataIndex="apiVersion"
|
||||||
|
title={<Translation>APIVersion</Translation>}
|
||||||
|
/>
|
||||||
|
<Table.Column
|
||||||
|
dataIndex="component"
|
||||||
|
title={<Translation>Component</Translation>}
|
||||||
|
/>
|
||||||
|
<Table.Column
|
||||||
|
dataIndex="deployVersion"
|
||||||
|
title={<Translation>Revision</Translation>}
|
||||||
|
cell={(v: string, i: number, row: AppliedResource) => {
|
||||||
|
if (row.latest) {
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
<Icon
|
||||||
|
style={{ color: 'green', marginRight: '8px' }}
|
||||||
|
type="NEW"
|
||||||
|
title="latest version resource"
|
||||||
|
/>
|
||||||
|
<Link to={`/applications/${applicationDetail?.name}/revisions`}>
|
||||||
|
{v}
|
||||||
|
</Link>
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Link to={`/applications/${applicationDetail?.name}/revisions`}>{v}</Link>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Table>
|
||||||
|
</Card>
|
||||||
|
|
||||||
<If condition={applicationStatus?.conditions}>
|
<If condition={applicationStatus?.conditions}>
|
||||||
<Card
|
<Card
|
||||||
locale={locale().Card}
|
locale={locale().Card}
|
||||||
|
@ -632,6 +665,20 @@ class ApplicationStatusPage extends React.Component<Props, State> {
|
||||||
</div>
|
</div>
|
||||||
</If>
|
</If>
|
||||||
</Loading>
|
</Loading>
|
||||||
|
</Tab.Item>
|
||||||
|
<Tab.Item title={i18n.t('Resource Graph')} key="resource-graph">
|
||||||
|
<Loading visible={loading && resourceLoading} style={{ width: '100%' }}>
|
||||||
|
<If condition={applicationStatus}>
|
||||||
|
<ApplicationGraph
|
||||||
|
applicationStatus={applicationStatus}
|
||||||
|
application={applicationDetail}
|
||||||
|
env={env}
|
||||||
|
resources={resources}
|
||||||
|
/>
|
||||||
|
</If>
|
||||||
|
</Loading>
|
||||||
|
</Tab.Item>
|
||||||
|
</Tab>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,8 @@ import SelectSearch from './components/SelectSearch';
|
||||||
import locale from '../../utils/locale';
|
import locale from '../../utils/locale';
|
||||||
import { getMatchParamObj } from '../../utils/utils';
|
import { getMatchParamObj } from '../../utils/utils';
|
||||||
import './index.less';
|
import './index.less';
|
||||||
|
import { checkPermission } from '../../utils/permission';
|
||||||
|
import type { LoginUserInfo } from '../../interface/user';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
match: {
|
match: {
|
||||||
|
@ -19,6 +21,7 @@ type Props = {
|
||||||
definitionType: string;
|
definitionType: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
userInfo?: LoginUserInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
|
@ -30,7 +33,7 @@ type State = {
|
||||||
};
|
};
|
||||||
|
|
||||||
@connect((store: any) => {
|
@connect((store: any) => {
|
||||||
return { ...store.definitions };
|
return { ...store.definitions, ...store.user };
|
||||||
})
|
})
|
||||||
class Definitions extends Component<Props, State> {
|
class Definitions extends Component<Props, State> {
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
|
@ -62,10 +65,14 @@ class Definitions extends Component<Props, State> {
|
||||||
}
|
}
|
||||||
|
|
||||||
lisDefinitions() {
|
lisDefinitions() {
|
||||||
|
const { userInfo } = this.props;
|
||||||
const { definitionType } = this.state;
|
const { definitionType } = this.state;
|
||||||
if (!definitionType) {
|
if (!definitionType) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!checkPermission({ resource: 'definition:*', action: 'list' }, '', userInfo)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const params = {
|
const params = {
|
||||||
definitionType,
|
definitionType,
|
||||||
queryAll: true,
|
queryAll: true,
|
||||||
|
|
Loading…
Reference in New Issue