mirror of
https://github.com/kubevela/kubevela.git
synced 2026-02-23 06:14:30 +00:00
Compare commits
50 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2943bc7ce1 | ||
|
|
da0f8916aa | ||
|
|
7609da212f | ||
|
|
7f87a47832 | ||
|
|
04868d217b | ||
|
|
56aa3c24d7 | ||
|
|
a54ba9bb54 | ||
|
|
fbe93dc847 | ||
|
|
dbd855cc25 | ||
|
|
7f136159c0 | ||
|
|
af61b59c5e | ||
|
|
c09e4df452 | ||
|
|
1694980eba | ||
|
|
feee1306fd | ||
|
|
0d56da4ab8 | ||
|
|
b8fd6f9823 | ||
|
|
0fab691ba3 | ||
|
|
3cb172f7ff | ||
|
|
e882a650ae | ||
|
|
ef9c26ffec | ||
|
|
cf2a57c96a | ||
|
|
7acc52ebdb | ||
|
|
3c35d9dadc | ||
|
|
07742b6349 | ||
|
|
d45d086efb | ||
|
|
a31a316171 | ||
|
|
ec287a181f | ||
|
|
50f4d10b00 | ||
|
|
9f27f70da8 | ||
|
|
3df55a92f3 | ||
|
|
fd65c27ecb | ||
|
|
576d928a83 | ||
|
|
d14558a227 | ||
|
|
f48aba6f66 | ||
|
|
f51dccf956 | ||
|
|
a961b002c2 | ||
|
|
bffd43fa2c | ||
|
|
2a88f9221f | ||
|
|
efdef27d0a | ||
|
|
58bef9791f | ||
|
|
c1de71d122 | ||
|
|
f8e320b97c | ||
|
|
f69476df37 | ||
|
|
922892a909 | ||
|
|
f36f7296fd | ||
|
|
eff9d5f6e9 | ||
|
|
a75f32857a | ||
|
|
f011fe14bc | ||
|
|
7889a8c467 | ||
|
|
f37cb3a1a7 |
12
.github/ISSUE_TEMPLATE/question.md
vendored
12
.github/ISSUE_TEMPLATE/question.md
vendored
@@ -1,12 +0,0 @@
|
||||
---
|
||||
name: Question
|
||||
about: Help wanted.
|
||||
title: "[Question]"
|
||||
labels: help wanted
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
Please write your questions.
|
||||
-->
|
||||
6
.github/workflows/dashboard.yml
vendored
6
.github/workflows/dashboard.yml
vendored
@@ -16,7 +16,7 @@ jobs:
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [10.x]
|
||||
node-version: [12.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
@@ -24,6 +24,6 @@ jobs:
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- run: npm install
|
||||
- run: npm run build
|
||||
- run: yarn
|
||||
- run: yarn build
|
||||
|
||||
|
||||
10
.github/workflows/release.yml
vendored
10
.github/workflows/release.yml
vendored
@@ -26,11 +26,11 @@ jobs:
|
||||
- name: Use Node.js 10.x
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: 10.x
|
||||
- name: Run npm install
|
||||
run: make npm-install
|
||||
- name: Run npm build
|
||||
run: make npm-build
|
||||
node-version: 12.x
|
||||
- name: Run dashboard install
|
||||
run: make dashboard-install
|
||||
- name: Run dashboard build
|
||||
run: make dashboard-build
|
||||
- name: Tag helm chart image
|
||||
run: |
|
||||
sed -i 's/latest/${{ steps.get_version.outputs.VERSION }}/g' charts/vela-core/values.yaml
|
||||
|
||||
@@ -103,6 +103,10 @@ linters-settings:
|
||||
rangeValCopy:
|
||||
sizeThreshold: 32
|
||||
|
||||
makezero:
|
||||
# Allow only slices initialized with a length of zero. Default is false.
|
||||
always: false
|
||||
|
||||
linters:
|
||||
enable:
|
||||
- megacheck
|
||||
|
||||
19
Makefile
19
Makefile
@@ -49,13 +49,15 @@ build: fmt vet lint
|
||||
@$(OK) build succeed
|
||||
|
||||
vela-cli:
|
||||
go run hack/chart/generate.go
|
||||
go build -o bin/vela -ldflags ${LDFLAGS} cmd/vela/main.go
|
||||
git checkout cmd/vela/fake/chart_source.go
|
||||
|
||||
npm-build:
|
||||
cd dashboard && npm run build && cd ./..
|
||||
dashboard-build:
|
||||
cd dashboard && yarn build && cd ./..
|
||||
|
||||
npm-install:
|
||||
cd dashboard && npm install && cd ./..
|
||||
dashboard-install:
|
||||
cd dashboard && yarn && cd ./..
|
||||
|
||||
doc-gen:
|
||||
rm -r docs/en/cli/*
|
||||
@@ -220,4 +222,11 @@ ifeq (, $(shell which cue))
|
||||
CUE=$(GOBIN)/cue
|
||||
else
|
||||
CUE=$(shell which cue)
|
||||
endif
|
||||
endif
|
||||
|
||||
start-dashboard:
|
||||
go run pkg/server/main/startAPIServer.go &
|
||||
cd dashboard && yarn && yarn start && cd ..
|
||||
|
||||
swagger-gen:
|
||||
$(GOBIN)/swag init -g server/route.go -d pkg/ -o pkg/server/docs/
|
||||
|
||||
@@ -17,7 +17,7 @@ For developers, KubeVela is an easy-to-use tool that enables them to describe an
|
||||
|
||||
For platform builders, KubeVela serves as a framework that empowers them to create developer facing yet highly extensible platforms at ease.
|
||||
|
||||
- Slack: [Discuss](https://cloud-native.slack.com/archives/C01BLQ3HTJA)
|
||||
- Slack: [CNCF Slack](https://slack.cncf.io/) #kubevela channel
|
||||
- Gitter: [Community](https://gitter.im/oam-dev/community)
|
||||
|
||||
> NOTE: KubeVela is still in early stage and iterating quickly. It's currently under preview release.
|
||||
|
||||
@@ -97,7 +97,7 @@ type WorkloadDefinitionList struct {
|
||||
// A TraitDefinitionSpec defines the desired state of a TraitDefinition.
|
||||
type TraitDefinitionSpec struct {
|
||||
// Reference to the CustomResourceDefinition that defines this trait kind.
|
||||
Reference DefinitionReference `json:"definitionRef"`
|
||||
Reference DefinitionReference `json:"definitionRef,omitempty"`
|
||||
|
||||
// Revision indicates whether a trait is aware of component revision
|
||||
// +optional
|
||||
|
||||
@@ -66,8 +66,6 @@ spec:
|
||||
workloadRefPath:
|
||||
description: WorkloadRefPath indicates where/if a trait accepts a workloadRef object
|
||||
type: string
|
||||
required:
|
||||
- definitionRef
|
||||
type: object
|
||||
type: object
|
||||
served: true
|
||||
|
||||
@@ -12,8 +12,6 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/oam-dev/kubevela/version"
|
||||
|
||||
monitoring "github.com/coreos/prometheus-operator/pkg/apis/monitoring/v1"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/logging"
|
||||
"github.com/go-logr/logr"
|
||||
@@ -42,6 +40,7 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/controller/utils"
|
||||
velawebhook "github.com/oam-dev/kubevela/pkg/webhook"
|
||||
oamwebhook "github.com/oam-dev/kubevela/pkg/webhook/core.oam.dev/v1alpha2"
|
||||
"github.com/oam-dev/kubevela/version"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
144
config/samples/vela-server/Demo.md
Normal file
144
config/samples/vela-server/Demo.md
Normal file
@@ -0,0 +1,144 @@
|
||||
# Application Example
|
||||
|
||||
In this Demo, Application application-sample will be converted to appconfig and component
|
||||
|
||||
The fields in the application spec come from the parametes defined in the definition template
|
||||
, so we must install Definition at first
|
||||
|
||||
Step 1: Install Workload Definition & Trait Definition
|
||||
```
|
||||
kubectl apply -f template.yaml
|
||||
```
|
||||
Step 2: Create a sample application in the cluster
|
||||
```
|
||||
kubectl apply -f application-sample.yaml
|
||||
```
|
||||
Step 3: View the application status
|
||||
```
|
||||
kubectl get -f application-sample.yaml -oyaml
|
||||
|
||||
// You can see the following
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: Application
|
||||
metadata:
|
||||
annotations:
|
||||
kubectl.kubernetes.io/last-applied-configuration: |
|
||||
{"apiVersion":"core.oam.dev/v1alpha2","kind":"Application","metadata":{"annotations":{},"name":"application-sample","namespace":"oam-test"},"spec":{"template":"services:\n myweb:\n type: worker\n image: \"busybox\"\n cmd:\n - sleep\n - \"1000\"\n scaler:\n replicas: 10"}}
|
||||
name: application-sample
|
||||
namespace: oam-test
|
||||
spec:
|
||||
services:
|
||||
myweb:
|
||||
cmd:
|
||||
- sleep
|
||||
- "1000"
|
||||
image: busybox
|
||||
scaler:
|
||||
replicas: 10
|
||||
service:
|
||||
http:
|
||||
server: 80
|
||||
sidecar:
|
||||
command:
|
||||
- sleep
|
||||
- "1000"
|
||||
image: busybox
|
||||
name: test-sidecar
|
||||
type: worker
|
||||
status:
|
||||
conditions:
|
||||
- lastTransitionTime: "2020-12-02T12:12:52Z"
|
||||
reason: Available
|
||||
status: "True"
|
||||
type: Parsed
|
||||
- lastTransitionTime: "2020-12-02T12:12:52Z"
|
||||
reason: Available
|
||||
status: "True"
|
||||
type: Built
|
||||
- lastTransitionTime: "2020-12-02T12:12:52Z"
|
||||
reason: Available
|
||||
status: "True"
|
||||
type: Applied
|
||||
status: running
|
||||
|
||||
```
|
||||
|
||||
Step 4: View the oam CR generated by application
|
||||
|
||||
```
|
||||
kubectl get appconfig/application-sample -oyaml
|
||||
|
||||
// appconfig is as follows
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: ApplicationConfiguration
|
||||
metadata:
|
||||
labels:
|
||||
application.oam.dev: application-sample
|
||||
name: application-sample
|
||||
namespace: oam-test
|
||||
ownerReferences:
|
||||
- apiVersion: core.oam.dev/v1alpha2
|
||||
controller: true
|
||||
kind: Application
|
||||
name: application-sample
|
||||
uid: dca7acc3-664c-422b-aa52-4fe012e37974
|
||||
spec:
|
||||
components:
|
||||
- componentName: myweb
|
||||
traits:
|
||||
- trait:
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: myweb
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 80
|
||||
selector:
|
||||
app: myweb
|
||||
|
||||
kubectl get component/myweb -oyaml
|
||||
|
||||
// component is as follows
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: Component
|
||||
metadata:
|
||||
labels:
|
||||
application.oam.dev: application-sample
|
||||
name: myweb
|
||||
namespace: oam-test
|
||||
ownerReferences:
|
||||
- apiVersion: core.oam.dev/v1alpha2
|
||||
controller: true
|
||||
kind: Application
|
||||
name: application-sample
|
||||
uid: dca7acc3-664c-422b-aa52-4fe012e37974
|
||||
spec:
|
||||
workload:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
spec:
|
||||
replicas: 10
|
||||
selector:
|
||||
matchLabels:
|
||||
app.oam.dev/component: myweb
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: myweb
|
||||
app.oam.dev/component: myweb
|
||||
spec:
|
||||
containers:
|
||||
- command:
|
||||
- sleep
|
||||
- "1000"
|
||||
image: busybox
|
||||
name: myweb
|
||||
- command:
|
||||
- sleep
|
||||
- "1000"
|
||||
image: busybox
|
||||
name: test-sidecar
|
||||
```
|
||||
|
||||
@@ -1,146 +1,332 @@
|
||||
# Vela Server
|
||||
## example
|
||||
# Definition Docs
|
||||
|
||||
In this Demo, Application application-sample will be converted to appconfig and component
|
||||
## Reserved word
|
||||
### patch
|
||||
Perform the CUE AND operation with the content declared by 'patch' and workload cr
|
||||
|
||||
The fields in the application spec come from the parametes defined in the definition template
|
||||
, so we must install Definition at first
|
||||
### output
|
||||
Generate a new cr, which is generally associated with workload cr
|
||||
|
||||
Step 1: Install Workload Definition & Trait Definition
|
||||
## Workload Definition
|
||||
The following workload definition is to generate a deployment
|
||||
```
|
||||
kubectl apply -f template.yaml
|
||||
```
|
||||
Step 2: Create a sample application in the cluster
|
||||
```
|
||||
kubectl apply -f application-sample.yaml
|
||||
```
|
||||
Step 3: View the application status
|
||||
```
|
||||
kubectl get -f application-sample.yaml -oyaml
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: WorkloadDefinition
|
||||
metadata:
|
||||
name: worker
|
||||
annotations:
|
||||
definition.oam.dev/description: "Long-running scalable backend worker without network endpoint"
|
||||
spec:
|
||||
definitionRef:
|
||||
name: deployments.apps
|
||||
extension:
|
||||
template: |
|
||||
output: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
spec: {
|
||||
selector: matchLabels: {
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
|
||||
// You can see the following
|
||||
template: {
|
||||
metadata: labels: {
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
|
||||
spec: {
|
||||
containers: [{
|
||||
name: context.name
|
||||
image: parameter.image
|
||||
|
||||
if parameter["cmd"] != _|_ {
|
||||
command: parameter.cmd
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parameter: {
|
||||
// +usage=Which image would you like to use for your service
|
||||
// +short=i
|
||||
image: string
|
||||
|
||||
cmd?: [...string]
|
||||
}
|
||||
```
|
||||
|
||||
If defined an application as follows
|
||||
```
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: Application
|
||||
metadata:
|
||||
annotations:
|
||||
kubectl.kubernetes.io/last-applied-configuration: |
|
||||
{"apiVersion":"core.oam.dev/v1alpha2","kind":"Application","metadata":{"annotations":{},"name":"application-sample","namespace":"oam-test"},"spec":{"template":"services:\n myweb:\n type: worker\n image: \"busybox\"\n cmd:\n - sleep\n - \"1000\"\n scaler:\n replicas: 10"}}
|
||||
name: application-sample
|
||||
namespace: oam-test
|
||||
spec:
|
||||
services:
|
||||
myweb:
|
||||
type: worker
|
||||
image: "busybox"
|
||||
cmd:
|
||||
- sleep
|
||||
- "1000"
|
||||
image: busybox
|
||||
scaler:
|
||||
replicas: 10
|
||||
type: worker
|
||||
status:
|
||||
conditions:
|
||||
- lastTransitionTime: "2020-12-02T12:12:52Z"
|
||||
reason: Available
|
||||
status: "True"
|
||||
type: Parsed
|
||||
- lastTransitionTime: "2020-12-02T12:12:52Z"
|
||||
reason: Available
|
||||
status: "True"
|
||||
type: Built
|
||||
- lastTransitionTime: "2020-12-02T12:12:52Z"
|
||||
reason: Available
|
||||
status: "True"
|
||||
type: Applied
|
||||
status: running
|
||||
|
||||
```
|
||||
|
||||
Step 4: View the oam CR generated by application
|
||||
|
||||
we will get a deployment
|
||||
```
|
||||
kubectl get appconfig/application-sample -oyaml
|
||||
|
||||
// appconfig is as follows
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: ApplicationConfiguration
|
||||
metadata:
|
||||
labels:
|
||||
application.oam.dev: application-sample
|
||||
name: application-sample
|
||||
namespace: oam-test
|
||||
ownerReferences:
|
||||
- apiVersion: core.oam.dev/v1alpha2
|
||||
controller: true
|
||||
kind: Application
|
||||
name: application-sample
|
||||
uid: dca7acc3-664c-422b-aa52-4fe012e37974
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
spec:
|
||||
components:
|
||||
- componentName: myweb
|
||||
traits:
|
||||
- trait:
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: ManualScalerTrait
|
||||
spec:
|
||||
replicaCount: 10
|
||||
status:
|
||||
conditions:
|
||||
- lastTransitionTime: "2020-12-02T12:12:52Z"
|
||||
reason: Successfully reconciled resource
|
||||
status: "True"
|
||||
type: Synced
|
||||
dependency: {}
|
||||
workloads:
|
||||
- componentName: myweb
|
||||
componentRevisionName: myweb-v1
|
||||
traits:
|
||||
- traitRef:
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: ManualScalerTrait
|
||||
name: myweb-trait-78fdd467d6
|
||||
workloadRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: myweb
|
||||
|
||||
kubectl get component/myweb -oyaml
|
||||
|
||||
// component is as follows
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: Component
|
||||
metadata:
|
||||
labels:
|
||||
application.oam.dev: application-sample
|
||||
name: myweb
|
||||
namespace: oam-test
|
||||
ownerReferences:
|
||||
- apiVersion: core.oam.dev/v1alpha2
|
||||
controller: true
|
||||
kind: Application
|
||||
name: application-sample
|
||||
uid: dca7acc3-664c-422b-aa52-4fe012e37974
|
||||
spec:
|
||||
workload:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
selector:
|
||||
matchLabels:
|
||||
app.oam.dev/component: myweb
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.oam.dev/component: myweb
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app.oam.dev/component: myweb
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.oam.dev/component: myweb
|
||||
spec:
|
||||
containers:
|
||||
- command:
|
||||
- sleep
|
||||
- "1000"
|
||||
image: busybox
|
||||
name: myweb
|
||||
status:
|
||||
latestRevision:
|
||||
name: myweb-v1
|
||||
revision: 1
|
||||
containers:
|
||||
- command:
|
||||
- sleep
|
||||
- "1000"
|
||||
image: busybox
|
||||
name: myweb
|
||||
```
|
||||
## Service Trait Definition
|
||||
|
||||
Define a trait Definition that appends service to workload(worker) , as shown below
|
||||
```
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: "service the app"
|
||||
name: service
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- webservice
|
||||
- worker
|
||||
definitionRef:
|
||||
name: service.v1
|
||||
extension:
|
||||
template: |-
|
||||
patch: {spec: template: metadata: labels: app: context.name}
|
||||
output: {
|
||||
apiVersion: "v1"
|
||||
kind: "Service"
|
||||
metadata: name: context.name
|
||||
spec: {
|
||||
selector: app: context.name
|
||||
ports: [
|
||||
for k, v in parameter.http {
|
||||
port: v
|
||||
targetPort: v
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
http: [string]: int
|
||||
}
|
||||
```
|
||||
|
||||
If add service capability to the application, as follows
|
||||
```
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: Application
|
||||
metadata:
|
||||
name: application-sample
|
||||
spec:
|
||||
services:
|
||||
myweb:
|
||||
type: worker
|
||||
image: "busybox"
|
||||
cmd:
|
||||
- sleep
|
||||
- "1000"
|
||||
service:
|
||||
http:
|
||||
server: 80
|
||||
```
|
||||
|
||||
we will get a new deployment and service
|
||||
```
|
||||
// origin deployment template add labels
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app.oam.dev/component: myweb
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
// add label app
|
||||
app: myweb
|
||||
app.oam.dev/component: myweb
|
||||
spec:
|
||||
containers:
|
||||
- command:
|
||||
- sleep
|
||||
- "1000"
|
||||
image: busybox
|
||||
name: myweb
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: myweb
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 80
|
||||
selector:
|
||||
app: myweb
|
||||
```
|
||||
|
||||
## Scaler Trait Definition
|
||||
|
||||
Define a trait Definition that scale workload(worker) replicas
|
||||
```
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: "Manually scale the app"
|
||||
name: scaler
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- webservice
|
||||
- worke
|
||||
extension:
|
||||
template: |-
|
||||
patch: {
|
||||
spec: replicas: parameter.replicas
|
||||
}
|
||||
parameter: {
|
||||
//+short=r
|
||||
replicas: *1 | int
|
||||
}
|
||||
```
|
||||
If add scaler capability to the application, as follows
|
||||
```
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: Application
|
||||
metadata:
|
||||
name: application-sample
|
||||
spec:
|
||||
services:
|
||||
myweb:
|
||||
type: worker
|
||||
image: "busybox"
|
||||
cmd:
|
||||
- sleep
|
||||
- "1000"
|
||||
service:
|
||||
http:
|
||||
server: 80
|
||||
scaler:
|
||||
replicas: 10
|
||||
```
|
||||
|
||||
The deployment replicas will be scale to 10
|
||||
```
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app.oam.dev/component: myweb
|
||||
// scale to 10
|
||||
replicas: 10
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
// add label app
|
||||
app: myweb
|
||||
app.oam.dev/component: myweb
|
||||
spec:
|
||||
containers:
|
||||
- command:
|
||||
- sleep
|
||||
- "1000"
|
||||
image: busybox
|
||||
name: myweb
|
||||
```
|
||||
|
||||
## Sidecar Trait Definition
|
||||
|
||||
Define a trait Definition that append containers to workload(worker)
|
||||
```
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: "add sidecar to the app"
|
||||
name: sidecar
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- webservice
|
||||
- worke
|
||||
extension:
|
||||
template: |-
|
||||
_containers: context.input.spec.template.spec.containers+[parameter]
|
||||
patch: {
|
||||
spec: template: spec: containers: _containers
|
||||
}
|
||||
parameter: {
|
||||
name: string
|
||||
image: string
|
||||
command?: [...string]
|
||||
}
|
||||
```
|
||||
|
||||
If add sidercar capability to the application, as follows
|
||||
```
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: Application
|
||||
metadata:
|
||||
name: application-sample
|
||||
spec:
|
||||
services:
|
||||
myweb:
|
||||
type: worker
|
||||
image: "busybox"
|
||||
cmd:
|
||||
- sleep
|
||||
- "1000"
|
||||
service:
|
||||
http:
|
||||
server: 80
|
||||
scaler:
|
||||
replicas: 10
|
||||
sidercar:
|
||||
name: "sidecar-test"
|
||||
image: "nginx"
|
||||
```
|
||||
The deployment updated as follows
|
||||
```
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app.oam.dev/component: myweb
|
||||
// scale to 10
|
||||
replicas: 10
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
// add label app
|
||||
app: myweb
|
||||
app.oam.dev/component: myweb
|
||||
spec:
|
||||
containers:
|
||||
- command:
|
||||
- sleep
|
||||
- "1000"
|
||||
image: busybox
|
||||
name: myweb
|
||||
- name: sidecar-test
|
||||
image: nginx
|
||||
```
|
||||
@@ -11,4 +11,10 @@ spec:
|
||||
- sleep
|
||||
- "1000"
|
||||
scaler:
|
||||
replicas: 10
|
||||
replicas: 10
|
||||
sidercar:
|
||||
name: "sidecar-test"
|
||||
image: "nginx"
|
||||
service:
|
||||
http:
|
||||
server: 80
|
||||
@@ -58,19 +58,76 @@ spec:
|
||||
appliesToWorkloads:
|
||||
- webservice
|
||||
- worker
|
||||
definitionRef:
|
||||
name: manualscalertraits.core.oam.dev
|
||||
workloadRefPath: spec.workloadRef
|
||||
extension:
|
||||
template: |-
|
||||
output: {
|
||||
apiVersion: "core.oam.dev/v1alpha2"
|
||||
kind: "ManualScalerTrait"
|
||||
spec: {
|
||||
replicaCount: parameter.replicas
|
||||
}
|
||||
patch: {
|
||||
spec: replicas: parameter.replicas
|
||||
}
|
||||
parameter: {
|
||||
//+short=r
|
||||
replicas: *1 | int
|
||||
}
|
||||
---
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: "add sidecar to the app"
|
||||
name: sidecar
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- webservice
|
||||
- worker
|
||||
extension:
|
||||
template: |-
|
||||
_containers: context.input.spec.template.spec.containers+[parameter]
|
||||
patch: {
|
||||
spec: template: spec: containers: _containers
|
||||
}
|
||||
parameter: {
|
||||
name: string
|
||||
image: string
|
||||
command?: [...string]
|
||||
}
|
||||
---
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: "service the app"
|
||||
name: service
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- webservice
|
||||
- worker
|
||||
definitionRef:
|
||||
name: services
|
||||
extension:
|
||||
template: |-
|
||||
patch: {spec: template: metadata: labels: app: context.name}
|
||||
output: {
|
||||
apiVersion: "v1"
|
||||
kind: "Service"
|
||||
metadata: name: context.name
|
||||
spec: {
|
||||
selector: app: context.name
|
||||
ports: [
|
||||
for k, v in parameter.http {
|
||||
port: v
|
||||
targetPort: v
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
http: [string]: int
|
||||
}
|
||||
---
|
||||
apiVersion: core.oam.dev/v1alpha2
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
name: services
|
||||
namespace: default
|
||||
spec:
|
||||
definitionRef:
|
||||
name: services
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
/lambda/
|
||||
/scripts
|
||||
/config
|
||||
.history
|
||||
.history
|
||||
public
|
||||
dist
|
||||
.umi
|
||||
mock
|
||||
@@ -5,4 +5,8 @@ module.exports = {
|
||||
page: true,
|
||||
REACT_APP_ENV: true,
|
||||
},
|
||||
rules: {
|
||||
'react/jsx-uses-react': 'off',
|
||||
'react/react-in-jsx-scope': 'off',
|
||||
},
|
||||
};
|
||||
|
||||
37
dashboard/.gitignore
vendored
Normal file
37
dashboard/.gitignore
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
**/node_modules
|
||||
# roadhog-api-doc ignore
|
||||
/src/utils/request-temp.js
|
||||
_roadhog-api-doc
|
||||
|
||||
# production
|
||||
/dist
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
npm-debug.log*
|
||||
yarn-error.log
|
||||
|
||||
/coverage
|
||||
.idea
|
||||
*bak
|
||||
.vscode
|
||||
|
||||
# visual studio code
|
||||
.history
|
||||
*.log
|
||||
functions/*
|
||||
.temp/**
|
||||
|
||||
# umi
|
||||
.umi
|
||||
.umi-production
|
||||
|
||||
# screenshot
|
||||
screenshot
|
||||
.firebase
|
||||
.eslintcache
|
||||
|
||||
build
|
||||
@@ -20,3 +20,4 @@ yarn-error.log
|
||||
.history
|
||||
CNAME
|
||||
/build
|
||||
/public
|
||||
@@ -5,12 +5,6 @@
|
||||
|
||||
Install `node_modules`:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```bash
|
||||
yarn
|
||||
```
|
||||
@@ -22,29 +16,29 @@ Scripts provided in `package.json`. It's safe to modify or add additional script
|
||||
### Start project
|
||||
|
||||
```bash
|
||||
npm start
|
||||
yarn start
|
||||
```
|
||||
|
||||
### Build project
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
yarn build
|
||||
```
|
||||
|
||||
### Check code style
|
||||
|
||||
```bash
|
||||
npm run lint
|
||||
yarn lint
|
||||
```
|
||||
|
||||
You can also use script to auto fix some lint error:
|
||||
|
||||
```bash
|
||||
npm run lint:fix
|
||||
yarn lint:fix
|
||||
```
|
||||
|
||||
### Test code
|
||||
|
||||
```bash
|
||||
npm test
|
||||
yarn test
|
||||
```
|
||||
@@ -1,153 +0,0 @@
|
||||
// https://umijs.org/config/
|
||||
import { defineConfig } from 'umi';
|
||||
import defaultSettings from './defaultSettings';
|
||||
import proxy from './proxy';
|
||||
|
||||
const { REACT_APP_ENV } = process.env;
|
||||
export default defineConfig({
|
||||
history: { type: 'hash' },
|
||||
hash: false,
|
||||
antd: {},
|
||||
dva: {
|
||||
hmr: true,
|
||||
},
|
||||
locale: {
|
||||
default: 'en-US',
|
||||
antd: false,
|
||||
baseNavigator: false,
|
||||
},
|
||||
dynamicImport: {
|
||||
loading: '@/components/PageLoading/index',
|
||||
},
|
||||
targets: {
|
||||
ie: 11,
|
||||
},
|
||||
// umi routes: https://umijs.org/docs/routing
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
component: '../layouts/SecurityLayout',
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
component: '../layouts/BasicLayout',
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
redirect: `/ApplicationList`,
|
||||
},
|
||||
{
|
||||
name: 'ApplicationList',
|
||||
icon: 'table',
|
||||
path: `/ApplicationList`,
|
||||
component: './ApplicationList',
|
||||
},
|
||||
{
|
||||
name: 'ApplicationList.WorkloadDetail',
|
||||
icon: 'smile',
|
||||
path: '/ApplicationList/WorkloadDetail',
|
||||
component: './Workload/Detail',
|
||||
hideInMenu: true,
|
||||
},
|
||||
{
|
||||
name: 'ApplicationList.TraitDetail',
|
||||
icon: 'smile',
|
||||
path: '/ApplicationList/TraitDetail',
|
||||
component: './Traits/Detail',
|
||||
hideInMenu: true,
|
||||
},
|
||||
{
|
||||
name: 'ApplicationList.Components',
|
||||
hideInMenu: true,
|
||||
path: '/ApplicationList/:appName/Components',
|
||||
component: './ApplicationList/Components',
|
||||
},
|
||||
{
|
||||
name: 'ApplicationList.Components.createComponent',
|
||||
hideInMenu: true,
|
||||
path: '/ApplicationList/:appName/createComponent',
|
||||
component: './ApplicationList/CreateComponent',
|
||||
},
|
||||
{
|
||||
name: 'Workload',
|
||||
icon: 'table',
|
||||
path: '/Workload',
|
||||
routes: [
|
||||
{
|
||||
name: 'WorkloadItem',
|
||||
icon: 'smile',
|
||||
path: '/Workload/:WorkloadType',
|
||||
component: './Workload/index.jsx',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/Traits',
|
||||
name: 'Traits',
|
||||
icon: 'table',
|
||||
routes: [
|
||||
{
|
||||
name: 'TraitItem',
|
||||
icon: 'smile',
|
||||
path: '/Traits/:traitType',
|
||||
component: './Traits/index.jsx',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Capability',
|
||||
icon: 'table',
|
||||
path: '/Capability',
|
||||
component: './Capability',
|
||||
},
|
||||
{
|
||||
path: '/System',
|
||||
name: 'System',
|
||||
icon: 'table',
|
||||
routes: [
|
||||
{
|
||||
name: 'Env',
|
||||
icon: 'table',
|
||||
path: '/System/Env',
|
||||
component: './System/Env',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Capability.Detail',
|
||||
hideInMenu: true,
|
||||
path: '/Capability/Detail',
|
||||
component: './Capability/Detail',
|
||||
},
|
||||
{
|
||||
component: './404',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
component: './404',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
component: './404',
|
||||
},
|
||||
],
|
||||
// Theme for antd: https://ant.design/docs/react/customize-theme-cn
|
||||
theme: {
|
||||
// 主题配置
|
||||
'primary-color': defaultSettings.primaryColor,
|
||||
'link-color': defaultSettings.linkColor,
|
||||
'link-hover-color': defaultSettings.linkHoverColor,
|
||||
'disabled-bg': defaultSettings.disabledBg,
|
||||
'disabled-color': defaultSettings.disabledColor,
|
||||
'btn-disable-color': defaultSettings.btnDisableColor,
|
||||
},
|
||||
// @ts-ignore
|
||||
title: false,
|
||||
ignoreMomentLocale: true,
|
||||
proxy: proxy[REACT_APP_ENV || 'dev'],
|
||||
manifest: {
|
||||
basePath: '/',
|
||||
},
|
||||
});
|
||||
68
dashboard/config/config.ts
Normal file
68
dashboard/config/config.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
// https://umijs.org/config/
|
||||
import { defineConfig } from 'umi';
|
||||
|
||||
import defaultSettings from './defaultSettings';
|
||||
import proxy from './proxy';
|
||||
import routes from './routes';
|
||||
import themeSettings from './themeSettings';
|
||||
|
||||
const { REACT_APP_ENV } = process.env;
|
||||
|
||||
export default defineConfig({
|
||||
hash: true,
|
||||
antd: {},
|
||||
dva: {
|
||||
hmr: true,
|
||||
},
|
||||
layout: {
|
||||
name: 'KubeVela',
|
||||
locale: true,
|
||||
siderWidth: 208,
|
||||
...defaultSettings,
|
||||
},
|
||||
locale: {
|
||||
// default en-US
|
||||
default: 'en-US',
|
||||
antd: true,
|
||||
// default true, when it is true, will use `navigator.language` overwrite default
|
||||
baseNavigator: true,
|
||||
},
|
||||
dynamicImport: {
|
||||
loading: '@ant-design/pro-layout/es/PageLoading',
|
||||
},
|
||||
nodeModulesTransform: {
|
||||
type: 'none',
|
||||
},
|
||||
targets: {
|
||||
ie: 11,
|
||||
},
|
||||
// umi routes: https://umijs.org/docs/routing
|
||||
routes,
|
||||
// Theme for antd: https://ant.design/docs/react/customize-theme-cn
|
||||
theme: {
|
||||
'primary-color': defaultSettings.primaryColor,
|
||||
'link-color': themeSettings.linkColor,
|
||||
'link-hover-color': themeSettings.linkHoverColor,
|
||||
'disabled-bg': themeSettings.disabledBg,
|
||||
'disabled-color': themeSettings.disabledColor,
|
||||
'btn-disable-color': themeSettings.btnDisableColor,
|
||||
},
|
||||
esbuild: {},
|
||||
title: false,
|
||||
ignoreMomentLocale: true,
|
||||
proxy: proxy[REACT_APP_ENV || 'dev'],
|
||||
manifest: {
|
||||
basePath: '/',
|
||||
},
|
||||
// https://github.com/zthxxx/react-dev-inspector
|
||||
plugins: ['react-dev-inspector/plugins/umi/react-inspector'],
|
||||
inspectorConfig: {
|
||||
// loader options type and docs see below
|
||||
exclude: [],
|
||||
babelPlugins: [],
|
||||
babelOptions: {},
|
||||
},
|
||||
resolve: {
|
||||
includes: ['src/components'],
|
||||
},
|
||||
});
|
||||
@@ -1,22 +0,0 @@
|
||||
const proSettings = {
|
||||
navTheme: 'dark',
|
||||
// 主题颜色配置
|
||||
primaryColor: '#1B58F4', // 全局主色
|
||||
linkColor: '#1B58F4', // 链接色
|
||||
linkHoverColor: '#1B58F4',
|
||||
disabledBg: '#EBEBEB', // 失效背景色,
|
||||
disabledColor: '#BEBEBE', // 失效文本色,
|
||||
btnDisableColor: '#A4A4A4', // 禁用btn文字颜色
|
||||
layout: 'side',
|
||||
contentWidth: 'Fluid',
|
||||
fixedHeader: false,
|
||||
fixSiderbar: true,
|
||||
colorWeak: false,
|
||||
menu: {
|
||||
locale: false,
|
||||
},
|
||||
title: 'Micro App Engine',
|
||||
pwa: false,
|
||||
iconfontUrl: '',
|
||||
};
|
||||
export default proSettings;
|
||||
22
dashboard/config/defaultSettings.ts
Normal file
22
dashboard/config/defaultSettings.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Settings as LayoutSettings } from '@ant-design/pro-layout';
|
||||
|
||||
import themeSettings from './themeSettings';
|
||||
|
||||
const Settings: LayoutSettings & {
|
||||
pwa?: boolean;
|
||||
logo?: string;
|
||||
} = {
|
||||
navTheme: 'dark',
|
||||
primaryColor: themeSettings.primaryColor, // 全局主色
|
||||
layout: 'mix',
|
||||
contentWidth: 'Fluid',
|
||||
fixedHeader: false,
|
||||
fixSiderbar: true,
|
||||
colorWeak: false,
|
||||
title: 'KubeVela',
|
||||
pwa: false,
|
||||
logo: 'https://gw.alipayobjects.com/zos/rmsportal/KDpgvguMpGfqaHPjicRK.svg',
|
||||
iconfontUrl: '',
|
||||
};
|
||||
|
||||
export default Settings;
|
||||
@@ -1,33 +0,0 @@
|
||||
/**
|
||||
* 在生产环境 代理是无法生效的,所以这里没有生产环境的配置
|
||||
* The agent cannot take effect in the production environment
|
||||
* so there is no configuration of the production environment
|
||||
* For details, please see
|
||||
* https://pro.ant.design/docs/deploy
|
||||
*/
|
||||
export default {
|
||||
dev: {
|
||||
'/api': {
|
||||
target: 'http://127.0.0.1:38081/',
|
||||
changeOrigin: true,
|
||||
},
|
||||
},
|
||||
test: {
|
||||
'/api/': {
|
||||
target: 'https://preview.pro.ant.design',
|
||||
changeOrigin: true,
|
||||
pathRewrite: {
|
||||
'^': '',
|
||||
},
|
||||
},
|
||||
},
|
||||
pre: {
|
||||
'/api/': {
|
||||
target: 'your pre url',
|
||||
changeOrigin: true,
|
||||
pathRewrite: {
|
||||
'^': '',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
20
dashboard/config/proxy.ts
Normal file
20
dashboard/config/proxy.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
export default {
|
||||
dev: {
|
||||
'/api/': {
|
||||
target: 'http://localhost:8081/',
|
||||
changeOrigin: true,
|
||||
},
|
||||
},
|
||||
test: {
|
||||
'/api/': {
|
||||
target: 'http://localhost:38081/',
|
||||
changeOrigin: true,
|
||||
},
|
||||
},
|
||||
pre: {
|
||||
'/api/': {
|
||||
target: 'http://localhost:38081/',
|
||||
changeOrigin: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
31
dashboard/config/routes.ts
Normal file
31
dashboard/config/routes.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
export default [
|
||||
{
|
||||
path: '/',
|
||||
redirect: `/System`,
|
||||
},
|
||||
{
|
||||
name: 'applications',
|
||||
icon: 'appstore',
|
||||
path: `/applications`,
|
||||
component: './Application',
|
||||
},
|
||||
{
|
||||
name: 'system',
|
||||
icon: 'setting',
|
||||
path: '/System',
|
||||
routes: [
|
||||
{
|
||||
path: '/System',
|
||||
redirect: `/System/Environment`,
|
||||
},
|
||||
{
|
||||
name: 'environment',
|
||||
path: '/System/Environment',
|
||||
component: './System/Environment',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
component: './404',
|
||||
},
|
||||
];
|
||||
9
dashboard/config/themeSettings.ts
Normal file
9
dashboard/config/themeSettings.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
const themeSettings = {
|
||||
primaryColor: '#1b58f4', // 全局主色
|
||||
linkColor: '#1b58f4', // 链接色
|
||||
linkHoverColor: '#1b58f4',
|
||||
disabledBg: '#ebebeb', // 失效背景色,
|
||||
disabledColor: '#bebebe', // 失效文本色,
|
||||
btnDisableColor: '#a4a4a4', // 禁用btn文字颜色
|
||||
};
|
||||
export default themeSettings;
|
||||
@@ -2,6 +2,7 @@ module.exports = {
|
||||
testURL: 'http://localhost:8000',
|
||||
testEnvironment: './tests/PuppeteerEnvironment',
|
||||
verbose: false,
|
||||
extraSetupFiles: ['./tests/setupTests.js'],
|
||||
globals: {
|
||||
ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: false,
|
||||
localStorage: null,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "micro-app-engine",
|
||||
"version": "4.2.0",
|
||||
"name": "kubevela",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"description": "An out-of-box UI solution for enterprise applications",
|
||||
"scripts": {
|
||||
@@ -8,19 +8,19 @@
|
||||
"build": "umi build",
|
||||
"deploy": "npm run site && npm run gh-pages",
|
||||
"dev": "npm run start:dev",
|
||||
"fetch:blocks": "pro fetch-blocks && npm run prettier",
|
||||
"gh-pages": "gh-pages -d dist",
|
||||
"i18n-remove": "pro i18n-remove --locale=zh-CN --write",
|
||||
"postinstall": "umi g tmp",
|
||||
"lint": "umi g tmp && npm run lint:js && npm run lint:style && npm run lint:prettier",
|
||||
"lint-staged": "lint-staged",
|
||||
"lint-staged:js": "eslint --ext .js,.jsx,.ts,.tsx ",
|
||||
"lint:fix": "eslint --fix --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src && npm run lint:style",
|
||||
"lint:js": "eslint --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src",
|
||||
"lint:prettier": "prettier --check \"**/*\" --end-of-line auto",
|
||||
"lint:prettier": "prettier --check \"src/**/*\" --end-of-line auto",
|
||||
"lint:style": "stylelint --fix \"src/**/*.less\" --syntax less",
|
||||
"precommit": "lint-staged",
|
||||
"prettier": "prettier -c --write \"**/*\"",
|
||||
"start": "cross-env UMI_UI=none umi dev",
|
||||
"prettier": "prettier -c --write \"src/**/*\"",
|
||||
"start": "umi dev",
|
||||
"start:dev": "cross-env REACT_APP_ENV=dev MOCK=none umi dev",
|
||||
"start:no-mock": "cross-env MOCK=none umi dev",
|
||||
"start:no-ui": "cross-env UMI_UI=none umi dev",
|
||||
@@ -30,7 +30,7 @@
|
||||
"test": "umi test",
|
||||
"test:all": "node ./tests/run-tests.js",
|
||||
"test:component": "umi test ./src/components",
|
||||
"tsc": "tsc"
|
||||
"tsc": "tsc --noEmit"
|
||||
},
|
||||
"lint-staged": {
|
||||
"**/*.less": "stylelint --syntax less",
|
||||
@@ -45,44 +45,46 @@
|
||||
"not ie <= 10"
|
||||
],
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^4.0.0",
|
||||
"@ant-design/pro-layout": "^6.2.5",
|
||||
"@ant-design/pro-table": "^2.4.0",
|
||||
"@antv/g6": "^3.6.2",
|
||||
"antd": "^4.4.0",
|
||||
"@ant-design/icons": "^4.3.0",
|
||||
"@ant-design/pro-descriptions": "^1.0.19",
|
||||
"@ant-design/pro-form": "^1.9.0",
|
||||
"@ant-design/pro-layout": "^6.6.1",
|
||||
"@ant-design/pro-table": "^2.15.1",
|
||||
"@umijs/route-utils": "^1.0.33",
|
||||
"antd": "^4.8.6",
|
||||
"classnames": "^2.2.6",
|
||||
"dva": "^2.4.1",
|
||||
"dayjs": "^1.9.7",
|
||||
"lodash": "^4.17.11",
|
||||
"moment": "^2.25.3",
|
||||
"omit.js": "^2.0.2",
|
||||
"path-to-regexp": "2.4.0",
|
||||
"qs": "^6.9.0",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6",
|
||||
"react": "^17.0.0",
|
||||
"react-dev-inspector": "^1.1.1",
|
||||
"react-dom": "^17.0.0",
|
||||
"react-helmet-async": "^1.0.4",
|
||||
"umi": "^3.2.13",
|
||||
"umi": "^3.2.14",
|
||||
"umi-request": "^1.0.8",
|
||||
"use-merge-value": "^1.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ant-design/pro-cli": "^1.0.18",
|
||||
"@ant-design/pro-cli": "^2.0.2",
|
||||
"@types/classnames": "^2.2.7",
|
||||
"@types/express": "^4.17.0",
|
||||
"@types/history": "^4.7.2",
|
||||
"@types/jest": "^26.0.0",
|
||||
"@types/lodash": "^4.14.144",
|
||||
"@types/qs": "^6.5.3",
|
||||
"@types/react": "^16.9.17",
|
||||
"@types/react-dom": "^16.8.4",
|
||||
"@types/react-helmet": "^5.0.13",
|
||||
"@umijs/fabric": "^2.2.0",
|
||||
"@types/react": "^17.0.0",
|
||||
"@types/react-dom": "^17.0.0",
|
||||
"@types/react-helmet": "^6.1.0",
|
||||
"@umijs/fabric": "^2.3.0",
|
||||
"@umijs/plugin-blocks": "^2.0.5",
|
||||
"@umijs/plugin-esbuild": "^1.0.1",
|
||||
"@umijs/preset-ant-design-pro": "^1.2.0",
|
||||
"@umijs/preset-react": "^1.4.8",
|
||||
"@umijs/preset-ui": "^2.0.9",
|
||||
"@umijs/preset-dumi": "^1.1.0-rc.6",
|
||||
"@umijs/preset-react": "^1.7.8",
|
||||
"@umijs/yorkie": "^2.0.3",
|
||||
"carlo": "^0.9.46",
|
||||
"chalk": "^4.0.0",
|
||||
"cross-env": "^7.0.0",
|
||||
"cross-port-killer": "^1.1.1",
|
||||
"detect-installer": "^1.0.1",
|
||||
@@ -96,16 +98,10 @@
|
||||
"prettier": "^2.0.1",
|
||||
"pro-download": "1.0.1",
|
||||
"puppeteer-core": "^5.0.0",
|
||||
"stylelint": "^13.0.0"
|
||||
"stylelint": "^13.0.0",
|
||||
"typescript": "^4.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"checkFiles": [
|
||||
"src/**/*.js*",
|
||||
"src/**/*.ts*",
|
||||
"src/**/*.less",
|
||||
"config/**/*.js*",
|
||||
"scripts/**/*.js"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
preview.pro.ant.design
|
||||
BIN
dashboard/public/favicon.ico
Normal file
BIN
dashboard/public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
BIN
dashboard/public/icons/icon-128x128.png
Normal file
BIN
dashboard/public/icons/icon-128x128.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
BIN
dashboard/public/icons/icon-192x192.png
Normal file
BIN
dashboard/public/icons/icon-192x192.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
BIN
dashboard/public/icons/icon-512x512.png
Normal file
BIN
dashboard/public/icons/icon-512x512.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.0 KiB |
1
dashboard/public/logo.svg
Normal file
1
dashboard/public/logo.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200" version="1.1" viewBox="0 0 200 200"><title>Group 28 Copy 5</title><desc>Created with Sketch.</desc><defs><linearGradient id="linearGradient-1" x1="62.102%" x2="108.197%" y1="0%" y2="37.864%"><stop offset="0%" stop-color="#4285EB"/><stop offset="100%" stop-color="#2EC7FF"/></linearGradient><linearGradient id="linearGradient-2" x1="69.644%" x2="54.043%" y1="0%" y2="108.457%"><stop offset="0%" stop-color="#29CDFF"/><stop offset="37.86%" stop-color="#148EFF"/><stop offset="100%" stop-color="#0A60FF"/></linearGradient><linearGradient id="linearGradient-3" x1="69.691%" x2="16.723%" y1="-12.974%" y2="117.391%"><stop offset="0%" stop-color="#FA816E"/><stop offset="41.473%" stop-color="#F74A5C"/><stop offset="100%" stop-color="#F51D2C"/></linearGradient><linearGradient id="linearGradient-4" x1="68.128%" x2="30.44%" y1="-35.691%" y2="114.943%"><stop offset="0%" stop-color="#FA8E7D"/><stop offset="51.264%" stop-color="#F74A5C"/><stop offset="100%" stop-color="#F51D2C"/></linearGradient></defs><g id="Page-1" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1"><g id="logo" transform="translate(-20.000000, -20.000000)"><g id="Group-28-Copy-5" transform="translate(20.000000, 20.000000)"><g id="Group-27-Copy-3"><g id="Group-25" fill-rule="nonzero"><g id="2"><path id="Shape" fill="url(#linearGradient-1)" d="M91.5880863,4.17652823 L4.17996544,91.5127728 C-0.519240605,96.2081146 -0.519240605,103.791885 4.17996544,108.487227 L91.5880863,195.823472 C96.2872923,200.518814 103.877304,200.518814 108.57651,195.823472 L145.225487,159.204632 C149.433969,154.999611 149.433969,148.181924 145.225487,143.976903 C141.017005,139.771881 134.193707,139.771881 129.985225,143.976903 L102.20193,171.737352 C101.032305,172.906015 99.2571609,172.906015 98.0875359,171.737352 L28.285908,101.993122 C27.1162831,100.824459 27.1162831,99.050775 28.285908,97.8821118 L98.0875359,28.1378823 C99.2571609,26.9692191 101.032305,26.9692191 102.20193,28.1378823 L129.985225,55.8983314 C134.193707,60.1033528 141.017005,60.1033528 145.225487,55.8983314 C149.433969,51.69331 149.433969,44.8756232 145.225487,40.6706018 L108.58055,4.05574592 C103.862049,-0.537986846 96.2692618,-0.500797906 91.5880863,4.17652823 Z"/><path id="Shape" fill="url(#linearGradient-2)" d="M91.5880863,4.17652823 L4.17996544,91.5127728 C-0.519240605,96.2081146 -0.519240605,103.791885 4.17996544,108.487227 L91.5880863,195.823472 C96.2872923,200.518814 103.877304,200.518814 108.57651,195.823472 L145.225487,159.204632 C149.433969,154.999611 149.433969,148.181924 145.225487,143.976903 C141.017005,139.771881 134.193707,139.771881 129.985225,143.976903 L102.20193,171.737352 C101.032305,172.906015 99.2571609,172.906015 98.0875359,171.737352 L28.285908,101.993122 C27.1162831,100.824459 27.1162831,99.050775 28.285908,97.8821118 L98.0875359,28.1378823 C100.999864,25.6271836 105.751642,20.541824 112.729652,19.3524487 C117.915585,18.4685261 123.585219,20.4140239 129.738554,25.1889424 C125.624663,21.0784292 118.571995,14.0340304 108.58055,4.05574592 C103.862049,-0.537986846 96.2692618,-0.500797906 91.5880863,4.17652823 Z"/></g><path id="Shape" fill="url(#linearGradient-3)" d="M153.685633,135.854579 C157.894115,140.0596 164.717412,140.0596 168.925894,135.854579 L195.959977,108.842726 C200.659183,104.147384 200.659183,96.5636133 195.960527,91.8688194 L168.690777,64.7181159 C164.472332,60.5180858 157.646868,60.5241425 153.435895,64.7316526 C149.227413,68.936674 149.227413,75.7543607 153.435895,79.9593821 L171.854035,98.3623765 C173.02366,99.5310396 173.02366,101.304724 171.854035,102.473387 L153.685633,120.626849 C149.47715,124.83187 149.47715,131.649557 153.685633,135.854579 Z"/></g><ellipse id="Combined-Shape" cx="100.519" cy="100.437" fill="url(#linearGradient-4)" rx="23.6" ry="23.581"/></g></g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 3.8 KiB |
5
dashboard/public/pro_icon.svg
Normal file
5
dashboard/public/pro_icon.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<svg width="42" height="42" xmlns="http://www.w3.org/2000/svg">
|
||||
<g>
|
||||
<path fill="#070707" d="m6.717392,13.773912l5.6,0c2.8,0 4.7,1.9 4.7,4.7c0,2.8 -2,4.7 -4.9,4.7l-2.5,0l0,4.3l-2.9,0l0,-13.7zm2.9,2.2l0,4.9l1.9,0c1.6,0 2.6,-0.9 2.6,-2.4c0,-1.6 -0.9,-2.4 -2.6,-2.4l-1.9,0l0,-0.1zm8.9,11.5l2.7,0l0,-5.7c0,-1.4 0.8,-2.3 2.2,-2.3c0.4,0 0.8,0.1 1,0.2l0,-2.4c-0.2,-0.1 -0.5,-0.1 -0.8,-0.1c-1.2,0 -2.1,0.7 -2.4,2l-0.1,0l0,-1.9l-2.7,0l0,10.2l0.1,0zm11.7,0.1c-3.1,0 -5,-2 -5,-5.3c0,-3.3 2,-5.3 5,-5.3s5,2 5,5.3c0,3.4 -1.9,5.3 -5,5.3zm0,-2.1c1.4,0 2.2,-1.1 2.2,-3.2c0,-2 -0.8,-3.2 -2.2,-3.2c-1.4,0 -2.2,1.2 -2.2,3.2c0,2.1 0.8,3.2 2.2,3.2z" class="st0" id="Ant-Design-Pro"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 677 B |
4
dashboard/src/access.ts
Normal file
4
dashboard/src/access.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
// src/access.ts
|
||||
export default function access() {
|
||||
return {};
|
||||
}
|
||||
79
dashboard/src/app.tsx
Normal file
79
dashboard/src/app.tsx
Normal file
@@ -0,0 +1,79 @@
|
||||
import React from 'react';
|
||||
|
||||
import { notification } from 'antd';
|
||||
import { RequestConfig, RunTimeLayoutConfig } from 'umi';
|
||||
import { ResponseError } from 'umi-request';
|
||||
|
||||
import Footer from '@/components/Footer';
|
||||
import RightContent from '@/components/RightContent';
|
||||
import { PageLoading, Settings as LayoutSettings } from '@ant-design/pro-layout';
|
||||
|
||||
import defaultSettings from '../config/defaultSettings';
|
||||
|
||||
export const initialStateConfig = {
|
||||
loading: <PageLoading />,
|
||||
};
|
||||
|
||||
export async function getInitialState(): Promise<{
|
||||
settings?: LayoutSettings;
|
||||
}> {
|
||||
return {
|
||||
settings: defaultSettings,
|
||||
};
|
||||
}
|
||||
|
||||
export const layout: RunTimeLayoutConfig = ({ initialState }) => {
|
||||
return {
|
||||
rightContentRender: () => <RightContent />,
|
||||
disableContentMargin: false,
|
||||
footerRender: () => <Footer />,
|
||||
menuHeaderRender: undefined,
|
||||
// custom 403 page
|
||||
// unAccessible: <div>unAccessible</div>,
|
||||
...initialState?.settings,
|
||||
};
|
||||
};
|
||||
|
||||
const codeMessage = {
|
||||
200: 'The server successfully returned the requested data. ',
|
||||
201: 'Create or modify data successfully. ',
|
||||
202: 'A request has entered the background queue (asynchronous task). ',
|
||||
204: 'Delete data successfully. ',
|
||||
400: 'There was an error in the request sent, and the server did not create or modify data. ',
|
||||
401: 'The user does not have permission (the token, username, password are wrong). ',
|
||||
403: 'The user is authorized, but access is forbidden. ',
|
||||
404: 'The request sent is for a record that does not exist, and the server is not operating. ',
|
||||
405: 'The requested method is not allowed. ',
|
||||
406: 'The requested format is not available. ',
|
||||
410: 'The requested resource has been permanently deleted and will no longer be available. ',
|
||||
422: 'When creating an object, a validation error occurred. ',
|
||||
500: 'An error occurred in the server, please check the server. ',
|
||||
502: 'Gateway error. ',
|
||||
503: 'The service is unavailable, the server is temporarily overloaded or maintained. ',
|
||||
504: 'The gateway has timed out. ',
|
||||
};
|
||||
|
||||
const errorHandler = (error: ResponseError) => {
|
||||
const { response, data } = error;
|
||||
if (response && response.status) {
|
||||
const errorText = data?.data || codeMessage[response.status] || response.statusText;
|
||||
const { status, url } = response;
|
||||
|
||||
notification.error({
|
||||
message: `Request error ${status}: ${url}`,
|
||||
description: errorText,
|
||||
});
|
||||
}
|
||||
|
||||
if (!response) {
|
||||
notification.error({
|
||||
description: 'Your network is abnormal and cannot connect to the server',
|
||||
message: 'Network failure',
|
||||
});
|
||||
}
|
||||
throw error;
|
||||
};
|
||||
|
||||
export const request: RequestConfig = {
|
||||
errorHandler,
|
||||
};
|
||||
@@ -1,148 +0,0 @@
|
||||
import { Form, Input, Select } from 'antd';
|
||||
import { connect } from 'dva';
|
||||
import React from 'react';
|
||||
import _ from 'lodash';
|
||||
|
||||
const { Option } = Select;
|
||||
const layout = {
|
||||
labelCol: {
|
||||
span: 8,
|
||||
},
|
||||
wrapperCol: {
|
||||
span: 16,
|
||||
},
|
||||
};
|
||||
|
||||
@connect(() => ({}))
|
||||
export default class CreateTraitItem extends React.PureComponent {
|
||||
formRefStep2 = React.createRef();
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
parameters: [],
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.props.onRef(this);
|
||||
if (this.props.initialValues && this.props.initialValues.name) {
|
||||
this.traitSelectChange(this.props.initialValues.name, 2);
|
||||
}
|
||||
}
|
||||
|
||||
getSelectValue = () => {
|
||||
return this.formRefStep2.current.getFieldsValue();
|
||||
};
|
||||
|
||||
resetFields = () => {
|
||||
return this.formRefStep2.current.resetFields();
|
||||
};
|
||||
|
||||
validateFields = () => {
|
||||
return this.formRefStep2.current.validateFields();
|
||||
};
|
||||
|
||||
setDefaultValue = (traitType) => {
|
||||
this.formRefStep2.current.setFieldsValue({ name: traitType });
|
||||
this.traitSelectChange(traitType);
|
||||
};
|
||||
|
||||
traitSelectChange = async (value, isType = 1) => {
|
||||
if (value) {
|
||||
const res = await this.props.dispatch({
|
||||
type: 'trait/getTraitByName',
|
||||
payload: {
|
||||
traitName: value,
|
||||
},
|
||||
});
|
||||
this.setState({
|
||||
parameters: res.parameters,
|
||||
});
|
||||
if (isType === 2) {
|
||||
this.formRefStep2.current.setFieldsValue(this.props.initialValues);
|
||||
} else if (isType) {
|
||||
// 进行默认值填写
|
||||
const parameters = _.get(res, 'parameters', []);
|
||||
if (parameters.length) {
|
||||
const initialObj = {};
|
||||
parameters.forEach((item) => {
|
||||
if (item.default) {
|
||||
initialObj[item.name] = item.default;
|
||||
}
|
||||
});
|
||||
this.formRefStep2.current.setFieldsValue(initialObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { availableTraitList } = this.props;
|
||||
return (
|
||||
<Form
|
||||
labelAlign="left"
|
||||
{...layout}
|
||||
ref={this.formRefStep2}
|
||||
name="control-ref"
|
||||
className="traitItem"
|
||||
>
|
||||
<Form.Item
|
||||
name="name"
|
||||
label="Trait"
|
||||
rules={[{ required: true, message: 'Please Select a Trait!' }]}
|
||||
>
|
||||
<Select placeholder="Select a Trait" onChange={this.traitSelectChange}>
|
||||
{availableTraitList.map((item) => {
|
||||
return (
|
||||
<Option value={item.name} key={item.name}>
|
||||
{item.name}
|
||||
</Option>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item label="Properties" />
|
||||
<div className="relativeBox">
|
||||
{this.state.parameters ? (
|
||||
this.state.parameters.map((item) => {
|
||||
return item.type === 4 ? (
|
||||
<Form.Item
|
||||
name={item.name}
|
||||
label={item.name}
|
||||
key={item.name}
|
||||
rules={[
|
||||
{
|
||||
required: item.required || false,
|
||||
message: `Please input ${item.name} !`,
|
||||
},
|
||||
{ pattern: /^[0-9]*$/, message: `${item.name} only use digits(0-9).` },
|
||||
]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
) : (
|
||||
<Form.Item
|
||||
name={item.name}
|
||||
label={item.name}
|
||||
key={item.name}
|
||||
rules={[
|
||||
{
|
||||
required: item.required || false,
|
||||
message: `Please input ${item.name} !`,
|
||||
},
|
||||
{ pattern: /^[^\s]*$/, message: 'Spaces are not allowed!' },
|
||||
]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</div>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
}
|
||||
5
dashboard/src/components/Footer/index.tsx
Normal file
5
dashboard/src/components/Footer/index.tsx
Normal file
@@ -0,0 +1,5 @@
|
||||
import React from 'react';
|
||||
|
||||
import { DefaultFooter } from '@ant-design/pro-layout';
|
||||
|
||||
export default () => <DefaultFooter copyright="2020 All Rights Reserved by KubeVela" links={[]} />;
|
||||
@@ -1,36 +0,0 @@
|
||||
import { Tag } from 'antd';
|
||||
import React from 'react';
|
||||
import { connect } from 'umi';
|
||||
import WorkSpaceDropDown from './WorkSpaceDropDown';
|
||||
import styles from './index.less';
|
||||
|
||||
const ENVTagColor = {
|
||||
dev: 'orange',
|
||||
test: 'green',
|
||||
pre: '#87d068',
|
||||
};
|
||||
|
||||
const GlobalHeaderRight = (props) => {
|
||||
const { theme, layout } = props;
|
||||
let className = styles.right;
|
||||
|
||||
if (theme === 'dark' && layout === 'top') {
|
||||
className = `${styles.right} ${styles.dark}`;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
{REACT_APP_ENV && (
|
||||
<span>
|
||||
<Tag color={ENVTagColor[REACT_APP_ENV]}>{REACT_APP_ENV}</Tag>
|
||||
</span>
|
||||
)}
|
||||
<WorkSpaceDropDown />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default connect(({ settings }) => ({
|
||||
theme: settings.navTheme,
|
||||
layout: settings.layout,
|
||||
}))(GlobalHeaderRight);
|
||||
@@ -1,96 +0,0 @@
|
||||
.ant-pro-global-header-layout-side {
|
||||
padding-right: 0;
|
||||
}
|
||||
.ant-dropdown-menu-item,
|
||||
.ant-dropdown-menu-submenu-title {
|
||||
clear: both;
|
||||
margin: 0;
|
||||
padding: 5px 20px;
|
||||
color: deepskyblue;
|
||||
font-weight: normal;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
border-top: 1px solid #dee4e6;
|
||||
}
|
||||
|
||||
.ant-dropdown-menu-item:nth-child(1) {
|
||||
border-top: 1px solid #fff;
|
||||
}
|
||||
|
||||
.ant-dropdown-menu-item-active {
|
||||
background: rgb(0, 21, 41) !important;
|
||||
}
|
||||
|
||||
.ant-dropdown-menu-item-active .box1 {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.ant-dropdown-menu-item-active .box2 {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.box {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.box1 {
|
||||
font-size: 16px;
|
||||
color: #5095d4;
|
||||
}
|
||||
|
||||
.box2 {
|
||||
font-size: 12px;
|
||||
color: #8d959b;
|
||||
}
|
||||
|
||||
.ant-dropdown-trigger {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.drop-box {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: left;
|
||||
height: 100%;
|
||||
background: rgb(0, 21, 41);
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.btn-box {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: space-between;
|
||||
overflow: hidden;
|
||||
margin-right: 20px;
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.btn-top {
|
||||
display: flex;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
font-size: 20px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-bottom {
|
||||
display: flex;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
font-size: 12px;
|
||||
color: #8d959b;
|
||||
}
|
||||
.btn-outlined {
|
||||
fontsize: 15px;
|
||||
color: #fff;
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
import { Menu, Dropdown, message } from 'antd';
|
||||
import { DownOutlined } from '@ant-design/icons';
|
||||
import React from 'react';
|
||||
import { connect } from 'dva';
|
||||
import './WorkSpaceDropDown.css';
|
||||
|
||||
@connect((env) => ({ envs: env.envs }))
|
||||
export default class WorkSpaceDropDown extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
workSpaceName: '',
|
||||
namespace: '',
|
||||
};
|
||||
}
|
||||
|
||||
async componentDidMount() {
|
||||
const envs = await this.props.dispatch({
|
||||
type: 'envs/getEnvs',
|
||||
});
|
||||
if (envs) {
|
||||
const { envName, namespace } = envs.find((env) => {
|
||||
return env.current === '*';
|
||||
});
|
||||
this.setState({
|
||||
workSpaceName: envName,
|
||||
namespace,
|
||||
});
|
||||
this.props.dispatch({
|
||||
type: 'globalData/currentEnv',
|
||||
payload: {
|
||||
currentEnv: envName,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
handleMenuClick = async (e) => {
|
||||
// 发送切换envs的接口
|
||||
const switchResult = await this.props.dispatch({
|
||||
type: 'envs/switchEnv',
|
||||
payload: {
|
||||
currentEnv: e.key,
|
||||
},
|
||||
});
|
||||
if (switchResult) {
|
||||
message.success(switchResult);
|
||||
}
|
||||
this.setState(
|
||||
{
|
||||
workSpaceName: e.key,
|
||||
namespace: e.item.props.title,
|
||||
},
|
||||
() => {
|
||||
// 值切换存储
|
||||
this.props.dispatch({
|
||||
type: 'globalData/currentEnv',
|
||||
payload: {
|
||||
currentEnv: e.key,
|
||||
},
|
||||
});
|
||||
},
|
||||
);
|
||||
await this.props.dispatch({
|
||||
type: 'envs/getEnvs', // applist对应models层的命名空间namespace
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { envs } = this.props;
|
||||
const menu = (
|
||||
<Menu onClick={this.handleMenuClick}>
|
||||
{envs.envs &&
|
||||
envs.envs.map((item) => {
|
||||
return (
|
||||
<Menu.Item key={item.envName} title={item.namespace}>
|
||||
<div className="box">
|
||||
<div className="box1">{item.envName}</div>
|
||||
<div className="box2">{item.namespace}</div>
|
||||
</div>
|
||||
</Menu.Item>
|
||||
);
|
||||
})}
|
||||
</Menu>
|
||||
);
|
||||
return (
|
||||
<Dropdown overlay={menu}>
|
||||
<div className="drop-box">
|
||||
<div className="btn-box">
|
||||
<div className="btn-top">{this.state.workSpaceName}</div>
|
||||
<div className="btn-bottom">{this.state.namespace}</div>
|
||||
</div>
|
||||
<DownOutlined style={{ fontSize: '15px', color: '#ffffff' }} />
|
||||
</div>
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
}
|
||||
16
dashboard/src/components/HeaderDropdown/index.less
Normal file
16
dashboard/src/components/HeaderDropdown/index.less
Normal file
@@ -0,0 +1,16 @@
|
||||
@import '~antd/es/style/themes/default.less';
|
||||
|
||||
.container > * {
|
||||
background-color: @popover-bg;
|
||||
border-radius: 4px;
|
||||
box-shadow: @shadow-1-down;
|
||||
}
|
||||
|
||||
@media screen and (max-width: @screen-xs) {
|
||||
.container {
|
||||
width: 100% !important;
|
||||
}
|
||||
.container > * {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
}
|
||||
21
dashboard/src/components/HeaderDropdown/index.tsx
Normal file
21
dashboard/src/components/HeaderDropdown/index.tsx
Normal file
@@ -0,0 +1,21 @@
|
||||
import React from 'react';
|
||||
|
||||
import { Dropdown } from 'antd';
|
||||
import { DropDownProps } from 'antd/es/dropdown';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import styles from './index.less';
|
||||
|
||||
declare type OverlayFunc = () => React.ReactNode;
|
||||
|
||||
export interface HeaderDropdownProps extends Omit<DropDownProps, 'overlay'> {
|
||||
overlayClassName?: string;
|
||||
overlay: React.ReactNode | OverlayFunc | any;
|
||||
placement?: 'bottomLeft' | 'bottomRight' | 'topLeft' | 'topCenter' | 'topRight' | 'bottomCenter';
|
||||
}
|
||||
|
||||
const HeaderDropdown: React.FC<HeaderDropdownProps> = ({ overlayClassName: cls, ...restProps }) => (
|
||||
<Dropdown overlayClassName={classNames(styles.container, cls)} {...restProps} />
|
||||
);
|
||||
|
||||
export default HeaderDropdown;
|
||||
@@ -1,4 +0,0 @@
|
||||
import { PageLoading } from '@ant-design/pro-layout'; // loading components from code split
|
||||
// https://umijs.org/plugin/umi-plugin-react.html#dynamicimport
|
||||
|
||||
export default PageLoading;
|
||||
66
dashboard/src/components/RightContent/WorkSpaceDropDown.tsx
Normal file
66
dashboard/src/components/RightContent/WorkSpaceDropDown.tsx
Normal file
@@ -0,0 +1,66 @@
|
||||
import React from 'react';
|
||||
|
||||
import { Menu, message, Spin, Typography } from 'antd';
|
||||
import { useModel } from 'umi';
|
||||
|
||||
import { DownOutlined } from '@ant-design/icons';
|
||||
|
||||
import HeaderDropdown from '../HeaderDropdown';
|
||||
import styles from './index.less';
|
||||
|
||||
export default () => {
|
||||
const {
|
||||
environments,
|
||||
currentEnvironment,
|
||||
switchCurrentEnvironment: switchEnvironment,
|
||||
} = useModel('useEnvironmentModel');
|
||||
|
||||
const menu = (
|
||||
<Menu
|
||||
className={styles.menu}
|
||||
selectedKeys={currentEnvironment == null ? undefined : [currentEnvironment.envName]}
|
||||
onClick={(e) => {
|
||||
switchEnvironment(e.key.toString()).then((env) => {
|
||||
if (env == null) {
|
||||
return;
|
||||
}
|
||||
message.success({
|
||||
content: `Set environment succeed, current environment is ${env.envName}, namespace is ${env.namespace}`,
|
||||
key: 'switchEnvironment',
|
||||
});
|
||||
});
|
||||
}}
|
||||
>
|
||||
{environments &&
|
||||
environments.map((item) => {
|
||||
return (
|
||||
<Menu.Item key={item.envName} title={item.namespace}>
|
||||
<div>
|
||||
<Typography.Text>{item.envName}</Typography.Text>
|
||||
</div>
|
||||
<div>
|
||||
<Typography.Text type="secondary">
|
||||
<small>{item.namespace}</small>
|
||||
</Typography.Text>
|
||||
</div>
|
||||
</Menu.Item>
|
||||
);
|
||||
})}
|
||||
</Menu>
|
||||
);
|
||||
|
||||
return (
|
||||
<HeaderDropdown overlay={menu}>
|
||||
<div className={`${styles.action}`}>
|
||||
{environments == null || currentEnvironment == null ? (
|
||||
<Spin size="small" />
|
||||
) : (
|
||||
<>
|
||||
<span className={`${styles.name} anticon`}>{currentEnvironment?.envName}</span>
|
||||
<DownOutlined style={{ marginLeft: '5px' }} />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</HeaderDropdown>
|
||||
);
|
||||
};
|
||||
@@ -20,7 +20,7 @@
|
||||
.action {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
height: 48px;
|
||||
padding: 0 12px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
@@ -42,7 +42,6 @@
|
||||
}
|
||||
.account {
|
||||
.avatar {
|
||||
margin: ~'calc((@{layout-header-height} - 24px) / 2)' 0;
|
||||
margin-right: 8px;
|
||||
color: @primary-color;
|
||||
vertical-align: top;
|
||||
@@ -53,52 +52,11 @@
|
||||
|
||||
.dark {
|
||||
.action {
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
> span {
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
&:hover {
|
||||
background: #252a3d;
|
||||
}
|
||||
&:hover,
|
||||
&:global(.opened) {
|
||||
background: @primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:global(.ant-pro-global-header) {
|
||||
.dark {
|
||||
.action {
|
||||
color: @text-color;
|
||||
> span {
|
||||
color: @text-color;
|
||||
}
|
||||
&:hover {
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
> span {
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: @screen-md) {
|
||||
:global(.ant-divider-vertical) {
|
||||
vertical-align: unset;
|
||||
}
|
||||
.name {
|
||||
display: none;
|
||||
}
|
||||
.right {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 12px;
|
||||
.account {
|
||||
.avatar {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
.search {
|
||||
display: none;
|
||||
background: #252a3d;
|
||||
}
|
||||
}
|
||||
}
|
||||
42
dashboard/src/components/RightContent/index.tsx
Normal file
42
dashboard/src/components/RightContent/index.tsx
Normal file
@@ -0,0 +1,42 @@
|
||||
import React from 'react';
|
||||
|
||||
import { Space, Tag } from 'antd';
|
||||
import { SelectLang, useModel } from 'umi';
|
||||
|
||||
import styles from './index.less';
|
||||
import WorkSpaceDropDown from './WorkSpaceDropDown';
|
||||
|
||||
export type SiderTheme = 'light' | 'dark';
|
||||
|
||||
const ENVTagColor = {
|
||||
dev: 'orange',
|
||||
test: 'green',
|
||||
pre: '#87d068',
|
||||
};
|
||||
|
||||
const GlobalHeaderRight: React.FC<{}> = () => {
|
||||
const { initialState } = useModel('@@initialState');
|
||||
|
||||
if (!initialState || !initialState.settings) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { navTheme, layout } = initialState.settings;
|
||||
let className = styles.right;
|
||||
|
||||
if ((navTheme === 'dark' && layout === 'top') || layout === 'mix') {
|
||||
className = `${styles.right} ${styles.dark}`;
|
||||
}
|
||||
return (
|
||||
<Space className={className}>
|
||||
{REACT_APP_ENV && (
|
||||
<span>
|
||||
<Tag color={ENVTagColor[REACT_APP_ENV]}>{REACT_APP_ENV}</Tag>
|
||||
</span>
|
||||
)}
|
||||
<WorkSpaceDropDown />
|
||||
<SelectLang className={styles.action} />
|
||||
</Space>
|
||||
);
|
||||
};
|
||||
export default GlobalHeaderRight;
|
||||
@@ -1,362 +0,0 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import { PageContainer } from '@ant-design/pro-layout';
|
||||
import { Button, Row, Col, Modal, Select, message, Breadcrumb, Form, Input } from 'antd';
|
||||
import './index.less';
|
||||
import { connect } from 'dva';
|
||||
import { Link } from 'umi';
|
||||
import _ from 'lodash';
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
const layout = {
|
||||
labelCol: {
|
||||
span: 8,
|
||||
},
|
||||
wrapperCol: {
|
||||
span: 16,
|
||||
},
|
||||
};
|
||||
|
||||
@connect(({ loading, applist, globalData }) => ({
|
||||
loadingAll: loading.models.applist,
|
||||
currentEnv: globalData.currentEnv,
|
||||
returnObj: applist.returnObj,
|
||||
}))
|
||||
class Trait extends React.Component {
|
||||
formRefStep2 = React.createRef();
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
visible: false,
|
||||
selectValue: null,
|
||||
compList: [],
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.getInitialData();
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
if (nextProps.currentEnv === this.props.currentEnv) {
|
||||
return true;
|
||||
}
|
||||
this.props.dispatch({
|
||||
type: 'applist/getList',
|
||||
payload: {
|
||||
url: `/api/envs/${nextProps.currentEnv}/apps/`,
|
||||
},
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
getInitialData = async () => {
|
||||
if (this.props.currentEnv) {
|
||||
await this.props.dispatch({
|
||||
type: 'applist/getList',
|
||||
payload: {
|
||||
url: `/api/envs/${this.props.currentEnv}/apps/`,
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
showModal = () => {
|
||||
this.setState(
|
||||
{
|
||||
visible: true,
|
||||
},
|
||||
() => {
|
||||
if (this.formRefStep2.current) {
|
||||
this.formRefStep2.current.resetFields();
|
||||
}
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
handleOk = async () => {
|
||||
await this.formRefStep2.current.validateFields();
|
||||
const { title } = this.props.propsObj;
|
||||
if (title) {
|
||||
const submitObj = {
|
||||
name: title,
|
||||
flags: [],
|
||||
};
|
||||
const submitData = this.formRefStep2.current.getFieldValue();
|
||||
Object.keys(submitData).forEach((currentKey) => {
|
||||
if (
|
||||
currentKey !== 'name' &&
|
||||
currentKey !== 'appName' &&
|
||||
currentKey !== 'compName' &&
|
||||
submitData[currentKey]
|
||||
) {
|
||||
submitObj.flags.push({
|
||||
name: currentKey,
|
||||
value: submitData[currentKey].toString(),
|
||||
});
|
||||
}
|
||||
});
|
||||
const { currentEnv: envName } = this.props;
|
||||
const { appName, compName } = submitData;
|
||||
if (envName && appName && compName) {
|
||||
const res = await this.props.dispatch({
|
||||
type: 'trait/attachOneTraits',
|
||||
payload: {
|
||||
envName,
|
||||
appName,
|
||||
compName,
|
||||
params: submitObj,
|
||||
},
|
||||
});
|
||||
if (res) {
|
||||
this.setState({
|
||||
visible: false,
|
||||
});
|
||||
message.success(res);
|
||||
const { history } = this.props.propsObj;
|
||||
history.push({
|
||||
pathname: `/ApplicationList/${appName}/Components`,
|
||||
state: { appName, envName },
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
handleCancel = () => {
|
||||
this.setState({
|
||||
visible: false,
|
||||
});
|
||||
};
|
||||
|
||||
onChange = async (value) => {
|
||||
this.setState({
|
||||
selectValue: value,
|
||||
compList: [],
|
||||
});
|
||||
const res = await this.props.dispatch({
|
||||
type: 'applist/getAppDetail',
|
||||
payload: {
|
||||
envName: this.props.currentEnv,
|
||||
appName: value,
|
||||
},
|
||||
});
|
||||
if (res) {
|
||||
const compData = _.get(res, 'components', []);
|
||||
const compList = [];
|
||||
compData.forEach((item) => {
|
||||
compList.push({
|
||||
compName: item.name,
|
||||
});
|
||||
});
|
||||
this.setState({
|
||||
compList,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
onSearch = () => {};
|
||||
|
||||
render() {
|
||||
const { btnValue, title, settings = [], btnIsShow, crdInfo, appliesTo } = this.props.propsObj;
|
||||
const initialObj = {};
|
||||
if (settings.length) {
|
||||
settings.forEach((item) => {
|
||||
if (item.default) {
|
||||
initialObj[item.name] = item.default;
|
||||
}
|
||||
});
|
||||
}
|
||||
let appList = _.get(this.props, 'returnObj', []);
|
||||
if (!appList) {
|
||||
appList = [];
|
||||
}
|
||||
const { compList = [] } = this.state;
|
||||
return (
|
||||
<div>
|
||||
<div className="breadCrumb">
|
||||
<Breadcrumb>
|
||||
<Breadcrumb.Item>
|
||||
<Link to="/ApplicationList">Home</Link>
|
||||
</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>Traits</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>{title}</Breadcrumb.Item>
|
||||
</Breadcrumb>
|
||||
</div>
|
||||
<PageContainer>
|
||||
<Row>
|
||||
<Col span="11">
|
||||
<div className="deployment">
|
||||
<Row>
|
||||
<Col span="22">
|
||||
<p className="title">{title}</p>
|
||||
{crdInfo ? (
|
||||
<p>
|
||||
{crdInfo.apiVersion}
|
||||
<span>,kind=</span>
|
||||
{crdInfo.kind}
|
||||
</p>
|
||||
) : (
|
||||
<p />
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col span="22">
|
||||
<p className="title">Applies To:</p>
|
||||
<p>{Array.isArray(appliesTo) ? appliesTo.join(', ') : appliesTo}</p>
|
||||
</Col>
|
||||
</Row>
|
||||
<p className="title">Configurable Properties:</p>
|
||||
{settings.map((item, index) => {
|
||||
return (
|
||||
<Row key={index.toString()}>
|
||||
<Col span="8">
|
||||
<p>{item.name}</p>
|
||||
</Col>
|
||||
<Col span="16">
|
||||
<p>{item.default || item.usage}</p>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<Button
|
||||
type="primary"
|
||||
className="create-button"
|
||||
onClick={this.showModal}
|
||||
style={{ display: btnIsShow ? 'block' : 'none' }}
|
||||
>
|
||||
{btnValue}
|
||||
</Button>
|
||||
<Modal
|
||||
title="Attach Trait"
|
||||
visible={this.state.visible}
|
||||
onOk={this.handleOk}
|
||||
onCancel={this.handleCancel}
|
||||
footer={[
|
||||
<Button key="back" onClick={this.handleCancel}>
|
||||
Cancel
|
||||
</Button>,
|
||||
<Button key="submit" type="primary" onClick={this.handleOk}>
|
||||
Submit
|
||||
</Button>,
|
||||
]}
|
||||
>
|
||||
<Form
|
||||
labelAlign="left"
|
||||
{...layout}
|
||||
ref={this.formRefStep2}
|
||||
name="control-ref"
|
||||
className="traitItem"
|
||||
initialValues={initialObj}
|
||||
>
|
||||
<Form.Item
|
||||
label="App"
|
||||
name="appName"
|
||||
rules={[{ required: true, message: 'Please Select a Application!' }]}
|
||||
>
|
||||
<Select
|
||||
showSearch
|
||||
value={this.state.selectValue}
|
||||
style={{ width: '100%' }}
|
||||
placeholder="Select a Application"
|
||||
optionFilterProp="children"
|
||||
onChange={this.onChange}
|
||||
onSearch={this.onSearch}
|
||||
filterOption={(input, option) =>
|
||||
option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}
|
||||
>
|
||||
{appList.length ? (
|
||||
appList.map((item, index) => {
|
||||
return (
|
||||
<Option key={index.toString()} value={item.name}>
|
||||
{item.name}
|
||||
</Option>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<Fragment />
|
||||
)}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="Component"
|
||||
name="compName"
|
||||
rules={[{ required: true, message: 'Please Select a Component!' }]}
|
||||
>
|
||||
<Select
|
||||
allowClear
|
||||
// value={this.state.selectValue}
|
||||
style={{ width: '100%' }}
|
||||
placeholder="Select a Component"
|
||||
>
|
||||
{compList.length ? (
|
||||
compList.map((item) => {
|
||||
return (
|
||||
<Option key={item.compName} value={item.compName}>
|
||||
{item.compName}
|
||||
</Option>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<Fragment />
|
||||
)}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<div className="relativeBox">
|
||||
<Form.Item label="Properties" />
|
||||
{settings ? (
|
||||
settings.map((item) => {
|
||||
return item.type === 4 ? (
|
||||
<Form.Item
|
||||
name={item.name}
|
||||
label={item.name}
|
||||
key={item.name}
|
||||
rules={[
|
||||
{
|
||||
required: item.required || false,
|
||||
message: `Please input ${item.name} !`,
|
||||
},
|
||||
{
|
||||
pattern: /^[0-9]*$/,
|
||||
message: `${item.name} only use digits(0-9).`,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
) : (
|
||||
<Form.Item
|
||||
name={item.name}
|
||||
label={item.name}
|
||||
key={item.name}
|
||||
rules={[
|
||||
{
|
||||
required: item.required || false,
|
||||
message: `Please input ${item.name} !`,
|
||||
},
|
||||
{ pattern: /^[^\s]*$/, message: 'Spaces are not allowed!' },
|
||||
]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</div>
|
||||
</Form>
|
||||
</Modal>
|
||||
</Col>
|
||||
</Row>
|
||||
</PageContainer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Trait;
|
||||
@@ -1,27 +0,0 @@
|
||||
.deployment {
|
||||
position: relative;
|
||||
padding: 10px;
|
||||
padding-left: 16px;
|
||||
background-color: #fff;
|
||||
border: 1px solid #eee;
|
||||
a {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 16px;
|
||||
font-size: 20px;
|
||||
}
|
||||
.title {
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
line-height: 36px;
|
||||
}
|
||||
p {
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
.create-button {
|
||||
float: right;
|
||||
margin-top: 16px;
|
||||
text-align: right;
|
||||
}
|
||||
@@ -1,226 +0,0 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import { PageContainer } from '@ant-design/pro-layout';
|
||||
import { Button, Row, Col, Modal, Select, Breadcrumb, Form } from 'antd';
|
||||
import { connect } from 'dva';
|
||||
import { Link } from 'umi';
|
||||
import _ from 'lodash';
|
||||
import './index.less';
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
const layout = {
|
||||
labelCol: {
|
||||
span: 8,
|
||||
},
|
||||
wrapperCol: {
|
||||
span: 16,
|
||||
},
|
||||
};
|
||||
|
||||
@connect(({ loading, applist, globalData }) => ({
|
||||
loadingAll: loading.models.applist,
|
||||
currentEnv: globalData.currentEnv,
|
||||
returnObj: applist.returnObj,
|
||||
}))
|
||||
export default class Workload extends React.Component {
|
||||
formRefStep2 = React.createRef();
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
visible: false,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.getInitialData();
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps) {
|
||||
if (nextProps.currentEnv === this.props.currentEnv) {
|
||||
return true;
|
||||
}
|
||||
this.props.dispatch({
|
||||
type: 'applist/getList',
|
||||
payload: {
|
||||
url: `/api/envs/${nextProps.currentEnv}/apps/`,
|
||||
},
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
getInitialData = async () => {
|
||||
if (this.props.currentEnv) {
|
||||
await this.props.dispatch({
|
||||
type: 'applist/getList',
|
||||
payload: {
|
||||
url: `/api/envs/${this.props.currentEnv}/apps/`,
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
showModal = () => {
|
||||
this.setState(
|
||||
{
|
||||
visible: true,
|
||||
},
|
||||
() => {
|
||||
if (this.formRefStep2.current) {
|
||||
this.formRefStep2.current.resetFields();
|
||||
}
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
handleOk = async () => {
|
||||
const submitData = await this.formRefStep2.current.validateFields();
|
||||
const { history } = this.props.propsObj;
|
||||
history.push({
|
||||
pathname: `/ApplicationList/${submitData.appName}/createComponent`,
|
||||
state: {
|
||||
...submitData,
|
||||
isCreate: false,
|
||||
envName: this.props.currentEnv,
|
||||
WorkloadType: this.props.propsObj.title,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
handleCancel = () => {
|
||||
this.setState({
|
||||
visible: false,
|
||||
});
|
||||
};
|
||||
|
||||
onChange = () => {};
|
||||
|
||||
onSearch = () => {};
|
||||
|
||||
render() {
|
||||
const { btnValue, title, crdInfo, settings, btnIsShow } = this.props.propsObj;
|
||||
let appList = _.get(this.props, 'returnObj', []);
|
||||
if (!appList) {
|
||||
appList = [];
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<div className="breadCrumb">
|
||||
<Breadcrumb>
|
||||
<Breadcrumb.Item>
|
||||
<Link to="/ApplicationList">Home</Link>
|
||||
</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>Workloads</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>{title}</Breadcrumb.Item>
|
||||
</Breadcrumb>
|
||||
</div>
|
||||
<PageContainer>
|
||||
<Row>
|
||||
<Col span="11">
|
||||
<div className="deployment">
|
||||
<Row>
|
||||
<Col span="22">
|
||||
<p className="title">{title}</p>
|
||||
{crdInfo ? (
|
||||
<p>
|
||||
{crdInfo.apiVersion}
|
||||
<span>,kind=</span>
|
||||
{crdInfo.kind}
|
||||
</p>
|
||||
) : (
|
||||
<p />
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
<p className="title">Configurable Settings:</p>
|
||||
{settings.map((item, index) => {
|
||||
if (item.name === 'name') {
|
||||
return <Fragment key={index.toString()} />;
|
||||
}
|
||||
return (
|
||||
<Row key={index.toString()}>
|
||||
<Col span="8">
|
||||
<p>{item.name}</p>
|
||||
</Col>
|
||||
<Col span="16">
|
||||
{
|
||||
// eslint-disable-next-line consistent-return
|
||||
}
|
||||
<p>{item.default || item.usage}</p>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{/* <Link to={{ pathname, state }} style={{ display: btnIsShow ? 'block' : 'none' }}>
|
||||
<Button type="primary" className="create-button">
|
||||
{btnValue}
|
||||
</Button>
|
||||
</Link> */}
|
||||
<Button
|
||||
type="primary"
|
||||
className="create-button"
|
||||
onClick={() => this.showModal()}
|
||||
style={{ display: btnIsShow ? 'block' : 'none' }}
|
||||
>
|
||||
{btnValue}
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
<Modal
|
||||
title="Add Component"
|
||||
visible={this.state.visible}
|
||||
onOk={this.handleOk}
|
||||
onCancel={this.handleCancel}
|
||||
footer={[
|
||||
<Button key="back" onClick={this.handleCancel}>
|
||||
Cancel
|
||||
</Button>,
|
||||
<Button key="submit" type="primary" onClick={this.handleOk}>
|
||||
Next
|
||||
</Button>,
|
||||
]}
|
||||
>
|
||||
<Form
|
||||
labelAlign="left"
|
||||
{...layout}
|
||||
ref={this.formRefStep2}
|
||||
name="control-ref"
|
||||
className="traitItem"
|
||||
>
|
||||
<Form.Item
|
||||
label="App"
|
||||
name="appName"
|
||||
rules={[{ required: true, message: 'Please Select a Application!' }]}
|
||||
>
|
||||
<Select
|
||||
showSearch
|
||||
style={{ width: '100%' }}
|
||||
placeholder="Select a Application"
|
||||
optionFilterProp="children"
|
||||
onChange={this.onChange}
|
||||
onSearch={this.onSearch}
|
||||
filterOption={(input, option) =>
|
||||
option.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
|
||||
}
|
||||
>
|
||||
{appList.length ? (
|
||||
appList.map((item, index) => {
|
||||
return (
|
||||
<Option key={index.toString()} value={item.name}>
|
||||
{item.name}
|
||||
</Option>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
<Fragment />
|
||||
)}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</Modal>
|
||||
</PageContainer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
.deployment {
|
||||
position: relative;
|
||||
padding: 10px;
|
||||
padding-left: 16px;
|
||||
background-color: #fff;
|
||||
border: 1px solid #eee;
|
||||
a {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 16px;
|
||||
font-size: 20px;
|
||||
}
|
||||
.title {
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
line-height: 36px;
|
||||
}
|
||||
p {
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
.create-button {
|
||||
float: right;
|
||||
margin-top: 16px;
|
||||
text-align: right;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export default undefined;
|
||||
@@ -29,6 +29,13 @@ beforeEach(async () => {
|
||||
describe('Ant Design Pro E2E test', () => {
|
||||
const testPage = (path) => async () => {
|
||||
await page.goto(`${BASE_URL}${path}`);
|
||||
await page.waitForSelector('footer', {
|
||||
timeout: 2000,
|
||||
});
|
||||
const haveFooter = await page.evaluate(
|
||||
() => document.getElementsByTagName('footer').length > 0,
|
||||
);
|
||||
expect(haveFooter).toBeTruthy();
|
||||
};
|
||||
|
||||
const routers = formatter(RouterConfig);
|
||||
@@ -39,5 +46,12 @@ describe('Ant Design Pro E2E test', () => {
|
||||
it('topmenu should have footer', async () => {
|
||||
const params = '?navTheme=light&layout=topmenu';
|
||||
await page.goto(`${BASE_URL}${params}`);
|
||||
await page.waitForSelector('footer', {
|
||||
timeout: 2000,
|
||||
});
|
||||
const haveFooter = await page.evaluate(
|
||||
() => document.getElementsByTagName('footer').length > 0,
|
||||
);
|
||||
expect(haveFooter).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,9 +13,6 @@ body,
|
||||
.ant-layout {
|
||||
min-height: 100vh;
|
||||
}
|
||||
.ant-card {
|
||||
margin-bottom: 30px !important;
|
||||
}
|
||||
|
||||
canvas {
|
||||
display: block;
|
||||
@@ -55,49 +52,3 @@ ol {
|
||||
min-height: 100vh;
|
||||
}
|
||||
}
|
||||
// 首页导航标题样式
|
||||
#logo {
|
||||
padding: 16px 8px;
|
||||
img {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
// 面包屑样式调整
|
||||
.ant-page-header {
|
||||
padding: 12px 24px !important;
|
||||
}
|
||||
.ant-page-header-heading {
|
||||
display: none !important;
|
||||
}
|
||||
.ant-pro-page-container-warp {
|
||||
display: none;
|
||||
}
|
||||
.ant-pro-basicLayout-content {
|
||||
margin: 0 !important;
|
||||
}
|
||||
.ant-pro-basicLayout-content .ant-pro-page-container {
|
||||
margin: 0 !important;
|
||||
}
|
||||
.breadCrumb {
|
||||
padding: 12px 24px;
|
||||
background: #fff;
|
||||
}
|
||||
.ant-breadcrumb a:hover {
|
||||
color: #1b58f4 !important;
|
||||
}
|
||||
// 对齐
|
||||
.ant-form-item-label > label::before {
|
||||
display: inline-block;
|
||||
width: 7.09px;
|
||||
height: 14px;
|
||||
margin-right: 4px;
|
||||
color: rgb(255, 77, 79);
|
||||
font-size: 14px;
|
||||
font-family: SimSun, sans-serif;
|
||||
line-height: 1;
|
||||
content: '';
|
||||
}
|
||||
|
||||
.ant-spin-nested-loading {
|
||||
height: calc(100% - 46px) !important;
|
||||
}
|
||||
|
||||
@@ -1,35 +1,32 @@
|
||||
import { Button, message, notification } from 'antd';
|
||||
|
||||
import React from 'react';
|
||||
import { useIntl } from 'umi';
|
||||
import defaultSettings from '../config/defaultSettings';
|
||||
|
||||
const { pwa } = defaultSettings; // if pwa is true
|
||||
const { pwa } = defaultSettings;
|
||||
const isHttps = document.location.protocol === 'https:';
|
||||
|
||||
// if pwa is true
|
||||
if (pwa) {
|
||||
// Notify user if offline now
|
||||
window.addEventListener('sw.offline', () => {
|
||||
message.warning(
|
||||
useIntl().formatMessage({
|
||||
id: 'app.pwa.offline',
|
||||
}),
|
||||
);
|
||||
}); // Pop up a prompt on the page asking the user if they want to use the latest version
|
||||
|
||||
window.addEventListener('sw.updated', (event) => {
|
||||
const e = event;
|
||||
message.warning(useIntl().formatMessage({ id: 'app.pwa.offline' }));
|
||||
});
|
||||
|
||||
// Pop up a prompt on the page asking the user if they want to use the latest version
|
||||
window.addEventListener('sw.updated', (event: Event) => {
|
||||
const e = event as CustomEvent;
|
||||
const reloadSW = async () => {
|
||||
// Check if there is sw whose state is waiting in ServiceWorkerRegistration
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration
|
||||
const worker = e.detail && e.detail.waiting;
|
||||
|
||||
if (!worker) {
|
||||
return true;
|
||||
} // Send skip-waiting event to waiting SW with MessageChannel
|
||||
|
||||
}
|
||||
// Send skip-waiting event to waiting SW with MessageChannel
|
||||
await new Promise((resolve, reject) => {
|
||||
const channel = new MessageChannel();
|
||||
|
||||
channel.port1.onmessage = (msgEvent) => {
|
||||
if (msgEvent.data.error) {
|
||||
reject(msgEvent.data.error);
|
||||
@@ -37,19 +34,12 @@ if (pwa) {
|
||||
resolve(msgEvent.data);
|
||||
}
|
||||
};
|
||||
|
||||
worker.postMessage(
|
||||
{
|
||||
type: 'skip-waiting',
|
||||
},
|
||||
[channel.port2],
|
||||
);
|
||||
}); // Refresh current page to use the updated HTML and other assets after SW has skiped waiting
|
||||
|
||||
worker.postMessage({ type: 'skip-waiting' }, [channel.port2]);
|
||||
});
|
||||
// Refresh current page to use the updated HTML and other assets after SW has skiped waiting
|
||||
window.location.reload(true);
|
||||
return true;
|
||||
};
|
||||
|
||||
const key = `open${Date.now()}`;
|
||||
const btn = (
|
||||
<Button
|
||||
@@ -59,27 +49,20 @@ if (pwa) {
|
||||
reloadSW();
|
||||
}}
|
||||
>
|
||||
{useIntl().formatMessage({
|
||||
id: 'app.pwa.serviceworker.updated.ok',
|
||||
})}
|
||||
{useIntl().formatMessage({ id: 'app.pwa.serviceworker.updated.ok' })}
|
||||
</Button>
|
||||
);
|
||||
notification.open({
|
||||
message: useIntl().formatMessage({
|
||||
id: 'app.pwa.serviceworker.updated',
|
||||
}),
|
||||
description: useIntl().formatMessage({
|
||||
id: 'app.pwa.serviceworker.updated.hint',
|
||||
}),
|
||||
message: useIntl().formatMessage({ id: 'app.pwa.serviceworker.updated' }),
|
||||
description: useIntl().formatMessage({ id: 'app.pwa.serviceworker.updated.hint' }),
|
||||
btn,
|
||||
key,
|
||||
onClose: async () => {},
|
||||
});
|
||||
});
|
||||
} else if ('serviceWorker' in navigator) {
|
||||
} else if ('serviceWorker' in navigator && isHttps) {
|
||||
// unregister service worker
|
||||
const { serviceWorker } = navigator;
|
||||
|
||||
if (serviceWorker.getRegistrations) {
|
||||
serviceWorker.getRegistrations().then((sws) => {
|
||||
sws.forEach((sw) => {
|
||||
@@ -87,11 +70,11 @@ if (pwa) {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
serviceWorker.getRegistration().then((sw) => {
|
||||
if (sw) sw.unregister();
|
||||
}); // remove all caches
|
||||
});
|
||||
|
||||
// remove all caches
|
||||
if (window.caches && window.caches.keys) {
|
||||
caches.keys().then((keys) => {
|
||||
keys.forEach((key) => {
|
||||
@@ -1,137 +0,0 @@
|
||||
/**
|
||||
* Ant Design Pro v4 use `@ant-design/pro-layout` to handle Layout.
|
||||
* You can view component api by:
|
||||
* https://github.com/ant-design/ant-design-pro-layout
|
||||
*/
|
||||
import ProLayout from '@ant-design/pro-layout';
|
||||
import React, { useEffect, useState, useRef } from 'react';
|
||||
import { Link, useIntl, connect, history } from 'umi';
|
||||
import RightContent from '@/components/GlobalHeader/RightContent';
|
||||
import {
|
||||
MenuOutlined,
|
||||
BranchesOutlined,
|
||||
ApartmentOutlined,
|
||||
DeploymentUnitOutlined,
|
||||
SettingOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import _ from 'lodash';
|
||||
|
||||
const AddIcon = (menuData) => {
|
||||
return menuData.map((item) => {
|
||||
const name = _.get(item, 'name', '');
|
||||
if (name) {
|
||||
if (name === 'Workload') {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
item.icon = <ApartmentOutlined />;
|
||||
} else if (name === 'Traits') {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
item.icon = <BranchesOutlined />;
|
||||
} else if (name === 'Capability') {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
item.icon = <DeploymentUnitOutlined />;
|
||||
} else if (name === 'System') {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
item.icon = <SettingOutlined />;
|
||||
} else {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
item.icon = <MenuOutlined />;
|
||||
}
|
||||
}
|
||||
return item;
|
||||
});
|
||||
};
|
||||
|
||||
const BasicLayout = (props) => {
|
||||
const { settings, dispatch, menus } = props;
|
||||
const [currentSelectKeys, setCurrentSelectedKeys] = useState('');
|
||||
const timerRef = useRef();
|
||||
const getCurrentSelectKeys = () => {
|
||||
const pathnameCur = props.history.location.pathname;
|
||||
if (pathnameCur) {
|
||||
if (pathnameCur.includes('Application')) {
|
||||
setCurrentSelectedKeys(['applist']);
|
||||
} else if (pathnameCur.includes('Capability')) {
|
||||
setCurrentSelectedKeys(['Capability']);
|
||||
} else if (pathnameCur.includes('System/Env')) {
|
||||
setCurrentSelectedKeys(['Env']);
|
||||
} else if (pathnameCur.includes('Workload')) {
|
||||
const arr = pathnameCur.split('/');
|
||||
const key = arr[arr.length - 1];
|
||||
setCurrentSelectedKeys([key]);
|
||||
} else if (pathnameCur.includes('Traits')) {
|
||||
const arr = pathnameCur.split('/');
|
||||
const key = arr[arr.length - 1];
|
||||
setCurrentSelectedKeys([key]);
|
||||
}
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
if (dispatch) {
|
||||
dispatch({
|
||||
type: 'menus/getMenuData',
|
||||
});
|
||||
}
|
||||
timerRef.current = props.history.listen((route) => {
|
||||
getCurrentSelectKeys(route.pathname);
|
||||
});
|
||||
return () => {
|
||||
if (timerRef.current) {
|
||||
timerRef.current = null;
|
||||
}
|
||||
};
|
||||
// setCurrentSelectedKeys('applist')
|
||||
}, []);
|
||||
|
||||
const { formatMessage } = useIntl();
|
||||
return (
|
||||
<ProLayout
|
||||
formatMessage={formatMessage}
|
||||
onMenuHeaderClick={() => history.push('/')}
|
||||
menuItemRender={(menuItemProps, defaultDom) => {
|
||||
if (menuItemProps.isUrl || !menuItemProps.path) {
|
||||
return defaultDom;
|
||||
}
|
||||
// return <Link to={menuItemProps.path}>{defaultDom}</Link>;
|
||||
return (
|
||||
<div
|
||||
onClick={() => {
|
||||
setCurrentSelectedKeys([menuItemProps.key]);
|
||||
history.push(menuItemProps.path);
|
||||
}}
|
||||
>
|
||||
{defaultDom}
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
selectedKeys={currentSelectKeys}
|
||||
breadcrumbRender={(routers = []) => [
|
||||
{
|
||||
path: '/',
|
||||
breadcrumbName: formatMessage({
|
||||
id: 'menu.home',
|
||||
}),
|
||||
},
|
||||
...routers,
|
||||
]}
|
||||
itemRender={(route, params, routes, paths) => {
|
||||
const first = routes.indexOf(route) === 0;
|
||||
return first ? (
|
||||
<Link to={paths.join('/')}>{route.breadcrumbName}</Link>
|
||||
) : (
|
||||
<span>{route.breadcrumbName}</span>
|
||||
);
|
||||
}}
|
||||
// menuDataRender={menuDataRender}
|
||||
menuDataRender={() => AddIcon(menus.menuData)}
|
||||
rightContentRender={() => <RightContent />}
|
||||
{...props}
|
||||
{...settings}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default connect(({ global, settings, menus }) => ({
|
||||
global,
|
||||
settings,
|
||||
menus,
|
||||
}))(BasicLayout);
|
||||
@@ -1,13 +0,0 @@
|
||||
import React from 'react';
|
||||
import { connect } from 'umi';
|
||||
|
||||
class SecurityLayout extends React.Component {
|
||||
render() {
|
||||
const { children } = this.props;
|
||||
return children;
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(({ loading }) => ({
|
||||
loading: loading.models.user,
|
||||
}))(SecurityLayout);
|
||||
@@ -1,22 +0,0 @@
|
||||
import component from './en-US/component';
|
||||
import globalHeader from './en-US/globalHeader';
|
||||
import menu from './en-US/menu';
|
||||
import pwa from './en-US/pwa';
|
||||
import settingDrawer from './en-US/settingDrawer';
|
||||
import settings from './en-US/settings';
|
||||
|
||||
export default {
|
||||
'navBar.lang': 'Languages',
|
||||
'layout.user.link.help': 'Help',
|
||||
'layout.user.link.privacy': 'Privacy',
|
||||
'layout.user.link.terms': 'Terms',
|
||||
'app.preview.down.block': 'Download this page to your local project',
|
||||
'app.welcome.link.fetch-blocks': 'Get all block',
|
||||
'app.welcome.link.block-list': 'Quickly build standard, pages based on `block` development',
|
||||
...globalHeader,
|
||||
...menu,
|
||||
...settingDrawer,
|
||||
...settings,
|
||||
...pwa,
|
||||
...component,
|
||||
};
|
||||
11
dashboard/src/locales/en-US.ts
Normal file
11
dashboard/src/locales/en-US.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import component from './en-US/component';
|
||||
import menu from './en-US/menu';
|
||||
import pages from './en-US/pages';
|
||||
import pwa from './en-US/pwa';
|
||||
|
||||
export default {
|
||||
...menu,
|
||||
...pwa,
|
||||
...component,
|
||||
...pages,
|
||||
};
|
||||
@@ -1,17 +0,0 @@
|
||||
export default {
|
||||
'component.globalHeader.search': 'Search',
|
||||
'component.globalHeader.search.example1': 'Search example 1',
|
||||
'component.globalHeader.search.example2': 'Search example 2',
|
||||
'component.globalHeader.search.example3': 'Search example 3',
|
||||
'component.globalHeader.help': 'Help',
|
||||
'component.globalHeader.notification': 'Notification',
|
||||
'component.globalHeader.notification.empty': 'You have viewed all notifications.',
|
||||
'component.globalHeader.message': 'Message',
|
||||
'component.globalHeader.message.empty': 'You have viewed all messsages.',
|
||||
'component.globalHeader.event': 'Event',
|
||||
'component.globalHeader.event.empty': 'You have viewed all events.',
|
||||
'component.noticeIcon.clear': 'Clear',
|
||||
'component.noticeIcon.cleared': 'Cleared',
|
||||
'component.noticeIcon.empty': 'No notifications',
|
||||
'component.noticeIcon.view-more': 'View more',
|
||||
};
|
||||
@@ -1,74 +0,0 @@
|
||||
export default {
|
||||
'menu.welcome': 'Welcome',
|
||||
'menu.more-blocks': 'More Blocks',
|
||||
'menu.home': 'Home',
|
||||
'menu.Traits': 'Traits',
|
||||
'menu.Traits.TraitItem': 'TraitItem',
|
||||
'menu.Traits.Scale': 'Scale',
|
||||
'menu.Traits.Rollout': 'Rollout',
|
||||
'menu.Traits.Route': 'Route',
|
||||
'menu.Traits.Manualscaler': 'Manualscaler',
|
||||
'menu.Traits.Detail': 'Detail',
|
||||
'menu.ApplicationList': 'Applications',
|
||||
'menu.ApplicationList.ApplicationListDetail': 'ApplicationListDetail',
|
||||
'menu.ApplicationList.CreateApplication': 'CreateApplication',
|
||||
'menu.ApplicationList.WorkloadDetail': 'WorkloadDetail',
|
||||
'menu.ApplicationList.TraitDetail': 'TraitDetail',
|
||||
'menu.Capability': 'Capability',
|
||||
'menu.Capability.Detail': 'Detail',
|
||||
'menu.System': 'System',
|
||||
'menu.System.Env': 'Env',
|
||||
'menu.Workload': 'Workloads',
|
||||
'menu.Workload.WorkloadItem': 'WorkloadItem',
|
||||
'menu.Workload.Deployment': 'Deployment',
|
||||
'menu.Workload.Containerized': 'Containerized',
|
||||
'menu.Workload.Detail': 'Detail',
|
||||
'menu.Release': 'Release',
|
||||
'menu.admin': 'Admin',
|
||||
'menu.admin.sub-page': 'Sub-Page',
|
||||
'menu.login': 'Login',
|
||||
'menu.register': 'Register',
|
||||
'menu.register.result': 'Register Result',
|
||||
'menu.dashboard': 'Dashboard',
|
||||
'menu.dashboard.analysis': 'Analysis',
|
||||
'menu.dashboard.monitor': 'Monitor',
|
||||
'menu.dashboard.workplace': 'Workplace',
|
||||
'menu.exception.403': '403',
|
||||
'menu.exception.404': '404',
|
||||
'menu.exception.500': '500',
|
||||
'menu.form': 'Form',
|
||||
'menu.form.basic-form': 'Basic Form',
|
||||
'menu.form.step-form': 'Step Form',
|
||||
'menu.form.step-form.info': 'Step Form(write transfer information)',
|
||||
'menu.form.step-form.confirm': 'Step Form(confirm transfer information)',
|
||||
'menu.form.step-form.result': 'Step Form(finished)',
|
||||
'menu.form.advanced-form': 'Advanced Form',
|
||||
'menu.list': 'List',
|
||||
'menu.list.table-list': 'Search Table',
|
||||
'menu.list.basic-list': 'Basic List',
|
||||
'menu.list.card-list': 'Card List',
|
||||
'menu.list.search-list': 'Search List',
|
||||
'menu.list.search-list.articles': 'Search List(articles)',
|
||||
'menu.list.search-list.projects': 'Search List(projects)',
|
||||
'menu.list.search-list.applications': 'Search List(applications)',
|
||||
'menu.profile': 'Profile',
|
||||
'menu.profile.basic': 'Basic Profile',
|
||||
'menu.profile.advanced': 'Advanced Profile',
|
||||
'menu.result': 'Result',
|
||||
'menu.result.success': 'Success',
|
||||
'menu.result.fail': 'Fail',
|
||||
'menu.exception': 'Exception',
|
||||
'menu.exception.not-permission': '403',
|
||||
'menu.exception.not-find': '404',
|
||||
'menu.exception.server-error': '500',
|
||||
'menu.exception.trigger': 'Trigger',
|
||||
'menu.account': 'Account',
|
||||
'menu.account.center': 'Account Center',
|
||||
'menu.account.settings': 'Account Settings',
|
||||
'menu.account.trigger': 'Trigger Error',
|
||||
'menu.account.logout': 'Logout',
|
||||
'menu.editor': 'Graphic Editor',
|
||||
'menu.editor.flow': 'Flow Editor',
|
||||
'menu.editor.mind': 'Mind Editor',
|
||||
'menu.editor.koni': 'Koni Editor',
|
||||
};
|
||||
6
dashboard/src/locales/en-US/menu.ts
Normal file
6
dashboard/src/locales/en-US/menu.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export default {
|
||||
'menu.home': 'Home',
|
||||
'menu.system': 'System',
|
||||
'menu.system.environment': 'Environment',
|
||||
'menu.applications': 'Applications',
|
||||
};
|
||||
6
dashboard/src/locales/en-US/pages.ts
Normal file
6
dashboard/src/locales/en-US/pages.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export default {
|
||||
'pages.welcome.advancedComponent': 'Advanced Component',
|
||||
'pages.welcome.link': 'Welcome',
|
||||
'pages.welcome.advancedLayout': 'Advanced Layout',
|
||||
'pages.welcome.alertMessage': 'Faster and stronger heavy-duty components have been released.',
|
||||
};
|
||||
@@ -1,31 +0,0 @@
|
||||
export default {
|
||||
'app.setting.pagestyle': 'Page style setting',
|
||||
'app.setting.pagestyle.dark': 'Dark style',
|
||||
'app.setting.pagestyle.light': 'Light style',
|
||||
'app.setting.content-width': 'Content Width',
|
||||
'app.setting.content-width.fixed': 'Fixed',
|
||||
'app.setting.content-width.fluid': 'Fluid',
|
||||
'app.setting.themecolor': 'Theme Color',
|
||||
'app.setting.themecolor.dust': 'Dust Red',
|
||||
'app.setting.themecolor.volcano': 'Volcano',
|
||||
'app.setting.themecolor.sunset': 'Sunset Orange',
|
||||
'app.setting.themecolor.cyan': 'Cyan',
|
||||
'app.setting.themecolor.green': 'Polar Green',
|
||||
'app.setting.themecolor.daybreak': 'Daybreak Blue (default)',
|
||||
'app.setting.themecolor.geekblue': 'Geek Glue',
|
||||
'app.setting.themecolor.purple': 'Golden Purple',
|
||||
'app.setting.navigationmode': 'Navigation Mode',
|
||||
'app.setting.sidemenu': 'Side Menu Layout',
|
||||
'app.setting.topmenu': 'Top Menu Layout',
|
||||
'app.setting.fixedheader': 'Fixed Header',
|
||||
'app.setting.fixedsidebar': 'Fixed Sidebar',
|
||||
'app.setting.fixedsidebar.hint': 'Works on Side Menu Layout',
|
||||
'app.setting.hideheader': 'Hidden Header when scrolling',
|
||||
'app.setting.hideheader.hint': 'Works when Hidden Header is enabled',
|
||||
'app.setting.othersettings': 'Other Settings',
|
||||
'app.setting.weakmode': 'Weak Mode',
|
||||
'app.setting.copy': 'Copy Setting',
|
||||
'app.setting.copyinfo': 'copy success,please replace defaultSettings in src/models/setting.js',
|
||||
'app.setting.production.hint':
|
||||
'Setting panel shows in development environment only, please manually modify',
|
||||
};
|
||||
@@ -1,60 +0,0 @@
|
||||
export default {
|
||||
'app.settings.menuMap.basic': 'Basic Settings',
|
||||
'app.settings.menuMap.security': 'Security Settings',
|
||||
'app.settings.menuMap.binding': 'Account Binding',
|
||||
'app.settings.menuMap.notification': 'New Message Notification',
|
||||
'app.settings.basic.avatar': 'Avatar',
|
||||
'app.settings.basic.change-avatar': 'Change avatar',
|
||||
'app.settings.basic.email': 'Email',
|
||||
'app.settings.basic.email-message': 'Please input your email!',
|
||||
'app.settings.basic.nickname': 'Nickname',
|
||||
'app.settings.basic.nickname-message': 'Please input your Nickname!',
|
||||
'app.settings.basic.profile': 'Personal profile',
|
||||
'app.settings.basic.profile-message': 'Please input your personal profile!',
|
||||
'app.settings.basic.profile-placeholder': 'Brief introduction to yourself',
|
||||
'app.settings.basic.country': 'Country/Region',
|
||||
'app.settings.basic.country-message': 'Please input your country!',
|
||||
'app.settings.basic.geographic': 'Province or city',
|
||||
'app.settings.basic.geographic-message': 'Please input your geographic info!',
|
||||
'app.settings.basic.address': 'Street Address',
|
||||
'app.settings.basic.address-message': 'Please input your address!',
|
||||
'app.settings.basic.phone': 'Phone Number',
|
||||
'app.settings.basic.phone-message': 'Please input your phone!',
|
||||
'app.settings.basic.update': 'Update Information',
|
||||
'app.settings.security.strong': 'Strong',
|
||||
'app.settings.security.medium': 'Medium',
|
||||
'app.settings.security.weak': 'Weak',
|
||||
'app.settings.security.password': 'Account Password',
|
||||
'app.settings.security.password-description': 'Current password strength',
|
||||
'app.settings.security.phone': 'Security Phone',
|
||||
'app.settings.security.phone-description': 'Bound phone',
|
||||
'app.settings.security.question': 'Security Question',
|
||||
'app.settings.security.question-description':
|
||||
'The security question is not set, and the security policy can effectively protect the account security',
|
||||
'app.settings.security.email': 'Backup Email',
|
||||
'app.settings.security.email-description': 'Bound Email',
|
||||
'app.settings.security.mfa': 'MFA Device',
|
||||
'app.settings.security.mfa-description':
|
||||
'Unbound MFA device, after binding, can be confirmed twice',
|
||||
'app.settings.security.modify': 'Modify',
|
||||
'app.settings.security.set': 'Set',
|
||||
'app.settings.security.bind': 'Bind',
|
||||
'app.settings.binding.taobao': 'Binding Taobao',
|
||||
'app.settings.binding.taobao-description': 'Currently unbound Taobao account',
|
||||
'app.settings.binding.alipay': 'Binding Alipay',
|
||||
'app.settings.binding.alipay-description': 'Currently unbound Alipay account',
|
||||
'app.settings.binding.dingding': 'Binding DingTalk',
|
||||
'app.settings.binding.dingding-description': 'Currently unbound DingTalk account',
|
||||
'app.settings.binding.bind': 'Bind',
|
||||
'app.settings.notification.password': 'Account Password',
|
||||
'app.settings.notification.password-description':
|
||||
'Messages from other users will be notified in the form of a station letter',
|
||||
'app.settings.notification.messages': 'System Messages',
|
||||
'app.settings.notification.messages-description':
|
||||
'System messages will be notified in the form of a station letter',
|
||||
'app.settings.notification.todo': 'To-do Notification',
|
||||
'app.settings.notification.todo-description':
|
||||
'The to-do list will be notified in the form of a letter from the station',
|
||||
'app.settings.open': 'Open',
|
||||
'app.settings.close': 'Close',
|
||||
};
|
||||
@@ -1,20 +0,0 @@
|
||||
import component from './pt-BR/component';
|
||||
import globalHeader from './pt-BR/globalHeader';
|
||||
import menu from './pt-BR/menu';
|
||||
import pwa from './pt-BR/pwa';
|
||||
import settingDrawer from './pt-BR/settingDrawer';
|
||||
import settings from './pt-BR/settings';
|
||||
|
||||
export default {
|
||||
'navBar.lang': 'Idiomas',
|
||||
'layout.user.link.help': 'ajuda',
|
||||
'layout.user.link.privacy': 'política de privacidade',
|
||||
'layout.user.link.terms': 'termos de serviços',
|
||||
'app.preview.down.block': 'Download this page to your local project',
|
||||
...globalHeader,
|
||||
...menu,
|
||||
...settingDrawer,
|
||||
...settings,
|
||||
...pwa,
|
||||
...component,
|
||||
};
|
||||
@@ -1,5 +0,0 @@
|
||||
export default {
|
||||
'component.tagSelect.expand': 'Expandir',
|
||||
'component.tagSelect.collapse': 'Diminuir',
|
||||
'component.tagSelect.all': 'Todas',
|
||||
};
|
||||
@@ -1,18 +0,0 @@
|
||||
export default {
|
||||
'component.globalHeader.search': 'Busca',
|
||||
'component.globalHeader.search.example1': 'Exemplo de busca 1',
|
||||
'component.globalHeader.search.example2': 'Exemplo de busca 2',
|
||||
'component.globalHeader.search.example3': 'Exemplo de busca 3',
|
||||
'component.globalHeader.help': 'Ajuda',
|
||||
'component.globalHeader.notification': 'Notificação',
|
||||
'component.globalHeader.notification.empty': 'Você visualizou todas as notificações.',
|
||||
'component.globalHeader.message': 'Mensagem',
|
||||
'component.globalHeader.message.empty': 'Você visualizou todas as mensagens.',
|
||||
'component.globalHeader.event': 'Evento',
|
||||
'component.globalHeader.event.empty': 'Você visualizou todos os eventos.',
|
||||
'component.noticeIcon.clear': 'Limpar',
|
||||
'component.noticeIcon.cleared': 'Limpo',
|
||||
'component.noticeIcon.empty': 'Sem notificações',
|
||||
'component.noticeIcon.loaded': 'Carregado',
|
||||
'component.noticeIcon.view-more': 'Veja mais',
|
||||
};
|
||||
@@ -1,52 +0,0 @@
|
||||
export default {
|
||||
'menu.welcome': 'Welcome',
|
||||
'menu.more-blocks': 'More Blocks',
|
||||
'menu.home': 'Início',
|
||||
'menu.login': 'Login',
|
||||
'menu.admin': 'Admin',
|
||||
'menu.admin.sub-page': 'Sub-Page',
|
||||
'menu.register': 'Registro',
|
||||
'menu.register.result': 'Resultado de registro',
|
||||
'menu.dashboard': 'Dashboard',
|
||||
'menu.dashboard.analysis': 'Análise',
|
||||
'menu.dashboard.monitor': 'Monitor',
|
||||
'menu.dashboard.workplace': 'Ambiente de Trabalho',
|
||||
'menu.exception.403': '403',
|
||||
'menu.exception.404': '404',
|
||||
'menu.exception.500': '500',
|
||||
'menu.form': 'Formulário',
|
||||
'menu.form.basic-form': 'Formulário Básico',
|
||||
'menu.form.step-form': 'Formulário Assistido',
|
||||
'menu.form.step-form.info': 'Formulário Assistido(gravar informações de transferência)',
|
||||
'menu.form.step-form.confirm': 'Formulário Assistido(confirmar informações de transferência)',
|
||||
'menu.form.step-form.result': 'Formulário Assistido(finalizado)',
|
||||
'menu.form.advanced-form': 'Formulário Avançado',
|
||||
'menu.list': 'Lista',
|
||||
'menu.list.table-list': 'Tabela de Busca',
|
||||
'menu.list.basic-list': 'Lista Básica',
|
||||
'menu.list.card-list': 'Lista de Card',
|
||||
'menu.list.search-list': 'Lista de Busca',
|
||||
'menu.list.search-list.articles': 'Lista de Busca(artigos)',
|
||||
'menu.list.search-list.projects': 'Lista de Busca(projetos)',
|
||||
'menu.list.search-list.applications': 'Lista de Busca(aplicações)',
|
||||
'menu.profile': 'Perfil',
|
||||
'menu.profile.basic': 'Perfil Básico',
|
||||
'menu.profile.advanced': 'Perfil Avançado',
|
||||
'menu.result': 'Resultado',
|
||||
'menu.result.success': 'Sucesso',
|
||||
'menu.result.fail': 'Falha',
|
||||
'menu.exception': 'Exceção',
|
||||
'menu.exception.not-permission': '403',
|
||||
'menu.exception.not-find': '404',
|
||||
'menu.exception.server-error': '500',
|
||||
'menu.exception.trigger': 'Disparar',
|
||||
'menu.account': 'Conta',
|
||||
'menu.account.center': 'Central da Conta',
|
||||
'menu.account.settings': 'Configurar Conta',
|
||||
'menu.account.trigger': 'Disparar Erro',
|
||||
'menu.account.logout': 'Sair',
|
||||
'menu.editor': 'Graphic Editor',
|
||||
'menu.editor.flow': 'Flow Editor',
|
||||
'menu.editor.mind': 'Mind Editor',
|
||||
'menu.editor.koni': 'Koni Editor',
|
||||
};
|
||||
@@ -1,7 +0,0 @@
|
||||
export default {
|
||||
'app.pwa.offline': 'Você está offline agora',
|
||||
'app.pwa.serviceworker.updated': 'Novo conteúdo está disponível',
|
||||
'app.pwa.serviceworker.updated.hint':
|
||||
'Por favor, pressione o botão "Atualizar" para recarregar a página atual',
|
||||
'app.pwa.serviceworker.updated.ok': 'Atualizar',
|
||||
};
|
||||
@@ -1,32 +0,0 @@
|
||||
export default {
|
||||
'app.setting.pagestyle': 'Configuração de estilo da página',
|
||||
'app.setting.pagestyle.dark': 'Dark style',
|
||||
'app.setting.pagestyle.light': 'Light style',
|
||||
'app.setting.content-width': 'Largura do conteúdo',
|
||||
'app.setting.content-width.fixed': 'Fixo',
|
||||
'app.setting.content-width.fluid': 'Fluido',
|
||||
'app.setting.themecolor': 'Cor do Tema',
|
||||
'app.setting.themecolor.dust': 'Dust Red',
|
||||
'app.setting.themecolor.volcano': 'Volcano',
|
||||
'app.setting.themecolor.sunset': 'Sunset Orange',
|
||||
'app.setting.themecolor.cyan': 'Cyan',
|
||||
'app.setting.themecolor.green': 'Polar Green',
|
||||
'app.setting.themecolor.daybreak': 'Daybreak Blue (default)',
|
||||
'app.setting.themecolor.geekblue': 'Geek Glue',
|
||||
'app.setting.themecolor.purple': 'Golden Purple',
|
||||
'app.setting.navigationmode': 'Modo de Navegação',
|
||||
'app.setting.sidemenu': 'Layout do Menu Lateral',
|
||||
'app.setting.topmenu': 'Layout do Menu Superior',
|
||||
'app.setting.fixedheader': 'Cabeçalho fixo',
|
||||
'app.setting.fixedsidebar': 'Barra lateral fixa',
|
||||
'app.setting.fixedsidebar.hint': 'Funciona no layout do menu lateral',
|
||||
'app.setting.hideheader': 'Esconder o cabeçalho quando rolar',
|
||||
'app.setting.hideheader.hint': 'Funciona quando o esconder cabeçalho está abilitado',
|
||||
'app.setting.othersettings': 'Outras configurações',
|
||||
'app.setting.weakmode': 'Weak Mode',
|
||||
'app.setting.copy': 'Copiar Configuração',
|
||||
'app.setting.copyinfo':
|
||||
'copiado com sucesso,por favor trocar o defaultSettings em src/models/setting.js',
|
||||
'app.setting.production.hint':
|
||||
'O painel de configuração apenas é exibido no ambiente de desenvolvimento, por favor modifique manualmente o',
|
||||
};
|
||||
@@ -1,60 +0,0 @@
|
||||
export default {
|
||||
'app.settings.menuMap.basic': 'Configurações Básicas',
|
||||
'app.settings.menuMap.security': 'Configurações de Segurança',
|
||||
'app.settings.menuMap.binding': 'Vinculação de Conta',
|
||||
'app.settings.menuMap.notification': 'Mensagens de Notificação',
|
||||
'app.settings.basic.avatar': 'Avatar',
|
||||
'app.settings.basic.change-avatar': 'Alterar avatar',
|
||||
'app.settings.basic.email': 'Email',
|
||||
'app.settings.basic.email-message': 'Por favor insira seu email!',
|
||||
'app.settings.basic.nickname': 'Nome de usuário',
|
||||
'app.settings.basic.nickname-message': 'Por favor insira seu nome de usuário!',
|
||||
'app.settings.basic.profile': 'Perfil pessoal',
|
||||
'app.settings.basic.profile-message': 'Por favor insira seu perfil pessoal!',
|
||||
'app.settings.basic.profile-placeholder': 'Breve introdução sua',
|
||||
'app.settings.basic.country': 'País/Região',
|
||||
'app.settings.basic.country-message': 'Por favor insira país!',
|
||||
'app.settings.basic.geographic': 'Província, estado ou cidade',
|
||||
'app.settings.basic.geographic-message': 'Por favor insira suas informações geográficas!',
|
||||
'app.settings.basic.address': 'Endereço',
|
||||
'app.settings.basic.address-message': 'Por favor insira seu endereço!',
|
||||
'app.settings.basic.phone': 'Número de telefone',
|
||||
'app.settings.basic.phone-message': 'Por favor insira seu número de telefone!',
|
||||
'app.settings.basic.update': 'Atualizar Informações',
|
||||
'app.settings.security.strong': 'Forte',
|
||||
'app.settings.security.medium': 'Média',
|
||||
'app.settings.security.weak': 'Fraca',
|
||||
'app.settings.security.password': 'Senha da Conta',
|
||||
'app.settings.security.password-description': 'Força da senha',
|
||||
'app.settings.security.phone': 'Telefone de Seguraça',
|
||||
'app.settings.security.phone-description': 'Telefone vinculado',
|
||||
'app.settings.security.question': 'Pergunta de Segurança',
|
||||
'app.settings.security.question-description':
|
||||
'A pergunta de segurança não está definida e a política de segurança pode proteger efetivamente a segurança da conta',
|
||||
'app.settings.security.email': 'Email de Backup',
|
||||
'app.settings.security.email-description': 'Email vinculado',
|
||||
'app.settings.security.mfa': 'Dispositivo MFA',
|
||||
'app.settings.security.mfa-description':
|
||||
'O dispositivo MFA não vinculado, após a vinculação, pode ser confirmado duas vezes',
|
||||
'app.settings.security.modify': 'Modificar',
|
||||
'app.settings.security.set': 'Atribuir',
|
||||
'app.settings.security.bind': 'Vincular',
|
||||
'app.settings.binding.taobao': 'Vincular Taobao',
|
||||
'app.settings.binding.taobao-description': 'Atualmente não vinculado à conta Taobao',
|
||||
'app.settings.binding.alipay': 'Vincular Alipay',
|
||||
'app.settings.binding.alipay-description': 'Atualmente não vinculado à conta Alipay',
|
||||
'app.settings.binding.dingding': 'Vincular DingTalk',
|
||||
'app.settings.binding.dingding-description': 'Atualmente não vinculado à conta DingTalk',
|
||||
'app.settings.binding.bind': 'Vincular',
|
||||
'app.settings.notification.password': 'Senha da Conta',
|
||||
'app.settings.notification.password-description':
|
||||
'Mensagens de outros usuários serão notificadas na forma de uma estação de letra',
|
||||
'app.settings.notification.messages': 'Mensagens de Sistema',
|
||||
'app.settings.notification.messages-description':
|
||||
'Mensagens de sistema serão notificadas na forma de uma estação de letra',
|
||||
'app.settings.notification.todo': 'Notificação de To-do',
|
||||
'app.settings.notification.todo-description':
|
||||
'A lista de to-do será notificada na forma de uma estação de letra',
|
||||
'app.settings.open': 'Aberto',
|
||||
'app.settings.close': 'Fechado',
|
||||
};
|
||||
@@ -1,22 +0,0 @@
|
||||
import component from './zh-CN/component';
|
||||
import globalHeader from './zh-CN/globalHeader';
|
||||
import menu from './zh-CN/menu';
|
||||
import pwa from './zh-CN/pwa';
|
||||
import settingDrawer from './zh-CN/settingDrawer';
|
||||
import settings from './zh-CN/settings';
|
||||
|
||||
export default {
|
||||
'navBar.lang': '语言',
|
||||
'layout.user.link.help': '帮助',
|
||||
'layout.user.link.privacy': '隐私',
|
||||
'layout.user.link.terms': '条款',
|
||||
'app.preview.down.block': '下载此页面到本地项目',
|
||||
'app.welcome.link.fetch-blocks': '获取全部区块',
|
||||
'app.welcome.link.block-list': '基于 block 开发,快速构建标准页面',
|
||||
...globalHeader,
|
||||
...menu,
|
||||
...settingDrawer,
|
||||
...settings,
|
||||
...pwa,
|
||||
...component,
|
||||
};
|
||||
11
dashboard/src/locales/zh-CN.ts
Normal file
11
dashboard/src/locales/zh-CN.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import component from './zh-CN/component';
|
||||
import menu from './zh-CN/menu';
|
||||
import pages from './zh-CN/pages';
|
||||
import pwa from './zh-CN/pwa';
|
||||
|
||||
export default {
|
||||
...pages,
|
||||
...menu,
|
||||
...pwa,
|
||||
...component,
|
||||
};
|
||||
@@ -1,17 +0,0 @@
|
||||
export default {
|
||||
'component.globalHeader.search': '站内搜索',
|
||||
'component.globalHeader.search.example1': '搜索提示一',
|
||||
'component.globalHeader.search.example2': '搜索提示二',
|
||||
'component.globalHeader.search.example3': '搜索提示三',
|
||||
'component.globalHeader.help': '使用文档',
|
||||
'component.globalHeader.notification': '通知',
|
||||
'component.globalHeader.notification.empty': '你已查看所有通知',
|
||||
'component.globalHeader.message': '消息',
|
||||
'component.globalHeader.message.empty': '您已读完所有消息',
|
||||
'component.globalHeader.event': '待办',
|
||||
'component.globalHeader.event.empty': '你已完成所有待办',
|
||||
'component.noticeIcon.clear': '清空',
|
||||
'component.noticeIcon.cleared': '清空了',
|
||||
'component.noticeIcon.empty': '暂无数据',
|
||||
'component.noticeIcon.view-more': '查看更多',
|
||||
};
|
||||
@@ -1,57 +0,0 @@
|
||||
export default {
|
||||
'menu.welcome': '欢迎',
|
||||
'menu.more-blocks': '更多区块',
|
||||
'menu.home': '应用中心',
|
||||
'menu.Traits': '总揽',
|
||||
'menu.ApplicationList': '应用列表',
|
||||
'menu.Capability': '组件模版',
|
||||
'menu.Workload': '工作负载',
|
||||
'menu.Release': '运维特性',
|
||||
'menu.admin': '管理页',
|
||||
'menu.admin.sub-page': '二级管理页',
|
||||
'menu.login': '登录',
|
||||
'menu.register': '注册',
|
||||
'menu.register.result': '注册结果',
|
||||
'menu.dashboard': 'Dashboard',
|
||||
'menu.dashboard.analysis': '分析页',
|
||||
'menu.dashboard.monitor': '监控页',
|
||||
'menu.dashboard.workplace': '工作台',
|
||||
'menu.exception.403': '403',
|
||||
'menu.exception.404': '404',
|
||||
'menu.exception.500': '500',
|
||||
'menu.form': '表单页',
|
||||
'menu.form.basic-form': '基础表单',
|
||||
'menu.form.step-form': '分步表单',
|
||||
'menu.form.step-form.info': '分步表单(填写转账信息)',
|
||||
'menu.form.step-form.confirm': '分步表单(确认转账信息)',
|
||||
'menu.form.step-form.result': '分步表单(完成)',
|
||||
'menu.form.advanced-form': '高级表单',
|
||||
'menu.list': '列表页',
|
||||
'menu.list.table-list': '查询表格',
|
||||
'menu.list.basic-list': '标准列表',
|
||||
'menu.list.card-list': '卡片列表',
|
||||
'menu.list.search-list': '搜索列表',
|
||||
'menu.list.search-list.articles': '搜索列表(文章)',
|
||||
'menu.list.search-list.projects': '搜索列表(项目)',
|
||||
'menu.list.search-list.applications': '搜索列表(应用)',
|
||||
'menu.profile': '详情页',
|
||||
'menu.profile.basic': '基础详情页',
|
||||
'menu.profile.advanced': '高级详情页',
|
||||
'menu.result': '结果页',
|
||||
'menu.result.success': '成功页',
|
||||
'menu.result.fail': '失败页',
|
||||
'menu.exception': '异常页',
|
||||
'menu.exception.not-permission': '403',
|
||||
'menu.exception.not-find': '404',
|
||||
'menu.exception.server-error': '500',
|
||||
'menu.exception.trigger': '触发错误',
|
||||
'menu.account': '个人页',
|
||||
'menu.account.center': '个人中心',
|
||||
'menu.account.settings': '个人设置',
|
||||
'menu.account.trigger': '触发报错',
|
||||
'menu.account.logout': '退出登录',
|
||||
'menu.editor': '图形编辑器',
|
||||
'menu.editor.flow': '流程编辑器',
|
||||
'menu.editor.mind': '脑图编辑器',
|
||||
'menu.editor.koni': '拓扑编辑器',
|
||||
};
|
||||
6
dashboard/src/locales/zh-CN/menu.ts
Normal file
6
dashboard/src/locales/zh-CN/menu.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export default {
|
||||
'menu.home': '首页',
|
||||
'menu.system': '系统',
|
||||
'menu.system.environment': '环境',
|
||||
'menu.applications': '应用列表',
|
||||
};
|
||||
6
dashboard/src/locales/zh-CN/pages.ts
Normal file
6
dashboard/src/locales/zh-CN/pages.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export default {
|
||||
'pages.welcome.advancedComponent': '高级表格',
|
||||
'pages.welcome.link': '欢迎使用',
|
||||
'pages.welcome.advancedLayout': '高级布局',
|
||||
'pages.welcome.alertMessage': '更快更强的重型组件,已经发布。',
|
||||
};
|
||||
@@ -1,31 +0,0 @@
|
||||
export default {
|
||||
'app.setting.pagestyle': '整体风格设置',
|
||||
'app.setting.pagestyle.dark': '暗色菜单风格',
|
||||
'app.setting.pagestyle.light': '亮色菜单风格',
|
||||
'app.setting.content-width': '内容区域宽度',
|
||||
'app.setting.content-width.fixed': '定宽',
|
||||
'app.setting.content-width.fluid': '流式',
|
||||
'app.setting.themecolor': '主题色',
|
||||
'app.setting.themecolor.dust': '薄暮',
|
||||
'app.setting.themecolor.volcano': '火山',
|
||||
'app.setting.themecolor.sunset': '日暮',
|
||||
'app.setting.themecolor.cyan': '明青',
|
||||
'app.setting.themecolor.green': '极光绿',
|
||||
'app.setting.themecolor.daybreak': '拂晓蓝(默认)',
|
||||
'app.setting.themecolor.geekblue': '极客蓝',
|
||||
'app.setting.themecolor.purple': '酱紫',
|
||||
'app.setting.navigationmode': '导航模式',
|
||||
'app.setting.sidemenu': '侧边菜单布局',
|
||||
'app.setting.topmenu': '顶部菜单布局',
|
||||
'app.setting.fixedheader': '固定 Header',
|
||||
'app.setting.fixedsidebar': '固定侧边菜单',
|
||||
'app.setting.fixedsidebar.hint': '侧边菜单布局时可配置',
|
||||
'app.setting.hideheader': '下滑时隐藏 Header',
|
||||
'app.setting.hideheader.hint': '固定 Header 时可配置',
|
||||
'app.setting.othersettings': '其他设置',
|
||||
'app.setting.weakmode': '色弱模式',
|
||||
'app.setting.copy': '拷贝设置',
|
||||
'app.setting.copyinfo': '拷贝成功,请到 src/defaultSettings.js 中替换默认配置',
|
||||
'app.setting.production.hint':
|
||||
'配置栏只在开发环境用于预览,生产环境不会展现,请拷贝后手动修改配置文件',
|
||||
};
|
||||
@@ -1,55 +0,0 @@
|
||||
export default {
|
||||
'app.settings.menuMap.basic': '基本设置',
|
||||
'app.settings.menuMap.security': '安全设置',
|
||||
'app.settings.menuMap.binding': '账号绑定',
|
||||
'app.settings.menuMap.notification': '新消息通知',
|
||||
'app.settings.basic.avatar': '头像',
|
||||
'app.settings.basic.change-avatar': '更换头像',
|
||||
'app.settings.basic.email': '邮箱',
|
||||
'app.settings.basic.email-message': '请输入您的邮箱!',
|
||||
'app.settings.basic.nickname': '昵称',
|
||||
'app.settings.basic.nickname-message': '请输入您的昵称!',
|
||||
'app.settings.basic.profile': '个人简介',
|
||||
'app.settings.basic.profile-message': '请输入个人简介!',
|
||||
'app.settings.basic.profile-placeholder': '个人简介',
|
||||
'app.settings.basic.country': '国家/地区',
|
||||
'app.settings.basic.country-message': '请输入您的国家或地区!',
|
||||
'app.settings.basic.geographic': '所在省市',
|
||||
'app.settings.basic.geographic-message': '请输入您的所在省市!',
|
||||
'app.settings.basic.address': '街道地址',
|
||||
'app.settings.basic.address-message': '请输入您的街道地址!',
|
||||
'app.settings.basic.phone': '联系电话',
|
||||
'app.settings.basic.phone-message': '请输入您的联系电话!',
|
||||
'app.settings.basic.update': '更新基本信息',
|
||||
'app.settings.security.strong': '强',
|
||||
'app.settings.security.medium': '中',
|
||||
'app.settings.security.weak': '弱',
|
||||
'app.settings.security.password': '账户密码',
|
||||
'app.settings.security.password-description': '当前密码强度',
|
||||
'app.settings.security.phone': '密保手机',
|
||||
'app.settings.security.phone-description': '已绑定手机',
|
||||
'app.settings.security.question': '密保问题',
|
||||
'app.settings.security.question-description': '未设置密保问题,密保问题可有效保护账户安全',
|
||||
'app.settings.security.email': '备用邮箱',
|
||||
'app.settings.security.email-description': '已绑定邮箱',
|
||||
'app.settings.security.mfa': 'MFA 设备',
|
||||
'app.settings.security.mfa-description': '未绑定 MFA 设备,绑定后,可以进行二次确认',
|
||||
'app.settings.security.modify': '修改',
|
||||
'app.settings.security.set': '设置',
|
||||
'app.settings.security.bind': '绑定',
|
||||
'app.settings.binding.taobao': '绑定淘宝',
|
||||
'app.settings.binding.taobao-description': '当前未绑定淘宝账号',
|
||||
'app.settings.binding.alipay': '绑定支付宝',
|
||||
'app.settings.binding.alipay-description': '当前未绑定支付宝账号',
|
||||
'app.settings.binding.dingding': '绑定钉钉',
|
||||
'app.settings.binding.dingding-description': '当前未绑定钉钉账号',
|
||||
'app.settings.binding.bind': '绑定',
|
||||
'app.settings.notification.password': '账户密码',
|
||||
'app.settings.notification.password-description': '其他用户的消息将以站内信的形式通知',
|
||||
'app.settings.notification.messages': '系统消息',
|
||||
'app.settings.notification.messages-description': '系统消息将以站内信的形式通知',
|
||||
'app.settings.notification.todo': '待办任务',
|
||||
'app.settings.notification.todo-description': '待办任务将以站内信的形式通知',
|
||||
'app.settings.open': '开',
|
||||
'app.settings.close': '关',
|
||||
};
|
||||
@@ -1,20 +0,0 @@
|
||||
import component from './zh-TW/component';
|
||||
import globalHeader from './zh-TW/globalHeader';
|
||||
import menu from './zh-TW/menu';
|
||||
import pwa from './zh-TW/pwa';
|
||||
import settingDrawer from './zh-TW/settingDrawer';
|
||||
import settings from './zh-TW/settings';
|
||||
|
||||
export default {
|
||||
'navBar.lang': '語言',
|
||||
'layout.user.link.help': '幫助',
|
||||
'layout.user.link.privacy': '隱私',
|
||||
'layout.user.link.terms': '條款',
|
||||
'app.preview.down.block': '下載此頁面到本地項目',
|
||||
...globalHeader,
|
||||
...menu,
|
||||
...settingDrawer,
|
||||
...settings,
|
||||
...pwa,
|
||||
...component,
|
||||
};
|
||||
@@ -1,5 +0,0 @@
|
||||
export default {
|
||||
'component.tagSelect.expand': '展開',
|
||||
'component.tagSelect.collapse': '收起',
|
||||
'component.tagSelect.all': '全部',
|
||||
};
|
||||
@@ -1,17 +0,0 @@
|
||||
export default {
|
||||
'component.globalHeader.search': '站內搜索',
|
||||
'component.globalHeader.search.example1': '搜索提示壹',
|
||||
'component.globalHeader.search.example2': '搜索提示二',
|
||||
'component.globalHeader.search.example3': '搜索提示三',
|
||||
'component.globalHeader.help': '使用手冊',
|
||||
'component.globalHeader.notification': '通知',
|
||||
'component.globalHeader.notification.empty': '妳已查看所有通知',
|
||||
'component.globalHeader.message': '消息',
|
||||
'component.globalHeader.message.empty': '您已讀完所有消息',
|
||||
'component.globalHeader.event': '待辦',
|
||||
'component.globalHeader.event.empty': '妳已完成所有待辦',
|
||||
'component.noticeIcon.clear': '清空',
|
||||
'component.noticeIcon.cleared': '清空了',
|
||||
'component.noticeIcon.empty': '暫無資料',
|
||||
'component.noticeIcon.view-more': '查看更多',
|
||||
};
|
||||
@@ -1,57 +0,0 @@
|
||||
export default {
|
||||
'menu.welcome': '歡迎',
|
||||
'menu.more-blocks': '更多區塊',
|
||||
'menu.home': '應用中心',
|
||||
'menu.Traits': '總覽',
|
||||
'menu.ApplicationList': '應用列表',
|
||||
'menu.Capability': '組件模版',
|
||||
'menu.Workload': '工作負載',
|
||||
'menu.Release': '運維特性',
|
||||
'menu.login': '登錄',
|
||||
'menu.admin': '管理頁',
|
||||
'menu.admin.sub-page': '二級管理頁',
|
||||
'menu.exception.403': '403',
|
||||
'menu.exception.404': '404',
|
||||
'menu.exception.500': '500',
|
||||
'menu.register': '註冊',
|
||||
'menu.register.result': '註冊結果',
|
||||
'menu.dashboard': 'Dashboard',
|
||||
'menu.dashboard.analysis': '分析頁',
|
||||
'menu.dashboard.monitor': '監控頁',
|
||||
'menu.dashboard.workplace': '工作臺',
|
||||
'menu.form': '表單頁',
|
||||
'menu.form.basic-form': '基礎表單',
|
||||
'menu.form.step-form': '分步表單',
|
||||
'menu.form.step-form.info': '分步表單(填寫轉賬信息)',
|
||||
'menu.form.step-form.confirm': '分步表單(確認轉賬信息)',
|
||||
'menu.form.step-form.result': '分步表單(完成)',
|
||||
'menu.form.advanced-form': '高級表單',
|
||||
'menu.list': '列表頁',
|
||||
'menu.list.table-list': '查詢表格',
|
||||
'menu.list.basic-list': '標淮列表',
|
||||
'menu.list.card-list': '卡片列表',
|
||||
'menu.list.search-list': '搜索列表',
|
||||
'menu.list.search-list.articles': '搜索列表(文章)',
|
||||
'menu.list.search-list.projects': '搜索列表(項目)',
|
||||
'menu.list.search-list.applications': '搜索列表(應用)',
|
||||
'menu.profile': '詳情頁',
|
||||
'menu.profile.basic': '基礎詳情頁',
|
||||
'menu.profile.advanced': '高級詳情頁',
|
||||
'menu.result': '結果頁',
|
||||
'menu.result.success': '成功頁',
|
||||
'menu.result.fail': '失敗頁',
|
||||
'menu.account': '個人頁',
|
||||
'menu.account.center': '個人中心',
|
||||
'menu.account.settings': '個人設置',
|
||||
'menu.account.trigger': '觸發報錯',
|
||||
'menu.account.logout': '退出登錄',
|
||||
'menu.exception': '异常页',
|
||||
'menu.exception.not-permission': '403',
|
||||
'menu.exception.not-find': '404',
|
||||
'menu.exception.server-error': '500',
|
||||
'menu.exception.trigger': '触发错误',
|
||||
'menu.editor': '圖形編輯器',
|
||||
'menu.editor.flow': '流程編輯器',
|
||||
'menu.editor.mind': '腦圖編輯器',
|
||||
'menu.editor.koni': '拓撲編輯器',
|
||||
};
|
||||
@@ -1,6 +0,0 @@
|
||||
export default {
|
||||
'app.pwa.offline': '當前處於離線狀態',
|
||||
'app.pwa.serviceworker.updated': '有新內容',
|
||||
'app.pwa.serviceworker.updated.hint': '請點擊“刷新”按鈕或者手動刷新頁面',
|
||||
'app.pwa.serviceworker.updated.ok': '刷新',
|
||||
};
|
||||
@@ -1,31 +0,0 @@
|
||||
export default {
|
||||
'app.setting.pagestyle': '整體風格設置',
|
||||
'app.setting.pagestyle.dark': '暗色菜單風格',
|
||||
'app.setting.pagestyle.light': '亮色菜單風格',
|
||||
'app.setting.content-width': '內容區域寬度',
|
||||
'app.setting.content-width.fixed': '定寬',
|
||||
'app.setting.content-width.fluid': '流式',
|
||||
'app.setting.themecolor': '主題色',
|
||||
'app.setting.themecolor.dust': '薄暮',
|
||||
'app.setting.themecolor.volcano': '火山',
|
||||
'app.setting.themecolor.sunset': '日暮',
|
||||
'app.setting.themecolor.cyan': '明青',
|
||||
'app.setting.themecolor.green': '極光綠',
|
||||
'app.setting.themecolor.daybreak': '拂曉藍(默認)',
|
||||
'app.setting.themecolor.geekblue': '極客藍',
|
||||
'app.setting.themecolor.purple': '醬紫',
|
||||
'app.setting.navigationmode': '導航模式',
|
||||
'app.setting.sidemenu': '側邊菜單布局',
|
||||
'app.setting.topmenu': '頂部菜單布局',
|
||||
'app.setting.fixedheader': '固定 Header',
|
||||
'app.setting.fixedsidebar': '固定側邊菜單',
|
||||
'app.setting.fixedsidebar.hint': '側邊菜單布局時可配置',
|
||||
'app.setting.hideheader': '下滑時隱藏 Header',
|
||||
'app.setting.hideheader.hint': '固定 Header 時可配置',
|
||||
'app.setting.othersettings': '其他設置',
|
||||
'app.setting.weakmode': '色弱模式',
|
||||
'app.setting.copy': '拷貝設置',
|
||||
'app.setting.copyinfo': '拷貝成功,請到 src/defaultSettings.js 中替換默認配置',
|
||||
'app.setting.production.hint':
|
||||
'配置欄只在開發環境用於預覽,生產環境不會展現,請拷貝後手動修改配置文件',
|
||||
};
|
||||
@@ -1,55 +0,0 @@
|
||||
export default {
|
||||
'app.settings.menuMap.basic': '基本設置',
|
||||
'app.settings.menuMap.security': '安全設置',
|
||||
'app.settings.menuMap.binding': '賬號綁定',
|
||||
'app.settings.menuMap.notification': '新消息通知',
|
||||
'app.settings.basic.avatar': '頭像',
|
||||
'app.settings.basic.change-avatar': '更換頭像',
|
||||
'app.settings.basic.email': '郵箱',
|
||||
'app.settings.basic.email-message': '請輸入您的郵箱!',
|
||||
'app.settings.basic.nickname': '昵稱',
|
||||
'app.settings.basic.nickname-message': '請輸入您的昵稱!',
|
||||
'app.settings.basic.profile': '個人簡介',
|
||||
'app.settings.basic.profile-message': '請輸入個人簡介!',
|
||||
'app.settings.basic.profile-placeholder': '個人簡介',
|
||||
'app.settings.basic.country': '國家/地區',
|
||||
'app.settings.basic.country-message': '請輸入您的國家或地區!',
|
||||
'app.settings.basic.geographic': '所在省市',
|
||||
'app.settings.basic.geographic-message': '請輸入您的所在省市!',
|
||||
'app.settings.basic.address': '街道地址',
|
||||
'app.settings.basic.address-message': '請輸入您的街道地址!',
|
||||
'app.settings.basic.phone': '聯系電話',
|
||||
'app.settings.basic.phone-message': '請輸入您的聯系電話!',
|
||||
'app.settings.basic.update': '更新基本信息',
|
||||
'app.settings.security.strong': '強',
|
||||
'app.settings.security.medium': '中',
|
||||
'app.settings.security.weak': '弱',
|
||||
'app.settings.security.password': '賬戶密碼',
|
||||
'app.settings.security.password-description': '當前密碼強度',
|
||||
'app.settings.security.phone': '密保手機',
|
||||
'app.settings.security.phone-description': '已綁定手機',
|
||||
'app.settings.security.question': '密保問題',
|
||||
'app.settings.security.question-description': '未設置密保問題,密保問題可有效保護賬戶安全',
|
||||
'app.settings.security.email': '備用郵箱',
|
||||
'app.settings.security.email-description': '已綁定郵箱',
|
||||
'app.settings.security.mfa': 'MFA 設備',
|
||||
'app.settings.security.mfa-description': '未綁定 MFA 設備,綁定後,可以進行二次確認',
|
||||
'app.settings.security.modify': '修改',
|
||||
'app.settings.security.set': '設置',
|
||||
'app.settings.security.bind': '綁定',
|
||||
'app.settings.binding.taobao': '綁定淘寶',
|
||||
'app.settings.binding.taobao-description': '當前未綁定淘寶賬號',
|
||||
'app.settings.binding.alipay': '綁定支付寶',
|
||||
'app.settings.binding.alipay-description': '當前未綁定支付寶賬號',
|
||||
'app.settings.binding.dingding': '綁定釘釘',
|
||||
'app.settings.binding.dingding-description': '當前未綁定釘釘賬號',
|
||||
'app.settings.binding.bind': '綁定',
|
||||
'app.settings.notification.password': '賬戶密碼',
|
||||
'app.settings.notification.password-description': '其他用戶的消息將以站內信的形式通知',
|
||||
'app.settings.notification.messages': '系統消息',
|
||||
'app.settings.notification.messages-description': '系統消息將以站內信的形式通知',
|
||||
'app.settings.notification.todo': '待辦任務',
|
||||
'app.settings.notification.todo-description': '待辦任務將以站內信的形式通知',
|
||||
'app.settings.open': '開',
|
||||
'app.settings.close': '關',
|
||||
};
|
||||
22
dashboard/src/manifest.json
Normal file
22
dashboard/src/manifest.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "KubeVela",
|
||||
"short_name": "KubeVela",
|
||||
"display": "standalone",
|
||||
"start_url": "./?utm_source=homescreen",
|
||||
"theme_color": "#002140",
|
||||
"background_color": "#001529",
|
||||
"icons": [
|
||||
{
|
||||
"src": "icons/icon-192x192.png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "icons/icon-128x128.png",
|
||||
"sizes": "128x128"
|
||||
},
|
||||
{
|
||||
"src": "icons/icon-512x512.png",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
import { getapplist, createApp, getAppDetail, deleteApp } from '@/services/application';
|
||||
|
||||
const TestModel = {
|
||||
namespace: 'applist',
|
||||
state: {},
|
||||
effects: {
|
||||
*getList({ payload }, { call, put }) {
|
||||
const res = yield call(getapplist, payload);
|
||||
// getlist是引入services层那个js文件的getlist方法,payload是后台要求传递的参数,res就是后台返过来的数据
|
||||
yield put({
|
||||
type: 'addList',
|
||||
payload: {
|
||||
returnObj: res,
|
||||
},
|
||||
});
|
||||
},
|
||||
*createApp({ payload }, { call }) {
|
||||
// 如果 method = Get,data 类型 = list/json 否则,data 类型 = string,存储的是操作成功的信息
|
||||
// 非get请求,将结果返回,在调用页面进行async await 来进行操作结果提示
|
||||
const res = yield call(createApp, payload);
|
||||
return res;
|
||||
},
|
||||
*getAppDetail({ payload }, { call }) {
|
||||
const res = yield call(getAppDetail, payload);
|
||||
return res;
|
||||
},
|
||||
*deleteApp({ payload }, { call }) {
|
||||
const res = yield call(deleteApp, payload);
|
||||
return res;
|
||||
},
|
||||
},
|
||||
reducers: {
|
||||
addList(state, { payload: { returnObj } }) {
|
||||
return { ...state, returnObj };
|
||||
},
|
||||
},
|
||||
};
|
||||
export default TestModel;
|
||||
@@ -1,48 +0,0 @@
|
||||
import {
|
||||
getCapabilityCenterlist,
|
||||
createCapabilityCenter,
|
||||
syncCapability,
|
||||
deleteCapability,
|
||||
syncOneCapability,
|
||||
deleteOneCapability,
|
||||
capabilityList,
|
||||
} from '@/services/capability.js';
|
||||
|
||||
const TestModel = {
|
||||
namespace: 'capability',
|
||||
state: {},
|
||||
effects: {
|
||||
*getCapabilityCenterlist({ payload }, { call }) {
|
||||
const res = yield call(getCapabilityCenterlist, payload);
|
||||
return res;
|
||||
},
|
||||
*createCapabilityCenter({ payload }, { call }) {
|
||||
// 如果 method = Get,data 类型 = list/json 否则,data 类型 = string,存储的是操作成功的信息
|
||||
// 非get请求,将结果返回,在调用页面进行async await 来进行操作结果提示
|
||||
const res = yield call(createCapabilityCenter, payload);
|
||||
return res;
|
||||
},
|
||||
*syncCapability({ payload }, { call }) {
|
||||
const res = yield call(syncCapability, payload);
|
||||
return res;
|
||||
},
|
||||
*deleteCapability({ payload }, { call }) {
|
||||
const res = yield call(deleteCapability, payload);
|
||||
return res;
|
||||
},
|
||||
*syncOneCapability({ payload }, { call }) {
|
||||
const res = yield call(syncOneCapability, payload);
|
||||
return res;
|
||||
},
|
||||
*deleteOneCapability({ payload }, { call }) {
|
||||
const res = yield call(deleteOneCapability, payload);
|
||||
return res;
|
||||
},
|
||||
*capabilityList({ payload }, { call }) {
|
||||
const res = yield call(capabilityList, payload);
|
||||
return res;
|
||||
},
|
||||
},
|
||||
reducers: {},
|
||||
};
|
||||
export default TestModel;
|
||||
@@ -1,22 +0,0 @@
|
||||
import { getComponentList, getComponentDetail, deleteComponent } from '@/services/components.js';
|
||||
|
||||
const TestModel = {
|
||||
namespace: 'components',
|
||||
state: {},
|
||||
effects: {
|
||||
*getComponentList({ payload }, { call }) {
|
||||
const res = yield call(getComponentList, payload);
|
||||
return res;
|
||||
},
|
||||
*getComponentDetail({ payload }, { call }) {
|
||||
const res = yield call(getComponentDetail, payload);
|
||||
return res;
|
||||
},
|
||||
*deleteComponent({ payload }, { call }) {
|
||||
const res = yield call(deleteComponent, payload);
|
||||
return res;
|
||||
},
|
||||
},
|
||||
reducers: {},
|
||||
};
|
||||
export default TestModel;
|
||||
@@ -1,58 +0,0 @@
|
||||
import { getEnvs, switchEnv, initialEnvs, deleteEnv, updateEnv } from '@/services/env';
|
||||
|
||||
const TestModel = {
|
||||
namespace: 'envs',
|
||||
state: {
|
||||
envs: undefined,
|
||||
},
|
||||
effects: {
|
||||
*getEnvs({ payload }, { call, put }) {
|
||||
const res = yield call(getEnvs, payload);
|
||||
yield put({
|
||||
type: 'onGetEnvsSuccess',
|
||||
payload: res,
|
||||
});
|
||||
return res;
|
||||
},
|
||||
*switchEnv({ payload }, { call }) {
|
||||
const res = yield call(switchEnv, payload);
|
||||
return res;
|
||||
},
|
||||
*initialEnvs({ payload }, { call, put }) {
|
||||
yield call(initialEnvs, payload);
|
||||
const res = yield call(getEnvs, payload);
|
||||
yield put({
|
||||
type: 'onGetEnvsSuccess',
|
||||
payload: res,
|
||||
});
|
||||
return res;
|
||||
},
|
||||
*deleteEnv({ payload }, { call, put }) {
|
||||
yield call(deleteEnv, payload);
|
||||
const res = yield call(getEnvs);
|
||||
yield put({
|
||||
type: 'onGetEnvsSuccess',
|
||||
payload: res,
|
||||
});
|
||||
return res;
|
||||
},
|
||||
*updateEnv({ payload }, { call, put }) {
|
||||
yield call(updateEnv, payload);
|
||||
const res = yield call(getEnvs);
|
||||
yield put({
|
||||
type: 'onGetEnvsSuccess',
|
||||
payload: res,
|
||||
});
|
||||
return res;
|
||||
},
|
||||
},
|
||||
reducers: {
|
||||
onGetEnvsSuccess(state, { payload }) {
|
||||
return {
|
||||
...state,
|
||||
envs: payload,
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
export default TestModel;
|
||||
@@ -1,20 +0,0 @@
|
||||
const globalModel = {
|
||||
namespace: 'globalData',
|
||||
state: {
|
||||
currentEnv: '',
|
||||
},
|
||||
effects: {
|
||||
*currentEnv({ payload }, { put }) {
|
||||
yield put({
|
||||
type: 'setCurrentEnv',
|
||||
payload,
|
||||
});
|
||||
},
|
||||
},
|
||||
reducers: {
|
||||
setCurrentEnv(state, { payload: { currentEnv } }) {
|
||||
return { ...state, currentEnv };
|
||||
},
|
||||
},
|
||||
};
|
||||
export default globalModel;
|
||||
@@ -1,125 +0,0 @@
|
||||
import { getTraits } from '@/services/trait.js';
|
||||
import { getWorkload } from '@/services/workload.js';
|
||||
|
||||
function getMenuList(workload, trait) {
|
||||
let workloadList = [];
|
||||
let traitList = [];
|
||||
if (workload) {
|
||||
workloadList = workload.map((item) => {
|
||||
let name1 = item.name;
|
||||
name1 = name1.charAt(0).toUpperCase() + name1.slice(1);
|
||||
return {
|
||||
name: name1,
|
||||
path: `/Workload/${name1}`,
|
||||
key: name1,
|
||||
};
|
||||
});
|
||||
}
|
||||
if (trait) {
|
||||
traitList = trait.map((item) => {
|
||||
let name1 = item.name;
|
||||
name1 = name1.charAt(0).toUpperCase() + name1.slice(1);
|
||||
return {
|
||||
name: name1,
|
||||
path: `/Traits/${name1}`,
|
||||
key: name1,
|
||||
};
|
||||
});
|
||||
}
|
||||
// 只是动态生成侧边栏(name,path,icon),路由还是config.js里面配置的路由
|
||||
const menuList = [
|
||||
{
|
||||
path: '/',
|
||||
redirect: `/ApplicationList`,
|
||||
},
|
||||
{
|
||||
name: 'ApplicationList',
|
||||
icon: 'Table',
|
||||
path: `/ApplicationList`,
|
||||
key: 'applist',
|
||||
},
|
||||
{
|
||||
name: 'ApplicationList.ApplicationListDetail',
|
||||
hideInMenu: true,
|
||||
path: '/ApplicationList/ApplicationListDetail',
|
||||
},
|
||||
{
|
||||
name: 'ApplicationList.CreateApplication',
|
||||
hideInMenu: true,
|
||||
path: '/ApplicationList/CreateApplication',
|
||||
},
|
||||
{
|
||||
name: 'Workload',
|
||||
path: '/Workload',
|
||||
routes: [
|
||||
...workloadList,
|
||||
{
|
||||
name: 'Detail',
|
||||
path: '/Workload/Detail',
|
||||
hideInMenu: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
path: '/Traits',
|
||||
name: 'Traits',
|
||||
routes: [
|
||||
...traitList,
|
||||
{
|
||||
name: 'Detail',
|
||||
path: '/Traits/Detail',
|
||||
hideInMenu: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Capability',
|
||||
path: '/Capability',
|
||||
key: 'Capability',
|
||||
},
|
||||
{
|
||||
path: '/System',
|
||||
name: 'System',
|
||||
routes: [
|
||||
{
|
||||
name: 'Env',
|
||||
path: '/System/Env',
|
||||
key: 'Env',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Capability.Detail',
|
||||
hideInMenu: true,
|
||||
path: '/Capability/Detail',
|
||||
},
|
||||
];
|
||||
return menuList;
|
||||
}
|
||||
|
||||
const TestModel = {
|
||||
namespace: 'menus',
|
||||
state: {
|
||||
menuData: [],
|
||||
},
|
||||
effects: {
|
||||
*getMenuData({ payload }, { call, put }) {
|
||||
const workloadList = yield call(getWorkload, payload);
|
||||
const traitList = yield call(getTraits, payload);
|
||||
const response = getMenuList(workloadList, traitList);
|
||||
yield put({
|
||||
type: 'saveMenuData',
|
||||
payload: response,
|
||||
});
|
||||
},
|
||||
},
|
||||
reducers: {
|
||||
saveMenuData(state, action) {
|
||||
return {
|
||||
...state,
|
||||
menuData: action.payload || [],
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
export default TestModel;
|
||||
@@ -1,27 +0,0 @@
|
||||
import defaultSettings from '../../config/defaultSettings';
|
||||
|
||||
const updateColorWeak = (colorWeak) => {
|
||||
const root = document.getElementById('root');
|
||||
|
||||
if (root) {
|
||||
root.className = colorWeak ? 'colorWeak' : '';
|
||||
}
|
||||
};
|
||||
|
||||
const SettingModel = {
|
||||
namespace: 'settings',
|
||||
state: defaultSettings,
|
||||
reducers: {
|
||||
changeSetting(state = defaultSettings, { payload }) {
|
||||
const { colorWeak, contentWidth } = payload;
|
||||
|
||||
if (state.contentWidth !== contentWidth && window.dispatchEvent) {
|
||||
window.dispatchEvent(new Event('resize'));
|
||||
}
|
||||
|
||||
updateColorWeak(!!colorWeak);
|
||||
return { ...state, ...payload };
|
||||
},
|
||||
},
|
||||
};
|
||||
export default SettingModel;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user