Compare commits

...

9 Commits
main ... v1.5.8

Author SHA1 Message Date
barnettZQG be7a7ba470
Fix: support to open the tcp address directly (#623)
Signed-off-by: barnettZQG <barnett.zqg@gmail.com>

Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
2022-10-24 11:03:52 +08:00
github-actions[bot] 9a30505e4e
[Backport release-1.5] Fix: enhance the drawer page of the addon (#621)
* Fix: enhance the drawer page of the addon

Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
(cherry picked from commit 389d9265f1)

* Fix: reset the schema after version changed

Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
(cherry picked from commit 780db24a22)

Co-authored-by: barnettZQG <barnett.zqg@gmail.com>
2022-10-22 13:51:10 +08:00
barnettZQG 56c4dc9ed5
Fix: can not show the detail of the first revision (#612) (#613)
Signed-off-by: barnettZQG <barnett.zqg@gmail.com>

Signed-off-by: barnettZQG <barnett.zqg@gmail.com>

Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
2022-08-31 19:11:48 +08:00
github-actions[bot] 7d64df983d
Fix: miss the form items after turning off the switch (#611)
Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
(cherry picked from commit 9d1af0b5ce)

Co-authored-by: barnettZQG <barnett.zqg@gmail.com>
2022-08-24 14:07:04 +08:00
github-actions[bot] 430a9c36ad
Fix: set the locale (#610)
Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
(cherry picked from commit c1257adf6f)

Co-authored-by: barnettZQG <barnett.zqg@gmail.com>
2022-08-24 10:29:13 +08:00
github-actions[bot] d007fc3f35
[Backport release-1.5] Feat: show the endpoints in the addon detail page (#607)
* Feat: show the endpoints in the addon detail page

Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
(cherry picked from commit 030d70df0c)

* Fix: js/unsafe-external-link

Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
(cherry picked from commit e24e4662b1)

Co-authored-by: barnettZQG <barnett.zqg@gmail.com>
2022-08-02 18:30:49 +08:00
github-actions[bot] b9f1663867
Fix: hidden cloudshell dialog scroll bar (#605)
Signed-off-by: Zhiyu Wang <cloudsky.newbis@gmail.com>
(cherry picked from commit 0d0fc6597a)

Co-authored-by: Zhiyu Wang <cloudsky.newbis@gmail.com>
2022-08-01 18:20:30 +08:00
github-actions[bot] a18675b341
Fix: incorrect dex redirect URL (#603)
Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
(cherry picked from commit a1d3910e99)

Co-authored-by: barnettZQG <barnett.zqg@gmail.com>
2022-07-31 17:07:53 +08:00
barnettZQG e431a48460
Fix: the email can not edit (#600) (#602)
Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
2022-07-31 17:07:42 +08:00
26 changed files with 369 additions and 171 deletions

View File

@ -1,6 +1,7 @@
import { post, get, rdelete, put } from './request';
import { addons, addonRegistries, enabledAddon } from './productionLink';
import { getDomain } from '../utils/common';
import type { EnableAddonRequest } from '../interface/addon';
const baseURLOject = getDomain();
const base = baseURLOject.MOCK || baseURLOject.APIBASE;
@ -23,7 +24,16 @@ export function getAddonsList(params: any) {
export function getAddonsDetails(params: { name: string; version?: string }) {
const gurl = `${base + addons}/${params.name}`;
return get(gurl, params).then((res) => res);
return get(
gurl,
params.version
? {
params: {
version: params.version,
},
}
: {},
).then((res) => res);
}
export function disableAddon(params: { name: string }) {
@ -31,12 +41,7 @@ export function disableAddon(params: { name: string }) {
return post(gurl, params).then((res) => res);
}
export function enableAddon(params: {
name: string;
version: string;
clusters?: string[];
properties: any;
}) {
export function enableAddon(params: EnableAddonRequest) {
const gurl = `${base + addons}/${params.name}/enable`;
const req: any = { args: params.properties, version: params.version };
if (params.clusters) {
@ -45,12 +50,7 @@ export function enableAddon(params: {
return post(gurl, req).then((res) => res);
}
export function upgradeAddon(params: {
name: string;
version: string;
clusters?: string[];
properties: any;
}) {
export function upgradeAddon(params: EnableAddonRequest) {
const gurl = `${base + addons}/${params.name}/update`;
const req: any = { args: params.properties, version: params.version };
if (params.clusters) {

View File

@ -470,15 +470,6 @@ a {
display: inline-block;
}
.next-drawer-close {
right: 24px;
.next-drawer-close-icon.next-icon::before {
width: 16px !important;
height: 16px !important;
font-size: 16px !important;
}
}
.next-btn.danger-btn {
color: @dangerColor !important;
border: @dangerColor 1px solid !important;

View File

@ -8,3 +8,46 @@
height: 60px;
background: #fff;
}
.next-drawer {
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
.next-drawer-header {
position: absolute;
top: 0;
z-index: 1000;
display: flex;
flex: 0;
align-items: center;
width: 100%;
height: 55px;
padding: 16px 24px;
font-size: 16px;
line-height: 22px;
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
}
.next-drawer-body {
flex: 1;
min-width: 0;
min-height: 0;
margin-top: 71px;
padding: 24px;
overflow: auto;
}
}
.next-drawer-close {
right: 26px !important;
.next-drawer-close-icon.next-icon::before {
color: #000;
font-weight: 800 !important;
font-size: 24px !important;
line-height: 24px !important;
&:hover {
color: var(--primary-color);
}
}
}

View File

@ -288,9 +288,6 @@ class UISchema extends Component<Props, State> {
if (!uiSchema || enableCodeEdit) {
return this.renderCodeEdit();
}
if (mode == 'edit' && value === undefined) {
return <div />;
}
let onlyShowRequired = false;
let couldShowParamCount = 0;
uiSchema.map((param) => {
@ -359,7 +356,7 @@ class UISchema extends Component<Props, State> {
if (initValue === undefined) {
initValue = param.validate?.defaultValue;
}
const disableEdit = (param.validate?.immutable && this.props.mode == 'edit') || false;
const disableEdit = (param.validate?.immutable && mode == 'edit') || false;
const getGroup = (children: React.ReactNode) => {
return (
<Group

View File

@ -120,8 +120,8 @@ class Group extends React.Component<Props, State> {
type: 'confirm',
content: (
<Translation>
If Switch is turned off, The configuration will be reset. Are you
sure you want to do this?
The configuration will be reset if the switch is turned off. Are you
sure want to do this?
</Translation>
),
onOk: () => {

View File

@ -16,6 +16,10 @@ export interface Addon {
registryName?: string;
availableVersions?: string[];
url?: string;
system?: {
vela?: string;
kubernetes?: string;
};
}
export interface AddonStatus {
@ -69,3 +73,10 @@ export interface AddonBaseStatus {
name: string;
phase: 'disabled' | 'enabled' | 'enabling' | 'suspend' | 'disabling';
}
export interface EnableAddonRequest {
name: string;
version: string;
properties: Record<string, any>;
clusters?: string[];
}

View File

@ -9,6 +9,7 @@
.next-drawer-body {
height: 100%;
padding: 0;
overflow: hidden;
background: rgb(59, 59, 59);
.prepare {
display: flex;

View File

@ -2,9 +2,10 @@ import React, { Component, Fragment } from 'react';
import { Grid, Form, Input, Field, Button, Message, Icon, Dialog } from '@b-design/ui';
import { updateUser } from '../../../../api/users';
import type { LoginUserInfo } from '../../../../interface/user';
import { checkUserPassword, checkUserEmail } from '../../../../utils/common';
import { checkUserPassword } from '../../../../utils/common';
import Translation from '../../../../components/Translation';
import i18n from '../../../../i18n';
import locale from '../../../../utils/locale';
type Props = {
userInfo?: LoginUserInfo;
@ -96,6 +97,7 @@ class EditPlatFormUserDialog extends Component<Props, State> {
title={this.showTitle()}
style={{ width: '600px' }}
onOk={this.onUpdateUser}
locale={locale().Dialog}
footerActions={['ok']}
>
<Form {...formItemLayout} field={this.field}>
@ -143,7 +145,7 @@ class EditPlatFormUserDialog extends Component<Props, State> {
rules: [
{
required: true,
pattern: checkUserEmail,
format: 'email',
message: <Translation>Please input a valid email</Translation>,
},
],

View File

@ -1,3 +1,7 @@
:root {
--primary-color: #1b58f4;
--warning-color: var(--message-warning-color-icon-inline, #fac800);
}
@border-radius-8: 8px;
@F7F7F7: #f7f7f7;
@F9F8FF: #f9f8ff;

View File

@ -342,7 +342,7 @@
"Instructions for assessing whether the container is alive.": "容器健康状态探针",
"Specify the annotations in the workload": "指定工作负载的注释",
"Specify the labels in the workload": "指定工作负载的标签",
"If Switch is turned off, The configuration will be reset. Are you sure you want to do this?": "如果关闭,配置将重置。确定操作吗?",
"The configuration will be reset if the switch is turned off. Are you sure want to do this?": "如果关闭,配置将重置。确定操作吗?",
"Mount PVC type volume": "挂载 PVC 数据卷",
"Mount HostPath type volume": "挂载 HostPath 数据卷",
"Mount EmptyDir type volume": "挂载 EmptyDir 数据卷",

View File

@ -146,7 +146,12 @@ class CardContent extends React.Component<Props, State> {
<Row className="content-main-btn">
{tags?.map((tag: string) => {
return (
<Tag style={{ marginRight: '8px' }} color={getTagColor(tag)} key={tag}>
<Tag
title={tag}
style={{ marginRight: '8px' }}
color={getTagColor(tag)}
key={tag}
>
{tag}
</Tag>
);

View File

@ -13,13 +13,18 @@
img {
width: 100%;
}
ol, ul {
ol,
ul {
list-style: decimal;
}
p {
font-size: 14px;
}
}
.addon-readme li>p {
.addon-readme li > p {
font-size: 14px;
}
}
.warning-text {
color: var(--warning-color);
}

View File

@ -1,4 +1,4 @@
import React, { Fragment } from 'react';
import React from 'react';
import {
Form,
Button,
@ -10,6 +10,10 @@ import {
Message,
Select,
Checkbox,
Grid,
Dropdown,
Menu,
Icon,
} from '@b-design/ui';
import type { Rule } from '@alifd/field';
import { If } from 'tsx-control-statements/components';
@ -24,18 +28,23 @@ import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import Empty from '../../../../components/Empty';
import DrawerWithFooter from '../../../../components/Drawer';
import Group from '../../../../extends/Group';
import Translation from '../../../../components/Translation';
import UISchema from '../../../../components/UISchema';
import type { Addon, AddonStatus } from '../../../../interface/addon';
import type { Addon, AddonStatus, EnableAddonRequest } from '../../../../interface/addon';
import locale from '../../../../utils/locale';
import StatusShow from '../../../../components/StatusShow';
import type { ApplicationStatus } from '../../../../interface/application';
import type { ApplicationStatus, UIParam } from '../../../../interface/application';
import i18n from '../../../../i18n';
import type { NameAlias } from '../../../../interface/env';
import Permission from '../../../../components/Permission';
import 'github-markdown-css/github-markdown-light.css';
import './index.less';
import { Link } from 'dva/router';
import { listApplicationServiceEndpoints } from '../../../../api/observation';
import type { Endpoint } from '../../../../interface/observation';
import { getLink } from '../../../../utils/utils';
const { Col, Row } = Grid;
type Props = {
addonName: string;
@ -58,17 +67,19 @@ type State = {
clusters?: string[];
allClusters?: NameAlias[];
enabledClusters?: string[];
endpoints?: Endpoint[];
propertiesMode: 'code' | 'native';
schema?: UIParam[];
};
class AddonDetailDialog extends React.Component<Props, State> {
timer?: number;
readonly refreshTime = 1000;
form: Field;
statusLoop: boolean;
uiSchemaRef: React.RefObject<UISchema>;
constructor(props: Props) {
super(props);
this.state = {
propertiesMode: 'native',
addonDetailInfo: {
name: '',
},
@ -86,12 +97,7 @@ class AddonDetailDialog extends React.Component<Props, State> {
componentDidMount() {
this.loadAddonDetail();
this.loadAddonStatus();
}
componentWillUnmount() {
if (this.timer) {
window.clearInterval(this.timer);
}
this.loadAddonEndpoints();
}
loadAddonDetail = async () => {
@ -100,7 +106,7 @@ class AddonDetailDialog extends React.Component<Props, State> {
getAddonsDetails({ name: this.props.addonName, version: version })
.then((res: Addon) => {
if (res) {
this.setState({ addonDetailInfo: res, loading: false });
this.setState({ addonDetailInfo: res, schema: res.uiSchema, loading: false });
if (!this.state.version && res.version) {
this.setState({ version: res.version });
}
@ -116,7 +122,7 @@ class AddonDetailDialog extends React.Component<Props, State> {
getAddonsStatus({ name: this.props.addonName })
.then((res: AddonStatus) => {
if (!res) return;
if (res.phase == 'enabling' && !this.statusLoop) {
if ((res.phase == 'enabling' || res.phase === 'disabling') && !this.statusLoop) {
this.statusLoop = true;
setTimeout(() => {
this.statusLoop = false;
@ -158,26 +164,40 @@ class AddonDetailDialog extends React.Component<Props, State> {
});
};
handleSubmit = () => {
const { status } = this.state;
if (status === 'enabled') {
Dialog.confirm({
content:
'Please make sure that the Addon is no longer in use and the related application has been recycled.',
onOk: this.disableAddon,
locale: locale().Dialog,
});
return;
}
if (status === 'disabled') {
this.form.validate((errors: any, values: any) => {
if (errors) {
return;
}
this.enableAddon(values.properties);
});
}
loadAddonEndpoints = () => {
// TODO: the app name and namespace should get from the api server.
const appName = 'addon-' + this.props.addonName;
listApplicationServiceEndpoints({
appName: appName,
appNs: 'vela-system',
}).then((re) => {
if (re && re.endpoints) {
this.setState({ endpoints: re.endpoints });
} else {
this.setState({ endpoints: [] });
}
});
};
onDisable = () => {
Dialog.confirm({
content:
'Please make sure that the Addon is no longer in use and the related application has been recycled.',
onOk: this.disableAddon,
locale: locale().Dialog,
});
return;
};
onEnable = () => {
this.form.validate((errors: any, values: any) => {
if (errors) {
return;
}
this.enableAddon(values.properties);
});
};
onUpgrade = () => {
this.form.validate((errors: any, values: any) => {
if (errors) {
@ -195,17 +215,21 @@ class AddonDetailDialog extends React.Component<Props, State> {
return;
}
this.setState({ upgradeLoading: true });
upgradeAddon({
const params: EnableAddonRequest = {
name: this.props.addonName,
version: this.state.version,
clusters: this.state.clusters,
properties: values.properties,
}).then(() => {
};
if (this.state.addonDetailInfo?.deployTo?.runtimeCluster) {
params.clusters = this.state.clusters;
}
upgradeAddon(params).then(() => {
this.loadAddonStatus();
this.setState({ upgradeLoading: false });
});
});
};
enableAddon = async (properties: any) => {
if (!this.state.version) {
Message.warning(i18n.t('Please firstly select want to enable version'));
@ -220,12 +244,15 @@ class AddonDetailDialog extends React.Component<Props, State> {
}
this.setState({ statusLoading: true }, () => {
if (this.state.version) {
enableAddon({
const params: EnableAddonRequest = {
name: this.props.addonName,
version: this.state.version,
clusters: this.state.clusters,
properties: properties,
}).then(() => {
};
if (this.state.addonDetailInfo?.deployTo?.runtimeCluster) {
params.clusters = this.state.clusters;
}
enableAddon(params).then(() => {
this.loadAddonStatus();
});
}
@ -253,7 +280,9 @@ class AddonDetailDialog extends React.Component<Props, State> {
};
changeVersion = (version: string) => {
this.setState({ version: version }, () => {
this.loadAddonDetail();
this.setState({ schema: undefined }, () => {
this.loadAddonDetail();
});
});
};
@ -278,6 +307,9 @@ class AddonDetailDialog extends React.Component<Props, State> {
clusters,
allClusters,
enabledClusters,
endpoints,
propertiesMode,
schema,
} = this.state;
const { showAddon, addonName } = this.props;
const validator = (rule: Rule, value: any, callback: (error?: string) => void) => {
@ -293,32 +325,30 @@ class AddonDetailDialog extends React.Component<Props, State> {
item.uiType = 'Password';
}
});
const buttons = [
<Fragment>
<Button type="secondary" onClick={this.onClose} style={{ marginRight: '16px' }}>
<Translation>Cancel</Translation>
</Button>
const buttons = [];
if (status === 'enabled' || status === 'enabling' || status === 'disabling') {
buttons.push(
<Permission
request={{
resource: `addon:${addonName}`,
action: status === 'enabled' ? 'disable' : 'enable',
action: 'disable',
}}
project={''}
>
<Button
type="primary"
onClick={this.handleSubmit}
warning={status === 'enabled'}
type="secondary"
onClick={this.onDisable}
title={status}
style={{ backgroundColor: status === 'enabled' ? 'red' : '' }}
loading={statusLoading || loading || status == 'enabling' || status == 'disabling'}
disabled={status == 'enabling' || status == 'disabling' || version == ''}
className="danger-btn"
loading={status === 'disabling'}
disabled={status === 'disabling'}
>
<Translation>{status === 'enabled' ? 'Disable' : 'Enable'}</Translation>
<Translation>Disable</Translation>
</Button>
</Permission>
</Fragment>,
];
</Permission>,
);
}
if (status == 'enabled' || status == 'suspend') {
buttons.push(
<Permission request={{ resource: `addon:${addonName}`, action: 'update' }} project={''}>
@ -334,6 +364,21 @@ class AddonDetailDialog extends React.Component<Props, State> {
);
}
if (status === 'disabled' || status === 'enabling') {
buttons.push(
<Permission request={{ resource: `addon:${addonName}`, action: 'enable' }} project={''}>
<Button
loading={status === 'enabling'}
type="primary"
onClick={this.onEnable}
style={{ marginLeft: '16px' }}
>
<Translation>Enable</Translation>
</Button>
</Permission>,
);
}
const getAppStatusShowType = (statusInfo: string | undefined) => {
if (!statusInfo) {
return 'notice';
@ -364,6 +409,8 @@ class AddonDetailDialog extends React.Component<Props, State> {
};
});
const outerEndpoint = endpoints?.filter((end) => !end.endpoint.inner);
return (
<div className="basic">
<DrawerWithFooter
@ -383,16 +430,52 @@ class AddonDetailDialog extends React.Component<Props, State> {
</If>
<If condition={addonsStatus && addonsStatus.status}>
<Message
type={getAppStatusShowType(addonsStatus?.status)}
size="medium"
style={{ padding: '8px', marginBottom: '10px' }}
>
{`${i18n.t('Addon status is ')}${addonsStatus?.status || 'Initing'}`}
<a style={{ marginLeft: '16px' }} onClick={() => this.updateStatusShow(true)}>
<Translation>Check the details</Translation>
</a>
</Message>
<Row>
<Col span={16}>
<Message
type={getAppStatusShowType(addonsStatus?.status)}
size="medium"
style={{ padding: '8px', marginBottom: '10px' }}
>
{`${i18n.t('Addon status is ')}${addonsStatus?.status || 'Init'}`}
<Link
style={{ marginLeft: '16px' }}
to={`/applications/addon-${addonDetailInfo?.name}`}
>
<Translation>Check the details</Translation>
</Link>
</Message>
</Col>
<If condition={outerEndpoint && outerEndpoint?.length > 0}>
<Col span={8} className={'flexright'}>
<Dropdown
trigger={
<Button style={{ marginLeft: '16px' }} type="secondary">
<Translation>Endpoints</Translation>
</Button>
}
>
<Menu>
{outerEndpoint?.map((item) => {
const linkURL = getLink(item);
return (
<Menu.Item key={linkURL}>
<a
style={{ color: '#1b58f4' }}
target="_blank"
href={linkURL}
rel="noopener noreferrer"
>
{linkURL}
</a>
</Menu.Item>
);
})}
</Menu>
</Dropdown>
</Col>
</If>
</Row>
</If>
{/* select the addon version */}
@ -405,6 +488,18 @@ class AddonDetailDialog extends React.Component<Props, State> {
value={version}
/>
</Form.Item>
{addonDetailInfo?.system && (
<span className="warning-text">
This version requirements: (
{addonDetailInfo?.system.vela
? `KubeVela: ${addonDetailInfo?.system.vela}`
: ''}
{addonDetailInfo?.system.kubernetes
? ` Kubernetes: ${addonDetailInfo?.system.kubernetes}`
: ''}
)
</span>
)}
</If>
<If condition={addonDetailInfo?.deployTo?.runtimeCluster}>
@ -419,34 +514,69 @@ class AddonDetailDialog extends React.Component<Props, State> {
</If>
</Card>
<If condition={addonDetailInfo?.uiSchema}>
<Group
title={<Translation>Properties</Translation>}
description={<Translation>Set the addon configuration parameters</Translation>}
required={true}
closed={status === 'enabled'}
alwaysShow={true}
disableAddon={true}
hasToggleIcon={true}
<If condition={schema}>
<Card
contentHeight={'auto'}
className="withActions"
title="Properties"
subTitle={
schema
? [
<Button
style={{ marginTop: '-12px' }}
onClick={() => {
if (propertiesMode === 'native') {
this.setState({ propertiesMode: 'code' });
} else {
this.setState({ propertiesMode: 'native' });
}
}}
>
<If condition={propertiesMode === 'native'}>
<Icon
style={{ color: '#1b58f4' }}
type={'display-code'}
title={'Switch to the coding mode'}
/>
</If>
<If condition={propertiesMode === 'code'}>
<Icon
style={{ color: '#1b58f4' }}
type={'laptop'}
title={'Switch to the native mode'}
/>
</If>
</Button>,
]
: []
}
>
<Form field={this.form}>
{this.state.mode && (
<UISchema
{...this.form.init('properties', {
rules: [
{
validator: validator,
message: 'Please check addon properties',
},
],
})}
ref={this.uiSchemaRef}
uiSchema={addonDetailInfo?.uiSchema}
mode={this.state.mode}
/>
)}
</Form>
</Group>
<Row>
<If condition={schema}>
{this.state.mode && (
<UISchema
{...this.form.init(`properties`, {
rules: [
{
validator: validator,
message: i18n.t('Please check the addon properties'),
},
],
})}
enableCodeEdit={propertiesMode === 'code'}
uiSchema={schema}
definition={{
name: addonDetailInfo?.name || '',
type: 'addon',
description: addonDetailInfo?.description || '',
}}
ref={this.uiSchemaRef}
mode={this.state.mode}
/>
)}
</If>
</Row>
</Card>
</If>
<If condition={addonDetailInfo?.dependencies}>
<Card

View File

@ -7,7 +7,6 @@ import {
Button,
Input,
Select,
Divider,
Icon,
Card,
Loading,
@ -246,14 +245,12 @@ class ComponentDialog extends React.Component<Props, State> {
return (
<div>
<span>{alias ? `${alias}(${name})` : name}</span>
<Divider />
</div>
);
} else {
return (
<div>
<span>{i18n.t('New Component')} </span>
<Divider />
</div>
);
}

View File

@ -289,7 +289,12 @@ class Header extends Component<Props, State> {
if (item && !item.endpoint.inner) {
return (
<Menu.Item key={linkURL}>
<a style={{ color: '#1b58f4' }} target="_blank" href={linkURL}>
<a
style={{ color: '#1b58f4' }}
target="_blank"
href={linkURL}
rel="noopener noreferrer"
>
{linkURL}
</a>
</Menu.Item>

View File

@ -71,8 +71,8 @@ class PodDetail extends React.Component<Props, State> {
}
};
onOpenCloudShell = () => {
const { env } = this.props;
onOpenCloudShell = (containerName: string) => {
const { env, pod } = this.props;
if (!checkEnabledAddon('cloudshell', this.props.enabledAddons)) {
Dialog.alert({
title: i18n.t('CloudShell feature is not enabled'),
@ -97,13 +97,15 @@ class PodDetail extends React.Component<Props, State> {
});
return;
}
const shellScript = `vela exec ${env?.appDeployName} -e ${env?.appDeployNamespace} -- bash`;
const shellScript = `vela exec ${env?.appDeployName} -n ${env?.appDeployNamespace} --component ${pod.component} --cluster ${pod.cluster} --pod ${pod.metadata.name} --container ${containerName} -- bash`;
Dialog.show({
footer: false,
style: { width: 400 },
style: { width: 600 },
content: (
<div>
<h5>1. Copy the command:</h5>
<h5>
1. <Translation>Copy the command</Translation>:
</h5>
<code className="code">
{shellScript}{' '}
<CopyToClipboard
@ -115,7 +117,9 @@ class PodDetail extends React.Component<Props, State> {
<AiOutlineCopy size={14} />
</CopyToClipboard>
</code>
<h5>2. Open Cloud Shell:</h5>
<h5>
2. <Translation>Open Cloud Shell</Translation>:
</h5>
<div>
<Button
size="small"
@ -128,7 +132,7 @@ class PodDetail extends React.Component<Props, State> {
}
}}
>
Open Cloud Shell
<Translation>Open Cloud Shell</Translation>
</Button>
</div>
</div>
@ -264,7 +268,7 @@ class PodDetail extends React.Component<Props, State> {
</a>
<a
title="Console Shell"
onClick={() => this.onOpenCloudShell()}
onClick={() => this.onOpenCloudShell(record.name)}
className="actionIcon"
>
<AiOutlineCode size={20} />

View File

@ -43,7 +43,7 @@ export const ShowRevision = (props: RevisionProps) => {
React.useEffect(() => {
loadRevisionDetail(props.appName, props.revision, setDetail);
}, [props.appName, props.revision]);
const containerId = props.revision.version;
const containerId = props.revision.version + 'detail';
return (
<React.Fragment>

View File

@ -37,7 +37,7 @@ export default class CallBackPage extends React.Component<Props> {
if (res && res.accessToken) {
localStorage.setItem('token', res.accessToken);
localStorage.setItem('refreshToken', res.refreshToken);
this.props.history.push('/');
this.props.history.push('/applications');
}
})
.catch((err) => {

View File

@ -1,6 +1,6 @@
.dialog-cluoudService-wraper {
.dialog-cloudService-wrapper {
width: 1000px;
.cloud-server-wraper {
.cloud-server-wrapper {
.next-select-trigger {
width: 100%;
}

View File

@ -271,7 +271,7 @@ class CloudServiceDialog extends React.Component<Props, State> {
<React.Fragment>
<Dialog
locale={locale().Dialog}
className="dialog-cluoudService-wraper"
className="dialog-cloudService-wrapper"
title={<Translation>Connect Kubernetes Cluster From Cloud</Translation>}
autoFocus={true}
visible={visible}
@ -294,7 +294,7 @@ class CloudServiceDialog extends React.Component<Props, State> {
available permission set
</Translation>
</Message>
<Form {...formItemLayout} field={this.field} className="cloud-server-wraper">
<Form {...formItemLayout} field={this.field} className="cloud-server-wrapper">
<FormItem label={<Translation>Provider</Translation>} required={true}>
<Select
locale={locale().Select}

View File

@ -25,7 +25,7 @@ type Props = {
};
type State = {
dexConfig: DexConfig;
dexConfig?: DexConfig;
loginType: string;
loginErrorMessage: string;
loginLoading: boolean;
@ -36,19 +36,12 @@ export default class LoginPage extends Component<Props, State> {
super(props);
this.field = new Field(this);
this.state = {
dexConfig: {
clientID: '',
clientSecret: '',
issuer: '',
redirectURL: '',
},
loginType: '',
loginErrorMessage: '',
loginLoading: false,
};
}
componentDidMount() {
this.ontDexConfig();
this.onGetLoginType();
}
onGetLoginType = () => {
@ -62,7 +55,7 @@ export default class LoginPage extends Component<Props, State> {
() => {
const { loginType } = this.state;
if (loginType === 'dex') {
this.onGetDexCode();
this.ontDexConfig();
}
},
);
@ -74,9 +67,14 @@ export default class LoginPage extends Component<Props, State> {
getDexConfig()
.then((res) => {
if (res) {
this.setState({
dexConfig: res,
});
this.setState(
{
dexConfig: res,
},
() => {
this.onGetDexCode();
},
);
}
})
.catch();
@ -116,10 +114,12 @@ export default class LoginPage extends Component<Props, State> {
});
};
onGetDexCode = () => {
const { clientID, issuer, redirectURL } = this.state.dexConfig;
const newRedirectURl = encodeURIComponent(redirectURL);
const dexClientURL = `${issuer}/auth?client_id=${clientID}&redirect_uri=${newRedirectURl}&response_type=code&scope=openid+profile+email+offline_access&state=velaux`;
window.location.href = dexClientURL;
if (this.state.dexConfig) {
const { clientID, issuer, redirectURL } = this.state.dexConfig;
const newRedirectURl = encodeURIComponent(redirectURL);
const dexClientURL = `${issuer}/auth?client_id=${clientID}&redirect_uri=${newRedirectURl}&response_type=code&scope=openid+profile+email+offline_access&state=velaux`;
window.location.href = dexClientURL;
}
};
render() {
const FormItem = Form.Item;

View File

@ -1,9 +1,4 @@
import React from 'react';
import Group from '../../extends/Group';
export default function NotFound() {
return (
<div>
<Group title="envplan" description="envplan" />
</div>
);
return <div>The route is not exist(404)</div>;
}

View File

@ -1,7 +1,7 @@
import React from 'react';
import { Grid, Form, Input, Field, Button, Message, Select } from '@b-design/ui';
import DrawerWithFooter from '../../../../components/Drawer';
import { checkUserPassword, checkUserEmail } from '../../../../utils/common';
import { checkUserPassword } from '../../../../utils/common';
import Translation from '../../../../components/Translation';
import { createUser, updateUser } from '../../../../api/users';
import { checkName } from '../../../../utils/common';
@ -231,7 +231,7 @@ class CreateUser extends React.Component<Props, State> {
rules: [
{
required: true,
pattern: checkUserEmail,
format: 'email',
message: <Translation>Please input a valid email</Translation>,
},
],

View File

@ -203,7 +203,6 @@ export const replaceUrl = function (text: string) {
};
export const checkUserPassword = /^(?=.*[0-9])(?=.*[a-zA-Z])([a-zA-Z0-9]{8,16})$/;
export const checkUserEmail = /^[a-z0-9._%+\-]+@[a-z0-9.\-]+\.[a-z]{2,4}$/;
export function isMatchBusinessCode(businessCode: number) {
const tokenExpiredList = [12002, 12010];

View File

@ -1,5 +1,6 @@
import { Dialog } from '@b-design/ui';
import i18n from '../i18n';
import locale from './locale';
class ResetLogin {
private static singleton: ResetLogin;
@ -14,6 +15,7 @@ class ResetLogin {
content: i18n.t('Authentication failed, please log in again'),
closeable: true,
closeMode: [],
locale: locale().Dialog,
footerActions: ['ok'],
onOk: () => {
localStorage.removeItem('token');

View File

@ -110,6 +110,13 @@ export function getLink(endpointObj: Endpoint) {
if (appProtocol && appProtocol !== '') {
protocol = appProtocol;
}
// Support to open this address in a new window directly.
if (protocol == 'tcp') {
protocol = 'http';
}
if (host == '') {
return path;
}
if (path === '/') {
path = '';
}