mirror of https://github.com/kubevela/velaux.git
Compare commits
7 Commits
Author | SHA1 | Date |
---|---|---|
|
d3710a66ca | |
|
cedb5774bc | |
|
74695e5d4f | |
|
108069563d | |
|
b959214ca7 | |
|
a61257617a | |
|
d342b28cd0 |
|
@ -165,7 +165,6 @@ export const ComponentNode = (props: ComponentNodeProps) => {
|
||||||
</Balloon>
|
</Balloon>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const graphNode = (
|
const graphNode = (
|
||||||
<div
|
<div
|
||||||
className={classNames('graph-node', 'graph-node-resource', {
|
className={classNames('graph-node', 'graph-node-resource', {
|
||||||
|
@ -203,7 +202,7 @@ export const ComponentNode = (props: ComponentNodeProps) => {
|
||||||
|
|
||||||
<If condition={traits.length > 0}>
|
<If condition={traits.length > 0}>
|
||||||
<div className={classNames('label-traits')}>
|
<div className={classNames('label-traits')}>
|
||||||
{traits && (
|
{traits && traits.length > 0 && traits[0] && (
|
||||||
<Tag animation={true}>
|
<Tag animation={true}>
|
||||||
<span
|
<span
|
||||||
className={classNames('circle', {
|
className={classNames('circle', {
|
||||||
|
|
|
@ -34,7 +34,7 @@ class MemoryNumber extends React.Component<Props, State> {
|
||||||
id={id}
|
id={id}
|
||||||
min="0"
|
min="0"
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
addonTextAfter="MB"
|
addonTextAfter="Mi"
|
||||||
htmlType="number"
|
htmlType="number"
|
||||||
onChange={this.onChange}
|
onChange={this.onChange}
|
||||||
value={initValue && initValue}
|
value={initValue && initValue}
|
||||||
|
|
|
@ -51,6 +51,8 @@
|
||||||
"Policies": "策略",
|
"Policies": "策略",
|
||||||
"Policy": "策略",
|
"Policy": "策略",
|
||||||
"New Policy": "新增策略",
|
"New Policy": "新增策略",
|
||||||
|
"Policy Type": "策略类型",
|
||||||
|
"Update Policy": "编辑策略",
|
||||||
"Warning": "部署异常",
|
"Warning": "部署异常",
|
||||||
"EnvironmentPlan": "环境规划",
|
"EnvironmentPlan": "环境规划",
|
||||||
"BasisConfig": "基准配置",
|
"BasisConfig": "基准配置",
|
||||||
|
|
|
@ -467,7 +467,8 @@ class PolicyDialog extends React.Component<Props, State> {
|
||||||
this.uiSchemaRef.current?.validate(callback);
|
this.uiSchemaRef.current?.validate(callback);
|
||||||
};
|
};
|
||||||
const init = this.field.init;
|
const init = this.field.init;
|
||||||
const span = selectedPolicyItem && selectedPolicyItem?.name == 'custom' ? 8 : 12;
|
const showType = (selectedPolicyItem && selectedPolicyItem?.name == 'custom') || policy != undefined;
|
||||||
|
const span = showType ? 8 : 12;
|
||||||
return (
|
return (
|
||||||
<DrawerWithFooter
|
<DrawerWithFooter
|
||||||
title={policy ? i18n.t('Update Policy') : i18n.t('New Policy')}
|
title={policy ? i18n.t('Update Policy') : i18n.t('New Policy')}
|
||||||
|
@ -478,7 +479,7 @@ class PolicyDialog extends React.Component<Props, State> {
|
||||||
>
|
>
|
||||||
<Form field={this.field}>
|
<Form field={this.field}>
|
||||||
<Card contentHeight="auto" title={i18n.t('Select a policy type').toString()}>
|
<Card contentHeight="auto" title={i18n.t('Select a policy type').toString()}>
|
||||||
<If condition={!policy}>
|
{!policy && (
|
||||||
<Row wrap={true}>
|
<Row wrap={true}>
|
||||||
{items.map((item) => {
|
{items.map((item) => {
|
||||||
return (
|
return (
|
||||||
|
@ -496,12 +497,12 @@ class PolicyDialog extends React.Component<Props, State> {
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</Row>
|
</Row>
|
||||||
</If>
|
)}
|
||||||
<If condition={selectedPolicyItem}>
|
{selectedPolicyItem && (
|
||||||
<Row wrap={true}>
|
<Row wrap={true}>
|
||||||
{selectedPolicyItem && selectedPolicyItem?.name == 'custom' && (
|
{showType && (
|
||||||
<Col span={span} style={{ padding: '0 8px' }}>
|
<Col span={span} style={{ padding: '0 8px' }}>
|
||||||
<Form.Item label="Policy Type" required>
|
<Form.Item label={i18n.t('Policy Type')} required>
|
||||||
<Select
|
<Select
|
||||||
{...init('type', {
|
{...init('type', {
|
||||||
rules: [
|
rules: [
|
||||||
|
@ -569,7 +570,7 @@ class PolicyDialog extends React.Component<Props, State> {
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</If>
|
)}
|
||||||
<If condition={selectedPolicyItem?.properties}>
|
<If condition={selectedPolicyItem?.properties}>
|
||||||
<Message style={{ marginTop: '8px' }} type="success">
|
<Message style={{ marginTop: '8px' }} type="success">
|
||||||
<Translation>This policy already have the default properties</Translation>
|
<Translation>This policy already have the default properties</Translation>
|
||||||
|
|
|
@ -27,6 +27,8 @@ import type { Endpoint } from '../../../../interface/observation';
|
||||||
import type { Target } from '../../../../interface/target';
|
import type { Target } from '../../../../interface/target';
|
||||||
import { locale } from '../../../../utils/locale';
|
import { locale } from '../../../../utils/locale';
|
||||||
import { getLink } from '../../../../utils/utils';
|
import { getLink } from '../../../../utils/utils';
|
||||||
|
import { checkPermission } from '../../../../utils/permission';
|
||||||
|
import { LoginUserInfo } from '../../../../interface/user';
|
||||||
|
|
||||||
export type GatewayIP = {
|
export type GatewayIP = {
|
||||||
ip: string;
|
ip: string;
|
||||||
|
@ -47,6 +49,7 @@ type Props = {
|
||||||
disableStatusShow?: boolean;
|
disableStatusShow?: boolean;
|
||||||
refresh: () => void;
|
refresh: () => void;
|
||||||
dispatch: ({}) => void;
|
dispatch: ({}) => void;
|
||||||
|
userInfo?: LoginUserInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
|
@ -162,11 +165,23 @@ class Header extends Component<Props, State> {
|
||||||
};
|
};
|
||||||
|
|
||||||
compareCurrentWithCluster = (appName: string, envName: string) => {
|
compareCurrentWithCluster = (appName: string, envName: string) => {
|
||||||
const { applicationStatus } = this.props;
|
const { applicationStatus, applicationDetail, userInfo } = this.props;
|
||||||
if (!applicationStatus) {
|
if (!applicationStatus) {
|
||||||
this.setState({ compare: undefined });
|
this.setState({ compare: undefined });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
!checkPermission(
|
||||||
|
{
|
||||||
|
resource: `project:${applicationDetail?.project?.name}/application:${applicationDetail?.name}`,
|
||||||
|
action: 'compare',
|
||||||
|
},
|
||||||
|
applicationDetail?.project?.name,
|
||||||
|
userInfo
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
compareApplication(appName, { compareLatestWithRunning: { env: envName } }).then(
|
compareApplication(appName, { compareLatestWithRunning: { env: envName } }).then(
|
||||||
(res: ApplicationCompareResponse) => {
|
(res: ApplicationCompareResponse) => {
|
||||||
this.setState({ compare: res });
|
this.setState({ compare: res });
|
||||||
|
|
|
@ -466,6 +466,7 @@ class ApplicationInstanceList extends React.Component<Props, State> {
|
||||||
<div>
|
<div>
|
||||||
<Header
|
<Header
|
||||||
envbinding={envbinding}
|
envbinding={envbinding}
|
||||||
|
userInfo={userInfo}
|
||||||
targets={this.getTargets()}
|
targets={this.getTargets()}
|
||||||
components={components}
|
components={components}
|
||||||
envName={envName}
|
envName={envName}
|
||||||
|
|
|
@ -306,6 +306,7 @@ class ApplicationStatusPage extends React.Component<Props, State> {
|
||||||
<div className="application-status-wrapper">
|
<div className="application-status-wrapper">
|
||||||
<Loading visible={loading && endpointLoading} style={{ width: '100%' }}>
|
<Loading visible={loading && endpointLoading} style={{ width: '100%' }}>
|
||||||
<Header
|
<Header
|
||||||
|
userInfo={userInfo}
|
||||||
envbinding={this.getEnvbindingByName()}
|
envbinding={this.getEnvbindingByName()}
|
||||||
targets={this.getTargets()}
|
targets={this.getTargets()}
|
||||||
envName={envName}
|
envName={envName}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import { beautifyTime } from '../../utils/common';
|
||||||
import { locale } from '../../utils/locale';
|
import { locale } from '../../utils/locale';
|
||||||
|
|
||||||
import ApplicationWorkflowRecord from './components/WorkflowRecord';
|
import ApplicationWorkflowRecord from './components/WorkflowRecord';
|
||||||
|
import { LoginUserInfo } from '../../interface/user';
|
||||||
|
|
||||||
const { Row, Col } = Grid;
|
const { Row, Col } = Grid;
|
||||||
|
|
||||||
|
@ -34,6 +35,7 @@ type Props = {
|
||||||
applicationStatus?: ApplicationStatus;
|
applicationStatus?: ApplicationStatus;
|
||||||
envbinding: EnvBinding[];
|
envbinding: EnvBinding[];
|
||||||
workflows: Workflow[];
|
workflows: Workflow[];
|
||||||
|
userInfo?: LoginUserInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
|
@ -49,7 +51,7 @@ type State = {
|
||||||
};
|
};
|
||||||
|
|
||||||
@connect((store: any) => {
|
@connect((store: any) => {
|
||||||
return { ...store.application };
|
return { ...store.application, ...store.user };
|
||||||
})
|
})
|
||||||
class ApplicationWorkflow extends React.Component<Props, State> {
|
class ApplicationWorkflow extends React.Component<Props, State> {
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
|
@ -136,7 +138,7 @@ class ApplicationWorkflow extends React.Component<Props, State> {
|
||||||
runApplicationWorkflow = () => {};
|
runApplicationWorkflow = () => {};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { applicationDetail, dispatch, applicationStatus, workflows } = this.props;
|
const { applicationDetail, dispatch, applicationStatus, workflows, userInfo } = this.props;
|
||||||
const {
|
const {
|
||||||
params: { record, appName, envName },
|
params: { record, appName, envName },
|
||||||
} = this.props.match;
|
} = this.props.match;
|
||||||
|
@ -177,6 +179,7 @@ class ApplicationWorkflow extends React.Component<Props, State> {
|
||||||
return (
|
return (
|
||||||
<div className="run-layout">
|
<div className="run-layout">
|
||||||
<Header
|
<Header
|
||||||
|
userInfo={userInfo}
|
||||||
envbinding={this.getEnvbindingByName()}
|
envbinding={this.getEnvbindingByName()}
|
||||||
envName={envName}
|
envName={envName}
|
||||||
appName={appName}
|
appName={appName}
|
||||||
|
|
|
@ -3,7 +3,6 @@ import React from 'react';
|
||||||
|
|
||||||
import { createUser, updateUser } from '../../../../api/users';
|
import { createUser, updateUser } from '../../../../api/users';
|
||||||
import DrawerWithFooter from '../../../../components/Drawer';
|
import DrawerWithFooter from '../../../../components/Drawer';
|
||||||
import { If } from '../../../../components/If';
|
|
||||||
import { Translation } from '../../../../components/Translation';
|
import { Translation } from '../../../../components/Translation';
|
||||||
import i18n from '../../../../i18n';
|
import i18n from '../../../../i18n';
|
||||||
import type { RolesBase } from '../../../../interface/roles';
|
import type { RolesBase } from '../../../../interface/roles';
|
||||||
|
@ -196,7 +195,7 @@ class CreateUser extends React.Component<Props, State> {
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<If condition={!isEditUser}>
|
{!isEditUser && (
|
||||||
<Col span={12} style={{ padding: '0 8px' }}>
|
<Col span={12} style={{ padding: '0 8px' }}>
|
||||||
<FormItem label={<Translation>Password</Translation>} required>
|
<FormItem label={<Translation>Password</Translation>} required>
|
||||||
<Input
|
<Input
|
||||||
|
@ -220,7 +219,7 @@ class CreateUser extends React.Component<Props, State> {
|
||||||
/>
|
/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
</Col>
|
</Col>
|
||||||
</If>
|
)}
|
||||||
<Col span={12} style={{ padding: '0 8px' }}>
|
<Col span={12} style={{ padding: '0 8px' }}>
|
||||||
<FormItem label={<Translation>Email</Translation>} required>
|
<FormItem label={<Translation>Email</Translation>} required>
|
||||||
<Input
|
<Input
|
||||||
|
|
|
@ -26,7 +26,6 @@ import (
|
||||||
"github.com/oam-dev/kubevela/pkg/multicluster"
|
"github.com/oam-dev/kubevela/pkg/multicluster"
|
||||||
"github.com/oam-dev/kubevela/pkg/oam"
|
"github.com/oam-dev/kubevela/pkg/oam"
|
||||||
"github.com/oam-dev/kubevela/pkg/utils"
|
"github.com/oam-dev/kubevela/pkg/utils"
|
||||||
velaerr "github.com/oam-dev/kubevela/pkg/utils/errors"
|
|
||||||
|
|
||||||
"github.com/kubevela/velaux/pkg/server/domain/model"
|
"github.com/kubevela/velaux/pkg/server/domain/model"
|
||||||
"github.com/kubevela/velaux/pkg/server/infrastructure/datastore"
|
"github.com/kubevela/velaux/pkg/server/infrastructure/datastore"
|
||||||
|
@ -38,28 +37,15 @@ func CreateTargetNamespace(ctx context.Context, k8sClient client.Client, cluster
|
||||||
if clusterName == "" || namespace == "" {
|
if clusterName == "" || namespace == "" {
|
||||||
return bcode.ErrTargetInvalidWithEmptyClusterOrNamespace
|
return bcode.ErrTargetInvalidWithEmptyClusterOrNamespace
|
||||||
}
|
}
|
||||||
err := utils.CreateOrUpdateNamespace(multicluster.ContextWithClusterName(ctx, clusterName), k8sClient, namespace, utils.MergeOverrideLabels(map[string]string{
|
return utils.CreateOrUpdateNamespace(multicluster.ContextWithClusterName(ctx, clusterName), k8sClient, namespace, utils.MergeOverrideLabels(map[string]string{
|
||||||
oam.LabelRuntimeNamespaceUsage: oam.VelaNamespaceUsageTarget,
|
oam.LabelRuntimeNamespaceUsage: oam.VelaNamespaceUsageTarget,
|
||||||
}), utils.MergeNoConflictLabels(map[string]string{
|
|
||||||
oam.LabelNamespaceOfTargetName: targetName,
|
oam.LabelNamespaceOfTargetName: targetName,
|
||||||
}))
|
}))
|
||||||
if velaerr.IsLabelConflict(err) {
|
|
||||||
klog.Errorf("update namespace for target err %v", err)
|
|
||||||
return bcode.ErrTargetNamespaceAlreadyBound
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteTargetNamespace delete the namespace of the target
|
// DeleteTargetNamespace delete the namespace of the target
|
||||||
func DeleteTargetNamespace(ctx context.Context, k8sClient client.Client, clusterName, namespace, targetName string) error {
|
func DeleteTargetNamespace(ctx context.Context, k8sClient client.Client, clusterName, namespace, targetName string) error {
|
||||||
err := utils.UpdateNamespace(multicluster.ContextWithClusterName(ctx, clusterName), k8sClient, namespace,
|
err := utils.UpdateNamespace(multicluster.ContextWithClusterName(ctx, clusterName), k8sClient, namespace,
|
||||||
// check no conflict label first to make sure the namespace belong to the target, then override it
|
|
||||||
utils.MergeNoConflictLabels(map[string]string{
|
|
||||||
oam.LabelNamespaceOfTargetName: targetName,
|
|
||||||
}),
|
|
||||||
utils.MergeOverrideLabels(map[string]string{
|
utils.MergeOverrideLabels(map[string]string{
|
||||||
oam.LabelRuntimeNamespaceUsage: "",
|
oam.LabelRuntimeNamespaceUsage: "",
|
||||||
oam.LabelNamespaceOfTargetName: "",
|
oam.LabelNamespaceOfTargetName: "",
|
||||||
|
|
|
@ -493,7 +493,13 @@ func (d *dexHandlerImpl) login(ctx context.Context) (*apisv1.UserBase, error) {
|
||||||
}
|
}
|
||||||
user := &model.User{
|
user := &model.User{
|
||||||
Email: claims.Email,
|
Email: claims.Email,
|
||||||
Name: strings.ToLower(claims.Sub),
|
Name: func() string {
|
||||||
|
sub := strings.ToLower(claims.Sub)
|
||||||
|
if len(sub) > datastore.PrimaryKeyMaxLength {
|
||||||
|
return sub[:datastore.PrimaryKeyMaxLength]
|
||||||
|
}
|
||||||
|
return sub
|
||||||
|
}(),
|
||||||
DexSub: claims.Sub,
|
DexSub: claims.Sub,
|
||||||
Alias: claims.Name,
|
Alias: claims.Name,
|
||||||
LastLoginTime: time.Now(),
|
LastLoginTime: time.Now(),
|
||||||
|
|
|
@ -46,6 +46,9 @@ var (
|
||||||
ErrEntityInvalid = NewDBError(fmt.Errorf("entity is invalid"))
|
ErrEntityInvalid = NewDBError(fmt.Errorf("entity is invalid"))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// PrimaryKeyMaxLength The primary key length should be limited when the datastore is kube-api
|
||||||
|
var PrimaryKeyMaxLength = 31
|
||||||
|
|
||||||
// DBError datastore error
|
// DBError datastore error
|
||||||
type DBError struct {
|
type DBError struct {
|
||||||
err error
|
err error
|
||||||
|
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"github.com/go-playground/validator/v10"
|
"github.com/go-playground/validator/v10"
|
||||||
|
|
||||||
"github.com/kubevela/velaux/pkg/server/domain/service"
|
"github.com/kubevela/velaux/pkg/server/domain/service"
|
||||||
|
"github.com/kubevela/velaux/pkg/server/infrastructure/datastore"
|
||||||
)
|
)
|
||||||
|
|
||||||
var validate = validator.New()
|
var validate = validator.New()
|
||||||
|
@ -72,7 +73,7 @@ func ValidatePayloadType(fl validator.FieldLevel) bool {
|
||||||
// ValidateName custom check name field
|
// ValidateName custom check name field
|
||||||
func ValidateName(fl validator.FieldLevel) bool {
|
func ValidateName(fl validator.FieldLevel) bool {
|
||||||
value := fl.Field().String()
|
value := fl.Field().String()
|
||||||
if len(value) > 31 || len(value) < 2 {
|
if len(value) > datastore.PrimaryKeyMaxLength || len(value) < 2 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return nameRegexp.MatchString(value)
|
return nameRegexp.MatchString(value)
|
||||||
|
|
Loading…
Reference in New Issue