mirror of
https://github.com/zitadel/zitadel.git
synced 2025-01-06 09:57:38 +00:00
Merge remote-tracking branch 'origin/master' into new-eventstore
This commit is contained in:
commit
147782332f
16
.dockerignore
Normal file
16
.dockerignore
Normal file
@ -0,0 +1,16 @@
|
||||
.git
|
||||
.codecov
|
||||
.github
|
||||
build/dockerfile
|
||||
site
|
||||
console/node_modules
|
||||
console/src/app/proto/generated
|
||||
console/tmp
|
||||
.releaserc.js
|
||||
.typo-ci.yml
|
||||
CONTRIBUTING.md
|
||||
LICENSE
|
||||
README.md
|
||||
SECURITY.md
|
||||
pkg/grpc/*/*.pb.*
|
||||
pkg/grpc/*/*.swagger.json
|
2
.github/dependabot.yml
vendored
2
.github/dependabot.yml
vendored
@ -17,7 +17,7 @@ updates:
|
||||
prefix: chore
|
||||
include: scope
|
||||
- package-ecosystem: "docker"
|
||||
directory: "/build/docker"
|
||||
directory: "/build/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
open-pull-requests-limit: 10
|
||||
|
54
.github/scripts/githelper.sh
vendored
54
.github/scripts/githelper.sh
vendored
@ -1,54 +0,0 @@
|
||||
#!/bin/bash
|
||||
#debugger
|
||||
set -x
|
||||
|
||||
source ./.github/scripts/variables.env
|
||||
|
||||
############################
|
||||
function setup_git {
|
||||
############################
|
||||
echo "###############"
|
||||
echo "set git config"
|
||||
echo "###############"
|
||||
|
||||
git config --global user.email "$GIT_USER_MAIL"
|
||||
git config --global user.name "$GIT_USER_NAME"
|
||||
}
|
||||
|
||||
############################
|
||||
function checkout_project {
|
||||
############################
|
||||
echo "###############"
|
||||
echo "clone repository $GIT_URL"
|
||||
echo "###############"
|
||||
|
||||
# clone opsrepo
|
||||
git clone $GIT_URL $LOCAL_TMP_DIR/$GIT_OPSREPO
|
||||
}
|
||||
|
||||
############################
|
||||
function change_image_version {
|
||||
############################
|
||||
echo "###############"
|
||||
echo "checkout master"
|
||||
echo "###############"
|
||||
|
||||
cd $LOCAL_TMP_DIR/$GIT_OPSREPO/$GIT_OPSREPO_APPFOLDER/$GIT_OPSREPO_APPLICATION_NAME/overlay/$TARGET_ENVIRONMENT
|
||||
git checkout master
|
||||
git pull
|
||||
echo "###############"
|
||||
echo "change image version and commit"
|
||||
echo "###############"
|
||||
sed -i "s#image: $REGISTRY_IMAGE:.*#image: $REGISTRY_IMAGE:$CAOS_NEXT_VERSION#g" $GIT_OPSREPO_IMAGEFILE
|
||||
git add $GIT_OPSREPO_IMAGEFILE
|
||||
git commit --message "Github Workflow: $GITHUB_WORKFLOW"
|
||||
}
|
||||
|
||||
############################
|
||||
function upload_files {
|
||||
############################
|
||||
echo "###############"
|
||||
echo "git push"
|
||||
echo "###############"
|
||||
git push --quiet --set-upstream origin
|
||||
}
|
21
.github/scripts/variables.env
vendored
21
.github/scripts/variables.env
vendored
@ -1,21 +0,0 @@
|
||||
### local vars
|
||||
export LOCAL_TMP_DIR="/tmp"
|
||||
|
||||
### git settings for cloning operations repository
|
||||
export GIT_USER_MAIL="hi@caos.ch"
|
||||
export GIT_USER_NAME="zitadel-pipeline"
|
||||
|
||||
#path of opsrepository
|
||||
export GIT_URL="https://$GIT_OPSREPO_DEPLOYTOKEN@github.com/caos/zitadel-ops.git"
|
||||
export GIT_OPSREPO="citadel-ops"
|
||||
|
||||
### application settings
|
||||
export GIT_OPSREPO_APPFOLDER="k8s/workload"
|
||||
export GIT_OPSREPO_APPLICATION_NAME="zitadel"
|
||||
export GIT_OPSREPO_IMAGEFILE="imageversion.yaml"
|
||||
export REGISTRY_IMAGE="$REGISTRY/$GITHUB_REPOSITORY/$IMAGE"
|
||||
|
||||
### environment settings
|
||||
#export TARGET_ENVIRONMENT="dev"
|
||||
|
||||
|
39
.github/workflows/codecov.yml
vendored
Normal file
39
.github/workflows/codecov.yml
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
name: Code Coverage
|
||||
on: push
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
NODE_VERSION: '12'
|
||||
GO_VERSION: '1.15'
|
||||
|
||||
jobs:
|
||||
container:
|
||||
runs-on: ubuntu-18.04
|
||||
steps:
|
||||
- name: Source checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Cache Docker layers
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: /tmp/.buildx-cache
|
||||
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-buildx-
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
- uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
file: ./build/dockerfile
|
||||
platforms: linux/amd64
|
||||
tags: ${{ env.REGISTRY }}/${{ github.repository }}:coverage
|
||||
push: false
|
||||
cache-from: type=local,src=/tmp/.buildx-cache
|
||||
target: go-codecov
|
||||
outputs: type=local,dest=.
|
||||
- uses: codecov/codecov-action@v1
|
||||
with:
|
||||
file: ./profile.cov
|
||||
name: codecov-go
|
169
.github/workflows/release.yml
vendored
169
.github/workflows/release.yml
vendored
@ -8,128 +8,49 @@ env:
|
||||
GO_VERSION: '1.15'
|
||||
|
||||
jobs:
|
||||
|
||||
## Angular test, will be added later
|
||||
|
||||
angular-lint:
|
||||
container:
|
||||
runs-on: ubuntu-18.04
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./console
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install Protoc
|
||||
uses: arduino/setup-protoc@master
|
||||
with:
|
||||
version: '3.x'
|
||||
- run: wget -O protoc-gen-grpc-web https://github.com/grpc/grpc-web/releases/download/1.2.0/protoc-gen-grpc-web-1.2.0-linux-x86_64
|
||||
- run: sudo mv protoc-gen-grpc-web /usr/local/bin/protoc-gen-grpc-web
|
||||
- run: sudo chmod +x /usr/local/bin/protoc-gen-grpc-web
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
- run: npm ci
|
||||
- run: npm run lint
|
||||
|
||||
angular-build:
|
||||
runs-on: ubuntu-18.04
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./console
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install Protoc
|
||||
uses: arduino/setup-protoc@master
|
||||
with:
|
||||
version: '3.x'
|
||||
- run: wget -O protoc-gen-grpc-web https://github.com/grpc/grpc-web/releases/download/1.2.0/protoc-gen-grpc-web-1.2.0-linux-x86_64
|
||||
- run: sudo mv protoc-gen-grpc-web /usr/local/bin/protoc-gen-grpc-web
|
||||
- run: sudo chmod +x /usr/local/bin/protoc-gen-grpc-web
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
- run: npm ci
|
||||
- run: npm run prodbuild
|
||||
- uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: angular
|
||||
path: console/dist/console
|
||||
|
||||
go-test:
|
||||
runs-on: ubuntu-18.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-go@v2-beta
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
- run: go test -race -v -coverprofile=profile.cov ./...
|
||||
- uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: go-coverage
|
||||
path: profile.cov
|
||||
- uses: codecov/codecov-action@v1
|
||||
with:
|
||||
file: ./profile.cov
|
||||
name: codecov-go
|
||||
|
||||
## go lint, will be added later
|
||||
|
||||
go-build:
|
||||
runs-on: ubuntu-18.04
|
||||
needs: [angular-build, angular-lint, go-test] ### We need the artifact from the angular build and that's why we wait here
|
||||
name: Build ${{ matrix.goos }}-${{ matrix.goarch }}
|
||||
strategy:
|
||||
matrix:
|
||||
goos: [ 'linux', 'darwin', 'windows' ]
|
||||
goarch: ['amd64']
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-go@v2-beta
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
- uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: angular
|
||||
path: console/dist/console
|
||||
- run: go get github.com/rakyll/statik
|
||||
- run: ./build/console/generate-static.sh
|
||||
- run: cat internal/ui/console/statik/statik.go
|
||||
- run: ./build/login/generate-static.sh
|
||||
- run: cat internal/ui/login/statik/statik.go
|
||||
- run: ./build/notification/generate-static.sh
|
||||
- run: cat internal/notification/statik/statik.go
|
||||
- run: ./build/zitadel/generate-static.sh
|
||||
- run: cat internal/statik/statik.go
|
||||
- run: CGO_ENABLED=0 GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} go build -a -installsuffix cgo -ldflags '-extldflags "-static"' -o zitadel-${{ matrix.goos }}-${{ matrix.goarch }} cmd/zitadel/main.go
|
||||
- uses: actions/upload-artifact@v1
|
||||
with:
|
||||
name: zitadel-${{ matrix.goos }}-${{ matrix.goarch }}
|
||||
path: zitadel-${{ matrix.goos }}-${{ matrix.goarch }}
|
||||
|
||||
container-prod:
|
||||
runs-on: ubuntu-18.04
|
||||
needs: go-build
|
||||
steps:
|
||||
- name: Source checkout
|
||||
uses: actions/checkout@v2
|
||||
- uses: actions/download-artifact@v2
|
||||
- name: Set output
|
||||
id: branch
|
||||
run: echo ::set-output name=short_ref::${GITHUB_REF#refs/*/}
|
||||
- name: Check output
|
||||
run: echo ${{ steps.branch.outputs.short_ref }}
|
||||
- name: Generate Short SHA Container Tag
|
||||
id: vars
|
||||
run: echo "::set-output name=sha_short::SHA-$(git rev-parse --short HEAD)"
|
||||
- name: Cache Docker layers
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
name: zitadel-linux-amd64
|
||||
path: .artifacts
|
||||
- uses: docker/build-push-action@v1
|
||||
path: /tmp/.buildx-cache
|
||||
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-buildx-
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
dockerfile: build/docker/Dockerfile
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.CR_PAT }}
|
||||
registry: ${{ env.REGISTRY }}
|
||||
repository: ${{ github.repository }}
|
||||
tag_with_ref: true
|
||||
tag_with_sha: true
|
||||
- uses: docker/build-push-action@v2
|
||||
with:
|
||||
context: .
|
||||
file: ./build/dockerfile
|
||||
platforms: linux/amd64
|
||||
tags: ${{ env.REGISTRY }}/${{ github.repository }}:${{ steps.vars.outputs.sha_short }},${{ env.REGISTRY }}/${{ github.repository }}:${{ steps.branch.outputs.short_ref }}
|
||||
push: true
|
||||
cache-from: type=local,src=/tmp/.buildx-cache
|
||||
cache-to: type=local,mode=max,dest=/tmp/.buildx-cache
|
||||
|
||||
release:
|
||||
runs-on: ubuntu-18.04
|
||||
needs: [container-prod]
|
||||
needs: [container]
|
||||
env:
|
||||
DOCKER_USERNAME: ${{ github.actor }}
|
||||
DOCKER_PASSWORD: ${{ secrets.CR_PAT }}
|
||||
@ -139,32 +60,32 @@ jobs:
|
||||
- name: Generate Short SHA Container Tag
|
||||
id: vars
|
||||
run: echo "::set-output name=sha_short::SHA-$(git rev-parse --short HEAD)"
|
||||
- uses: actions/download-artifact@v2
|
||||
with:
|
||||
path: .artifacts
|
||||
- name: Display structure of downloaded files
|
||||
run: ls -R
|
||||
working-directory: .artifacts
|
||||
- name: Docker Login
|
||||
run: docker login $REGISTRY -u $GITHUB_ACTOR -p $GITHUB_TOKEN
|
||||
- name: Docker Pull short-sha
|
||||
run: docker pull $REGISTRY/$GITHUB_REPOSITORY:${{ steps.vars.outputs.sha_short }}
|
||||
- name: Semantic Release
|
||||
id: semantic
|
||||
uses: cycjimmy/semantic-release-action@v2
|
||||
with:
|
||||
dry_run: false
|
||||
semantic_version: 17.0.4
|
||||
extra_plugins: |
|
||||
@semantic-release/exec@5.0.0
|
||||
- name: Do something when a new release published
|
||||
if: steps.semantic.outputs.new_release_published == 'true'
|
||||
run: |
|
||||
echo ${{ steps.semantic.outputs.new_release_version }}
|
||||
echo ${{ steps.semantic.outputs.new_release_major_version }}
|
||||
echo ${{ steps.semantic.outputs.new_release_minor_version }}
|
||||
echo ${{ steps.semantic.outputs.new_release_patch_version }}
|
||||
- name: Docker Tag Version
|
||||
run: docker tag $REGISTRY/$GITHUB_REPOSITORY:${{ steps.vars.outputs.sha_short }} $REGISTRY/$GITHUB_REPOSITORY:$CAOS_NEXT_VERSION
|
||||
if: env.CAOS_NEXT_VERSION != ''
|
||||
run: docker tag $REGISTRY/$GITHUB_REPOSITORY:${{ steps.vars.outputs.sha_short }} $REGISTRY/$GITHUB_REPOSITORY:${{ steps.semantic.outputs.new_release_version }}
|
||||
if: steps.semantic.outputs.new_release_published == 'true'
|
||||
- name: Docker Tag Latest
|
||||
run: docker tag $REGISTRY/$GITHUB_REPOSITORY:${{ steps.vars.outputs.sha_short }} $REGISTRY/$GITHUB_REPOSITORY:latest
|
||||
if: env.CAOS_NEXT_VERSION != ''
|
||||
if: steps.semantic.outputs.new_release_published == 'true'
|
||||
- name: Docker Push Version
|
||||
run: docker push $REGISTRY/$GITHUB_REPOSITORY:$CAOS_NEXT_VERSION
|
||||
if: env.CAOS_NEXT_VERSION != ''
|
||||
run: docker push $REGISTRY/$GITHUB_REPOSITORY:${{ steps.semantic.outputs.new_release_version }}
|
||||
if: steps.semantic.outputs.new_release_published == 'true'
|
||||
- name: Docker Push Latest
|
||||
run: docker push $REGISTRY/$GITHUB_REPOSITORY:latest
|
||||
if: env.CAOS_NEXT_VERSION != ''
|
||||
if: steps.semantic.outputs.new_release_published == 'true'
|
||||
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -41,4 +41,7 @@ cmd/zitadel/zitadel
|
||||
|
||||
# buildfolders and generated js
|
||||
tmp/
|
||||
console/src/app/proto/generated/
|
||||
console/src/app/proto/generated/
|
||||
|
||||
pkg/grpc/*/*.pb.*
|
||||
pkg/grpc/*/*.swagger.json
|
@ -3,15 +3,6 @@ module.exports = {
|
||||
plugins: [
|
||||
"@semantic-release/commit-analyzer",
|
||||
"@semantic-release/release-notes-generator",
|
||||
["@semantic-release/github", {
|
||||
"assets": [
|
||||
{"path": ".artifacts/zitadel-darwin-amd64/zitadel-darwin-amd64", "label": "Darwin x86_64"},
|
||||
{"path": ".artifacts/zitadel-linux-amd64/zitadel-linux-amd64", "label": "Linux x86_64"},
|
||||
{"path": ".artifacts/zitadel-windows-amd64/zitadel-windows-amd64", "label": "Windows x86_64"}
|
||||
]
|
||||
}],
|
||||
["@semantic-release/exec", {
|
||||
"publishCmd": "echo '::set-env name=CAOS_NEXT_VERSION::${nextRelease.version}'"
|
||||
}],
|
||||
"@semantic-release/github"
|
||||
]
|
||||
};
|
||||
};
|
||||
|
@ -2,6 +2,10 @@
|
||||
|
||||
## **Did you find a bug?**
|
||||
|
||||
## **Want to contribute code?**
|
||||
|
||||
* Check out our [Dev Build Guide](build/README.md).
|
||||
|
||||
## **Did you find a security flaw?**
|
||||
|
||||
* Please read [Security Policy](SECURITY.md).
|
||||
|
@ -60,4 +60,3 @@ See the policy [here](./SECURITY.md)
|
||||
See the exact licensing terms [here](./LICENSE)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
|
||||
|
||||
|
60
build/README.md
Normal file
60
build/README.md
Normal file
@ -0,0 +1,60 @@
|
||||
|
||||
# Development
|
||||
|
||||
## Prerequisite
|
||||
|
||||
- Buildkit compatible docker installation
|
||||
|
||||
## Generate Proto Clients
|
||||
|
||||
### Angular
|
||||
|
||||
This command generates the grpc stub for angular into the folder console/src/app/proto/generated for local development
|
||||
|
||||
```Bash
|
||||
DOCKER_BUILDKIT=1 docker build -f build/dockerfile . -t zitadel:local --target npm-copy -o console/src/app/proto/generated
|
||||
```
|
||||
|
||||
### Go
|
||||
|
||||
With this command you can generate the stub for golang into the correct dir pkg/
|
||||
|
||||
```Bash
|
||||
DOCKER_BUILDKIT=1 docker build -f build/dockerfile . -t zitadel:local --target go-copy -o pkg
|
||||
```
|
||||
|
||||
## Run
|
||||
|
||||
### Run Angular
|
||||
|
||||
```Bash
|
||||
COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 docker-compose -f build/docker-compose-dev.yml up --build angular
|
||||
```
|
||||
|
||||
### Run Go
|
||||
|
||||
```Bash
|
||||
COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 docker-compose -f build/docker-compose-dev.yml up --build go
|
||||
```
|
||||
|
||||
### Fullstack including database
|
||||
|
||||
```Bash
|
||||
COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 docker-compose -f build/docker-compose.yml up --build
|
||||
```
|
||||
|
||||
## Debug
|
||||
|
||||
### Debug Go
|
||||
|
||||
```Bash
|
||||
COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 docker-compose -f build/docker-compose-debug.yml up --build go
|
||||
```
|
||||
|
||||
## Production Build
|
||||
|
||||
This can also be run locally!
|
||||
|
||||
```Bash
|
||||
DOCKER_BUILDKIT=1 docker build -f build/dockerfile . -t zitadel:local --build-arg ENV=prod
|
||||
```
|
@ -4,38 +4,24 @@ set -eux
|
||||
|
||||
GEN_PATH=src/app/proto/generated
|
||||
|
||||
echo "Remove old files"
|
||||
rm -rf $GEN_PATH
|
||||
|
||||
echo "Create folders"
|
||||
mkdir -p $GEN_PATH
|
||||
|
||||
targetcurl () {
|
||||
mkdir -p $1 && cd $1 && { curl -O $2; cd -; }
|
||||
}
|
||||
|
||||
echo "Download additional protofiles"
|
||||
targetcurl tmp/validate https://raw.githubusercontent.com/envoyproxy/protoc-gen-validate/v0.4.0/validate/validate.proto
|
||||
targetcurl tmp/protoc-gen-swagger/options https://raw.githubusercontent.com/grpc-ecosystem/grpc-gateway/v1.14.6/protoc-gen-swagger/options/annotations.proto
|
||||
targetcurl tmp/protoc-gen-swagger/options https://raw.githubusercontent.com/grpc-ecosystem/grpc-gateway/v1.14.6/protoc-gen-swagger/options/openapiv2.proto
|
||||
|
||||
echo "Generate grpc"
|
||||
|
||||
protoc \
|
||||
-I=/usr/local/include \
|
||||
-I=../pkg/grpc/message \
|
||||
-I=../pkg/grpc/management/proto \
|
||||
-I=../pkg/grpc/auth/proto \
|
||||
-I=../pkg/grpc/admin/proto \
|
||||
-I=../internal/protoc/protoc-gen-authoption \
|
||||
-I=.tmp/protos/message \
|
||||
-I=.tmp/protos/admin/proto \
|
||||
-I=.tmp/protos/management/proto \
|
||||
-I=.tmp/protos/auth/proto \
|
||||
-I=node_modules/google-proto-files \
|
||||
-I=tmp \
|
||||
-I=.tmp/protos \
|
||||
--js_out=import_style=commonjs,binary:$GEN_PATH \
|
||||
--grpc-web_out=import_style=commonjs+dts,mode=grpcweb:$GEN_PATH \
|
||||
../pkg/grpc/message/proto/*.proto \
|
||||
../pkg/grpc/management/proto/*.proto \
|
||||
../pkg/grpc/admin/proto/*.proto \
|
||||
../pkg/grpc/auth/proto/*.proto
|
||||
.tmp/protos/message/proto/*.proto \
|
||||
.tmp/protos/admin/proto/*.proto \
|
||||
.tmp/protos/auth/proto/*.proto \
|
||||
.tmp/protos/management/proto/*.proto
|
||||
|
||||
echo "Generate annotations js file (compatibility)"
|
||||
|
||||
|
30
build/docker-compose-debug.yml
Normal file
30
build/docker-compose-debug.yml
Normal file
@ -0,0 +1,30 @@
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
angular:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: build/dockerfile
|
||||
target: dev-angular-build
|
||||
args:
|
||||
ENV: dev
|
||||
command: sh -c "ng serve --host 0.0.0.0"
|
||||
ports:
|
||||
- 4200:4200
|
||||
go:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: build/dockerfile
|
||||
target: dev-go-build
|
||||
args:
|
||||
ENV: dev
|
||||
command: dlv --listen=:2345 --headless=true --log=true --log-output=debugger,debuglineerr,gdbwire,lldbout,rpc --accept-multiclient --api-version=2 debug cmd/zitadel/main.go
|
||||
ports:
|
||||
- 2345:2345
|
||||
- 50000:50000
|
||||
db:
|
||||
image: cockroachdb/cockroach:v20.2.0
|
||||
command: start-single-node --insecure
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 26257:26257
|
31
build/docker-compose-dev.yml
Normal file
31
build/docker-compose-dev.yml
Normal file
@ -0,0 +1,31 @@
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
angular:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: build/dockerfile
|
||||
target: dev-angular-build
|
||||
args:
|
||||
ENV: dev
|
||||
command: sh -c "ng serve --host 0.0.0.0"
|
||||
ports:
|
||||
- 4200:4200
|
||||
go:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: build/dockerfile
|
||||
target: dev-go-build
|
||||
args:
|
||||
ENV: dev
|
||||
command: go run cmd/zitadel/main.go
|
||||
ports:
|
||||
- 50000:50000
|
||||
db:
|
||||
image: cockroachdb/cockroach:v20.2.0
|
||||
command: start-single-node --insecure
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 26257:26257
|
||||
volumes:
|
||||
- "../cockroach-data/zitadel1:/cockroach/cockroach-data"
|
@ -1,5 +0,0 @@
|
||||
# Exclude system dirs
|
||||
|
||||
.dependabot
|
||||
.github
|
||||
.git
|
@ -1,14 +0,0 @@
|
||||
# This Stage prepares the user in the container and copies the files
|
||||
FROM alpine:latest as prepare
|
||||
RUN adduser -D zitadel
|
||||
COPY .artifacts/zitadel-linux-amd64 /zitadel
|
||||
COPY cmd/zitadel/*.yaml /
|
||||
RUN chmod a+x /zitadel
|
||||
|
||||
# This Stage is intended as production image
|
||||
FROM scratch as final
|
||||
COPY --from=prepare /etc/passwd /etc/passwd
|
||||
COPY --from=prepare / /
|
||||
USER zitadel
|
||||
HEALTHCHECK NONE
|
||||
ENTRYPOINT ["/zitadel"]
|
129
build/dockerfile
Normal file
129
build/dockerfile
Normal file
@ -0,0 +1,129 @@
|
||||
#######################
|
||||
## By default we build the prod enviroment
|
||||
ARG ENV=prod
|
||||
|
||||
#######################
|
||||
## This step downloads the protofiles, protoc and protoc-gen-grpc-web for later use
|
||||
#######################
|
||||
FROM alpine as base
|
||||
RUN apk add tar curl
|
||||
WORKDIR /.tmp
|
||||
RUN wget -O protoc https://github.com/protocolbuffers/protobuf/releases/download/v3.13.0/protoc-3.13.0-linux-x86_64.zip \
|
||||
&& unzip protoc \
|
||||
&& wget -O bin/protoc-gen-grpc-web https://github.com/grpc/grpc-web/releases/download/1.2.0/protoc-gen-grpc-web-1.2.0-linux-x86_64 \
|
||||
&& chmod +x bin/protoc-gen-grpc-web
|
||||
RUN curl https://raw.githubusercontent.com/envoyproxy/protoc-gen-validate/v0.4.0/validate/validate.proto --create-dirs -o validate/validate.proto \
|
||||
&& curl https://raw.githubusercontent.com/grpc-ecosystem/grpc-gateway/v1.14.6/protoc-gen-swagger/options/annotations.proto --create-dirs -o protoc-gen-swagger/options/annotations.proto \
|
||||
&& curl https://raw.githubusercontent.com/grpc-ecosystem/grpc-gateway/v1.14.6/protoc-gen-swagger/options/openapiv2.proto --create-dirs -o protoc-gen-swagger/options/openapiv2.proto \
|
||||
&& curl https://raw.githubusercontent.com/googleapis/googleapis/master/google/api/annotations.proto --create-dirs -o google/api/annotations.proto \
|
||||
&& curl https://raw.githubusercontent.com/googleapis/googleapis/master/google/api/http.proto --create-dirs -o google/api/http.proto \
|
||||
&& curl https://raw.githubusercontent.com/protocolbuffers/protobuf/master/src/google/protobuf/empty.proto --create-dirs -o google/protobuf/empty.proto \
|
||||
&& curl https://raw.githubusercontent.com/protocolbuffers/protobuf/master/src/google/protobuf/timestamp.proto --create-dirs -o google/protobuf/timestamp.proto \
|
||||
&& curl https://raw.githubusercontent.com/protocolbuffers/protobuf/master/src/google/protobuf/descriptor.proto --create-dirs -o google/protobuf/descriptor.proto \
|
||||
&& curl https://raw.githubusercontent.com/protocolbuffers/protobuf/master/src/google/protobuf/duration.proto --create-dirs -o google/protobuf/duration.proto \
|
||||
&& curl https://raw.githubusercontent.com/protocolbuffers/protobuf/master/src/google/protobuf/any.proto --create-dirs -o google/protobuf/any.proto \
|
||||
&& curl https://raw.githubusercontent.com/protocolbuffers/protobuf/master/src/google/protobuf/struct.proto --create-dirs -o google/protobuf/struct.proto
|
||||
|
||||
COPY pkg/grpc/admin/proto/admin.proto admin/proto/admin.proto
|
||||
COPY pkg/grpc/auth/proto/auth.proto auth/proto/auth.proto
|
||||
COPY pkg/grpc/management/proto/management.proto management/proto/management.proto
|
||||
COPY pkg/grpc/message/proto/message.proto message/proto/message.proto
|
||||
COPY internal/protoc/protoc-gen-authoption/authoption/options.proto authoption/options.proto
|
||||
|
||||
#######################
|
||||
## With this step we prepare all node_modules, this helps caching the build
|
||||
## Speed up this step by mounting your local node_modules directory
|
||||
#######################
|
||||
FROM node:12 as npm-base
|
||||
WORKDIR console
|
||||
COPY console/package.json console/package-lock.json ./
|
||||
RUN npm install \
|
||||
&& mkdir .tmp
|
||||
COPY console .
|
||||
COPY --from=base /.tmp/bin /usr/local/bin/
|
||||
COPY --from=base /.tmp .tmp/protos/
|
||||
COPY build/console build/console/
|
||||
RUN build/console/generate-grpc.sh
|
||||
|
||||
FROM scratch as npm-copy
|
||||
COPY --from=npm-base /console/src/app/proto/generated .
|
||||
|
||||
## anular dev build
|
||||
FROM npm-base as dev-angular-build
|
||||
RUN npm install -g @angular/cli
|
||||
|
||||
## anular prod build
|
||||
FROM npm-base as prod-angular-build
|
||||
RUN npm run prodbuild
|
||||
|
||||
#######################
|
||||
## Go base build
|
||||
## Speed up this step by mounting your local go mod pkg directory
|
||||
#######################
|
||||
FROM golang:1.15 as go-base
|
||||
WORKDIR src/github.com/caos/zitadel/
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
COPY --from=base /.tmp .tmp/protos/
|
||||
COPY --from=base /.tmp/bin /usr/local/bin/
|
||||
COPY internal/protoc/protoc-base internal/protoc/protoc-base/
|
||||
COPY internal/protoc/protoc-gen-authoption internal/protoc/protoc-gen-authoption/
|
||||
|
||||
RUN go install \
|
||||
github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway \
|
||||
github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger \
|
||||
github.com/golang/protobuf/protoc-gen-go \
|
||||
github.com/envoyproxy/protoc-gen-validate
|
||||
|
||||
RUN go get -u github.com/go-bindata/go-bindata/...
|
||||
|
||||
RUN go-bindata ./internal/protoc/protoc-gen-authoption/templates \
|
||||
&& go install ./internal/protoc/protoc-gen-authoption
|
||||
|
||||
COPY build/zitadel build/zitadel/
|
||||
RUN build/zitadel/generate-grpc.sh
|
||||
|
||||
FROM scratch as go-copy
|
||||
COPY --from=go-base /go/src/github.com/caos/zitadel/pkg/ .
|
||||
|
||||
## Go test
|
||||
FROM go-base as go-test
|
||||
COPY . .
|
||||
RUN go test -race -v -coverprofile=profile.cov ./...
|
||||
|
||||
## Go test
|
||||
FROM scratch as go-codecov
|
||||
COPY --from=go-test /go/src/github.com/caos/zitadel/profile.cov profile.cov
|
||||
|
||||
## Go prod build
|
||||
FROM go-test as prod-go-build
|
||||
COPY --from=prod-angular-build console/dist/console console/dist/console/
|
||||
RUN go get github.com/rakyll/statik \
|
||||
&& ./build/console/generate-static.sh \
|
||||
&& ./build/login/generate-static.sh \
|
||||
&& ./build/notification/generate-static.sh \
|
||||
&& ./build/zitadel/generate-static.sh
|
||||
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -installsuffix cgo -ldflags '-extldflags "-static"' -o zitadel-linux-amd64 cmd/zitadel/main.go
|
||||
|
||||
## Go dev build
|
||||
FROM go-base as dev-go-build
|
||||
RUN go get github.com/go-delve/delve/cmd/dlv
|
||||
|
||||
#######################
|
||||
## Final Production Image
|
||||
#######################
|
||||
FROM alpine:latest as artifact
|
||||
RUN adduser -D zitadel
|
||||
COPY cmd/zitadel/*.yaml /
|
||||
COPY --from=prod-go-build /go/src/github.com/caos/zitadel/zitadel-linux-amd64 /zitadel
|
||||
RUN chmod a+x zitadel
|
||||
RUN ls -la /
|
||||
|
||||
## Scratch Image
|
||||
FROM scratch as final
|
||||
COPY --from=artifact /etc/passwd /etc/passwd
|
||||
## TODO copy should be removed once the operator branch is merged
|
||||
COPY --from=artifact / /
|
||||
USER zitadel
|
||||
HEALTHCHECK NONE
|
||||
ENTRYPOINT ["/zitadel"]
|
65
build/zitadel/generate-grpc.sh
Executable file
65
build/zitadel/generate-grpc.sh
Executable file
@ -0,0 +1,65 @@
|
||||
#! /bin/sh
|
||||
|
||||
set -eux
|
||||
|
||||
echo "Generate grpc"
|
||||
|
||||
protoc \
|
||||
-I=.tmp/protos/message \
|
||||
-I=.tmp/protos/admin/proto \
|
||||
-I=.tmp/protos/management/proto \
|
||||
-I=.tmp/protos/auth/proto \
|
||||
-I=.tmp/protos \
|
||||
-I=${GOPATH}/src \
|
||||
--go_out=plugins=grpc:$GOPATH/src \
|
||||
.tmp/protos/message/proto/message.proto
|
||||
|
||||
protoc \
|
||||
-I=.tmp/protos/message \
|
||||
-I=.tmp/protos/admin/proto \
|
||||
-I=.tmp/protos/management/proto \
|
||||
-I=.tmp/protos/auth/proto \
|
||||
-I=.tmp/protos \
|
||||
-I=${GOPATH}/src \
|
||||
--go_out=plugins=grpc:$GOPATH/src \
|
||||
--grpc-gateway_out=logtostderr=true:$GOPATH/src \
|
||||
--swagger_out=logtostderr=true:. \
|
||||
--authoption_out=. \
|
||||
--validate_out=lang=go:${GOPATH}/src \
|
||||
.tmp/protos/admin/proto/admin.proto
|
||||
|
||||
mv admin* $GOPATH/src/github.com/caos/zitadel/pkg/grpc/admin/
|
||||
|
||||
protoc \
|
||||
-I=.tmp/protos/message \
|
||||
-I=.tmp/protos/admin/proto \
|
||||
-I=.tmp/protos/management/proto \
|
||||
-I=.tmp/protos/auth/proto \
|
||||
-I=.tmp/protos \
|
||||
-I=${GOPATH}/src \
|
||||
--go_out=plugins=grpc:$GOPATH/src \
|
||||
--grpc-gateway_out=logtostderr=true,allow_delete_body=true:${GOPATH}/src \
|
||||
--swagger_out=logtostderr=true,allow_delete_body=true:. \
|
||||
--authoption_out=. \
|
||||
--validate_out=lang=go:${GOPATH}/src \
|
||||
.tmp/protos/management/proto/management.proto
|
||||
|
||||
mv management* $GOPATH/src/github.com/caos/zitadel/pkg/grpc/management/
|
||||
|
||||
protoc \
|
||||
-I=.tmp/protos/message \
|
||||
-I=.tmp/protos/admin/proto \
|
||||
-I=.tmp/protos/management/proto \
|
||||
-I=.tmp/protos/auth/proto \
|
||||
-I=.tmp/protos \
|
||||
-I=${GOPATH}/src \
|
||||
--go_out=plugins=grpc:$GOPATH/src \
|
||||
--grpc-gateway_out=logtostderr=true:$GOPATH/src \
|
||||
--swagger_out=logtostderr=true:. \
|
||||
--authoption_out=. \
|
||||
--validate_out=lang=go:${GOPATH}/src \
|
||||
.tmp/protos/auth/proto/auth.proto
|
||||
|
||||
mv auth* $GOPATH/src/github.com/caos/zitadel/pkg/grpc/auth/
|
||||
|
||||
echo "done generating"
|
@ -54,8 +54,8 @@ SystemDefaults:
|
||||
PasswordCheck: 240h #10d
|
||||
ExternalLoginCheck: 240h #10d
|
||||
MfaInitSkip: 720h #30d
|
||||
MfaSoftwareCheck: 18h
|
||||
MfaHardwareCheck: 12h
|
||||
SecondFactorCheck: 18h
|
||||
MultiFactorCheck: 12h
|
||||
IamID: 'IAM'
|
||||
DomainVerification:
|
||||
VerificationKey:
|
||||
|
@ -50,7 +50,6 @@
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
"sourceMap": false,
|
||||
"extractCss": true,
|
||||
"namedChunks": false,
|
||||
"extractLicenses": true,
|
||||
"vendorChunk": false,
|
||||
|
3265
console/package-lock.json
generated
3265
console/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -6,29 +6,29 @@
|
||||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"prodbuild": "ng build --prod",
|
||||
"lint": "ng lint && stylelint './src/**/*.scss' --syntax scss",
|
||||
"postinstall": "../build/console/generate-grpc.sh"
|
||||
"lint": "ng lint && stylelint './src/**/*.scss' --syntax scss"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@angular/animations": "~10.0.11",
|
||||
"@angular/cdk": "~10.1.3",
|
||||
"@angular/common": "~10.0.11",
|
||||
"@angular/compiler": "~10.0.11",
|
||||
"@angular/core": "~10.0.11",
|
||||
"@angular/forms": "~10.0.11",
|
||||
"@angular/material": "^10.1.3",
|
||||
"@angular/platform-browser": "~10.0.11",
|
||||
"@angular/platform-browser-dynamic": "~10.0.11",
|
||||
"@angular/router": "~10.0.11",
|
||||
"@angular/service-worker": "~10.0.11",
|
||||
"@angular/animations": "~11.0.0",
|
||||
"@angular/cdk": "~11.0.0",
|
||||
"@angular/common": "~11.0.0",
|
||||
"@angular/compiler": "~11.0.0",
|
||||
"@angular/core": "~11.0.0",
|
||||
"@angular/forms": "~11.0.0",
|
||||
"@angular/material": "^11.0.0",
|
||||
"@angular/material-moment-adapter": "^11.0.0",
|
||||
"@angular/platform-browser": "~11.0.0",
|
||||
"@angular/platform-browser-dynamic": "~11.0.0",
|
||||
"@angular/router": "~11.0.0",
|
||||
"@angular/service-worker": "~11.0.0",
|
||||
"@ngx-translate/core": "^13.0.0",
|
||||
"@ngx-translate/http-loader": "^6.0.0",
|
||||
"@types/file-saver": "^2.0.1",
|
||||
"@types/google-protobuf": "^3.7.4",
|
||||
"@types/uuid": "^8.3.0",
|
||||
"@types/google-protobuf": "^3.7.3",
|
||||
"angularx-qrcode": "^10.0.11",
|
||||
"angular-oauth2-oidc": "^10.0.3",
|
||||
"angularx-qrcode": "^10.0.11",
|
||||
"cors": "^2.8.5",
|
||||
"file-saver": "^2.0.2",
|
||||
"google-proto-files": "^2.2.0",
|
||||
@ -36,29 +36,28 @@
|
||||
"grpc": "^1.24.3",
|
||||
"grpc-web": "^1.2.1",
|
||||
"moment": "^2.29.1",
|
||||
"ngx-moment": "^5.0.0",
|
||||
"ngx-quicklink": "^0.2.4",
|
||||
"ngx-quicklink": "^0.2.6",
|
||||
"rxjs": "~6.6.3",
|
||||
"ts-protoc-gen": "^0.13.0",
|
||||
"tslib": "^2.0.3",
|
||||
"tslib": "^2.0.0",
|
||||
"uuid": "^8.3.1",
|
||||
"zone.js": "~0.11.2"
|
||||
"zone.js": "~0.11.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "~0.1002.0",
|
||||
"@angular/cli": "~10.2.0",
|
||||
"@angular/compiler-cli": "~10.0.11",
|
||||
"@angular-devkit/build-angular": "~0.1100.1",
|
||||
"@angular/cli": "~11.0.1",
|
||||
"@angular/compiler-cli": "~11.0.0",
|
||||
"@angular/language-service": "~11.0.0",
|
||||
"@types/jasmine": "~3.6.0",
|
||||
"@angular/language-service": "~10.2.0",
|
||||
"@types/jasminewd2": "~2.0.3",
|
||||
"@types/node": "^14.14.3",
|
||||
"codelyzer": "^6.0.1",
|
||||
"@types/node": "^14.14.6",
|
||||
"codelyzer": "^6.0.0",
|
||||
"jasmine-core": "~3.6.0",
|
||||
"jasmine-spec-reporter": "~6.0.0",
|
||||
"jasmine-spec-reporter": "~5.0.0",
|
||||
"karma": "~5.2.3",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-coverage-istanbul-reporter": "~3.0.2",
|
||||
"karma-jasmine": "~4.0.1",
|
||||
"karma-jasmine": "~4.0.0",
|
||||
"karma-jasmine-html-reporter": "^1.5.0",
|
||||
"prettier": "^2.1.2",
|
||||
"protractor": "~7.0.0",
|
||||
@ -67,6 +66,6 @@
|
||||
"stylelint-scss": "^3.18.0",
|
||||
"ts-node": "~9.0.0",
|
||||
"tslint": "~6.1.3",
|
||||
"typescript": "^3.9.7"
|
||||
"typescript": "^4.0.5"
|
||||
}
|
||||
}
|
||||
|
@ -131,6 +131,7 @@ const routes: Routes = [
|
||||
routes,
|
||||
{
|
||||
preloadingStrategy: QuicklinkStrategy,
|
||||
relativeLinkResolution: 'legacy',
|
||||
},
|
||||
),
|
||||
],
|
||||
|
@ -29,10 +29,12 @@
|
||||
placeholder="{{'ORG.PAGES.FILTERPLACEHOLDER' | translate}}" #input>
|
||||
</mat-form-field>
|
||||
|
||||
<button [ngClass]="{'active': temporg.id === org?.id}" [disabled]="!temporg.id"
|
||||
*ngFor="let temporg of orgs$ | async" mat-menu-item (click)="setActiveOrg(temporg)">
|
||||
{{temporg?.name ? temporg.name : 'NO NAME'}}
|
||||
</button>
|
||||
<div class="org-wrapper">
|
||||
<button [ngClass]="{'active': temporg.id === org?.id}" [disabled]="!temporg.id"
|
||||
*ngFor="let temporg of orgs$ | async" mat-menu-item (click)="setActiveOrg(temporg)">
|
||||
{{temporg?.name ? temporg.name : 'NO NAME'}}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<button class="show-all" mat-menu-item
|
||||
[routerLink]="[ '/org/overview' ]">{{'MENU.SHOWORGS' | translate}}</button>
|
||||
@ -70,8 +72,10 @@
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="iamuser$ | async">
|
||||
<div class="divider">
|
||||
<div @navitem class="divider">
|
||||
<div class="line"></div>
|
||||
<span>{{'MENU.ADMINSECTION' | translate}}</span>
|
||||
<div class="hiddenline"></div>
|
||||
</div>
|
||||
<a @navitem class="nav-item" [routerLinkActive]="['active']" [routerLink]="[ '/iam']">
|
||||
<i class="icon las la-gem"></i>
|
||||
@ -92,7 +96,7 @@
|
||||
<div @navitem class="divider">
|
||||
<div class="line"></div>
|
||||
<span>{{'MENU.PROJECTSSECTION' | translate}}</span>
|
||||
<div class="line"></div>
|
||||
<div class="hiddenline"></div>
|
||||
</div>
|
||||
|
||||
<a @navitem class="nav-item" [routerLinkActive]="['active']"
|
||||
@ -102,17 +106,19 @@
|
||||
<div class="c_label">
|
||||
<span>{{org?.name ? org.name : 'MENU.ORGANIZATION' | translate}}
|
||||
{{'MENU.PROJECT' | translate}} </span>
|
||||
<span *ngIf="ownedProjectsCount as ownedPCount"
|
||||
class="count">{{ownedPCount}}</span>
|
||||
<span *ngIf="(mgmtService?.ownedProjectsCount | async)"
|
||||
class="count">{{mgmtService?.ownedProjectsCount | async}}</span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a @navitem *ngIf="grantedProjectsCount as grantPCount" class="nav-item"
|
||||
[routerLinkActive]="['active']" [routerLink]="[ '/granted-projects']">
|
||||
<a @navitem
|
||||
*ngIf="mgmtService?.grantedProjectsCount && (mgmtService?.grantedProjectsCount | async)"
|
||||
class="nav-item" [routerLinkActive]="['active']"
|
||||
[routerLink]="[ '/granted-projects']">
|
||||
<i class="icon las la-layer-group"></i>
|
||||
<div class="c_label">
|
||||
<span>{{ 'MENU.GRANTEDPROJECT' | translate }}</span>
|
||||
<span class="count">{{grantPCount}}</span>
|
||||
<span class="count">{{mgmtService?.grantedProjectsCount | async}}</span>
|
||||
</div>
|
||||
</a>
|
||||
</ng-template>
|
||||
@ -122,7 +128,7 @@
|
||||
<div class="line"></div>
|
||||
<span class="label">
|
||||
{{ 'MENU.USERSECTION' | translate }}</span>
|
||||
<div class="line"></div>
|
||||
<div class="hiddenline"></div>
|
||||
</div>
|
||||
|
||||
<a @navitem class="nav-item" [routerLinkActive]="['active']"
|
||||
@ -144,7 +150,7 @@
|
||||
<div class="line"></div>
|
||||
<span class="label">
|
||||
{{ 'MENU.GRANTSECTION' | translate }}</span>
|
||||
<div class="line"></div>
|
||||
<div class="hiddenline"></div>
|
||||
</div>
|
||||
|
||||
<a @navitem class="nav-item" [routerLinkActive]="['active']" [routerLink]="[ '/grants']"
|
||||
@ -161,13 +167,18 @@
|
||||
</div>
|
||||
</mat-drawer>
|
||||
<mat-drawer-content class="content">
|
||||
<div @toolbar *ngIf="iamuser$ | async" class="admin-line" matTooltip="IAM Administrator">
|
||||
<span>{{'MENU.IAMADMIN' | translate}}</span>
|
||||
</div>
|
||||
<div class="router" [@routeAnimations]="prepareRoute(outlet)">
|
||||
<router-outlet #outlet="outlet"></router-outlet>
|
||||
</div>
|
||||
</mat-drawer-content>
|
||||
</mat-drawer-container>
|
||||
<div @toolbar *ngIf="iamuser$ | async" class="admin-line" [ngClass]="{'expanded': !hideAdminWarn}"
|
||||
matTooltip="IAM Administrator">
|
||||
<button [matTooltip]="!hideAdminWarn ? 'Unpin': 'Pin'" (click)="toggleAdminHide()" mat-icon-button>
|
||||
<mat-icon *ngIf="!hideAdminWarn" svgIcon="mdi_pin"></mat-icon>
|
||||
<mat-icon *ngIf="hideAdminWarn" svgIcon="mdi_pin_outline"></mat-icon>
|
||||
</button>
|
||||
<span>{{'MENU.IAMADMIN' | translate}}</span>
|
||||
</div>
|
||||
</ng-container>
|
||||
</ng-container>
|
@ -66,13 +66,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
.admin-line {
|
||||
font-size: 12px;
|
||||
padding: 4px 2rem;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.main-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -222,6 +215,13 @@
|
||||
margin: .5rem 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.hiddenline {
|
||||
display: block;
|
||||
visibility: hidden;
|
||||
// flex: 1;
|
||||
width: 4rem;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin textvar($theme) {
|
||||
@ -255,3 +255,8 @@
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
.org-wrapper {
|
||||
max-height: 350px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { async, TestBed } from '@angular/core/testing';
|
||||
import { TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
describe('AppComponent', () => {
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [RouterTestingModule],
|
||||
declarations: [AppComponent],
|
||||
|
@ -23,7 +23,6 @@ import { AuthenticationService } from './services/authentication.service';
|
||||
import { GrpcAuthService } from './services/grpc-auth.service';
|
||||
import { ManagementService } from './services/mgmt.service';
|
||||
import { ThemeService } from './services/theme.service';
|
||||
import { ToastService } from './services/toast.service';
|
||||
import { UpdateService } from './services/update.service';
|
||||
|
||||
@Component({
|
||||
@ -57,13 +56,11 @@ export class AppComponent implements OnDestroy {
|
||||
|
||||
public showProjectSection: boolean = false;
|
||||
|
||||
public grantedProjectsCount: number = 0;
|
||||
public ownedProjectsCount: number = 0;
|
||||
|
||||
public filterControl: FormControl = new FormControl('');
|
||||
private authSub: Subscription = new Subscription();
|
||||
private orgSub: Subscription = new Subscription();
|
||||
|
||||
public hideAdminWarn: boolean = true;
|
||||
constructor(
|
||||
public viewPortScroller: ViewportScroller,
|
||||
@Inject('windowObject') public window: Window,
|
||||
@ -73,15 +70,14 @@ export class AppComponent implements OnDestroy {
|
||||
private breakpointObserver: BreakpointObserver,
|
||||
public overlayContainer: OverlayContainer,
|
||||
private themeService: ThemeService,
|
||||
private mgmtService: ManagementService,
|
||||
public mgmtService: ManagementService,
|
||||
public matIconRegistry: MatIconRegistry,
|
||||
public domSanitizer: DomSanitizer,
|
||||
private toast: ToastService,
|
||||
private router: Router,
|
||||
update: UpdateService,
|
||||
@Inject(DOCUMENT) private document: Document,
|
||||
) {
|
||||
console.log('%cWait!', 'text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black; color: #5282c1; font-size: 50px');
|
||||
console.log('%cWait!', 'text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black; color: #5469D4; font-size: 50px');
|
||||
console.log('%cInserting something here could give attackers access to your zitadel account.', 'color: red; font-size: 18px');
|
||||
console.log('%cIf you don\'t know exactly what you\'re doing, close the window and stay on the safe side', 'font-size: 16px');
|
||||
console.log('%cIf you know exactly what you are doing, you should work for us', 'font-size: 16px');
|
||||
@ -179,6 +175,8 @@ export class AppComponent implements OnDestroy {
|
||||
value.trim().toLowerCase(),
|
||||
);
|
||||
});
|
||||
|
||||
this.hideAdminWarn = localStorage.getItem('hideAdministratorWarning') === 'true' ? true : false;
|
||||
}
|
||||
|
||||
public ngOnDestroy(): void {
|
||||
@ -186,6 +184,11 @@ export class AppComponent implements OnDestroy {
|
||||
this.orgSub.unsubscribe();
|
||||
}
|
||||
|
||||
public toggleAdminHide(): void {
|
||||
this.hideAdminWarn = !this.hideAdminWarn;
|
||||
localStorage.setItem('hideAdministratorWarning', this.hideAdminWarn.toString());
|
||||
}
|
||||
|
||||
public loadOrgs(filter?: string): void {
|
||||
let query;
|
||||
if (filter) {
|
||||
@ -249,13 +252,9 @@ export class AppComponent implements OnDestroy {
|
||||
private getProjectCount(): void {
|
||||
this.authService.isAllowed(['project.read$']).subscribe((allowed) => {
|
||||
if (allowed) {
|
||||
this.mgmtService.SearchProjects(0, 0).then(res => {
|
||||
this.ownedProjectsCount = res.toObject().totalResult;
|
||||
});
|
||||
this.mgmtService.SearchProjects(0, 0);
|
||||
|
||||
this.mgmtService.SearchGrantedProjects(0, 0).then(res => {
|
||||
this.grantedProjectsCount = res.toObject().totalResult;
|
||||
});
|
||||
this.mgmtService.SearchGrantedProjects(0, 0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { AccountsCardComponent } from './accounts-card.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('AccountsCardComponent', () => {
|
||||
let component: AccountsCardComponent;
|
||||
let fixture: ComponentFixture<AccountsCardComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [AccountsCardComponent],
|
||||
}).compileComponents();
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { MemberCreateDialogComponent } from './member-create-dialog.component';
|
||||
|
||||
@ -7,7 +7,7 @@ describe('AddMemberDialogComponent', () => {
|
||||
let component: MemberCreateDialogComponent;
|
||||
let fixture: ComponentFixture<MemberCreateDialogComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [MemberCreateDialogComponent],
|
||||
})
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { AvatarComponent } from './avatar.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('AvatarComponent', () => {
|
||||
let component: AvatarComponent;
|
||||
let fixture: ComponentFixture<AvatarComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [AvatarComponent],
|
||||
})
|
||||
|
@ -4,6 +4,7 @@
|
||||
padding: 1.5rem;
|
||||
border-radius: .5rem;
|
||||
padding-top: 1rem;
|
||||
min-width: 350px;
|
||||
|
||||
.header {
|
||||
margin-top: 0;
|
||||
@ -42,5 +43,6 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { CardComponent } from './card.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('CardComponent', () => {
|
||||
let component: CardComponent;
|
||||
let fixture: ComponentFixture<CardComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [CardComponent],
|
||||
})
|
||||
|
@ -16,6 +16,7 @@
|
||||
box-sizing: border-box;
|
||||
border-radius: .5rem;
|
||||
outline: none;
|
||||
height: 100%;
|
||||
|
||||
.selection-icon {
|
||||
opacity: 0;
|
||||
|
@ -5,6 +5,7 @@
|
||||
margin-bottom: 1rem;
|
||||
font-weight: 400;
|
||||
margin-top: 1rem;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
@mixin changes-theme($theme) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { ChangesComponent } from './changes.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('ChangesComponent', () => {
|
||||
let component: ChangesComponent;
|
||||
let fixture: ComponentFixture<ChangesComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ChangesComponent],
|
||||
})
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { ContributorsComponent } from './contributors.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('ContributorsComponent', () => {
|
||||
let component: ContributorsComponent;
|
||||
let fixture: ComponentFixture<ContributorsComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ContributorsComponent],
|
||||
})
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { DetailLayoutComponent } from './detail-layout.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('DetailLayoutComponent', () => {
|
||||
let component: DetailLayoutComponent;
|
||||
let fixture: ComponentFixture<DetailLayoutComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [DetailLayoutComponent],
|
||||
})
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { IdpCreateComponent } from './idp-create.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('IdpCreateComponent', () => {
|
||||
let component: IdpCreateComponent;
|
||||
let fixture: ComponentFixture<IdpCreateComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [IdpCreateComponent],
|
||||
})
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { IdpTableComponent } from './idp-table.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('UserTableComponent', () => {
|
||||
let component: IdpTableComponent;
|
||||
let fixture: ComponentFixture<IdpTableComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [IdpTableComponent],
|
||||
})
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { IdpComponent } from './idp.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('IdComponent', () => {
|
||||
let component: IdpComponent;
|
||||
let fixture: ComponentFixture<IdpComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [IdpComponent],
|
||||
})
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { MatPaginatorModule } from '@angular/material/paginator';
|
||||
import { MatSortModule } from '@angular/material/sort';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
@ -10,7 +10,7 @@ describe('MembersTableComponent', () => {
|
||||
let component: MembersTableComponent;
|
||||
let fixture: ComponentFixture<MembersTableComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [MembersTableComponent],
|
||||
imports: [
|
||||
|
@ -8,6 +8,7 @@
|
||||
display: relative;
|
||||
width: 100%;
|
||||
overflow-y: auto;
|
||||
padding-bottom: 50px;
|
||||
|
||||
&.hidden {
|
||||
flex-basis: 100%;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { MetaLayoutComponent } from './meta-layout.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('MetaLayoutComponent', () => {
|
||||
let component: MetaLayoutComponent;
|
||||
let fixture: ComponentFixture<MetaLayoutComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [MetaLayoutComponent],
|
||||
})
|
||||
|
@ -7,17 +7,10 @@
|
||||
$primary-dark: mat-color($primary, A800);
|
||||
/* stylelint-enable */
|
||||
|
||||
$lighter-color: rgba(mat-color($primary, 300), .5);
|
||||
|
||||
.meta-wrapper {
|
||||
.meta {
|
||||
position: relative;
|
||||
flex: 1 0 300px;
|
||||
background: linear-gradient(to bottom right, rgba($lighter-color, .05) 20%, transparent 50%);
|
||||
|
||||
&.hidden {
|
||||
background: linear-gradient(to bottom right, rgba($lighter-color, .05), transparent 50%);
|
||||
}
|
||||
|
||||
&::after {
|
||||
border-left: 2px solid $primary-color;
|
||||
@ -27,7 +20,7 @@
|
||||
left top,
|
||||
left bottom,
|
||||
from($primary-color),
|
||||
to($primary-dark),
|
||||
to(rgb(0, 0, 0, .5)),
|
||||
color-stop(
|
||||
01,
|
||||
$primary-dark
|
||||
@ -39,7 +32,7 @@
|
||||
left top,
|
||||
left bottom,
|
||||
from($primary-color),
|
||||
to($primary-dark),
|
||||
to(rgb(0, 0, 0, .5)),
|
||||
color-stop(
|
||||
01,
|
||||
$primary-dark
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { PasswordComplexityViewComponent } from './password-complexity-view.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('PasswordComplexityViewComponent', () => {
|
||||
let component: PasswordComplexityViewComponent;
|
||||
let fixture: ComponentFixture<PasswordComplexityViewComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [PasswordComplexityViewComponent],
|
||||
})
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { LabelPolicyComponent } from './label-policy.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('LabelPolicyComponent', () => {
|
||||
let component: LabelPolicyComponent;
|
||||
let fixture: ComponentFixture<LabelPolicyComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [LabelPolicyComponent],
|
||||
})
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { AddIdpDialogComponent } from './add-idp-dialog.component';
|
||||
|
||||
@ -7,7 +7,7 @@ describe('AddIdpDialogComponent', () => {
|
||||
let component: AddIdpDialogComponent;
|
||||
let fixture: ComponentFixture<AddIdpDialogComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [AddIdpDialogComponent],
|
||||
})
|
||||
|
@ -1,5 +1,5 @@
|
||||
.default {
|
||||
color: #5282c1;
|
||||
color: var(--color-main);
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { LoginPolicyComponent } from './login-policy.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('LoginPolicyComponent', () => {
|
||||
let component: LoginPolicyComponent;
|
||||
let fixture: ComponentFixture<LoginPolicyComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [LoginPolicyComponent],
|
||||
})
|
||||
|
@ -1,5 +1,5 @@
|
||||
.default {
|
||||
color: #5282c1;
|
||||
color: var(--color-main);
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { OrgIamPolicyComponent } from './org-iam-policy.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('OrgIamPolicyComponent', () => {
|
||||
let component: OrgIamPolicyComponent;
|
||||
let fixture: ComponentFixture<OrgIamPolicyComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [OrgIamPolicyComponent],
|
||||
})
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { PasswordAgePolicyComponent } from './password-age-policy.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('PasswordAgePolicyComponent', () => {
|
||||
let component: PasswordAgePolicyComponent;
|
||||
let fixture: ComponentFixture<PasswordAgePolicyComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [PasswordAgePolicyComponent],
|
||||
})
|
||||
|
@ -1,5 +1,5 @@
|
||||
.default {
|
||||
color: #5282c1;
|
||||
color: var(--color-main);
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { PasswordComplexityPolicyComponent } from './password-complexity-policy.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('PasswordComplexityPolicyComponent', () => {
|
||||
let component: PasswordComplexityPolicyComponent;
|
||||
let fixture: ComponentFixture<PasswordComplexityPolicyComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [PasswordComplexityPolicyComponent],
|
||||
})
|
||||
|
@ -1,5 +1,5 @@
|
||||
.default {
|
||||
color: #5282c1;
|
||||
color: var(--color-main);
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { PasswordLockoutPolicyComponent } from './password-lockout-policy.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('PasswordLockoutPolicyComponent', () => {
|
||||
let component: PasswordLockoutPolicyComponent;
|
||||
let fixture: ComponentFixture<PasswordLockoutPolicyComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [PasswordLockoutPolicyComponent],
|
||||
})
|
||||
|
@ -16,8 +16,9 @@ h1 {
|
||||
margin: .5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 200px;
|
||||
min-height: 250px;
|
||||
padding: 1rem;
|
||||
height: 100%;
|
||||
|
||||
@media only screen and (max-width: 450px) {
|
||||
flex-basis: 100%;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { PolicyGridComponent } from './policy-grid.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('PolicyGridComponent', () => {
|
||||
let component: PolicyGridComponent;
|
||||
let fixture: ComponentFixture<PolicyGridComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [PolicyGridComponent],
|
||||
})
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { MatPaginatorModule } from '@angular/material/paginator';
|
||||
import { MatSortModule } from '@angular/material/sort';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
@ -10,7 +10,7 @@ describe('ProjectMembersComponent', () => {
|
||||
let component: ProjectMembersComponent;
|
||||
let fixture: ComponentFixture<ProjectMembersComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ProjectMembersComponent],
|
||||
imports: [
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { ProjectRoleDetailComponent } from './project-role-detail.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('ProjectRoleDetailComponent', () => {
|
||||
let component: ProjectRoleDetailComponent;
|
||||
let fixture: ComponentFixture<ProjectRoleDetailComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ProjectRoleDetailComponent],
|
||||
})
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { MatPaginatorModule } from '@angular/material/paginator';
|
||||
import { MatSortModule } from '@angular/material/sort';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
@ -10,7 +10,7 @@ describe('ProjectRolesComponent', () => {
|
||||
let component: ProjectRolesComponent;
|
||||
let fixture: ComponentFixture<ProjectRolesComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ProjectRolesComponent],
|
||||
imports: [
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { RefreshTableComponent } from './refresh-table.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('RefreshTableComponent', () => {
|
||||
let component: RefreshTableComponent;
|
||||
let fixture: ComponentFixture<RefreshTableComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [RefreshTableComponent],
|
||||
})
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { SearchProjectAutocompleteComponent } from './search-project-autocomplete.component';
|
||||
|
||||
@ -7,7 +7,7 @@ describe('SearchProjectComponent', () => {
|
||||
let component: SearchProjectAutocompleteComponent;
|
||||
let fixture: ComponentFixture<SearchProjectAutocompleteComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [SearchProjectAutocompleteComponent],
|
||||
})
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { SearchRolesAutocompleteComponent } from './search-roles-autocomplete.component';
|
||||
|
||||
@ -8,7 +8,7 @@ describe('SearchProjectComponent', () => {
|
||||
let component: SearchRolesAutocompleteComponent;
|
||||
let fixture: ComponentFixture<SearchRolesAutocompleteComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [SearchRolesAutocompleteComponent],
|
||||
})
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { SearchUserAutocompleteComponent } from './search-user-autocomplete.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('SearchUserAutocompleteComponent', () => {
|
||||
let component: SearchUserAutocompleteComponent;
|
||||
let fixture: ComponentFixture<SearchUserAutocompleteComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [SearchUserAutocompleteComponent],
|
||||
})
|
||||
|
@ -103,7 +103,7 @@ export class UserGrantsDataSource extends DataSource<UserGrant.AsObject> {
|
||||
break;
|
||||
default:
|
||||
this.loadingSubject.next(true);
|
||||
const promise3 = this.userService.SearchUserGrants(pageSize, pageSize * pageIndex, []);
|
||||
const promise3 = this.userService.SearchUserGrants(pageSize, pageSize * pageIndex, queries ?? []);
|
||||
this.loadResponse(promise3);
|
||||
break;
|
||||
}
|
||||
|
@ -1,6 +1,12 @@
|
||||
<app-refresh-table [loading]="dataSource?.loading$ | async" (refreshed)="changePage()"
|
||||
[emitRefreshOnPreviousRoutes]="refreshOnPreviousRoutes" [timestamp]="dataSource?.viewTimestamp"
|
||||
[dataSize]="dataSource?.totalResult" [selection]="selection">
|
||||
<mat-form-field @appearfade *ngIf="userGrantSearchKey != undefined" actions class="filtername">
|
||||
<mat-label>{{'USER.PAGES.FILTER' | translate}}</mat-label>
|
||||
<input matInput (keyup)="applyFilter($event)"
|
||||
[placeholder]="('USER.TABLE.FILTER.' + userGrantSearchKey.toString()) | translate" #input>
|
||||
</mat-form-field>
|
||||
|
||||
<button color="warn" matTooltip="{{'GRANTS.DELETE' | translate}}" class="icon-button" mat-icon-button actions
|
||||
(click)="deleteGrantSelection()" *ngIf="selection.hasValue() && disableDelete == false">
|
||||
<i class="las la-trash"></i>
|
||||
@ -33,19 +39,28 @@
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="user">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'PROJECT.GRANT.USER' | translate }} </th>
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'PROJECT.GRANT.USER' | translate }}
|
||||
<template [ngTemplateOutlet]="templateRef"
|
||||
[ngTemplateOutletContext]="{key: UserGrantSearchKey.USERGRANTSEARCHKEY_DISPLAY_NAME}"></template>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let grant">
|
||||
{{grant?.displayName}}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="org">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'PROJECT.GRANT.GRANTEDORGDOMAIN' | translate }} </th>
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'PROJECT.GRANT.GRANTEDORGDOMAIN' | translate }}
|
||||
<template [ngTemplateOutlet]="templateRef"
|
||||
[ngTemplateOutletContext]="{key: UserGrantSearchKey.USERGRANTSEARCHKEY_ORG_NAME}"></template>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let grant">
|
||||
{{grant.orgName}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="projectId">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'PROJECT.GRANT.PROJECTNAME' | translate }} </th>
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'PROJECT.GRANT.PROJECTNAME' | translate }}
|
||||
<template [ngTemplateOutlet]="templateRef"
|
||||
[ngTemplateOutletContext]="{key: UserGrantSearchKey.USERGRANTSEARCHKEY_PROJECT_NAME}"></template>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let grant">
|
||||
{{grant.projectName}} </td>
|
||||
</ng-container>
|
||||
@ -63,29 +78,32 @@
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="roleNamesList">
|
||||
<th mat-header-cell *matHeaderCellDef> {{ 'PROJECT.GRANT.ROLENAMESLIST' | translate }} </th>
|
||||
<th mat-header-cell *matHeaderCellDef>
|
||||
{{ 'PROJECT.GRANT.ROLENAMESLIST' | translate }}
|
||||
<template [ngTemplateOutlet]="templateRef"
|
||||
[ngTemplateOutletContext]="{key: UserGrantSearchKey.USERGRANTSEARCHKEY_ROLE_KEY}"></template>
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let grant; let i = index">
|
||||
<ng-container *ngIf="context === UserGrantContext.USER || context === UserGrantContext.NONE">
|
||||
<ng-container
|
||||
*ngIf="(grant.grantId && loadedGrantId !== grant.grantId) || (loadedProjectId !== grant.projectId)">
|
||||
<div class="flex-row">
|
||||
<span class="role" *ngFor="let role of grant.roleKeysList">{{ role }}</span>
|
||||
<button mat-stroked-button
|
||||
*ngIf="grant.grantId ? loadedGrantId !== grant.grantId : loadedProjectId !== grant.projectId"
|
||||
[disabled]="disableWrite || !((['user.grant.write$'] | hasRole | async) || ((context === UserGrantContext.OWNED_PROJECT ? ['user.grant.write:' + grant?.projectId] : context === UserGrantContext.GRANTED_PROJECT ? ['user.grant.write:' + grant?.grantId] : []) | hasRole | async))"
|
||||
(click)="grant.grantId ? getGrantRoleOptions(grant.grantId, grant.projectId) : getProjectRoleOptions(grant.projectId)"
|
||||
matTooltip="{{'ACTIONS.CHANGE' | translate}}">
|
||||
<i class="las la-edit"></i>
|
||||
{{'ACTIONS.EDIT' | translate}}
|
||||
</button>
|
||||
<ng-container
|
||||
*ngIf="(context === UserGrantContext.USER || context === UserGrantContext.NONE) && (grant.grantId && grantToEdit !== grant.id) || (grantToEdit !== grant.id)">
|
||||
<div class="flex-row">
|
||||
<div class="role">
|
||||
<span *ngFor="let role of grant.roleKeysList">{{ role }}</span>
|
||||
</div>
|
||||
</ng-container>
|
||||
<span class="fill-space"></span>
|
||||
<button mat-stroked-button
|
||||
*ngIf="grant.grantId ? grantToEdit !== grant.id : grantToEdit !== grant.id"
|
||||
[disabled]="disableWrite || !((['user.grant.write$'] | hasRole | async) || ((context === UserGrantContext.OWNED_PROJECT ? ['user.grant.write:' + grant?.projectId] : context === UserGrantContext.GRANTED_PROJECT ? ['user.grant.write:' + grant?.grantId] : []) | hasRole | async))"
|
||||
(click)="loadGrantOptions(grant)" matTooltip="{{'ACTIONS.CHANGE' | translate}}">
|
||||
<i class="las la-edit"></i>
|
||||
{{'ACTIONS.EDIT' | translate}}
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container
|
||||
*ngIf="context === UserGrantContext.OWNED_PROJECT || context === UserGrantContext.USER || context === UserGrantContext.NONE">
|
||||
<mat-form-field class="form-field" appearance="outline"
|
||||
*ngIf="loadedProjectId && loadedProjectId === grant.projectId">
|
||||
*ngIf="(context === UserGrantContext.OWNED_PROJECT || context === UserGrantContext.USER || context === UserGrantContext.NONE) && grantToEdit == grant.id && loadedProjectId && loadedProjectId === grant.projectId">
|
||||
<mat-form-field class="form-field" appearance="outline">
|
||||
<mat-label>{{ 'PROJECT.GRANT.ROLENAMESLIST' | translate }}</mat-label>
|
||||
<mat-select [(ngModel)]="grant.roleKeysList" multiple
|
||||
[disabled]="disableWrite || !((['user.grant.write$'] | hasRole | async) || ((context === UserGrantContext.OWNED_PROJECT ? ['user.grant.write:' + grant?.projectId] : context === UserGrantContext.GRANTED_PROJECT ? ['user.grant.write:' + grant?.grantId] : []) | hasRole | async))"
|
||||
@ -95,12 +113,15 @@
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<button *ngIf="context === UserGrantContext.USER || context === UserGrantContext.NONE"
|
||||
mat-icon-button (click)="grantToEdit=''">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</ng-container>
|
||||
|
||||
<ng-container
|
||||
*ngIf="context === UserGrantContext.GRANTED_PROJECT || context === UserGrantContext.USER || context === UserGrantContext.NONE">
|
||||
<mat-form-field class="form-field" appearance="outline"
|
||||
*ngIf="loadedGrantId && loadedGrantId === grant.grantId">
|
||||
*ngIf="(context === UserGrantContext.GRANTED_PROJECT || context === UserGrantContext.USER || context === UserGrantContext.NONE) && loadedGrantId && loadedGrantId === grant.grantId && grantToEdit == grant.id">
|
||||
<mat-form-field class="form-field" appearance="outline">
|
||||
<mat-label>{{ 'PROJECT.GRANT.ROLENAMESLIST' | translate }}</mat-label>
|
||||
<mat-select [(ngModel)]="grant.roleKeysList" multiple
|
||||
[disabled]="disableWrite || !((['user.grant.write$'] | hasRole | async) || ((context === UserGrantContext.OWNED_PROJECT ? ['user.grant.write:' + grant?.projectId] : context === UserGrantContext.GRANTED_PROJECT ? ['user.grant.write:' + grant?.grantId] : []) | hasRole | async))"
|
||||
@ -110,6 +131,10 @@
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<button *ngIf="context === UserGrantContext.USER || context === UserGrantContext.NONE"
|
||||
mat-icon-button (click)="grantToEdit=''">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</ng-container>
|
||||
</td>
|
||||
</ng-container>
|
||||
@ -123,4 +148,11 @@
|
||||
[length]="dataSource.totalResult" [pageSizeOptions]="[2, 3, 25, 50, 100, 250]" (page)="changePage($event)">
|
||||
</mat-paginator>
|
||||
</div>
|
||||
</app-refresh-table>
|
||||
</app-refresh-table>
|
||||
|
||||
<ng-template #templateRef let-key="key">
|
||||
<button class="search-button" mat-icon-button (click)="setFilter(key)">
|
||||
<mat-icon *ngIf="this.userGrantSearchKey != key">search</mat-icon>
|
||||
<mat-icon *ngIf="this.userGrantSearchKey == key">search_off</mat-icon>
|
||||
</button>
|
||||
</ng-template>
|
@ -21,6 +21,19 @@
|
||||
}
|
||||
}
|
||||
|
||||
th {
|
||||
.search-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&.search-active {
|
||||
.search-button {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.selection {
|
||||
width: 50px;
|
||||
max-width: 50px;
|
||||
@ -35,15 +48,22 @@
|
||||
|
||||
.flex-row {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-direction: row;
|
||||
max-width: 400px;
|
||||
|
||||
.role {
|
||||
display: block;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: .25rem;
|
||||
font-size: 14px;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
justify-items: center;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.fill-space {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
button {
|
||||
@ -60,3 +80,7 @@
|
||||
.fill-space {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.filtername {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { UserGrantsComponent } from './user-grants.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('UserGrantsComponent', () => {
|
||||
let component: UserGrantsComponent;
|
||||
let fixture: ComponentFixture<UserGrantsComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [UserGrantsComponent],
|
||||
})
|
||||
|
@ -1,10 +1,19 @@
|
||||
import { SelectionModel } from '@angular/cdk/collections';
|
||||
import { AfterViewInit, Component, Input, OnInit, ViewChild } from '@angular/core';
|
||||
import { MatInput } from '@angular/material/input';
|
||||
import { MatPaginator, PageEvent } from '@angular/material/paginator';
|
||||
import { MatSelectChange } from '@angular/material/select';
|
||||
import { MatTable } from '@angular/material/table';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { ProjectRoleView, UserGrant, UserGrantView } from 'src/app/proto/generated/management_pb';
|
||||
import { enterAnimations } from 'src/app/animations';
|
||||
import {
|
||||
ProjectRoleView,
|
||||
SearchMethod,
|
||||
UserGrant,
|
||||
UserGrantSearchKey,
|
||||
UserGrantSearchQuery,
|
||||
UserGrantView,
|
||||
} from 'src/app/proto/generated/management_pb';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
@ -14,12 +23,17 @@ import { UserGrantContext, UserGrantsDataSource } from './user-grants-datasource
|
||||
selector: 'app-user-grants',
|
||||
templateUrl: './user-grants.component.html',
|
||||
styleUrls: ['./user-grants.component.scss'],
|
||||
animations: [
|
||||
enterAnimations,
|
||||
],
|
||||
})
|
||||
export class UserGrantsComponent implements OnInit, AfterViewInit {
|
||||
public userGrantSearchKey: UserGrantSearchKey | undefined = undefined;
|
||||
public UserGrantSearchKey: any = UserGrantSearchKey;
|
||||
|
||||
public INITIAL_PAGE_SIZE: number = 50;
|
||||
@Input() context: UserGrantContext = UserGrantContext.NONE;
|
||||
@Input() refreshOnPreviousRoutes: string[] = [];
|
||||
public grants: UserGrantView.AsObject[] = [];
|
||||
|
||||
public dataSource!: UserGrantsDataSource;
|
||||
public selection: SelectionModel<UserGrantView.AsObject> = new SelectionModel<UserGrantView.AsObject>(true, []);
|
||||
@ -32,6 +46,7 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
|
||||
@Input() userId: string = '';
|
||||
@Input() projectId: string = '';
|
||||
@Input() grantId: string = '';
|
||||
@ViewChild('input') public filter!: MatInput;
|
||||
|
||||
public grantRoleOptions: string[] = [];
|
||||
public projectRoleOptions: ProjectRoleView.AsObject[] = [];
|
||||
@ -39,6 +54,7 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
|
||||
|
||||
public loadedGrantId: string = '';
|
||||
public loadedProjectId: string = '';
|
||||
public grantToEdit: string = '';
|
||||
|
||||
public UserGrantContext: any = UserGrantContext;
|
||||
|
||||
@ -89,7 +105,16 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
private loadGrantsPage(): void {
|
||||
private loadGrantsPage(filterValue?: string): void {
|
||||
let queries: UserGrantSearchQuery[] = [];
|
||||
if (this.userGrantSearchKey !== undefined && filterValue) {
|
||||
const query = new UserGrantSearchQuery();
|
||||
query.setKey(this.userGrantSearchKey);
|
||||
query.setMethod(SearchMethod.SEARCHMETHOD_CONTAINS_IGNORE_CASE);
|
||||
query.setValue(filterValue);
|
||||
queries = [query];
|
||||
}
|
||||
|
||||
this.dataSource.loadGrants(
|
||||
this.context,
|
||||
this.paginator?.pageIndex ?? 0,
|
||||
@ -99,6 +124,7 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
|
||||
grantId: this.grantId,
|
||||
userId: this.userId,
|
||||
},
|
||||
queries,
|
||||
);
|
||||
}
|
||||
|
||||
@ -114,7 +140,16 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
|
||||
this.dataSource.grantsSubject.value.forEach(row => this.selection.select(row));
|
||||
}
|
||||
|
||||
public getGrantRoleOptions(grantId: string, projectId: string): void {
|
||||
public loadGrantOptions(grant: UserGrantView.AsObject): void {
|
||||
this.grantToEdit = grant.id;
|
||||
if (grant.grantId && grant.projectId) {
|
||||
this.getGrantRoleOptions(grant.grantId, grant.projectId);
|
||||
} else if (grant.projectId) {
|
||||
this.getProjectRoleOptions(grant.projectId);
|
||||
}
|
||||
}
|
||||
|
||||
private getGrantRoleOptions(grantId: string, projectId: string): void {
|
||||
this.mgmtService.GetGrantedProjectByID(projectId, grantId).then(resp => {
|
||||
this.loadedGrantId = grantId;
|
||||
this.grantRoleOptions = resp.toObject().roleKeysList;
|
||||
@ -123,7 +158,7 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
|
||||
});
|
||||
}
|
||||
|
||||
public getProjectRoleOptions(projectId: string): void {
|
||||
private getProjectRoleOptions(projectId: string): void {
|
||||
this.mgmtService.SearchProjectRoles(projectId, 100, 0).then(resp => {
|
||||
this.loadedProjectId = projectId;
|
||||
this.projectRoleOptions = resp.toObject().resultList;
|
||||
@ -168,4 +203,26 @@ export class UserGrantsComponent implements OnInit, AfterViewInit {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
public applyFilter(event: Event): void {
|
||||
this.selection.clear();
|
||||
const filterValue = (event.target as HTMLInputElement).value;
|
||||
|
||||
this.loadGrantsPage(filterValue);
|
||||
}
|
||||
|
||||
public setFilter(key: UserGrantSearchKey): void {
|
||||
setTimeout(() => {
|
||||
if (this.filter) {
|
||||
(this.filter as any).nativeElement.focus();
|
||||
}
|
||||
}, 100);
|
||||
|
||||
if (this.userGrantSearchKey !== key) {
|
||||
this.userGrantSearchKey = key;
|
||||
} else {
|
||||
this.userGrantSearchKey = undefined;
|
||||
this.loadGrantsPage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatPaginatorModule } from '@angular/material/paginator';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
@ -39,6 +40,7 @@ import { UserGrantsComponent } from './user-grants.component';
|
||||
MatCheckboxModule,
|
||||
MatTooltipModule,
|
||||
MatSelectModule,
|
||||
MatInputModule,
|
||||
MatFormFieldModule,
|
||||
TranslateModule,
|
||||
HasRolePipeModule,
|
||||
|
@ -11,6 +11,10 @@
|
||||
.action {
|
||||
display: flex;
|
||||
|
||||
button {
|
||||
border-radius: .5rem;
|
||||
}
|
||||
|
||||
.ok-button {
|
||||
margin-left: .5rem;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { WarnDialogComponent } from './warn-dialog.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('WarnDialogComponent', () => {
|
||||
let component: WarnDialogComponent;
|
||||
let fixture: ComponentFixture<WarnDialogComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [WarnDialogComponent],
|
||||
})
|
||||
|
@ -24,6 +24,23 @@
|
||||
{{'HOME.IAM'| translate}}</h2>
|
||||
<p>{{'HOME.IAM_DESC'| translate}}</p>
|
||||
</div>
|
||||
|
||||
<ng-template appHasRole [appHasRole]="['org.create','iam.write']">
|
||||
<a class="short-link" [routerLink]="[ '/org', 'create']">{{'HOME.IAM_CREATE_ORG' | translate}}<i
|
||||
class="las la-link"></i></a>
|
||||
</ng-template>
|
||||
<ng-template appHasRole [appHasRole]="['iam.policy.read']">
|
||||
<a class="short-link"
|
||||
[routerLink]="[ '/iam', 'policy','iam']">{{'HOME.IAM_POLICY_IAM' | translate}}<i
|
||||
class="las la-link"></i></a>
|
||||
<a class="short-link"
|
||||
[routerLink]="[ '/iam', 'policy','complexity']">{{'HOME.IAM_POLICY_COMPLEXITY' | translate}}<i
|
||||
class="las la-link"></i></a>
|
||||
<a class="short-link"
|
||||
[routerLink]="[ '/iam', 'policy','login']">{{'HOME.IAM_POLICY_LOGIN' | translate}}<i
|
||||
class="las la-link"></i></a>
|
||||
</ng-template>
|
||||
|
||||
<span class="fill-space"></span>
|
||||
<div class="footer">
|
||||
<a color="primary" mat-stroked-button [routerLink]="['/iam']">{{'HOME.IAM_BUTTON' | translate}}</a>
|
||||
@ -37,6 +54,9 @@
|
||||
{{'HOME.SECURITYANDPRIVACY'| translate}}</h2>
|
||||
<p>{{'HOME.SECURITYANDPRIVACY_DESC'| translate}}</p>
|
||||
</div>
|
||||
<a class="short-link" [routerLink]="[ '/users', 'me','password']">{{'HOME.CHANGE_PWD' | translate}}<i
|
||||
class="las la-link"></i></a>
|
||||
|
||||
<span class="fill-space"></span>
|
||||
<div class="footer">
|
||||
<a color="primary" mat-stroked-button
|
||||
@ -51,6 +71,11 @@
|
||||
<i class="icon las la-layer-group"></i>
|
||||
{{'HOME.PROJECTS'| translate}}</h2>
|
||||
<p>{{'HOME.PROJECTS_DESC'| translate}}</p>
|
||||
<ng-template appHasRole [appHasRole]="['project.create']">
|
||||
<a class="short-link"
|
||||
[routerLink]="[ '/projects', 'create']">{{'HOME.PROJECTS_NEW_LINK' | translate}}<i
|
||||
class="las la-link"></i></a>
|
||||
</ng-template>
|
||||
</div>
|
||||
<span class="fill-space"></span>
|
||||
<div class="footer">
|
||||
@ -66,6 +91,19 @@
|
||||
<h2> <i class="icon las la-archway"></i>
|
||||
{{'HOME.PROTECTION'| translate}}</h2>
|
||||
<p>{{'HOME.PROTECTION_DESC'| translate}}</p>
|
||||
<ng-template appHasRole [appHasRole]="['iam.policy.read']">
|
||||
<a class="short-link"
|
||||
[routerLink]="[ '/org', 'policy','iam']">{{'HOME.ORG_POLICY_IAM' | translate}}<i
|
||||
class="las la-link"></i></a>
|
||||
</ng-template>
|
||||
<ng-template appHasRole [appHasRole]="['policy.read']">
|
||||
<a class="short-link"
|
||||
[routerLink]="[ '/org', 'policy','complexity']">{{'HOME.ORG_POLICY_COMPLEXITY' | translate}}<i
|
||||
class="las la-link"></i></a>
|
||||
<a class="short-link"
|
||||
[routerLink]="[ '/org', 'policy','login']">{{'HOME.ORG_POLICY_LOGIN' | translate}}<i
|
||||
class="las la-link"></i></a>
|
||||
</ng-template>
|
||||
</div>
|
||||
<span class="fill-space"></span>
|
||||
<div class="footer">
|
||||
@ -82,6 +120,18 @@
|
||||
<i class="las la-users"></i>
|
||||
{{'HOME.USERS'| translate}}</h2>
|
||||
<p>{{'HOME.USERS_DESC'| translate}}</p>
|
||||
<ng-template appHasRole [appHasRole]="['user.read(:[0-9]*)?']">
|
||||
<a class="short-link"
|
||||
[routerLink]="[ '/users', 'list', 'humans']">{{'HOME.USERS_HUMANS' | translate}}<i
|
||||
class="las la-link"></i></a>
|
||||
<a class="short-link"
|
||||
[routerLink]="[ '/users', 'list', 'machines']">{{'HOME.USERS_MACHINES' | translate}}<i
|
||||
class="las la-link"></i></a>
|
||||
</ng-template>
|
||||
<ng-template appHasRole [appHasRole]="['user.read']">
|
||||
<a class="short-link" [routerLink]="[ '/users', 'create']">{{'HOME.USERS_CREATE' | translate}}<i
|
||||
class="las la-link"></i></a>
|
||||
</ng-template>
|
||||
</div>
|
||||
<span class="fill-space"></span>
|
||||
<div class="footer">
|
||||
|
@ -32,7 +32,7 @@
|
||||
justify-content: space-evenly;
|
||||
|
||||
.item {
|
||||
flex: 1 1 45%;
|
||||
flex: 1 0 45%;
|
||||
margin: 0 1rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@ -80,3 +80,25 @@
|
||||
margin-top: 3rem;
|
||||
}
|
||||
}
|
||||
|
||||
.short-link {
|
||||
margin-bottom: .5rem;
|
||||
font-size: 15px;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
position: relative;
|
||||
|
||||
.las {
|
||||
font-size: 1.5rem !important;
|
||||
height: 1.5rem;
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.las {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { HomeComponent } from './home.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('HomeComponent', () => {
|
||||
let component: HomeComponent;
|
||||
let fixture: ComponentFixture<HomeComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [HomeComponent],
|
||||
}).compileComponents();
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { FailedEventsComponent } from './failed-events.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('FailedEventsComponent', () => {
|
||||
let component: FailedEventsComponent;
|
||||
let fixture: ComponentFixture<FailedEventsComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [FailedEventsComponent],
|
||||
})
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { MatPaginatorModule } from '@angular/material/paginator';
|
||||
import { MatSortModule } from '@angular/material/sort';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
@ -10,7 +10,7 @@ describe('IamMembersComponent', () => {
|
||||
let component: IamMembersComponent;
|
||||
let fixture: ComponentFixture<IamMembersComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [IamMembersComponent],
|
||||
imports: [
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { IamViewsComponent } from './iam-views.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('IamViewsComponent', () => {
|
||||
let component: IamViewsComponent;
|
||||
let fixture: ComponentFixture<IamViewsComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [IamViewsComponent],
|
||||
})
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { IamComponent } from './iam.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('IamComponent', () => {
|
||||
let component: IamComponent;
|
||||
let fixture: ComponentFixture<IamComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [IamComponent],
|
||||
})
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { OrgCreateComponent } from './org-create.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('OrgCreateComponent', () => {
|
||||
let component: OrgCreateComponent;
|
||||
let fixture: ComponentFixture<OrgCreateComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [OrgCreateComponent],
|
||||
})
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { AddDomainDialogComponent } from './add-domain-dialog.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('WarnDialogComponent', () => {
|
||||
let component: AddDomainDialogComponent;
|
||||
let fixture: ComponentFixture<AddDomainDialogComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [AddDomainDialogComponent],
|
||||
})
|
||||
|
@ -12,8 +12,10 @@
|
||||
{{'ORG.PAGES.ORGDOMAIN.TYPES.'+ domain.validationType | translate}}</p>
|
||||
<div *ngIf="domain.validationType !== OrgDomainValidationType.ORGDOMAINVALIDATIONTYPE_UNSPECIFIED"
|
||||
class="btn-container">
|
||||
<button color="primary" type="submit" mat-raised-button *ngIf="!(dns || http)"
|
||||
(click)="validate()">{{ 'ACTIONS.VERIFY' | translate }}</button>
|
||||
<button color="primary" type="submit" mat-raised-button *ngIf="!(dns || http)" (click)="validate()">
|
||||
{{ 'ACTIONS.VERIFY' | translate }}
|
||||
</button>
|
||||
<mat-spinner class="spinner" *ngIf="validating" diameter="20" mode="indeterminate"></mat-spinner>
|
||||
|
||||
<button *ngIf="!showNew" mat-stroked-button color="primary"
|
||||
(click)="showNew = true">{{'ORG.PAGES.ORGDOMAIN.REQUESTNEWTOKEN' | translate}}</button>
|
||||
@ -34,8 +36,11 @@
|
||||
<div class="btn-container">
|
||||
<button mat-stroked-button (click)="saveFile()"
|
||||
color="primary">{{ 'ORG.PAGES.DOWNLOAD_FILE' | translate }}</button>
|
||||
<button color="primary" type="submit" mat-raised-button
|
||||
(click)="validate()">{{ 'ACTIONS.VERIFY' | translate }}</button>
|
||||
<button color="primary" class="verify-button" type="submit" mat-raised-button (click)="validate()">
|
||||
<span>{{ 'ACTIONS.VERIFY' | translate }}</span>
|
||||
<mat-spinner class="spinner" *ngIf="!validating" diameter="20" mode="indeterminate"></mat-spinner>
|
||||
</button>
|
||||
<mat-spinner class="spinner" *ngIf="validating" diameter="20" mode="indeterminate"></mat-spinner>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -48,8 +53,10 @@
|
||||
<i *ngIf="copied != dns.token" class="las la-clipboard"></i>
|
||||
<i *ngIf="copied == dns.token" class="las la-clipboard-check"></i>
|
||||
</button>
|
||||
<button color="primary" type="submit" mat-raised-button
|
||||
(click)="validate()">{{ 'ACTIONS.VERIFY' | translate }}</button>
|
||||
<button color="primary" type="submit" mat-raised-button class="verify-button" (click)="validate()">
|
||||
{{ 'ACTIONS.VERIFY' | translate }}
|
||||
</button>
|
||||
<mat-spinner class="spinner" *ngIf="validating" diameter="20" mode="indeterminate"></mat-spinner>
|
||||
</div>
|
||||
<p class="entry">{{dns?.url}}</p>
|
||||
</div>
|
||||
|
@ -1,10 +1,10 @@
|
||||
.btn-container {
|
||||
display: flex;
|
||||
margin: -.5rem;
|
||||
align-items: center;
|
||||
|
||||
button {
|
||||
margin: 1rem .5rem;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { DomainVerificationComponent } from './domain-verification.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('DomainVerificationComponent', () => {
|
||||
let component: DomainVerificationComponent;
|
||||
let fixture: ComponentFixture<DomainVerificationComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [DomainVerificationComponent],
|
||||
})
|
||||
|
@ -21,6 +21,7 @@ export class DomainVerificationComponent {
|
||||
|
||||
public showNew: boolean = false;
|
||||
|
||||
public validating: boolean = false;
|
||||
constructor(
|
||||
private toast: ToastService,
|
||||
public dialogRef: MatDialogRef<DomainVerificationComponent>,
|
||||
@ -54,10 +55,14 @@ export class DomainVerificationComponent {
|
||||
}
|
||||
|
||||
public validate(): void {
|
||||
this.validating = true;
|
||||
this.mgmtService.ValidateMyOrgDomain(this.domain.domain).then(() => {
|
||||
this.dialogRef.close(false);
|
||||
this.dialogRef.close(true);
|
||||
this.toast.showInfo('ORG.PAGES.ORGDOMAIN.VERIFICATION_SUCCESSFUL', true);
|
||||
this.validating = false;
|
||||
}).catch((error) => {
|
||||
this.toast.showError(error);
|
||||
this.validating = false;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@
|
||||
|
||||
.verified,
|
||||
.primary {
|
||||
color: #5282c1;
|
||||
color: var(--color-main);
|
||||
margin-right: 1rem;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { OrgDetailComponent } from './org-detail.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('OrgDetailComponent', () => {
|
||||
let component: OrgDetailComponent;
|
||||
let fixture: ComponentFixture<OrgDetailComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [OrgDetailComponent],
|
||||
})
|
||||
|
@ -79,10 +79,12 @@ export class OrgDetailComponent implements OnInit, OnDestroy {
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
|
||||
this.loadMembers();
|
||||
this.loadDomains();
|
||||
}
|
||||
|
||||
this.mgmtService.SearchMyOrgDomains(0, 100).then(result => {
|
||||
public loadDomains(): void {
|
||||
this.mgmtService.SearchMyOrgDomains().then(result => {
|
||||
this.domains = result.toObject().resultList;
|
||||
this.primaryDomain = this.domains.find(domain => domain.primary)?.domain ?? '';
|
||||
});
|
||||
@ -91,7 +93,7 @@ export class OrgDetailComponent implements OnInit, OnDestroy {
|
||||
public setPrimary(domain: OrgDomainView.AsObject): void {
|
||||
this.mgmtService.setMyPrimaryOrgDomain(domain.domain).then(() => {
|
||||
this.toast.showInfo('ORG.TOAST.SETPRIMARY', true);
|
||||
this.getData();
|
||||
this.loadDomains();
|
||||
}).catch((error) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
@ -202,12 +204,18 @@ export class OrgDetailComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
public verifyDomain(domain: OrgDomainView.AsObject): void {
|
||||
this.dialog.open(DomainVerificationComponent, {
|
||||
const dialogRef = this.dialog.open(DomainVerificationComponent, {
|
||||
data: {
|
||||
domain: domain,
|
||||
},
|
||||
width: '500px',
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe((reload) => {
|
||||
if (reload) {
|
||||
this.loadDomains();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public loadMembers(): void {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { OrgListComponent } from './org-list.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('OrgListComponent', () => {
|
||||
let component: OrgListComponent;
|
||||
let fixture: ComponentFixture<OrgListComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [OrgListComponent],
|
||||
})
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { OrgMemberRolesAutocompleteComponent } from './org-member-roles-autocomplete.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('OrgMemberRolesAutocompleteComponent', () => {
|
||||
let component: OrgMemberRolesAutocompleteComponent;
|
||||
let fixture: ComponentFixture<OrgMemberRolesAutocompleteComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [OrgMemberRolesAutocompleteComponent],
|
||||
})
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
import { MatPaginatorModule } from '@angular/material/paginator';
|
||||
import { MatSortModule } from '@angular/material/sort';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
@ -10,7 +10,7 @@ describe('OrgMembersComponent', () => {
|
||||
let component: OrgMembersComponent;
|
||||
let fixture: ComponentFixture<OrgMembersComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [OrgMembersComponent],
|
||||
imports: [
|
||||
|
@ -8,6 +8,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatTabsModule } from '@angular/material/tabs';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
@ -51,6 +52,7 @@ import { OrgsRoutingModule } from './orgs-routing.module';
|
||||
MemberCreateDialogModule,
|
||||
MatMenuModule,
|
||||
ChangesModule,
|
||||
MatProgressSpinnerModule,
|
||||
AddDomainDialogModule,
|
||||
TranslateModule,
|
||||
SharedModule,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { AppCreateComponent } from './app-create.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('AppCreateComponent', () => {
|
||||
let component: AppCreateComponent;
|
||||
let fixture: ComponentFixture<AppCreateComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [AppCreateComponent],
|
||||
})
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { AppDetailComponent } from './app-detail.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('AppDetailComponent', () => {
|
||||
let component: AppDetailComponent;
|
||||
let fixture: ComponentFixture<AppDetailComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [AppDetailComponent],
|
||||
})
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { AppSecretDialogComponent } from './app-secret-dialog.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('AppSecretDialogComponent', () => {
|
||||
let component: AppSecretDialogComponent;
|
||||
let fixture: ComponentFixture<AppSecretDialogComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [AppSecretDialogComponent],
|
||||
})
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { GrantedProjectDetailComponent } from './granted-project-detail.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('GrantedProjectDetailComponent', () => {
|
||||
let component: GrantedProjectDetailComponent;
|
||||
let fixture: ComponentFixture<GrantedProjectDetailComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [GrantedProjectDetailComponent],
|
||||
})
|
||||
|
@ -22,11 +22,10 @@
|
||||
{{ item.creationDate | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm' }}</span>
|
||||
<span class="fill-space"></span>
|
||||
</div>
|
||||
<button [ngClass]="{ selected: selection.isSelected(item)}" (click)="selection.toggle(item)" class="edit-button"
|
||||
mat-icon-button>
|
||||
<mat-icon *ngIf="selection.isSelected(item)" svgIcon="mdi_pin"></mat-icon>
|
||||
<mat-icon svgIcon="mdi_pin_outline" *ngIf="!selection.isSelected(item)"></mat-icon>
|
||||
</button>
|
||||
|
||||
<template [ngTemplateOutlet]="toggleButton" [ngTemplateOutletContext]="{key: item}"></template>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@ -47,12 +46,20 @@
|
||||
{{ item.creationDate | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm' }}</span>
|
||||
<span class="fill-space"></span>
|
||||
</div>
|
||||
<button [ngClass]="{ selected: selection.isSelected(item)}" (click)="selection.toggle(item)" class="edit-button"
|
||||
mat-icon-button>
|
||||
<button [ngClass]="{ selected: selection.isSelected(item)}"
|
||||
(click)="selection.toggle(item); $event.stopPropagation()" class="edit-button" mat-icon-button>
|
||||
<mat-icon *ngIf="selection.isSelected(item)" svgIcon="mdi_pin"></mat-icon>
|
||||
<mat-icon svgIcon="mdi_pin_outline" *ngIf="!selection.isSelected(item)"></mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
<p class="n-items" *ngIf="!loading && items.length === 0 && selection.selected.length === 0">
|
||||
{{'PROJECT.PAGES.NOITEMS' | translate}}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-template #toggleButton let-key="key">
|
||||
<button matTooltip="{{'ACTIONS.PIN' | translate}}" [ngClass]="{ selected: selection.isSelected(key)}"
|
||||
(click)="selection.toggle(key); $event.stopPropagation()" class="edit-button" mat-icon-button>
|
||||
<mat-icon *ngIf="selection.isSelected(key)" svgIcon="mdi_pin"></mat-icon>
|
||||
<mat-icon svgIcon="mdi_pin_outline" *ngIf="!selection.isSelected(key)"></mat-icon>
|
||||
</button>
|
||||
</ng-template>
|
@ -1,4 +1,4 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { GrantedProjectGridComponent } from './granted-project-grid.component';
|
||||
|
||||
@ -6,7 +6,7 @@ describe('GridComponent', () => {
|
||||
let component: GrantedProjectGridComponent;
|
||||
let fixture: ComponentFixture<GrantedProjectGridComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [GrantedProjectGridComponent],
|
||||
})
|
||||
|
@ -47,11 +47,10 @@ export class GrantedProjectGridComponent implements OnChanges {
|
||||
this.setPrefixedItem('pinned-granted-projects', JSON.stringify(
|
||||
this.selection.selected.map(item => item.projectId),
|
||||
)).then(() => {
|
||||
const filtered = this.notPinned.filter(item => item === selection.added.find(i => i === item));
|
||||
filtered.forEach((f, i) => {
|
||||
this.notPinned.splice(i, 1);
|
||||
selection.added.forEach(item => {
|
||||
const index = this.notPinned.findIndex(i => i.projectId === item.projectId);
|
||||
this.notPinned.splice(index, 1);
|
||||
});
|
||||
|
||||
this.notPinned.push(...selection.removed);
|
||||
});
|
||||
});
|
||||
@ -74,18 +73,10 @@ export class GrantedProjectGridComponent implements OnChanges {
|
||||
const array: string[] = JSON.parse(storageEntry);
|
||||
const toSelect: ProjectGrantView.AsObject[] = this.items.filter((item, index) => {
|
||||
if (array.includes(item.projectId)) {
|
||||
// this.notPinned.splice(index, 1);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
this.selection.select(...toSelect);
|
||||
|
||||
const toNotPinned: ProjectGrantView.AsObject[] = this.items.filter((item, index) => {
|
||||
if (!array.includes(item.projectId)) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
this.notPinned = toNotPinned;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user