diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e34f2d89e..e369c9170 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -4,9 +4,9 @@ name: CI # Define em quais situações esse workflow será executado on: push: - branches: [ master ] + branches: [ master, '[0-9]+.x.x' ] pull_request: - branches: [ master ] + branches: [ master, '[0-9]+.x.x' ] # Os jobs são conjuntos de actions que são executados na mesma máquina virtual. # É possível ter mais de um job e assim executar ações paralelamente. diff --git a/.github/workflows/publish_po_angular_ci-beta.yml b/.github/workflows/publish_po_angular_ci-beta.yml new file mode 100644 index 000000000..18bff0b40 --- /dev/null +++ b/.github/workflows/publish_po_angular_ci-beta.yml @@ -0,0 +1,128 @@ +name: PO-UI Publish Beta + +# URL para os pacotes po-ui no npm +env: + SCHEMATICS_NPM_PATH: po-ui/ng-schematics + STORAGE_NPM_PATH: po-ui/ng-storage + SYNC_NPM_PATH: po-ui/ng-sync + COMPONENTS_NPM_PATH: po-ui/ng-components + TEMPLATES_NPM_PATH: po-ui/ng-templates + CODE_EDITOR_NPM_PATH: po-ui/ng-code-editor + WORKING_DIR: /home/runner/work/po-angular/po-angular/po-angular + +on: + workflow_dispatch: + +jobs: + build-and-publish: + runs-on: ubuntu-latest + steps: + + - name: Check out po-angular + uses: actions/checkout@v4 + with: + path: po-angular + + - name: Check out style + uses: actions/checkout@v4 + with: + repository: po-ui/po-style + path: po-style + + - name: Check out lint + uses: actions/checkout@v4 + with: + repository: po-ui/po-tslint + path: po-tslint + + - name: Install and Build + run: npm install && npm run build + working-directory: ${{env.WORKING_DIR}} + + # Pega a última versão dos pacotes publicados no npm e armazena em variáveis + - run: echo "SCHEMATICS_LAST_PUBLISHED_VERSION=$(npm view @${{ env.SCHEMATICS_NPM_PATH }} dist-tags.beta)" >> $GITHUB_ENV + - run: echo "STORAGE_LAST_PUBLISHED_VERSION=$(npm view @${{ env.STORAGE_NPM_PATH }} dist-tags.beta)" >> $GITHUB_ENV + - run: echo "SYNC_LAST_PUBLISHED_VERSION=$(npm view @${{ env.SYNC_NPM_PATH }} dist-tags.beta)" >> $GITHUB_ENV + - run: echo "COMPONENTS_LAST_PUBLISHED_VERSION=$(npm view @${{ env.COMPONENTS_NPM_PATH }} dist-tags.beta)" >> $GITHUB_ENV + - run: echo "TEMPLATES_LAST_PUBLISHED_VERSION=$(npm view @${{ env.TEMPLATES_NPM_PATH }} dist-tags.beta)" >> $GITHUB_ENV + - run: echo "CODE_EDITOR_LAST_PUBLISHED_VERSION=$(npm view @${{ env.CODE_EDITOR_NPM_PATH }} dist-tags.beta)" >> $GITHUB_ENV + + # Pega a versão no package.json + - name: Get package.json version. + id: package-version + uses: martinbeentjes/npm-get-version-action@main + with: + path: po-angular + + # PUBLISH NG-SCHEMATICS + - name: ng-schematics - publish + # Se a versão remota for igual à versão que será publicada então ele pula o publish deste pacote e tenta publicar os demais pacotes + if: (!contains(env.PACKAGE_VERSION, env.SCHEMATICS_LAST_PUBLISHED_VERSION)) + uses: actions/setup-node@v3 + with: + node-version: '16.x' + registry-url: 'https://registry.npmjs.org' + - run: npm publish ${{env.WORKING_DIR}}/dist/ng-schematics --tag beta --ignore-scripts + env: + PACKAGE_VERSION: ${{ steps.package-version.outputs.current-version }} + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + # PUBLISH NG-STORAGE + - name: ng-storage - publish + if: (!contains(env.PACKAGE_VERSION, env.STORAGE_LAST_PUBLISHED_VERSION)) + uses: actions/setup-node@v3 + with: + node-version: '16.x' + registry-url: 'https://registry.npmjs.org' + - run: npm publish ${{env.WORKING_DIR}}/dist/ng-storage --tag beta --ignore-scripts + env: + PACKAGE_VERSION: ${{ steps.package-version.outputs.current-version }} + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + # PUBLISH NG-SYNC + - name: ng-sync - publish + if: (!contains(env.PACKAGE_VERSION, env.SYNC_LAST_PUBLISHED_VERSION)) + uses: actions/setup-node@v3 + with: + node-version: '16.x' + registry-url: 'https://registry.npmjs.org' + - run: npm publish ${{env.WORKING_DIR}}/dist/ng-sync --tag beta --ignore-scripts + env: + PACKAGE_VERSION: ${{ steps.package-version.outputs.current-version }} + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + # PUBLISH NG-COMPONENTS + - name: ng-components - publish + if: (!contains(env.PACKAGE_VERSION, env.COMPONENTS_LAST_PUBLISHED_VERSION)) + uses: actions/setup-node@v3 + with: + node-version: '16.x' + registry-url: 'https://registry.npmjs.org' + - run: npm publish ${{env.WORKING_DIR}}/dist/ng-components --tag beta --ignore-scripts + env: + PACKAGE_VERSION: ${{ steps.package-version.outputs.current-version }} + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + # PUBLISH NG-TEMPLATES + - name: ng-templates - publish + if: (!contains(env.PACKAGE_VERSION, env.TEMPLATES_LAST_PUBLISHED_VERSION)) + uses: actions/setup-node@v3 + with: + node-version: '16.x' + registry-url: 'https://registry.npmjs.org' + - run: npm publish ${{env.WORKING_DIR}}/dist/ng-templates --tag beta --ignore-scripts + env: + PACKAGE_VERSION: ${{ steps.package-version.outputs.current-version }} + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + # PUBLISH NG-CODE-EDITOR + - name: ng-code-editor - publish + if: (!contains(env.PACKAGE_VERSION, env.CODE_EDITOR_LAST_PUBLISHED_VERSION)) + uses: actions/setup-node@v3 + with: + node-version: '16.x' + registry-url: 'https://registry.npmjs.org' + - run: npm publish ${{env.WORKING_DIR}}/dist/ng-code-editor --tag beta --ignore-scripts + env: + PACKAGE_VERSION: ${{ steps.package-version.outputs.current-version }} + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/publish_po_angular_ci.yml b/.github/workflows/publish_po_angular_ci-latest.yml similarity index 58% rename from .github/workflows/publish_po_angular_ci.yml rename to .github/workflows/publish_po_angular_ci-latest.yml index 0f17735cd..693064d62 100644 --- a/.github/workflows/publish_po_angular_ci.yml +++ b/.github/workflows/publish_po_angular_ci-latest.yml @@ -1,4 +1,4 @@ -name: PO-UI Publish +name: PO-UI Publish Latest # URL para os pacotes po-ui no npm env: @@ -42,12 +42,12 @@ jobs: working-directory: ${{env.WORKING_DIR}} # Pega a última versão dos pacotes publicados no npm e armazena em variáveis - - run: echo "SCHEMATICS_LAST_PUBLISHED_VERSION=$(npm view @${{ env.SCHEMATICS_NPM_PATH }} dist-tags.next)" >> $GITHUB_ENV - - run: echo "STORAGE_LAST_PUBLISHED_VERSION=$(npm view @${{ env.STORAGE_NPM_PATH }} dist-tags.next)" >> $GITHUB_ENV - - run: echo "SYNC_LAST_PUBLISHED_VERSION=$(npm view @${{ env.SYNC_NPM_PATH }} dist-tags.next)" >> $GITHUB_ENV - - run: echo "COMPONENTS_LAST_PUBLISHED_VERSION=$(npm view @${{ env.COMPONENTS_NPM_PATH }} dist-tags.next)" >> $GITHUB_ENV - - run: echo "TEMPLATES_LAST_PUBLISHED_VERSION=$(npm view @${{ env.TEMPLATES_NPM_PATH }} dist-tags.next)" >> $GITHUB_ENV - - run: echo "CODE_EDITOR_LAST_PUBLISHED_VERSION=$(npm view @${{ env.CODE_EDITOR_NPM_PATH }} dist-tags.next)" >> $GITHUB_ENV + - run: echo "SCHEMATICS_LAST_PUBLISHED_VERSION=$(npm view @${{ env.SCHEMATICS_NPM_PATH }} dist-tags.latest)" >> $GITHUB_ENV + - run: echo "STORAGE_LAST_PUBLISHED_VERSION=$(npm view @${{ env.STORAGE_NPM_PATH }} dist-tags.latest)" >> $GITHUB_ENV + - run: echo "SYNC_LAST_PUBLISHED_VERSION=$(npm view @${{ env.SYNC_NPM_PATH }} dist-tags.latest)" >> $GITHUB_ENV + - run: echo "COMPONENTS_LAST_PUBLISHED_VERSION=$(npm view @${{ env.COMPONENTS_NPM_PATH }} dist-tags.latest)" >> $GITHUB_ENV + - run: echo "TEMPLATES_LAST_PUBLISHED_VERSION=$(npm view @${{ env.TEMPLATES_NPM_PATH }} dist-tags.latest)" >> $GITHUB_ENV + - run: echo "CODE_EDITOR_LAST_PUBLISHED_VERSION=$(npm view @${{ env.CODE_EDITOR_NPM_PATH }} dist-tags.latest)" >> $GITHUB_ENV # Pega a versão no package.json - name: Get package.json version. @@ -59,20 +59,12 @@ jobs: # PUBLISH NG-SCHEMATICS - name: ng-schematics - publish # Se a versão remota for igual à versão que será publicada então ele pula o publish deste pacote e tenta publicar os demais pacotes - #if: (!contains(env.PACKAGE_VERSION, env.SCHEMATICS_LAST_PUBLISHED_VERSION)) + if: (!contains(env.PACKAGE_VERSION, env.SCHEMATICS_LAST_PUBLISHED_VERSION)) uses: actions/setup-node@v3 with: node-version: '16.x' registry-url: 'https://registry.npmjs.org' - - run: npm publish ${{env.WORKING_DIR}}/dist/ng-schematics --ignore-scripts - env: - PACKAGE_VERSION: ${{ steps.package-version.outputs.current-version }} - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - - - name: ng-schematics - add "latest" tag - if: (!contains(env.PACKAGE_VERSION, env.SCHEMATICS_LAST_PUBLISHED_VERSION) && !contains(env.PACKAGE_VERSION, '-next') && !contains(env.PACKAGE_VERSION, '-rc')) - run: npm dist-tags add @${{ env.SCHEMATICS_NPM_PATH }}@${{ env.PACKAGE_VERSION }} - working-directory: ${{env.WORKING_DIR}} + - run: npm publish ${{env.WORKING_DIR}}/dist/ng-schematics --tag latest --ignore-scripts env: PACKAGE_VERSION: ${{ steps.package-version.outputs.current-version }} NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} @@ -84,15 +76,7 @@ jobs: with: node-version: '16.x' registry-url: 'https://registry.npmjs.org' - - run: npm publish ${{env.WORKING_DIR}}/dist/ng-storage --ignore-scripts - env: - PACKAGE_VERSION: ${{ steps.package-version.outputs.current-version }} - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - - - name: ng-storage - add "latest" tag - if: (!contains(env.PACKAGE_VERSION, env.STORAGE_LAST_PUBLISHED_VERSION) && !contains(env.PACKAGE_VERSION, '-next') && !contains(env.PACKAGE_VERSION, '-rc')) - run: npm dist-tags add @${{ env.STORAGE_NPM_PATH }}@${{ env.PACKAGE_VERSION }} - working-directory: ${{env.WORKING_DIR}} + - run: npm publish ${{env.WORKING_DIR}}/dist/ng-storage --tag latest --ignore-scripts env: PACKAGE_VERSION: ${{ steps.package-version.outputs.current-version }} NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} @@ -104,15 +88,7 @@ jobs: with: node-version: '16.x' registry-url: 'https://registry.npmjs.org' - - run: npm publish ${{env.WORKING_DIR}}/dist/ng-sync --ignore-scripts - env: - PACKAGE_VERSION: ${{ steps.package-version.outputs.current-version }} - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - - - name: ng-sync - add "latest" tag - if: (!contains(env.PACKAGE_VERSION, env.SYNC_LAST_PUBLISHED_VERSION) && !contains(env.PACKAGE_VERSION, '-next') && !contains(env.PACKAGE_VERSION, '-rc')) - run: npm dist-tags add @${{ env.SYNC_NPM_PATH }}@${{ env.PACKAGE_VERSION }} - working-directory: ${{env.WORKING_DIR}} + - run: npm publish ${{env.WORKING_DIR}}/dist/ng-sync --tag latest --ignore-scripts env: PACKAGE_VERSION: ${{ steps.package-version.outputs.current-version }} NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} @@ -124,19 +100,11 @@ jobs: with: node-version: '16.x' registry-url: 'https://registry.npmjs.org' - - run: npm publish ${{env.WORKING_DIR}}/dist/ng-components --ignore-scripts + - run: npm publish ${{env.WORKING_DIR}}/dist/ng-components --tag latest --ignore-scripts env: PACKAGE_VERSION: ${{ steps.package-version.outputs.current-version }} NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - - name: ng-components - add "latest" tag - if: (!contains(env.PACKAGE_VERSION, env.COMPONENTS_LAST_PUBLISHED_VERSION) && !contains(env.PACKAGE_VERSION, '-next') && !contains(env.PACKAGE_VERSION, '-rc')) - run: npm dist-tags add @${{ env.COMPONENTS_NPM_PATH }}@${{ env.PACKAGE_VERSION }} - working-directory: ${{env.WORKING_DIR}} - env: - PACKAGE_VERSION: ${{ steps.package-version.outputs.current-version }} - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - # PUBLISH NG-TEMPLATES - name: ng-templates - publish if: (!contains(env.PACKAGE_VERSION, env.TEMPLATES_LAST_PUBLISHED_VERSION)) @@ -144,19 +112,11 @@ jobs: with: node-version: '16.x' registry-url: 'https://registry.npmjs.org' - - run: npm publish ${{env.WORKING_DIR}}/dist/ng-templates --ignore-scripts + - run: npm publish ${{env.WORKING_DIR}}/dist/ng-templates --tag latest --ignore-scripts env: PACKAGE_VERSION: ${{ steps.package-version.outputs.current-version }} NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - - name: ng-templates - add "latest" tag - if: (!contains(env.PACKAGE_VERSION, env.TEMPLATES_LAST_PUBLISHED_VERSION) && !contains(env.PACKAGE_VERSION, '-next') && !contains(env.PACKAGE_VERSION, '-rc')) - run: npm dist-tags add @${{ env.TEMPLATES_NPM_PATH }}@${{ env.PACKAGE_VERSION }} - working-directory: ${{env.WORKING_DIR}} - env: - PACKAGE_VERSION: ${{ steps.package-version.outputs.current-version }} - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - # PUBLISH NG-CODE-EDITOR - name: ng-code-editor - publish if: (!contains(env.PACKAGE_VERSION, env.CODE_EDITOR_LAST_PUBLISHED_VERSION)) @@ -164,15 +124,7 @@ jobs: with: node-version: '16.x' registry-url: 'https://registry.npmjs.org' - - run: npm publish ${{env.WORKING_DIR}}/dist/ng-code-editor --ignore-scripts - env: - PACKAGE_VERSION: ${{ steps.package-version.outputs.current-version }} - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - - - name: ng-code-editor - add "latest" tag - if: (!contains(env.PACKAGE_VERSION, env.CODE_EDITOR_LAST_PUBLISHED_VERSION) && !contains(env.PACKAGE_VERSION, '-next') && !contains(env.PACKAGE_VERSION, '-rc')) - run: npm dist-tags add @${{ env.CODE_EDITOR_NPM_PATH }}@${{ env.PACKAGE_VERSION }} - working-directory: ${{env.WORKING_DIR}} + - run: npm publish ${{env.WORKING_DIR}}/dist/ng-code-editor --tag latest --ignore-scripts env: PACKAGE_VERSION: ${{ steps.package-version.outputs.current-version }} NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/publish_po_angular_ci-next.yml b/.github/workflows/publish_po_angular_ci-next.yml new file mode 100644 index 000000000..7d383f4fe --- /dev/null +++ b/.github/workflows/publish_po_angular_ci-next.yml @@ -0,0 +1,128 @@ +name: PO-UI Publish Next + +# URL para os pacotes po-ui no npm +env: + SCHEMATICS_NPM_PATH: po-ui/ng-schematics + STORAGE_NPM_PATH: po-ui/ng-storage + SYNC_NPM_PATH: po-ui/ng-sync + COMPONENTS_NPM_PATH: po-ui/ng-components + TEMPLATES_NPM_PATH: po-ui/ng-templates + CODE_EDITOR_NPM_PATH: po-ui/ng-code-editor + WORKING_DIR: /home/runner/work/po-angular/po-angular/po-angular + +on: + workflow_dispatch: + +jobs: + build-and-publish: + runs-on: ubuntu-latest + steps: + + - name: Check out po-angular + uses: actions/checkout@v4 + with: + path: po-angular + + - name: Check out style + uses: actions/checkout@v4 + with: + repository: po-ui/po-style + path: po-style + + - name: Check out lint + uses: actions/checkout@v4 + with: + repository: po-ui/po-tslint + path: po-tslint + + - name: Install and Build + run: npm install && npm run build + working-directory: ${{env.WORKING_DIR}} + + # Pega a última versão dos pacotes publicados no npm e armazena em variáveis + - run: echo "SCHEMATICS_LAST_PUBLISHED_VERSION=$(npm view @${{ env.SCHEMATICS_NPM_PATH }} dist-tags.next)" >> $GITHUB_ENV + - run: echo "STORAGE_LAST_PUBLISHED_VERSION=$(npm view @${{ env.STORAGE_NPM_PATH }} dist-tags.next)" >> $GITHUB_ENV + - run: echo "SYNC_LAST_PUBLISHED_VERSION=$(npm view @${{ env.SYNC_NPM_PATH }} dist-tags.next)" >> $GITHUB_ENV + - run: echo "COMPONENTS_LAST_PUBLISHED_VERSION=$(npm view @${{ env.COMPONENTS_NPM_PATH }} dist-tags.next)" >> $GITHUB_ENV + - run: echo "TEMPLATES_LAST_PUBLISHED_VERSION=$(npm view @${{ env.TEMPLATES_NPM_PATH }} dist-tags.next)" >> $GITHUB_ENV + - run: echo "CODE_EDITOR_LAST_PUBLISHED_VERSION=$(npm view @${{ env.CODE_EDITOR_NPM_PATH }} dist-tags.next)" >> $GITHUB_ENV + + # Pega a versão no package.json + - name: Get package.json version. + id: package-version + uses: martinbeentjes/npm-get-version-action@main + with: + path: po-angular + + # PUBLISH NG-SCHEMATICS + - name: ng-schematics - publish + # Se a versão remota for igual à versão que será publicada então ele pula o publish deste pacote e tenta publicar os demais pacotes + if: (!contains(env.PACKAGE_VERSION, env.SCHEMATICS_LAST_PUBLISHED_VERSION)) + uses: actions/setup-node@v3 + with: + node-version: '16.x' + registry-url: 'https://registry.npmjs.org' + - run: npm publish ${{env.WORKING_DIR}}/dist/ng-schematics --tag next --ignore-scripts + env: + PACKAGE_VERSION: ${{ steps.package-version.outputs.current-version }} + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + # PUBLISH NG-STORAGE + - name: ng-storage - publish + if: (!contains(env.PACKAGE_VERSION, env.STORAGE_LAST_PUBLISHED_VERSION)) + uses: actions/setup-node@v3 + with: + node-version: '16.x' + registry-url: 'https://registry.npmjs.org' + - run: npm publish ${{env.WORKING_DIR}}/dist/ng-storage --tag next --ignore-scripts + env: + PACKAGE_VERSION: ${{ steps.package-version.outputs.current-version }} + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + # PUBLISH NG-SYNC + - name: ng-sync - publish + if: (!contains(env.PACKAGE_VERSION, env.SYNC_LAST_PUBLISHED_VERSION)) + uses: actions/setup-node@v3 + with: + node-version: '16.x' + registry-url: 'https://registry.npmjs.org' + - run: npm publish ${{env.WORKING_DIR}}/dist/ng-sync --tag next --ignore-scripts + env: + PACKAGE_VERSION: ${{ steps.package-version.outputs.current-version }} + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + # PUBLISH NG-COMPONENTS + - name: ng-components - publish + if: (!contains(env.PACKAGE_VERSION, env.COMPONENTS_LAST_PUBLISHED_VERSION)) + uses: actions/setup-node@v3 + with: + node-version: '16.x' + registry-url: 'https://registry.npmjs.org' + - run: npm publish ${{env.WORKING_DIR}}/dist/ng-components --tag next --ignore-scripts + env: + PACKAGE_VERSION: ${{ steps.package-version.outputs.current-version }} + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + # PUBLISH NG-TEMPLATES + - name: ng-templates - publish + if: (!contains(env.PACKAGE_VERSION, env.TEMPLATES_LAST_PUBLISHED_VERSION)) + uses: actions/setup-node@v3 + with: + node-version: '16.x' + registry-url: 'https://registry.npmjs.org' + - run: npm publish ${{env.WORKING_DIR}}/dist/ng-templates --tag next --ignore-scripts + env: + PACKAGE_VERSION: ${{ steps.package-version.outputs.current-version }} + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + # PUBLISH NG-CODE-EDITOR + - name: ng-code-editor - publish + if: (!contains(env.PACKAGE_VERSION, env.CODE_EDITOR_LAST_PUBLISHED_VERSION)) + uses: actions/setup-node@v3 + with: + node-version: '16.x' + registry-url: 'https://registry.npmjs.org' + - run: npm publish ${{env.WORKING_DIR}}/dist/ng-code-editor --tag next --ignore-scripts + env: + PACKAGE_VERSION: ${{ steps.package-version.outputs.current-version }} + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/publish_po_angular_ci-portal.yml b/.github/workflows/publish_po_angular_ci-portal.yml new file mode 100644 index 000000000..ec54d0b68 --- /dev/null +++ b/.github/workflows/publish_po_angular_ci-portal.yml @@ -0,0 +1,47 @@ +name: PO-UI Publish Portal + +env: + AZURE_WEBAPP_NAME: wa-po-ui + AZURE_WEBAPP_PACKAGE_PATH: /home/runner/work/po-angular/po-angular/po-angular/dist/portal + WORKING_DIR: /home/runner/work/po-angular/po-angular/po-angular + +on: + workflow_dispatch: + +jobs: + build-and-publish: + runs-on: ubuntu-latest + steps: + + - name: Check out po-angular + uses: actions/checkout@v4 + with: + path: po-angular + + - name: Check out style + uses: actions/checkout@v4 + with: + repository: po-ui/po-style + path: po-style + + - name: Check out lint + uses: actions/checkout@v4 + with: + repository: po-ui/po-tslint + path: po-tslint + + - name: Install and Build + run: npm install && npm run build + working-directory: ${{env.WORKING_DIR}} + + # PUBLISH PORTAL + - name: portal build + run: npm run build:portal:docs && npm run build:portal:prod + working-directory: ${{env.WORKING_DIR}} + + - name: 'Deploy to Azure Web App' + uses: azure/webapps-deploy@v2 + with: + app-name: ${{ env.AZURE_WEBAPP_NAME }} + package: ${{ env.AZURE_WEBAPP_PACKAGE_PATH }} + publish-profile: ${{ secrets.AZURE_TOKEN }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ccbd7181..4a545702a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,104 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +# [16.12.0](https://github.com/po-ui/po-angular/compare/v16.11.0...v16.12.0) (2024-01-22) + + +### Bug Fixes + +* **multiselect:** corrige comportamento ao utilizar a tecla Tab ([36cf24c](https://github.com/po-ui/po-angular/commit/36cf24c58bcba3e4e3b762253b19b9568fb24e65)) + + +### Features + +* **disclaimer-group:** reutiliza `po-tag` no componente ([e8ab1a7](https://github.com/po-ui/po-angular/commit/e8ab1a7d5c7fa475f1f3c19182d17dacd3747b6e)) +* **po-dynamic-view:** adiciona `format` aos valores ([c4ac760](https://github.com/po-ui/po-angular/commit/c4ac760552a17d12b1a63304e6035cbaee69fe95)) +* **tag:** ajusta área de click mínima ([5e47c82](https://github.com/po-ui/po-angular/commit/5e47c82731d48b0880c99adfd9a73401a9fc0a9a)) + + + +# [16.11.0](https://github.com/po-ui/po-angular/compare/v16.10.0...v16.11.0) (2024-01-12) + + +### Bug Fixes + +* **dynamic-search:** limpa campo de busca rápida ([6ca2dbd](https://github.com/po-ui/po-angular/commit/6ca2dbd6c21ca1d335584e77f974a5aade4fc6c8)) + + +### Features + +* **badge:** novo componente ([43f3186](https://github.com/po-ui/po-angular/commit/43f318639d0069e56841d5a1cc8e4e3e149b0dde)) +* **menu:** permite habilitar o automatic toggle ([610f087](https://github.com/po-ui/po-angular/commit/610f087f19c88cf8bf5205e28e33379b0c3bc18e)) +* **po-dynamic-view:** aprimora exibição de booleans ([9ff2721](https://github.com/po-ui/po-angular/commit/9ff27212a0733c8bf7bdf2fdb3420bfccbaafc31)) + + + +# [16.10.0](https://github.com/po-ui/po-angular/compare/v16.9.0...v16.10.0) (2023-12-21) + + +### Bug Fixes + +* **select:** trata o placeholder do componente no browser Safari ([7fe25b5](https://github.com/po-ui/po-angular/commit/7fe25b590e538bdd8732cf2cc7030fec21b334ca)) + + +### Features + +* **job-scheduler:** cria evento de output de erro e sucesso ([809cee2](https://github.com/po-ui/po-angular/commit/809cee2c2f5e1c4df693a12b003407e696cccb34)) +* **search:** implementa modo trigger no componente ([196ba3e](https://github.com/po-ui/po-angular/commit/196ba3ef6d47d72715b796d9dc3012afeb96dae7)) + + + +# [16.9.0](https://github.com/po-ui/po-angular/compare/v16.8.0...v16.9.0) (2023-12-11) + + +### Bug Fixes + +* **listbox:** ajusta redimensionamento do loading ([9d78856](https://github.com/po-ui/po-angular/commit/9d7885677c2ef5a4b612808b73f5bd8b9ed7953a)) +* **table:** ajusta redimensionamento do loading ([482cc97](https://github.com/po-ui/po-angular/commit/482cc97cee44ed33adb25dcda2bd184283c1ec6f)) + + +### Features + +* **loading-overlay:** inclui controle de tamanho ([0f72ba9](https://github.com/po-ui/po-angular/commit/0f72ba9b7612cc39aff1a99278f30468303d0071)) +* **loading:** torna o p-size dinâmico ([8365698](https://github.com/po-ui/po-angular/commit/8365698f21ec553046dda6af815acb5941eaa97e)) + + + +# [16.8.0](https://github.com/po-ui/po-angular/compare/v16.7.0...v16.8.0) (2023-12-05) + + +### Features + +* **progress:** implementa definições do AnimaliaDS ([ad59a5e](https://github.com/po-ui/po-angular/commit/ad59a5ee0f92e7fe14ef9cf83101188622017564)) +* **search:** implementa animaliaDS e externaliza para uso no portal ([0bdc067](https://github.com/po-ui/po-angular/commit/0bdc067478afdc80c6c018fc2ad00d5145b2b395)) + + + +# [16.7.0](https://github.com/po-ui/po-angular/compare/v16.6.1...v16.7.0) (2023-11-17) + + +### Features + +* **accordion:** ajusta navegação do elemento através de viewChild ([cbb93e8](https://github.com/po-ui/po-angular/commit/cbb93e8091fb92a76527d02f7a08e296d3b832dc)) +* **dynamic-form:** adiciona escolha entre `po-switch` ou `po-checkbox` ([1b91e50](https://github.com/po-ui/po-angular/commit/1b91e50a90647aa7e8406ae906cf1a3f7a48158f)), closes [#1420](https://github.com/po-ui/po-angular/issues/1420) +* **loading-icon:** implementa definições do AnimaliaDS ([d126499](https://github.com/po-ui/po-angular/commit/d12649995734f35b78c81efb84ebc359d213e907)) +* **loading-overlay:** implementações AnimaliaDS ([dee3db4](https://github.com/po-ui/po-angular/commit/dee3db49141d0b1adc9907d5ef191213686c0651)) +* **overlay:** novo componente de uso interno ([5698533](https://github.com/po-ui/po-angular/commit/5698533dfbfa547b49ce12bf7e99210ece7f2b03)) +* **theme-builder:** implementa novos componentes animalizados ([2f6b1a6](https://github.com/po-ui/po-angular/commit/2f6b1a6f130aab6e636ef6b821ec458b140cf1b3)) + + + +## [16.6.1](https://github.com/po-ui/po-angular/compare/v16.6.0...v16.6.1) (2023-11-13) + + +### Bug Fixes + +* **combo:** corrige fechamento do listbox após perda de foco ([a6cfa1a](https://github.com/po-ui/po-angular/commit/a6cfa1abaefb589453441742ca3e5ba78892ef8c)) +* **listbox:** corrige clique no checkbox ([d303af0](https://github.com/po-ui/po-angular/commit/d303af0aba21e956be81636ffc8a24d36ad1683f)) +* **multiselect:** corrige fechamento do listbox após perda de foco ([f4d9437](https://github.com/po-ui/po-angular/commit/f4d9437ed753aa2c4e0b5fe5c3b1200f3a868971)) + + + # [16.6.0](https://github.com/po-ui/po-angular/compare/v16.5.0...v16.6.0) (2023-11-03) diff --git a/docs/guides/sync-fundamentals.md b/docs/guides/sync-fundamentals.md index 3f15a20f9..2181b3e8c 100644 --- a/docs/guides/sync-fundamentals.md +++ b/docs/guides/sync-fundamentals.md @@ -113,8 +113,8 @@ import { PoSyncSchema } from '@po-ui/ng-sync'; const conferenceSchema: PoSyncSchema = { // Endpoint para o método GET - getUrlApi: 'https://po-sample-conference.fly.dev/conferences', - diffUrlApi: 'https://po-sample-conference.fly.dev/conferences/diff', + getUrlApi: 'https://po-sample-conference.onrender.com/conferences', + diffUrlApi: 'https://po-sample-conference.onrender.com/conferences/diff', deletedField: 'isDeleted', fields: [ 'id', 'title', 'date', 'location', 'description' ], idField: 'id', @@ -190,8 +190,8 @@ propriedade `deletedField` na interface [PoSyncSchema](/documentation/po-sync), import { PoSyncSchema } from '@po-ui/ng-sync'; const conferenceSchema: PoSyncSchema = { - getUrlApi: 'https://po-sample-conference.fly.dev/conferences', - diffUrlApi: 'https://po-sample-conference.fly.dev/conferences/diff', + getUrlApi: 'https://po-sample-conference.onrender.com/conferences', + diffUrlApi: 'https://po-sample-conference.onrender.com/conferences/diff', // Definição do nome do campo deletedField: 'isDeleted', fields: [ 'id', 'title', 'date', 'location', 'description' ], @@ -218,7 +218,7 @@ tiveram a última atualização maior ou igual a data que foi recebida como par sincronizados serão retornados. Para cada um dos *schemas* é necessário ter um *endpoint* de sincronização. Abra o seu navegador e acesse a URL -https://po-sample-conference.fly.dev/conferences/diff/2018-10-08T13:23:31.893Z. +https://po-sample-conference.onrender.com/conferences/diff/2018-10-08T13:23:31.893Z. O *endpoint* de sincronização deve retornar uma resposta com a estrutura como a da URL acima, por exemplo: @@ -251,9 +251,9 @@ abaixo: import { PoSyncSchema } from '@po-ui/ng-sync'; const conferenceSchema: PoSyncSchema = { - getUrlApi: 'https://po-sample-conference.fly.dev/conferences', + getUrlApi: 'https://po-sample-conference.onrender.com/conferences', // Definição da URL de sincronização - diffUrlApi: 'https://po-sample-conference.fly.dev/conferences/diff', + diffUrlApi: 'https://po-sample-conference.onrender.com/conferences/diff', deletedField: 'isDeleted', fields: [ 'id', 'title', 'date', 'location', 'description' ], idField: 'id', diff --git a/docs/guides/sync-get-started.md b/docs/guides/sync-get-started.md index 98a6555f9..fc5bf192b 100644 --- a/docs/guides/sync-get-started.md +++ b/docs/guides/sync-get-started.md @@ -151,8 +151,8 @@ Crie o arquivo `src/app/home/conference-schema.constants.ts` e adicione o conte import { PoSyncSchema } from '@po-ui/ng-sync'; export const conferenceSchema: PoSyncSchema = { - getUrlApi: 'https://po-sample-conference.fly.dev/conferences', - diffUrlApi: 'https://po-sample-conference.fly.dev/conferences/diff', + getUrlApi: 'https://po-sample-conference.onrender.com/conferences', + diffUrlApi: 'https://po-sample-conference.onrender.com/conferences/diff', deletedField: 'deleted', fields: [ 'id', 'title', 'location', 'description' ], idField: 'id', diff --git a/package.json b/package.json index bdb2c509f..47a10090b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "po-ui-sources", - "version": "16.6.0", + "version": "16.12.0", "description": "PO UI", "homepage": "https://po-ui.io", "license": "MIT", @@ -74,7 +74,7 @@ "@angular/router": "~16.2.0", "@capacitor/core": "4.6.3", "@capacitor/network": "^4.1.0", - "@po-ui/style": "16.6.0", + "@po-ui/style": "16.12.0", "capitalize": "^2.0.3", "colors": "1.4.0", "core-js": "3.13.0", diff --git a/projects/portal/src/app/theme-builder/theme-builder.component.css b/projects/portal/src/app/theme-builder/theme-builder.component.css index 5b938ef30..af29d61f9 100644 --- a/projects/portal/src/app/theme-builder/theme-builder.component.css +++ b/projects/portal/src/app/theme-builder/theme-builder.component.css @@ -3,8 +3,8 @@ --color-calendar-background-color-border-today: var(--color-primary); --color-calendar-color-box-foreground-today: var(--color-primary); --color-calendar-arrow: var(--color-primary); - --color-calendar-background-color-box-background-selected: var(--color-tertiary); - --color-calendar-background-color-box-background-active: var(--color-tertiary); + --color-calendar-background-color-box-background-selected: var(--color-brand-03-base); + --color-calendar-background-color-box-background-active: var(--color-brand-03-base); } p { @@ -456,6 +456,89 @@ p { } } +.multiselect-hover .po-multiselect-input { + border-color: var(--color-hover); + background-color: var(--background-hover); + cursor: pointer; +} + +.multiselect-focus .po-multiselect-input { + outline-color: var(--outline-color-focused); + outline-width: var(--outline-width); + border: 1px solid var(--color-focused); + outline-style: solid; + outline-offset: 2px; +} + +.multiselect-focus .po-multiselect-input .po-field-icon-container-right .po-icon-input { + color: var(--color-focused); +} + +.combo-hover .po-combo-input { + border-color: var(--color-hover); + background-color: var(--background-hover); +} + +.combo-hover .po-combo-container-content span.po-field-icon.po-icon.po-icon-arrow-down.po-icon-input { + border-color: var(--color-hover); + background: var(--background-hover); +} + +.combo-focus .po-combo-input { + border-color: var(--color-focused); + outline-color: var(--outline-color-focused); + outline-width: var(--outline-width); + outline-style: solid; + outline-offset: 2px; +} + +.combo-focus .po-combo-input ~ .po-field-icon-container-right .po-field-icon.po-icon.po-icon-arrow-down, +.combo-focus .po-combo-input ~ .po-field-icon-container-right .po-field-icon.po-icon.po-icon-arrow-up { + border-color: var(--color-focused); +} + +.accordion-hover .po-accordion-item-header-button { + color: var(--color-hover); + background-color: var(--background-hover); +} + +.accordion-hover .po-accordion-item-header-button .po-accordion-item-header-icon { + color: var(--color-hover); +} + +.accordion-focus .po-accordion-item-header-button { + color: var(--color-focus); + position: relative; + outline-color: var(--outline-color-focused); + outline-width: var(--outline-width); + outline-style: solid; + outline-offset: 2px; + z-index: 1; +} + +.accordion-focus .po-accordion-item-header-button .po-accordion-item-header-icon { + color: var(--color-focus); +} + +.accordion-pressed .po-accordion-item-header-button { + background-color: var(--background-pressed); + color: var(--color-pressed); + outline: none; +} + +.accordion-pressed .po-accordion-item-header-button .po-accordion-item-header-icon { + color: var(--color-pressed); +} + +.breadcrumb-default ul, +.breadcrumb-default li { + margin-bottom: 0 !important; +} + +.tag-hover .po-tag-remove { + background-color: var(--color-hover); +} + .menu-item { height: 80%; display: flex; diff --git a/projects/portal/src/app/theme-builder/theme-builder.component.html b/projects/portal/src/app/theme-builder/theme-builder.component.html index d0f67ea2a..ed3bd1af8 100644 --- a/projects/portal/src/app/theme-builder/theme-builder.component.html +++ b/projects/portal/src/app/theme-builder/theme-builder.component.html @@ -709,6 +709,234 @@ + + +
+
+ + + +
+
+ +

Live demo

+
+
+
+
+
+

Multiselect

+ +
+
+ +
+
+
+ + +
+
+ + + +
+
+ +

Live demo

+
+
+
+
+
+

Combo

+ +
+
+ +
+
+
+ + +
+
+ + + +
+
+ +

Live demo

+
+
+
+
+
+

Accordion

+ +
+
+ +
+
+
+ + +
+
+ +

Live demo

+
+
+
+
+
+

Breadcrumb

+ +
+
+ +
+
+
+ + +
+
+ + + +
+
+ +

Live demo

+
+
+
+
+
+

Tag

+ +
+
+ +
+
+
@@ -2374,63 +2602,755 @@

Nenhum componente selecionado

- - - -
-
-

Nível de Contraste

- -
-
-
-
-

Texto normal

- - - - + +
+

Estados

-
-
-
-

Texto grande

- - - - + +
+
+

Live demo

+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+

Acessibilidade

-
-
-
-

Gráficos

- +
+
+

Personalizar

+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ + +
+

Estados

+
+ +
+
+

Live demo

+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+

Acessibilidade

+
+ +
+
+

Personalizar

+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ +
+

Estados

+
+ +
+
+

Live demo

+
+
+
+
+ + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. + + + +
+
+ + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. + + + +
+
+ + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. + + + +
+
+ + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. + + + +
+
+ + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. + + + +
+
+
+
+

Acessibilidade

+
+ +
+
+

Personalizar

+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ +
+

Estados

+
+ +
+
+

Live demo

+
+
+
+
+ + + +
+
+
+
+

Acessibilidade

+
+
+

É necessário cor do background e cor do texto para funcionamento da acessibilidade

+
+
+

Personalizar

+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ +
+

Estados

+
+ +
+
+

Live demo

+
+
+ + +
+
+
+
+ + + + + + + +
+
+ + +
+
+ + +
+
+
+
+

Acessibilidade

+
+ +
+
+

Personalizar

+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+
+ + + +
+
+

Nível de Contraste

+ +
+
+
+
+

Texto normal

+ + + + +
+
+
+
+

Texto grande

+ + + + +
+
+
+
+

Gráficos

+
@@ -2476,6 +3396,12 @@

Nenhum componente selecionado

#resultPopupContainer >

+        

+        

+        

+        

+        

+        

       
@@ -2634,6 +3560,42 @@

[(ngModel)]="disclaimerView" (p-change)="switchIndividual()" > + + + +

diff --git a/projects/portal/src/app/theme-builder/theme-builder.component.ts b/projects/portal/src/app/theme-builder/theme-builder.component.ts index 0c27bd030..ae15f2ac1 100644 --- a/projects/portal/src/app/theme-builder/theme-builder.component.ts +++ b/projects/portal/src/app/theme-builder/theme-builder.component.ts @@ -3,15 +3,17 @@ import { ChangeDetectorRef, Component, ElementRef, - Renderer2, - ViewChild, OnInit, + ViewChild, ViewEncapsulation } from '@angular/core'; import { FormBuilder, FormGroup } from '@angular/forms'; import { + PoAccordionComponent, + PoBreadcrumbComponent, PoButtonComponent, + PoComboComponent, PoDatepickerComponent, PoDisclaimerComponent, PoDropdownComponent, @@ -19,10 +21,12 @@ import { PoListViewAction, PoListViewLiterals, PoModalComponent, + PoMultiselectComponent, PoPageSlideComponent, PoPopupComponent, PoSelectComponent, PoSwitchComponent, + PoTagComponent, PoTextareaComponent } from '../../../../ui/src/lib'; @@ -108,6 +112,34 @@ export class ThemeBuilderComponent implements AfterViewInit, OnInit { @ViewChild('checkboxChecked', { read: ElementRef }) checkboxChecked: ElementRef; @ViewChild('checkboxUnchecked', { read: ElementRef }) checkboxUnchecked: ElementRef; @ViewChild('checkboxHover', { read: ElementRef }) checkboxHover: ElementRef; + @ViewChild('multiselect') multiselectComponent: PoMultiselectComponent; + @ViewChild('multiselectDefault', { read: ElementRef }) multiselectDefault: ElementRef; + @ViewChild('multiselectHover') multiselectHover: PoMultiselectComponent; + @ViewChild('multiselectFocus') multiselectFocus: PoMultiselectComponent; + @ViewChild('multiselectDisabled') multiselectDisabled: PoMultiselectComponent; + @ViewChild('combo') comboComponent: PoComboComponent; + @ViewChild('comboDefault', { read: ElementRef }) comboDefault: ElementRef; + @ViewChild('comboHover') comboHover: PoComboComponent; + @ViewChild('comboFocus') comboFocus: PoComboComponent; + @ViewChild('comboDisabled') comboDisabled: PoComboComponent; + @ViewChild('accordion') accordionComponent: PoAccordionComponent; + @ViewChild('accordionDefault', { read: ElementRef }) accordionDefault: ElementRef; + @ViewChild('accordionHover') accordionHover: PoAccordionComponent; + @ViewChild('accordionFocus') accordionFocus: PoAccordionComponent; + @ViewChild('accordionPressed') accordionPressed: PoAccordionComponent; + @ViewChild('accordionDisabled') accordionDisabled: PoAccordionComponent; + @ViewChild('breadcrumb') breadcrumbComponent: PoBreadcrumbComponent; + @ViewChild('breadcrumbDefault', { read: ElementRef }) breadcrumbDefault: ElementRef; + @ViewChild('tag') tagComponent: PoTagComponent; + @ViewChild('tagDefault', { read: ElementRef }) tagDefault: ElementRef; + @ViewChild('tagDanger', { read: ElementRef }) tagDanger: ElementRef; + @ViewChild('tagSuccess', { read: ElementRef }) tagSuccess: ElementRef; + @ViewChild('tagWarning', { read: ElementRef }) tagWarning: ElementRef; + @ViewChild('tagNeutral', { read: ElementRef }) tagNeutral: ElementRef; + @ViewChild('tagRemovable', { read: ElementRef }) tagRemovable: ElementRef; + @ViewChild('tagHover', { read: ElementRef }) tagHover: ElementRef; + @ViewChild('tagDisabled', { read: ElementRef }) tagDisabled: ElementRef; + @ViewChild('resultButtonD') resultButtonD: HTMLElement; @ViewChild('resultButtonP') resultButtonP: HTMLElement; @ViewChild('resultButtonL') resultButtonL: HTMLElement; @@ -126,6 +158,12 @@ export class ThemeBuilderComponent implements AfterViewInit, OnInit { @ViewChild('resultPopup') resultPopup: HTMLElement; @ViewChild('resultPopupContainer') resultPopupContainer: HTMLElement; @ViewChild('resultCheckbox') resultCheckbox: HTMLElement; + @ViewChild('resultMultiselect') resultMultiselect: HTMLElement; + @ViewChild('resultCombo') resultCombo: HTMLElement; + @ViewChild('resultAccordion') resultAccordion: HTMLElement; + @ViewChild('resultBreadcrumb') resultBreadcrumb: HTMLElement; + @ViewChild('resultTag') resultTag: HTMLElement; + @ViewChild('resultTagsGlobal') resultTagsGlobal: HTMLElement; botaoPrimaryView = true; switchView = true; @@ -141,26 +179,52 @@ export class ThemeBuilderComponent implements AfterViewInit, OnInit { dropdownView = true; popupView = true; checkboxView = true; + multiselectView = true; + comboView = true; + accordionView = true; + breadcrumbView = true; + tagView = true; switchSampleBuilder = true; + resultTagI = ''; + resultTagD = ''; + resultTagS = ''; + resultTagW = ''; + resultTagN = ''; + resultTagR = ''; + switchAllComponentes = true; - colorBack!: string; colorText = '#ffffff'; changedColorButton = false; changedColorPopup = false; - itemSelected!: string; + changedColorAccordion = false; kindButton = 1; + tagSelected = 1; + + colorBack!: string; + itemSelected!: string; nameItem!: string; ratio!: number; ratioButton!: number; ratioDisclaimer!: number; ratioInput!: number; ratioSelect!: number; + ratioMultiselect!: number; + ratioCombo!: number; + ratioAccordion!: number; + ratioTag!: number; + ratioTagDefault!: number; + ratioTagDanger!: number; + ratioTagSuccess!: number; + ratioTagWarning!: number; + ratioTagNeutral!: number; + ratioTagRemovable!: number; ratioTextarea!: number; ratioDatepicker!: number; ratioTooltip!: number; ratioPopup!: number; + tagActive; // Cor primária brandFormP: FormGroup; @@ -225,16 +289,38 @@ export class ThemeBuilderComponent implements AfterViewInit, OnInit { //checkbox checkboxForm: FormGroup; + //multiselect + multiselectForm: FormGroup; + + //combo + comboForm: FormGroup; + + //accordion + accordionForm: FormGroup; + + //breadcrumb + breadcrumbForm: FormGroup; + + //tag + tagForm; + tagsFormGlobal: FormGroup; + tagFormI: FormGroup; + tagFormD: FormGroup; + tagFormS: FormGroup; + tagFormW: FormGroup; + tagFormN: FormGroup; + tagFormR: FormGroup; + private readonly formPropertyP = { colorAction: '--color-primary' }; private readonly formPropertyS = { - colorAction: '--color-secondary' + colorAction: '--color-action-default' }; private readonly formPropertyT = { - colorAction: '--color-tertiary' + colorAction: '--color-brand-03-base' }; // Variáveis customizaveis @@ -388,6 +474,90 @@ export class ThemeBuilderComponent implements AfterViewInit, OnInit { borderColor: '--border-color' }; + private readonly formPropertyDictMultiselect = { + borderColor: '--color', + borderColorHover: '--color-hover', + colorBackground: '--background', + colorBackgroundHover: '--background-hover', + textColor: '--text-color-placeholder', + fontSize: '--font-size', + colorFocus: '--color-focused', + colorDisabled: '--background-disabled' + }; + + private readonly formPropertyDictCombo = { + borderColor: '--color', + borderColorHover: '--color-hover', + colorBackground: '--background', + colorBackgroundHover: '--background-hover', + colorFocus: '--color-focused', + colorDisabled: '--background-disabled', + fontSize: '--font-size', + textColor: '--text-color', + textColorPlaceholder: '--text-color-placeholder' + }; + + private readonly formPropertyDictAccordion = { + colorBackground: '--background-color', + colorHover: '--background-hover', + colorPressed: '--background-pressed', + colorDisabled: '--background-disabled', + textColor: '--color', + textColorDisabled: '--color-disabled', + textColorHover: '--color-hover', + textColorPressed: '--color-pressed', + textColorFocus: '--color-focus', + fontSize: '--font-size' + }; + + private readonly formPropertyDictBreadcrumb = { + colorIcon: '--color-icon', + colorCurrentPage: '--color-current-page', + color: '--color' + }; + + private formPropertyDictTag; + private readonly formPropertyDictTagI = { + backgroundColor: '--color-info', + textColor: '--text-color-info' + }; + + private readonly formPropertyDictTagD = { + backgroundColor: '--color-negative', + textColor: '--text-color-negative' + }; + + private readonly formPropertyDictTagS = { + backgroundColor: '--color-positive', + textColor: '--text-color-positive' + }; + + private readonly formPropertyDictTagW = { + backgroundColor: '--color-tag-warning', + textColor: '--text-color-warning' + }; + + private readonly formPropertyDictTagN = { + backgroundColor: '--color-neutral', + textColor: '--text-color-neutral' + }; + + private readonly formPropertyDictTagR = { + backgroundColor: '--color', + textColor: '--text-color', + borderColor: '--border-color', + colorHover: '--color-hover', + colorDisabled: '--color-disabled', + textColorDisabled: '--text-color-disabled', + borderColorDisabled: '--border-color-disabled' + }; + + private readonly formPropertyDictTagsGlobal = { + borderRadius: '--border-radius', + fontSize: '--font-size', + lineHeight: '--line-height' + }; + listViewLiterals: PoListViewLiterals = { showDetails: 'Mais Detalhes', hideDetails: 'Menos Detalhes' @@ -401,7 +571,7 @@ export class ThemeBuilderComponent implements AfterViewInit, OnInit { } ]; - constructor(private formBuilder: FormBuilder, private renderer: Renderer2, private cdr: ChangeDetectorRef) {} + constructor(private formBuilder: FormBuilder, private cdr: ChangeDetectorRef) {} ngOnInit(): void { this.brandFormP = this.formBuilder.group({ @@ -566,6 +736,90 @@ export class ThemeBuilderComponent implements AfterViewInit, OnInit { colorHover: [null], borderColor: [null] }); + + this.multiselectForm = this.formBuilder.group({ + borderColor: [null], + borderColorHover: [null], + colorBackground: [null], + colorBackgroundHover: [null], + textColor: [null], + fontSize: [null], + colorFocus: [null], + colorDisabled: [null] + }); + + this.comboForm = this.formBuilder.group({ + borderColor: [null], + borderColorHover: [null], + colorBackground: [null], + colorBackgroundHover: [null], + textColor: [null], + textColorPlaceholder: [null], + fontSize: [null], + colorFocus: [null], + colorDisabled: [null] + }); + + this.accordionForm = this.formBuilder.group({ + fontSize: [null], + colorBackground: [null], + colorHover: [null], + colorPressed: [null], + textColor: [null], + textColorHover: [null], + textColorPressed: [null], + textColorFocus: [null], + colorDisabled: [null], + textColorDisabled: [null] + }); + + this.breadcrumbForm = this.formBuilder.group({ + colorIcon: [null], + colorCurrentPage: [null], + color: [null] + }); + + this.tagFormI = this.formBuilder.group({ + backgroundColor: [null], + textColor: [null] + }); + + this.tagFormD = this.formBuilder.group({ + backgroundColor: [null], + textColor: [null] + }); + + this.tagFormS = this.formBuilder.group({ + backgroundColor: [null], + textColor: [null] + }); + + this.tagFormW = this.formBuilder.group({ + backgroundColor: [null], + textColor: [null] + }); + + this.tagFormN = this.formBuilder.group({ + backgroundColor: [null], + textColor: [null] + }); + + this.tagFormR = this.formBuilder.group({ + backgroundColor: [null], + textColor: [null], + borderColor: [null], + colorHover: [null], + colorDisabled: [null], + textColorDisabled: [null], + borderColorDisabled: [null] + }); + + this.tagsFormGlobal = this.formBuilder.group({ + borderRadius: [null], + fontSize: [null], + lineHeight: [null] + }); + this.tagForm = this.tagFormI; } openGetcss() { @@ -581,12 +835,12 @@ export class ThemeBuilderComponent implements AfterViewInit, OnInit { this.brandFormS.reset({ colorAction: ['#753399'] }); - document.getElementById('myPortal').style.setProperty('--color-secondary', null); + document.getElementById('myPortal').style.setProperty('--color-action-default', null); this.brandFormT.reset({ colorAction: ['#ffd464'] }); - document.getElementById('myPortal').style.setProperty('--color-tertiary', null); + document.getElementById('myPortal').style.setProperty('--color-brand-03-base', null); this.buttonFormDefault.reset(); Object.keys(this.formPropertyDictButtonD).forEach((fieldName: string) => { @@ -872,15 +1126,187 @@ export class ThemeBuilderComponent implements AfterViewInit, OnInit { } } + this.multiselectForm.reset(); + Object.keys(this.formPropertyDictMultiselect).forEach((fieldName: string) => { + this.multiselectComponent.inputElement.nativeElement.style.setProperty( + this.formPropertyDictMultiselect[fieldName], + null + ); + if (this.itemSelected === 'multiselect') { + this.multiselectDefault.nativeElement.style.setProperty(this.formPropertyDictMultiselect[fieldName], null); + this.multiselectHover.inputElement.nativeElement.style.setProperty( + this.formPropertyDictMultiselect[fieldName], + null + ); + this.multiselectFocus.inputElement.nativeElement.style.setProperty( + this.formPropertyDictMultiselect[fieldName], + null + ); + this.multiselectDisabled.inputElement.nativeElement.style.setProperty( + this.formPropertyDictMultiselect[fieldName], + null + ); + } + }); + + this.comboForm.reset(); + Object.keys(this.formPropertyDictCombo).forEach((fieldName: string) => { + this.comboComponent.inputEl.nativeElement.style.setProperty(this.formPropertyDictCombo[fieldName], null); + if (this.itemSelected === 'combo') { + this.comboDefault.nativeElement.style.setProperty(this.formPropertyDictCombo[fieldName], null); + this.comboHover.inputEl.nativeElement.style.setProperty(this.formPropertyDictCombo[fieldName], null); + this.comboFocus.inputEl.nativeElement.style.setProperty(this.formPropertyDictCombo[fieldName], null); + this.comboDisabled.inputEl.nativeElement.style.setProperty(this.formPropertyDictCombo[fieldName], null); + this.comboHover.iconElement.nativeElement.style.setProperty(this.formPropertyDictCombo[fieldName], null); + this.comboFocus.iconElement.nativeElement.style.setProperty(this.formPropertyDictCombo[fieldName], null); + } + }); + + this.accordionForm.reset(); + Object.keys(this.formPropertyDictAccordion).forEach((fieldName: string) => { + const accordionList = this.accordionComponent.accordionsHeader.toArray(); + accordionList[0].accordionElement.nativeElement.style.setProperty( + this.formPropertyDictAccordion[fieldName], + null + ); + if (this.itemSelected === 'accordion') { + this.accordionDefault.nativeElement.style.setProperty(this.formPropertyDictAccordion[fieldName], null); + this.accordionHover.accordionsHeader + .toArray()[0] + .accordionElement.nativeElement.style.setProperty(this.formPropertyDictAccordion[fieldName], null); + this.accordionFocus.accordionsHeader + .toArray()[0] + .accordionElement.nativeElement.style.setProperty(this.formPropertyDictAccordion[fieldName], null); + this.accordionPressed.accordionsHeader + .toArray()[0] + .accordionElement.nativeElement.style.setProperty(this.formPropertyDictAccordion[fieldName], null); + this.accordionDisabled.accordionsHeader + .toArray()[0] + .accordionElement.nativeElement.style.setProperty(this.formPropertyDictAccordion[fieldName], null); + } + }); + + this.breadcrumbForm.reset(); + Object.keys(this.formPropertyDictBreadcrumb).forEach((fieldName: string) => { + this.breadcrumbComponent.breadcrumbElement.nativeElement.style.setProperty( + this.formPropertyDictBreadcrumb[fieldName], + null + ); + if (this.itemSelected === 'breadcrumb') { + this.breadcrumbDefault.nativeElement.style.setProperty(this.formPropertyDictBreadcrumb[fieldName], null); + } + }); + + this.tagsFormGlobal.reset(); + this.tagFormI.reset(); + Object.keys(this.formPropertyDictTagI).forEach((fieldName: string) => { + this.tagComponent.poTag.nativeElement.style.setProperty(this.formPropertyDictTagI[fieldName], null); + if (this.itemSelected === 'tag') { + this.tagDefault.nativeElement.style.setProperty(this.formPropertyDictTagI[fieldName], null); + this.tagDefault.nativeElement.style.setProperty(this.formPropertyDictTagsGlobal[fieldName], null); + } + }); + + this.tagFormD.reset(); + Object.keys(this.formPropertyDictTagD).forEach((fieldName: string) => { + if (this.itemSelected === 'tag') { + this.tagDanger.nativeElement.style.setProperty(this.formPropertyDictTagD[fieldName], null); + this.tagDanger.nativeElement.style.setProperty(this.formPropertyDictTagsGlobal[fieldName], null); + } + }); + + this.tagFormS.reset(); + Object.keys(this.formPropertyDictTagS).forEach((fieldName: string) => { + if (this.itemSelected === 'tag') { + this.tagSuccess.nativeElement.style.setProperty(this.formPropertyDictTagS[fieldName], null); + this.tagSuccess.nativeElement.style.setProperty(this.formPropertyDictTagsGlobal[fieldName], null); + } + }); + + this.tagFormW.reset(); + Object.keys(this.formPropertyDictTagW).forEach((fieldName: string) => { + if (this.itemSelected === 'tag') { + this.tagWarning.nativeElement.style.setProperty(this.formPropertyDictTagW[fieldName], null); + this.tagWarning.nativeElement.style.setProperty(this.formPropertyDictTagsGlobal[fieldName], null); + } + }); + + this.tagFormN.reset(); + Object.keys(this.formPropertyDictTagN).forEach((fieldName: string) => { + if (this.itemSelected === 'tag') { + this.tagNeutral.nativeElement.style.setProperty(this.formPropertyDictTagN[fieldName], null); + this.tagNeutral.nativeElement.style.setProperty(this.formPropertyDictTagsGlobal[fieldName], null); + } + }); + + this.tagFormR.reset(); + Object.keys(this.formPropertyDictTagR).forEach((fieldName: string) => { + if (this.itemSelected === 'tag') { + this.tagRemovable.nativeElement.style.setProperty(this.formPropertyDictTagR[fieldName], null); + this.tagHover.nativeElement.style.setProperty(this.formPropertyDictTagR[fieldName], null); + this.tagDisabled.nativeElement.style.setProperty(this.formPropertyDictTagR[fieldName], null); + this.tagRemovable.nativeElement.style.setProperty(this.formPropertyDictTagsGlobal[fieldName], null); + this.tagHover.nativeElement.style.setProperty(this.formPropertyDictTagsGlobal[fieldName], null); + this.tagDisabled.nativeElement.style.setProperty(this.formPropertyDictTagsGlobal[fieldName], null); + } + }); + this.setRatioDefault(); this.changedColorButton = false; this.changedColorPopup = false; + this.changedColorAccordion = false; } changeKindButton(kindValue: number): void { this.kindButton = kindValue; } + changeTag(tagValue: number): void { + this.tagSelected = tagValue; + if (tagValue === 1) { + this.formPropertyDictTag = this.formPropertyDictTagI; + this.ratio = this.ratioTagDefault; + this.ratioTag = this.ratioTagDefault; + this.tagActive = this.tagDefault; + this.tagForm = this.tagFormI; + } + if (tagValue === 2) { + this.formPropertyDictTag = this.formPropertyDictTagD; + this.ratio = this.ratioTagDanger; + this.ratioTag = this.ratioTagDanger; + this.tagActive = this.tagDanger; + this.tagForm = this.tagFormD; + } + if (tagValue === 3) { + this.formPropertyDictTag = this.formPropertyDictTagS; + this.ratio = this.ratioTagSuccess; + this.ratioTag = this.ratioTagSuccess; + this.tagActive = this.tagSuccess; + this.tagForm = this.tagFormS; + } + if (tagValue === 4) { + this.formPropertyDictTag = this.formPropertyDictTagW; + this.ratio = this.ratioTagWarning; + this.ratioTag = this.ratioTagWarning; + this.tagActive = this.tagWarning; + this.tagForm = this.tagFormW; + } + if (tagValue === 5) { + this.formPropertyDictTag = this.formPropertyDictTagN; + this.ratio = this.ratioTagNeutral; + this.ratioTag = this.ratioTagNeutral; + this.tagActive = this.tagNeutral; + this.tagForm = this.tagFormN; + } + if (tagValue === 6) { + this.formPropertyDictTag = this.formPropertyDictTagR; + this.ratio = this.ratioTagRemovable; + this.ratioTag = this.ratioTagRemovable; + this.tagActive = this.tagRemovable; + this.tagForm = this.tagFormR; + } + } + copyToClipboard() { const fieldJsonElement = document.querySelector('#fieldsCSS'); @@ -920,6 +1346,35 @@ export class ThemeBuilderComponent implements AfterViewInit, OnInit { this.popupForm.valueChanges.subscribe(changes => this.checkChangesPopup(changes)); this.popupContainerForm.valueChanges.subscribe(changes => this.checkChangesPopupContainer(changes)); this.checkboxForm.valueChanges.subscribe(changes => this.checkChangesCheckbox(changes)); + this.multiselectForm.valueChanges.subscribe(changes => this.checkChangesMultiselect(changes)); + this.comboForm.valueChanges.subscribe(changes => this.checkChangesCombo(changes)); + this.accordionForm.valueChanges.subscribe(changes => this.checkChangesAccordion(changes)); + this.breadcrumbForm.valueChanges.subscribe(changes => this.checkChangesBreadcrumb(changes)); + this.tagFormI.valueChanges.subscribe(changes => { + this.resultTagI = ''; + this.checkChangesTag(changes); + }); + this.tagFormD.valueChanges.subscribe(changes => { + this.resultTagD = ''; + this.checkChangesTag(changes); + }); + this.tagFormS.valueChanges.subscribe(changes => { + this.resultTagS = ''; + this.checkChangesTag(changes); + }); + this.tagFormW.valueChanges.subscribe(changes => { + this.resultTagW = ''; + this.checkChangesTag(changes); + }); + this.tagFormN.valueChanges.subscribe(changes => { + this.resultTagN = ''; + this.checkChangesTag(changes); + }); + this.tagFormR.valueChanges.subscribe(changes => { + this.resultTagR = ''; + this.checkChangesTag(changes); + }); + this.tagsFormGlobal.valueChanges.subscribe(changes => this.checkChangesTagsGlobal(changes)); this.setRatioDefault(); } @@ -955,6 +1410,37 @@ export class ThemeBuilderComponent implements AfterViewInit, OnInit { const popup = this.popupBuilder.poListBoxRef.listboxItemList.nativeElement.children[0].children[0]; this.setColorsBackAndText(popup, this.ratioPopup, '--background', '--color'); } + if (item === 'multiselect') { + this.setColorsBackAndText( + this.multiselectDefault.nativeElement, + this.ratioMultiselect, + '--background', + '--text-color-placeholder' + ); + } + if (item === 'combo') { + this.setColorsBackAndText(this.comboDefault.nativeElement, this.ratioCombo); + } + if (item === 'accordion') { + this.setColorsBackAndText( + this.accordionDefault.nativeElement, + this.ratioAccordion, + '--background-color', + '--color' + ); + } + if (item === 'tag') { + this.tagSelected = 1; + this.tagActive = this.tagDefault; + this.formPropertyDictTag = this.formPropertyDictTagI; + this.tagForm = this.tagFormI; + this.setColorsBackAndText( + this.tagDefault.nativeElement, + this.ratioTagDefault, + '--color-info', + '--text-color-info' + ); + } } switchIndividual() { @@ -983,6 +1469,11 @@ export class ThemeBuilderComponent implements AfterViewInit, OnInit { this.tooltipView = true; this.popupView = true; this.checkboxView = true; + this.multiselectView = true; + this.accordionView = true; + this.breadcrumbView = true; + this.comboView = true; + this.tagView = true; } else { this.botaoPrimaryView = false; this.switchView = false; @@ -998,6 +1489,11 @@ export class ThemeBuilderComponent implements AfterViewInit, OnInit { this.tooltipView = false; this.popupView = false; this.checkboxView = false; + this.multiselectView = false; + this.accordionView = false; + this.breadcrumbView = false; + this.comboView = false; + this.tagView = false; } } @@ -1016,7 +1512,12 @@ export class ThemeBuilderComponent implements AfterViewInit, OnInit { this.linkView || this.tooltipView || this.popupView || - this.checkboxView + this.checkboxView || + this.multiselectView || + this.comboView || + this.accordionView || + this.breadcrumbView || + this.tagView ); } @@ -1085,7 +1586,7 @@ export class ThemeBuilderComponent implements AfterViewInit, OnInit { if (changes[fieldName]) { document.getElementById('myPortal').style.setProperty(this.formPropertyS[fieldName], value); const colorBack = getComputedStyle(document.querySelector('po-page-default')).getPropertyValue( - '--color-secondary' + '--color-action-default' ); if (!this.changedColorButton) { this.ratioButton = this.setRatioComponent(this.changedColorButton, colorBack, '#ffffff'); @@ -1093,6 +1594,9 @@ export class ThemeBuilderComponent implements AfterViewInit, OnInit { if (!this.changedColorPopup) { this.ratioPopup = this.setRatioComponent(this.changedColorPopup, colorBack, '#ffffff'); } + if (!this.changedColorAccordion) { + this.ratioAccordion = this.setRatioComponent(this.changedColorAccordion, '#ffffff', colorBack); + } } }); } @@ -1806,6 +2310,252 @@ export class ThemeBuilderComponent implements AfterViewInit, OnInit { } } + private checkChangesMultiselect(changes: { [key: string]: string }): void { + if (!this.isEmpty(changes)) { + this.resultMultiselect['nativeElement'].innerHTML = 'po-multiselect {
'; + + Object.keys(changes).forEach((fieldName: string) => { + let value; + if (typeof changes[fieldName] === 'number') { + value = `${changes[fieldName]}px`; + } else { + value = /color/i.test(fieldName) ? changes[fieldName] : `var(--${changes[fieldName]})`; + } + if (changes[fieldName]) { + this.multiselectComponent.inputElement.nativeElement.style.setProperty( + this.formPropertyDictMultiselect[fieldName], + value + ); + this.multiselectDefault.nativeElement.style.setProperty(this.formPropertyDictMultiselect[fieldName], value); + this.multiselectHover.inputElement.nativeElement.style.setProperty( + this.formPropertyDictMultiselect[fieldName], + value + ); + this.multiselectFocus.inputElement.nativeElement.style.setProperty( + this.formPropertyDictMultiselect[fieldName], + value + ); + this.multiselectDisabled.inputElement.nativeElement.style.setProperty( + this.formPropertyDictMultiselect[fieldName], + value + ); + + this.resultMultiselect[ + 'nativeElement' + ].innerHTML += `${this.formPropertyDictMultiselect[fieldName]}: ${value};
`; + this.ratio = this.ratioMultiselect = this.checkChangesContrast( + changes, + fieldName, + this.ratioMultiselect, + 'colorBackground' + ); + } + }); + + this.resultMultiselect['nativeElement'].innerHTML += '}'; + } else { + this.resultMultiselect['nativeElement'].innerHTML = ''; + } + } + + private checkChangesCombo(changes: { [key: string]: string }): void { + if (!this.isEmpty(changes)) { + this.resultCombo['nativeElement'].innerHTML = 'po-combo {
'; + + Object.keys(changes).forEach((fieldName: string) => { + let value; + if (typeof changes[fieldName] === 'number') { + value = `${changes[fieldName]}px`; + } else { + value = /color/i.test(fieldName) ? changes[fieldName] : `var(--${changes[fieldName]})`; + } + if (changes[fieldName]) { + this.comboComponent.inputEl.nativeElement.style.setProperty(this.formPropertyDictCombo[fieldName], value); + this.comboDefault.nativeElement.style.setProperty(this.formPropertyDictCombo[fieldName], value); + this.comboHover.inputEl.nativeElement.style.setProperty(this.formPropertyDictCombo[fieldName], value); + this.comboHover.iconElement.nativeElement.style.setProperty(this.formPropertyDictCombo[fieldName], value); + this.comboFocus.inputEl.nativeElement.style.setProperty(this.formPropertyDictCombo[fieldName], value); + this.comboFocus.iconElement.nativeElement.style.setProperty(this.formPropertyDictCombo[fieldName], value); + this.comboDisabled.inputEl.nativeElement.style.setProperty(this.formPropertyDictCombo[fieldName], value); + + this.resultCombo['nativeElement'].innerHTML += `${this.formPropertyDictCombo[fieldName]}: ${value};
`; + this.ratio = this.ratioCombo = this.checkChangesContrast( + changes, + fieldName, + this.ratioCombo, + 'colorBackground' + ); + } + }); + + this.resultCombo['nativeElement'].innerHTML += '}'; + } else { + this.resultCombo['nativeElement'].innerHTML = ''; + } + } + + private checkChangesAccordion(changes: { [key: string]: string }): void { + if (!this.isEmpty(changes)) { + this.resultAccordion['nativeElement'].innerHTML = 'po-accordion {
'; + + Object.keys(changes).forEach((fieldName: string) => { + let value; + if (typeof changes[fieldName] === 'number') { + value = `${changes[fieldName]}px`; + } else { + value = /color/i.test(fieldName) ? changes[fieldName] : `var(--${changes[fieldName]})`; + } + if (changes[fieldName]) { + this.accordionComponent.accordionsHeader + .toArray()[0] + .accordionElement.nativeElement.style.setProperty(this.formPropertyDictAccordion[fieldName], value); + this.accordionDefault.nativeElement.style.setProperty(this.formPropertyDictAccordion[fieldName], value); + this.accordionHover.accordionsHeader + .toArray()[0] + .accordionElement.nativeElement.style.setProperty(this.formPropertyDictAccordion[fieldName], value); + this.accordionFocus.accordionsHeader + .toArray()[0] + .accordionElement.nativeElement.style.setProperty(this.formPropertyDictAccordion[fieldName], value); + this.accordionPressed.accordionsHeader + .toArray()[0] + .accordionElement.nativeElement.style.setProperty(this.formPropertyDictAccordion[fieldName], value); + this.accordionDisabled.accordionsHeader + .toArray()[0] + .accordionElement.nativeElement.style.setProperty(this.formPropertyDictAccordion[fieldName], value); + + this.resultAccordion[ + 'nativeElement' + ].innerHTML += `${this.formPropertyDictAccordion[fieldName]}: ${value};
`; + this.ratio = this.ratioAccordion = this.checkChangesContrast( + changes, + fieldName, + this.ratioAccordion, + 'colorBackground' + ); + if (fieldName === 'textColor') { + this.changedColorAccordion = true; + } + } + }); + + this.resultAccordion['nativeElement'].innerHTML += '}'; + } else { + this.resultAccordion['nativeElement'].innerHTML = ''; + } + } + + private checkChangesBreadcrumb(changes: { [key: string]: string }): void { + if (!this.isEmpty(changes)) { + this.resultBreadcrumb['nativeElement'].innerHTML = 'po-breadcrumb {
'; + + Object.keys(changes).forEach((fieldName: string) => { + let value; + if (typeof changes[fieldName] === 'number') { + value = `${changes[fieldName]}px`; + } else { + value = /color/i.test(fieldName) ? changes[fieldName] : `var(--${changes[fieldName]})`; + } + if (changes[fieldName]) { + this.breadcrumbComponent.breadcrumbElement.nativeElement.style.setProperty( + this.formPropertyDictBreadcrumb[fieldName], + value + ); + this.breadcrumbDefault.nativeElement.style.setProperty(this.formPropertyDictBreadcrumb[fieldName], value); + + this.resultBreadcrumb[ + 'nativeElement' + ].innerHTML += `${this.formPropertyDictBreadcrumb[fieldName]}: ${value};
`; + } + }); + + this.resultBreadcrumb['nativeElement'].innerHTML += '}'; + } else { + this.resultBreadcrumb['nativeElement'].innerHTML = ''; + } + } + + private checkChangesTag(changes: { [key: string]: string }): void { + if (!this.isEmpty(changes)) { + this.resultTag['nativeElement'].innerHTML = 'po-tag {
'; + Object.keys(changes).forEach((fieldName: string) => { + let value; + if (typeof changes[fieldName] === 'number') { + value = `${changes[fieldName]}px`; + } else { + value = /color/i.test(fieldName) ? changes[fieldName] : `var(--${changes[fieldName]})`; + } + if (changes[fieldName]) { + this.tagActive.nativeElement.style.setProperty(this.formPropertyDictTag[fieldName], value); + + this.ratio = this.ratioTag = this.checkChangesContrast(changes, fieldName, this.ratioTag, 'backgroundColor'); + if (this.tagSelected === 1) { + this.tagComponent.poTag.nativeElement.style.setProperty(this.formPropertyDictTag[fieldName], value); + this.ratioTagDefault = this.ratioTag; + this.resultTagI += `${this.formPropertyDictTag[fieldName]}: ${value};
`; + } else if (this.tagSelected === 2) { + this.ratioTagDanger = this.ratioTag; + this.resultTagD += `${this.formPropertyDictTag[fieldName]}: ${value};
`; + } else if (this.tagSelected === 3) { + this.ratioTagSuccess = this.ratioTag; + this.resultTagS += `${this.formPropertyDictTag[fieldName]}: ${value};
`; + } else if (this.tagSelected === 4) { + this.ratioTagWarning = this.ratioTag; + this.resultTagW += `${this.formPropertyDictTag[fieldName]}: ${value};
`; + } else if (this.tagSelected === 5) { + this.ratioTagNeutral = this.ratioTag; + this.resultTagN += `${this.formPropertyDictTag[fieldName]}: ${value};
`; + } else if (this.tagSelected === 6) { + this.ratioTagRemovable = this.ratioTag; + this.resultTagR += `${this.formPropertyDictTag[fieldName]}: ${value};
`; + this.tagHover.nativeElement.style.setProperty(this.formPropertyDictTag[fieldName], value); + this.tagDisabled.nativeElement.style.setProperty(this.formPropertyDictTag[fieldName], value); + } + this.resultTag['nativeElement'].innerHTML = `po-tag {
${this.resultTagI || ''}${this.resultTagD || ''}${ + this.resultTagS || '' + }${this.resultTagW || ''}${this.resultTagN || ''}${this.resultTagR || ''}`; + } + }); + + this.resultTag['nativeElement'].innerHTML += '}'; + } else { + this.resultTag['nativeElement'].innerHTML = ''; + } + } + + private checkChangesTagsGlobal(changes: { [key: string]: string }): void { + if (!this.isEmpty(changes)) { + this.resultTagsGlobal['nativeElement'].innerHTML = 'po-tag {
'; + + Object.keys(changes).forEach((fieldName: string) => { + let value; + if (typeof changes[fieldName] === 'number') { + value = `${changes[fieldName]}px`; + } else { + value = /color/i.test(fieldName) ? changes[fieldName] : `var(--${changes[fieldName]})`; + } + if (changes[fieldName]) { + this.tagComponent.poTag.nativeElement.style.setProperty(this.formPropertyDictTagsGlobal[fieldName], value); + this.tagDefault.nativeElement.style.setProperty(this.formPropertyDictTagsGlobal[fieldName], value); + this.tagSuccess.nativeElement.style.setProperty(this.formPropertyDictTagsGlobal[fieldName], value); + this.tagDanger.nativeElement.style.setProperty(this.formPropertyDictTagsGlobal[fieldName], value); + this.tagWarning.nativeElement.style.setProperty(this.formPropertyDictTagsGlobal[fieldName], value); + this.tagNeutral.nativeElement.style.setProperty(this.formPropertyDictTagsGlobal[fieldName], value); + this.tagRemovable.nativeElement.style.setProperty(this.formPropertyDictTagsGlobal[fieldName], value); + this.tagHover.nativeElement.style.setProperty(this.formPropertyDictTagsGlobal[fieldName], value); + this.tagDisabled.nativeElement.style.setProperty(this.formPropertyDictTagsGlobal[fieldName], value); + + this.resultTagsGlobal[ + 'nativeElement' + ].innerHTML += `${this.formPropertyDictTagsGlobal[fieldName]}: ${value};
`; + } + }); + + this.resultTagsGlobal['nativeElement'].innerHTML += '}'; + } else { + this.resultTagsGlobal['nativeElement'].innerHTML = ''; + } + } + private checkChanges() { return ( !!this.resultButtonD?.['nativeElement']?.innerHTML || @@ -1815,6 +2565,11 @@ export class ThemeBuilderComponent implements AfterViewInit, OnInit { !!this.resultDisclaimer?.['nativeElement']?.innerHTML || !!this.resultSwitch?.['nativeElement']?.innerHTML || !!this.resultSelect?.['nativeElement']?.innerHTML || + !!this.resultMultiselect?.['nativeElement']?.innerHTML || + !!this.resultCombo?.['nativeElement']?.innerHTML || + !!this.resultAccordion?.['nativeElement']?.innerHTML || + !!this.resultTag?.['nativeElement']?.innerHTML || + !!this.resultTagsGlobal?.['nativeElement']?.innerHTML || !!this.resultTextarea?.['nativeElement']?.innerHTML || !!this.resultDropdown?.['nativeElement']?.innerHTML || !!this.resultDatepicker?.['nativeElement']?.innerHTML || @@ -1851,13 +2606,20 @@ export class ThemeBuilderComponent implements AfterViewInit, OnInit { private setRatioDefault() { this.ratioButton = this.setRatioComponent(false, '#2c3739', '#ffffff'); this.ratioDisclaimer = this.setRatioComponent(false, '#f2eaf6', '#2c3739'); - this.ratioDatepicker = this.ratioTextarea = this.ratioInput = this.ratioSelect = this.setRatioComponent( + this.ratioDatepicker = this.ratioTextarea = this.ratioInput = this.ratioSelect = this.ratioMultiselect = this.ratioCombo = this.setRatioComponent( false, '#fbfbfb', '#1d2426' ); this.ratioTooltip = this.setRatioComponent(false, '#2c3739', '#ffffff'); this.ratioPopup = this.setRatioComponent(false, '#ffffff', '#753399'); + this.ratioAccordion = this.setRatioComponent(false, '#753399', '#ffffff'); + this.ratioTagDefault = this.setRatioComponent(false, '#e3e9f7', '#173782'); + this.ratioTagDanger = this.setRatioComponent(false, '#f6e6e5', '#72211d'); + this.ratioTagSuccess = this.setRatioComponent(false, '#def7ed', '#0f5236'); + this.ratioTagWarning = this.setRatioComponent(false, '#fcf6e3', '#473400'); + this.ratioTagNeutral = this.setRatioComponent(false, '#eceeee', '#2c3739'); + this.ratioTagRemovable = this.setRatioComponent(false, '#f2eaf6', '#2c3739'); this.cdr.detectChanges(); } @@ -1876,7 +2638,12 @@ export class ThemeBuilderComponent implements AfterViewInit, OnInit { !this.linkView || !this.tooltipView || !this.popupView || - !this.checkboxView + !this.checkboxView || + !this.multiselectView || + !this.comboView || + !this.accordionView || + !this.breadcrumbView || + !this.tagView ); } @@ -1895,7 +2662,12 @@ export class ThemeBuilderComponent implements AfterViewInit, OnInit { this.linkView && this.tooltipView && this.popupView && - this.checkboxView + this.checkboxView && + this.multiselectView && + this.comboView && + this.accordionView && + this.breadcrumbView && + this.tagView ); } diff --git a/projects/portal/src/app/tools/tools-dynamic-form/tools-dynamic-form.component.ts b/projects/portal/src/app/tools/tools-dynamic-form/tools-dynamic-form.component.ts index 75217a6ac..d68b81684 100644 --- a/projects/portal/src/app/tools/tools-dynamic-form/tools-dynamic-form.component.ts +++ b/projects/portal/src/app/tools/tools-dynamic-form/tools-dynamic-form.component.ts @@ -1,16 +1,15 @@ import { Component, ViewChild } from '@angular/core'; import { NgForm } from '@angular/forms'; -import { trigger, state, style, transition, animate } from '@angular/animations'; import { PoDynamicFormField, - PoTableColumn, - PoTableAction, - PoNotificationService, - PoToasterOrientation, PoModalAction, PoModalComponent, - PoPageAction + PoNotificationService, + PoPageAction, + PoTableAction, + PoTableColumn, + PoToasterOrientation } from '@po-ui/ng-components'; @Component({ @@ -99,7 +98,7 @@ export class ToolsDynamicFormComponent { readonly serviceFields: Array = [ { property: 'searchService', - help: 'https://po-sample-api.fly.dev/v1/heroes', + help: 'https://po-sample-api.onrender.com/v1/heroes', label: 'SearchService', gridColumns: 12, gridLgColumns: 6, @@ -107,7 +106,7 @@ export class ToolsDynamicFormComponent { }, { property: 'optionsService', - help: 'https://po-sample-api.fly.dev/v1/heroes', + help: 'https://po-sample-api.onrender.com/v1/heroes', label: 'OptionsService', gridColumns: 12, gridLgColumns: 6, diff --git a/projects/portal/src/index.html b/projects/portal/src/index.html index acb5cb0bb..a948aaaac 100644 --- a/projects/portal/src/index.html +++ b/projects/portal/src/index.html @@ -197,6 +197,7 @@

+ diff --git a/projects/templates/src/lib/components/po-modal-password-recovery/samples/sample-po-modal-password-recovery-request/sample-po-modal-password-recovery-request.component.ts b/projects/templates/src/lib/components/po-modal-password-recovery/samples/sample-po-modal-password-recovery-request/sample-po-modal-password-recovery-request.component.ts index 9d04b4ffe..edb0c1b51 100644 --- a/projects/templates/src/lib/components/po-modal-password-recovery/samples/sample-po-modal-password-recovery-request/sample-po-modal-password-recovery-request.component.ts +++ b/projects/templates/src/lib/components/po-modal-password-recovery/samples/sample-po-modal-password-recovery-request/sample-po-modal-password-recovery-request.component.ts @@ -10,7 +10,7 @@ export class SamplePoModalPasswordRecoveryRequestComponent { @ViewChild(PoModalPasswordRecoveryComponent) poModalPasswordRecovery: PoModalPasswordRecoveryComponent; type: PoModalPasswordRecoveryType = PoModalPasswordRecoveryType.All; - urlRecovery: string = 'https://po-sample-api.fly.dev/v1/users'; + urlRecovery: string = 'https://po-sample-api.onrender.com/v1/users'; openPasswordRecoveryModal() { this.poModalPasswordRecovery.open(); diff --git a/projects/templates/src/lib/components/po-page-change-password/samples/sample-po-page-change-password-request/sample-po-page-change-password-request.component.html b/projects/templates/src/lib/components/po-page-change-password/samples/sample-po-page-change-password-request/sample-po-page-change-password-request.component.html index 9f2274d8a..ac4b23cb2 100644 --- a/projects/templates/src/lib/components/po-page-change-password/samples/sample-po-page-change-password-request/sample-po-page-change-password-request.component.html +++ b/projects/templates/src/lib/components/po-page-change-password/samples/sample-po-page-change-password-request/sample-po-page-change-password-request.component.html @@ -11,6 +11,6 @@ p-secondary-logo="https://via.placeholder.com/80x24?text=SECONDARY+LOGO" p-token="rzDsQiSYoq" p-url-new-password="https://thf.totvs.com.br/sample/api/new-password" - [p-recovery]="{ url: 'https://po-sample-api.fly.dev/v1/users', type: 'all', contactMail: 'support@mail.com' }" + [p-recovery]="{ url: 'https://po-sample-api.onrender.com/v1/users', type: 'all', contactMail: 'support@mail.com' }" > diff --git a/projects/templates/src/lib/components/po-page-dynamic-detail/po-page-dynamic-detail.component.ts b/projects/templates/src/lib/components/po-page-dynamic-detail/po-page-dynamic-detail.component.ts index 799eefa9c..81425d18d 100644 --- a/projects/templates/src/lib/components/po-page-dynamic-detail/po-page-dynamic-detail.component.ts +++ b/projects/templates/src/lib/components/po-page-dynamic-detail/po-page-dynamic-detail.component.ts @@ -78,30 +78,39 @@ export const poPageDynamicDetailLiteralsDefault = { * * ### Utilização via rota * - * Ao utilizar as rotas para carregar o template, o `page-dynamic-detail` disponibiliza propriedades para - * poder especificar o endpoint dos dados e dos metadados. Exemplo de utilização: + * Ao utilizar as rotas para inicializar o template, o `page-dynamic-detail` disponibiliza propriedades que devem ser fornecidas no arquivo de configuração de rotas da aplicação, para + * poder especificar o endpoint dos dados e dos metadados que serão carregados na inicialização. * - * O componente primeiro irá carregar o metadado da rota definida na propriedade serviceMetadataApi - * e depois irá buscar da rota definida na propriedade serviceLoadApi. - * - * > Caso o servidor retornar um erro ao recuperar o metadados, será repassado o metadados salvo em cache, - * se o cache não existe será disparado uma notificação. + * Exemplo de utilização: * + * Arquivo de configuração de rotas da aplicação: `app-routing.module.ts` * ``` + * const routes: Routes = [ * { * path: 'people/:id', * component: PoPageDynamicDetailComponent, * data: { * serviceApi: 'http://localhost:3000/v1/people', // endpoint dos dados - * serviceMetadataApi: 'http://localhost:3000/v1/metadata', // endpoint dos metadados - * serviceLoadApi: 'http://localhost:3000/load-metadata' // endpoint de customizações dos metadados + * serviceMetadataApi: 'http://localhost:3000/v1/metadata', // endpoint dos metadados utilizando o método HTTP Get + * serviceLoadApi: 'http://localhost:3000/load-metadata' // endpoint de customizações dos metadados utilizando o método HTTP Post * } - * } + * }, + * { + * path: 'home', + * component: HomeExampleComponent + * } + * ]; + * * ``` + * O componente primeiro irá carregar o metadado da rota definida na propriedade serviceMetadataApi + * e depois irá buscar da rota definida na propriedade serviceLoadApi. * * A requisição dos metadados é feita na inicialização do template para buscar os metadados da página passando o * tipo do metadado esperado e a versão cacheada pelo browser. * + * > Caso o servidor retornar um erro ao recuperar os metadados, serão repassados os metadados salvos em cache, + * se o cache não existir será disparada uma notificação. + * * O formato esperado na resposta da requisição está especificado na interface * [PoPageDynamicDetailMetadata](/documentation/po-page-dynamic-detail#po-page-dynamic-detail-metadata). Por exemplo: * diff --git a/projects/templates/src/lib/components/po-page-dynamic-detail/samples/sample-po-page-dynamic-detail-user/sample-po-page-dynamic-detail-user.component.ts b/projects/templates/src/lib/components/po-page-dynamic-detail/samples/sample-po-page-dynamic-detail-user/sample-po-page-dynamic-detail-user.component.ts index 751d15d76..dd41324ee 100644 --- a/projects/templates/src/lib/components/po-page-dynamic-detail/samples/sample-po-page-dynamic-detail-user/sample-po-page-dynamic-detail-user.component.ts +++ b/projects/templates/src/lib/components/po-page-dynamic-detail/samples/sample-po-page-dynamic-detail-user/sample-po-page-dynamic-detail-user.component.ts @@ -8,7 +8,7 @@ import { PoPageDynamicDetailActions, PoPageDynamicDetailField } from '@po-ui/ng- templateUrl: './sample-po-page-dynamic-detail-user.component.html' }) export class SamplePoPageDynamicDetailUserComponent { - public readonly serviceApi = 'https://po-sample-api.fly.dev/v1/people'; + public readonly serviceApi = 'https://po-sample-api.onrender.com/v1/people'; public readonly actions: PoPageDynamicDetailActions = { back: '/documentation/po-page-dynamic-table' diff --git a/projects/templates/src/lib/components/po-page-dynamic-edit/po-page-dynamic-edit.component.ts b/projects/templates/src/lib/components/po-page-dynamic-edit/po-page-dynamic-edit.component.ts index ad5dcc783..7a08b4d1f 100644 --- a/projects/templates/src/lib/components/po-page-dynamic-edit/po-page-dynamic-edit.component.ts +++ b/projects/templates/src/lib/components/po-page-dynamic-edit/po-page-dynamic-edit.component.ts @@ -87,16 +87,14 @@ export const poPageDynamicEditLiteralsDefault = { * * ### Utilização via rota * - * Ao utilizar as rotas para carregar o template, o `page-dynamic-edit` disponibiliza propriedades para - * poder especificar o endpoint dos dados e dos metadados. Exemplo de utilização: + * Ao utilizar as rotas para inicializar o template, o `page-dynamic-edit` disponibiliza propriedades que devem ser fornecidas no arquivo de configuração de rotas da aplicação, para + * poder especificar o endpoint dos dados e dos metadados que serão carregados na inicialização. * - * O componente primeiro irá carregar o metadado da rota definida na propriedade serviceMetadataApi - * e depois irá buscar da rota definida na propriedade serviceLoadApi - * - * > Caso o servidor retornar um erro ao recuperar o metadados, será repassado o metadados salvo em cache, - * se o cache não existe será disparado uma notificação. + * Exemplo de utilização: * + * Arquivo de configuração de rotas da aplicação: `app-routing.module.ts` * ``` + * const routes: Routes = [ * { * path: 'people', * component: PoPageDynamicEditComponent, @@ -105,9 +103,22 @@ export const poPageDynamicEditLiteralsDefault = { * serviceMetadataApi: 'http://localhost:3000/v1/metadata', // endpoint dos metadados utilizando o método HTTP Get * serviceLoadApi: 'http://localhost:3000/load-metadata' // endpoint de customizações dos metadados utilizando o método HTTP Post * } - * } + * }, + * { + * path: 'home', + * component: HomeExampleComponent + * } + * ]; * * ``` + * O componente primeiro irá carregar o metadado da rota definida na propriedade serviceMetadataApi + * e depois irá buscar da rota definida na propriedade serviceLoadApi. + * + * A requisição dos metadados é feita na inicialização do template para buscar os metadados da página passando o + * tipo do metadado esperado e a versão cacheada pelo browser. + * + * > Caso o servidor retornar um erro ao recuperar os metadados, serão repassados os metadados salvos em cache, + * se o cache não existir será disparada uma notificação. * * Para carregar com um recurso já existente, deve-se ser incluído um parâmetro na rota chamado `id`: * diff --git a/projects/templates/src/lib/components/po-page-dynamic-edit/samples/sample-po-page-dynamic-edit-basic/sample-po-page-dynamic-edit-basic.component.html b/projects/templates/src/lib/components/po-page-dynamic-edit/samples/sample-po-page-dynamic-edit-basic/sample-po-page-dynamic-edit-basic.component.html index f34fac1e4..bcc689464 100644 --- a/projects/templates/src/lib/components/po-page-dynamic-edit/samples/sample-po-page-dynamic-edit-basic/sample-po-page-dynamic-edit-basic.component.html +++ b/projects/templates/src/lib/components/po-page-dynamic-edit/samples/sample-po-page-dynamic-edit-basic/sample-po-page-dynamic-edit-basic.component.html @@ -1,6 +1,6 @@ diff --git a/projects/templates/src/lib/components/po-page-dynamic-edit/samples/sample-po-page-dynamic-edit-user/sample-po-page-dynamic-edit-user.component.ts b/projects/templates/src/lib/components/po-page-dynamic-edit/samples/sample-po-page-dynamic-edit-user/sample-po-page-dynamic-edit-user.component.ts index 53826d0da..04c579c6f 100644 --- a/projects/templates/src/lib/components/po-page-dynamic-edit/samples/sample-po-page-dynamic-edit-user/sample-po-page-dynamic-edit-user.component.ts +++ b/projects/templates/src/lib/components/po-page-dynamic-edit/samples/sample-po-page-dynamic-edit-user/sample-po-page-dynamic-edit-user.component.ts @@ -9,7 +9,7 @@ import { PoPageDynamicEditActions, PoPageDynamicEditLiterals } from '@po-ui/ng-t templateUrl: './sample-po-page-dynamic-edit-user.component.html' }) export class SamplePoPageDynamicEditUserComponent { - public readonly serviceApi = 'https://po-sample-api.fly.dev/v1/people'; + public readonly serviceApi = 'https://po-sample-api.onrender.com/v1/people'; public readonly actions: PoPageDynamicEditActions = { save: '/documentation/po-page-dynamic-detail', @@ -63,7 +63,7 @@ export class SamplePoPageDynamicEditUserComponent { }, { property: 'city', - optionsService: 'https://po-sample-api.fly.dev/v1/cities?transform=true', + optionsService: 'https://po-sample-api.onrender.com/v1/cities?transform=true', offsetColumns: 4, gridColumns: 4 } diff --git a/projects/templates/src/lib/components/po-page-dynamic-search/po-page-dynamic-search.component.html b/projects/templates/src/lib/components/po-page-dynamic-search/po-page-dynamic-search.component.html index 68a6adca3..708c735d0 100644 --- a/projects/templates/src/lib/components/po-page-dynamic-search/po-page-dynamic-search.component.html +++ b/projects/templates/src/lib/components/po-page-dynamic-search/po-page-dynamic-search.component.html @@ -1,4 +1,5 @@ diff --git a/projects/templates/src/lib/components/po-page-dynamic-search/po-page-dynamic-search.component.spec.ts b/projects/templates/src/lib/components/po-page-dynamic-search/po-page-dynamic-search.component.spec.ts index 851855d88..ac6e625f6 100644 --- a/projects/templates/src/lib/components/po-page-dynamic-search/po-page-dynamic-search.component.spec.ts +++ b/projects/templates/src/lib/components/po-page-dynamic-search/po-page-dynamic-search.component.spec.ts @@ -246,6 +246,30 @@ describe('PoPageDynamicSearchComponent:', () => { expect(component['convertToFilters']).toHaveBeenCalledWith(filters); }); + it(`onAdvancedSearch: should call 'clearInputSearch' if isAdvancedSearch is true`, () => { + const fakeThis = { + setDisclaimers: () => ['test'], + _disclaimerGroup: { + disclaimers: ['test'] + }, + setFilters: () => {}, + advancedSearch: { + emit: () => {} + }, + poPageList: { + clearInputSearch: () => {} + } + }; + const filteredItems = { filter: 'fakeFilter', optionsService: 'fakeOptionsService' }; + const isAdvancedSearch = true; + + spyOn(fakeThis.poPageList, 'clearInputSearch'); + + component.onAdvancedSearch.call(fakeThis, filteredItems, isAdvancedSearch); + + expect(fakeThis.poPageList.clearInputSearch).toHaveBeenCalled(); + }); + it(`setFilters: should update filters value if the objects are compatible`, () => { const filterThatWillBeApplied = { city: 'Ontario' }; const formattedFilters = [{ property: 'city', value: 'Ontario' }]; diff --git a/projects/templates/src/lib/components/po-page-dynamic-search/po-page-dynamic-search.component.ts b/projects/templates/src/lib/components/po-page-dynamic-search/po-page-dynamic-search.component.ts index 9798f155d..344c7b2ab 100644 --- a/projects/templates/src/lib/components/po-page-dynamic-search/po-page-dynamic-search.component.ts +++ b/projects/templates/src/lib/components/po-page-dynamic-search/po-page-dynamic-search.component.ts @@ -8,7 +8,8 @@ import { PoLanguageService, PoPageFilter, PoDisclaimerGroupRemoveAction, - PoComboOption + PoComboOption, + PoPageListComponent } from '@po-ui/ng-components'; import { capitalizeFirstLetter, getBrowserLanguage } from '../../utils/util'; @@ -44,6 +45,7 @@ type UrlOrPoCustomizationFunction = string | (() => PoPageDynamicSearchOptions); }) export class PoPageDynamicSearchComponent extends PoPageDynamicSearchBaseComponent implements OnInit, OnDestroy { @ViewChild(PoAdvancedFilterComponent, { static: true }) poAdvancedFilter: PoAdvancedFilterComponent; + @ViewChild(PoPageListComponent, { static: true }) poPageList: PoPageListComponent; private loadSubscription: Subscription; @@ -147,7 +149,7 @@ export class PoPageDynamicSearchComponent extends PoPageDynamicSearchBaseCompone this.poAdvancedFilter.open(); } - onAdvancedSearch(filteredItems) { + onAdvancedSearch(filteredItems, isAdvancedSearch?) { const { filter, optionsService } = filteredItems; this._disclaimerGroup.disclaimers = this.setDisclaimers(filter, optionsService); @@ -155,6 +157,10 @@ export class PoPageDynamicSearchComponent extends PoPageDynamicSearchBaseCompone this.setFilters(filter); this.advancedSearch.emit(filter); + + if (isAdvancedSearch) { + this.poPageList.clearInputSearch(); + } } private getDisclaimersWithoutQuickSearch() { diff --git a/projects/templates/src/lib/components/po-page-dynamic-table/po-page-dynamic-table.component.ts b/projects/templates/src/lib/components/po-page-dynamic-table/po-page-dynamic-table.component.ts index 67f78906f..1f3c9f560 100644 --- a/projects/templates/src/lib/components/po-page-dynamic-table/po-page-dynamic-table.component.ts +++ b/projects/templates/src/lib/components/po-page-dynamic-table/po-page-dynamic-table.component.ts @@ -55,16 +55,14 @@ type UrlOrPoCustomizationFunction = string | (() => PoPageDynamicTableOptions); * * ### Utilização via rota * - * Ao utilizar as rotas para carregar o template, o `page-dynamic-table` disponibiliza propriedades para - * poder especificar o endpoint dos dados e dos metadados. Exemplo de utilização: + * Ao utilizar as rotas para inicializar o template, o `page-dynamic-table` disponibiliza propriedades que devem ser fornecidas no arquivo de configuração de rotas da aplicação, para + * poder especificar o endpoint dos dados e dos metadados que serão carregados na inicialização. * - * O componente primeiro irá carregar o metadado da rota definida na propriedade serviceMetadataApi - * e depois irá buscar da rota definida na propriedade serviceLoadApi - * - * > Caso o servidor retornar um erro ao recuperar o metadados, será repassado o metadados salvo em cache, - * se o cache não existe será disparado uma notificação. + * Exemplo de utilização: * + * Arquivo de configuração de rotas da aplicação: `app-routing.module.ts` * ``` + * const routes: Routes = [ * { * path: 'people', * component: PoPageDynamicTableComponent, @@ -73,13 +71,23 @@ type UrlOrPoCustomizationFunction = string | (() => PoPageDynamicTableOptions); * serviceMetadataApi: 'http://localhost:3000/v1/metadata', // endpoint dos metadados utilizando o método HTTP Get * serviceLoadApi: 'http://localhost:3000/load-metadata' // endpoint de customizações dos metadados utilizando o método HTTP Post * } - * } + * }, + * { + * path: 'home', + * component: HomeExampleComponent + * } + * ]; * * ``` + * O componente primeiro irá carregar o metadado da rota definida na propriedade serviceMetadataApi + * e depois irá buscar da rota definida na propriedade serviceLoadApi. * * A requisição dos metadados é feita na inicialização do template para buscar os metadados da página passando o * tipo do metadado esperado e a versão cacheada pelo browser. * + * > Caso o servidor retornar um erro ao recuperar os metadados, serão repassados os metadados salvos em cache, + * se o cache não existir será disparada uma notificação. + * * O formato esperado na resposta da requisição está especificado na interface * [PoPageDynamicTableMetadata](/documentation/po-page-dynamic-table#po-page-dynamic-table-metadata). Por exemplo: * diff --git a/projects/templates/src/lib/components/po-page-dynamic-table/samples/sample-po-page-dynamic-table-basic/sample-po-page-dynamic-table-basic.component.html b/projects/templates/src/lib/components/po-page-dynamic-table/samples/sample-po-page-dynamic-table-basic/sample-po-page-dynamic-table-basic.component.html index 8758bae4c..f3fe9d83b 100644 --- a/projects/templates/src/lib/components/po-page-dynamic-table/samples/sample-po-page-dynamic-table-basic/sample-po-page-dynamic-table-basic.component.html +++ b/projects/templates/src/lib/components/po-page-dynamic-table/samples/sample-po-page-dynamic-table-basic/sample-po-page-dynamic-table-basic.component.html @@ -1,2 +1,2 @@ - + diff --git a/projects/templates/src/lib/components/po-page-dynamic-table/samples/sample-po-page-dynamic-table-drag-and-drop/sample-po-page-dynamic-table-drag-and-drop.component.ts b/projects/templates/src/lib/components/po-page-dynamic-table/samples/sample-po-page-dynamic-table-drag-and-drop/sample-po-page-dynamic-table-drag-and-drop.component.ts index 88db49ec2..055a44b44 100644 --- a/projects/templates/src/lib/components/po-page-dynamic-table/samples/sample-po-page-dynamic-table-drag-and-drop/sample-po-page-dynamic-table-drag-and-drop.component.ts +++ b/projects/templates/src/lib/components/po-page-dynamic-table/samples/sample-po-page-dynamic-table-drag-and-drop/sample-po-page-dynamic-table-drag-and-drop.component.ts @@ -5,7 +5,7 @@ import { Component } from '@angular/core'; templateUrl: './sample-po-page-dynamic-table-drag-and-drop.component.html' }) export class SamplePoPageDynamicTableDragAndDropComponent { - readonly serviceApi = 'https://po-sample-api.fly.dev/v1/people'; + readonly serviceApi = 'https://po-sample-api.onrender.com/v1/people'; readonly fields: Array = [ { property: 'id', key: true, visible: false }, diff --git a/projects/templates/src/lib/components/po-page-dynamic-table/samples/sample-po-page-dynamic-table-hotels/sample-po-page-dynamic-table-hotels.component.ts b/projects/templates/src/lib/components/po-page-dynamic-table/samples/sample-po-page-dynamic-table-hotels/sample-po-page-dynamic-table-hotels.component.ts index 9cc2194f3..a82618e4c 100644 --- a/projects/templates/src/lib/components/po-page-dynamic-table/samples/sample-po-page-dynamic-table-hotels/sample-po-page-dynamic-table-hotels.component.ts +++ b/projects/templates/src/lib/components/po-page-dynamic-table/samples/sample-po-page-dynamic-table-hotels/sample-po-page-dynamic-table-hotels.component.ts @@ -14,7 +14,7 @@ import { export class SamplePoPageDynamicTableHotelsComponent { @ViewChild('hotelDetailModal') hotelDetailModal!: PoModalComponent; - readonly serviceApi = 'https://po-sample-api.fly.dev/v1/hotels'; + readonly serviceApi = 'https://po-sample-api.onrender.com/v1/hotels'; actionsRight = true; detailedHotel: any; diff --git a/projects/templates/src/lib/components/po-page-dynamic-table/samples/sample-po-page-dynamic-table-people/sample-po-page-dynamic-table-people.component.ts b/projects/templates/src/lib/components/po-page-dynamic-table/samples/sample-po-page-dynamic-table-people/sample-po-page-dynamic-table-people.component.ts index c551a7ea5..c25181d25 100644 --- a/projects/templates/src/lib/components/po-page-dynamic-table/samples/sample-po-page-dynamic-table-people/sample-po-page-dynamic-table-people.component.ts +++ b/projects/templates/src/lib/components/po-page-dynamic-table/samples/sample-po-page-dynamic-table-people/sample-po-page-dynamic-table-people.component.ts @@ -5,7 +5,7 @@ import { Component } from '@angular/core'; templateUrl: './sample-po-page-dynamic-table-people.component.html' }) export class SamplePoPageDynamicTablePeopleComponent { - readonly serviceApi = 'https://po-sample-api.fly.dev/v1/people'; + readonly serviceApi = 'https://po-sample-api.onrender.com/v1/people'; readonly fields: Array = [ { property: 'id', key: true, visible: false }, diff --git a/projects/templates/src/lib/components/po-page-dynamic-table/samples/sample-po-page-dynamic-table-users/sample-po-page-dynamic-table-users.component.ts b/projects/templates/src/lib/components/po-page-dynamic-table/samples/sample-po-page-dynamic-table-users/sample-po-page-dynamic-table-users.component.ts index e59dde42a..79dfec841 100644 --- a/projects/templates/src/lib/components/po-page-dynamic-table/samples/sample-po-page-dynamic-table-users/sample-po-page-dynamic-table-users.component.ts +++ b/projects/templates/src/lib/components/po-page-dynamic-table/samples/sample-po-page-dynamic-table-users/sample-po-page-dynamic-table-users.component.ts @@ -1,4 +1,4 @@ -import { Component, ViewChild, OnInit } from '@angular/core'; +import { Component, OnInit, ViewChild } from '@angular/core'; import { PoBreadcrumb, PoDynamicViewField, PoModalComponent } from '@po-ui/ng-components'; @@ -20,7 +20,7 @@ export class SamplePoPageDynamicTableUsersComponent implements OnInit { @ViewChild('userDetailModal') userDetailModal!: PoModalComponent; @ViewChild('dependentsModal') dependentsModal!: PoModalComponent; - readonly serviceApi = 'https://po-sample-api.fly.dev/v1/people'; + readonly serviceApi = 'https://po-sample-api.onrender.com/v1/people'; actionsRight = false; detailedUser: any; diff --git a/projects/templates/src/lib/components/po-page-job-scheduler/po-page-job-scheduler-base.component.ts b/projects/templates/src/lib/components/po-page-job-scheduler/po-page-job-scheduler-base.component.ts index ceb9636b0..5c1d0b0b0 100644 --- a/projects/templates/src/lib/components/po-page-job-scheduler/po-page-job-scheduler-base.component.ts +++ b/projects/templates/src/lib/components/po-page-job-scheduler/po-page-job-scheduler-base.component.ts @@ -1,5 +1,5 @@ import { AbstractControl } from '@angular/forms'; -import { Input, Directive, OnDestroy } from '@angular/core'; +import { Input, Directive, OnDestroy, Output, EventEmitter } from '@angular/core'; import { PoBreadcrumb, PoDynamicFormField, PoStepperOrientation } from '@po-ui/ng-components'; @@ -219,6 +219,25 @@ export class PoPageJobSchedulerBaseComponent implements OnDestroy { */ @Input('p-before-send') beforeSendAction: (model: PoJobSchedulerInternal) => PoJobSchedulerInternal; + /** + * @optional + * + * @description + * + * Evento disparado ao concluir o processo de agendamento com sucesso. + */ + @Output('p-success') success = new EventEmitter(); + + /** + * @optional + * + * @description + * + * Evento disparado ao ocorrer um erro impossibilitando a conclusão do agendamento. + * Para este evento será passado como parâmetro os detalhes do erro. + */ + @Output('p-error') error = new EventEmitter(); + model: PoJobSchedulerInternal = new PoPageJobSchedulerInternal(); private _subscription = new Subscription(); diff --git a/projects/templates/src/lib/components/po-page-job-scheduler/po-page-job-scheduler.component.spec.ts b/projects/templates/src/lib/components/po-page-job-scheduler/po-page-job-scheduler.component.spec.ts index f5d1fddb1..9a580a5d1 100644 --- a/projects/templates/src/lib/components/po-page-job-scheduler/po-page-job-scheduler.component.spec.ts +++ b/projects/templates/src/lib/components/po-page-job-scheduler/po-page-job-scheduler.component.spec.ts @@ -1,7 +1,16 @@ -import { ComponentFixture, fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing'; +import { + ComponentFixture, + discardPeriodicTasks, + fakeAsync, + flush, + flushMicrotasks, + TestBed, + tick, + waitForAsync +} from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; -import { Observable, of } from 'rxjs'; +import { delay, Observable, of, throwError } from 'rxjs'; import { changeBrowserInnerWidth } from './../../util-test/util-expect.spec'; import { getObservable } from '../../util-test/util-expect.spec'; @@ -433,17 +442,49 @@ describe('PoPageJobSchedulerComponent:', () => { }); }); - it(`emitSuccessMessage: should call 'poNotification.success' with message and call 'resetJobSchedulerForm'`, async () => { - const message = 'msgSuccess'; + it('should emit success event, show notification, and reset form on successful save', fakeAsync(() => { + const model = { + periodicity: 'always', + firstExecution: new Date(), + firstExecutionHour: '23:55:00', + recurrent: true + }; + const parameters = ['']; + const successSpy = spyOn(component.success, 'emit').and.callThrough(); spyOn(component['poNotification'], 'success'); spyOn(component, 'resetJobSchedulerForm'); + spyOn(component['poPageJobSchedulerService'], 'createResource').and.returnValue(getObservable(parameters)); - await component['emitSuccessMessage'](message, of()); + component['save'](model, null); + + tick(50); - expect(component['poNotification'].success).toHaveBeenCalledWith(message); expect(component['resetJobSchedulerForm']).toHaveBeenCalled(); - }); + expect(component['poNotification'].success).toHaveBeenCalled(); + expect(successSpy).toHaveBeenCalled(); + + discardPeriodicTasks(); + })); + + it('should emit error if there is an error in the API return', fakeAsync(() => { + const model = { + periodicity: 'always', + firstExecution: new Date(), + firstExecutionHour: '23:55:00', + recurrent: true + }; + + const errorSpy = spyOn(component.error, 'emit').and.callThrough(); + spyOn(component['poPageJobSchedulerService'], 'createResource').and.returnValue(throwError(() => {})); + + component['save'](model, null); + + tick(50); + expect(errorSpy).toHaveBeenCalled(); + + discardPeriodicTasks(); + })); it(`getParametersByProcess: should call 'getParametersByProcess' with process and set 'component.parameters' with 'parameters'`, fakeAsync(() => { diff --git a/projects/templates/src/lib/components/po-page-job-scheduler/po-page-job-scheduler.component.ts b/projects/templates/src/lib/components/po-page-job-scheduler/po-page-job-scheduler.component.ts index 741204756..cc86e7244 100644 --- a/projects/templates/src/lib/components/po-page-job-scheduler/po-page-job-scheduler.component.ts +++ b/projects/templates/src/lib/components/po-page-job-scheduler/po-page-job-scheduler.component.ts @@ -222,10 +222,15 @@ export class PoPageJobSchedulerComponent extends PoPageJobSchedulerBaseComponent }); } - private async emitSuccessMessage(msgSuccess: any, saveOperation: Observable) { - await saveOperation.toPromise(); - this.poNotification.success(msgSuccess); - this.resetJobSchedulerForm(); + private emitSuccessMessage(msgSuccess: any, saveOperation: Observable) { + saveOperation.subscribe({ + next: () => { + this.success.emit(); + this.poNotification.success(msgSuccess); + this.resetJobSchedulerForm(); + }, + error: e => this.error.emit(e) + }); } private getParametersByProcess(process: any) { diff --git a/projects/templates/src/lib/components/po-page-job-scheduler/samples/sample-po-page-job-scheduler-background-process/sample-po-page-job-scheduler-background-process.component.html b/projects/templates/src/lib/components/po-page-job-scheduler/samples/sample-po-page-job-scheduler-background-process/sample-po-page-job-scheduler-background-process.component.html index 0aefce460..8cbbe1817 100644 --- a/projects/templates/src/lib/components/po-page-job-scheduler/samples/sample-po-page-job-scheduler-background-process/sample-po-page-job-scheduler-background-process.component.html +++ b/projects/templates/src/lib/components/po-page-job-scheduler/samples/sample-po-page-job-scheduler-background-process/sample-po-page-job-scheduler-background-process.component.html @@ -1,5 +1,5 @@ diff --git a/projects/templates/src/lib/components/po-page-login/samples/sample-po-page-login-automatic-service/sample-po-page-login-automatic-service.component.html b/projects/templates/src/lib/components/po-page-login/samples/sample-po-page-login-automatic-service/sample-po-page-login-automatic-service.component.html index f5b0e175a..3f0897cd0 100644 --- a/projects/templates/src/lib/components/po-page-login/samples/sample-po-page-login-automatic-service/sample-po-page-login-automatic-service.component.html +++ b/projects/templates/src/lib/components/po-page-login/samples/sample-po-page-login-automatic-service/sample-po-page-login-automatic-service.component.html @@ -5,7 +5,7 @@
diff --git a/projects/ui/src/lib/components/components.module.ts b/projects/ui/src/lib/components/components.module.ts index 9ca6ea1f3..0f065c3c5 100644 --- a/projects/ui/src/lib/components/components.module.ts +++ b/projects/ui/src/lib/components/components.module.ts @@ -29,6 +29,7 @@ import { PoMenuPanelModule } from './po-menu-panel/po-menu-panel.module'; import { PoMenuModule } from './po-menu/po-menu.module'; import { PoModalModule } from './po-modal/po-modal.module'; import { PoNavbarModule } from './po-navbar/po-navbar.module'; +import { PoOverlayModule } from './po-overlay/po-overlay.module'; import { PoPageModule } from './po-page/po-page.module'; import { PoPageSlideModule } from './po-page/po-page-slide/po-page-slide.module'; import { PoSwitchModule } from './po-field/po-switch/po-switch.module'; @@ -45,6 +46,7 @@ import { PoTreeViewModule } from './po-tree-view/po-tree-view.module'; import { PoWidgetModule } from './po-widget/po-widget.module'; import { PoSearchModule } from './po-search'; import { PoMessageHourModule } from './po-message-hour'; +import { PoBadgeModule } from './po-badge/po-badge.module'; @NgModule({ imports: [ @@ -74,6 +76,7 @@ import { PoMessageHourModule } from './po-message-hour'; PoMenuPanelModule, PoModalModule, PoNavbarModule, + PoOverlayModule, PoPageModule, PoPopoverModule, PoPopupModule, @@ -92,7 +95,8 @@ import { PoMessageHourModule } from './po-message-hour'; PoPageSlideModule, PoSwitchModule, PoSearchModule, - PoMessageHourModule + PoMessageHourModule, + PoBadgeModule ], exports: [ PoAccordionModule, @@ -121,6 +125,7 @@ import { PoMessageHourModule } from './po-message-hour'; PoMenuPanelModule, PoModalModule, PoNavbarModule, + PoOverlayModule, PoPageModule, PoPopoverModule, PoPopupModule, @@ -139,7 +144,8 @@ import { PoMessageHourModule } from './po-message-hour'; PoPageSlideModule, PoSwitchModule, PoSearchModule, - PoMessageHourModule + PoMessageHourModule, + PoBadgeModule ], providers: [], bootstrap: [], diff --git a/projects/ui/src/lib/components/index.ts b/projects/ui/src/lib/components/index.ts index 3747125d4..e8cfb73ec 100644 --- a/projects/ui/src/lib/components/index.ts +++ b/projects/ui/src/lib/components/index.ts @@ -2,6 +2,7 @@ export * from './components.module'; export * from './po-accordion/index'; export * from './po-avatar/index'; +export * from './po-badge/index'; export * from './po-breadcrumb/index'; export * from './po-button-group/index'; export * from './po-button/index'; @@ -29,6 +30,7 @@ export * from './po-menu-panel/index'; export * from './po-menu/index'; export * from './po-modal/index'; export * from './po-navbar/index'; +export * from './po-overlay/index'; export * from './po-page/index'; export * from './po-page/po-page-slide/index'; export * from './po-popover/index'; diff --git a/projects/ui/src/lib/components/po-accordion/po-accordion-item-header/po-accordion-item-header.component.html b/projects/ui/src/lib/components/po-accordion/po-accordion-item-header/po-accordion-item-header.component.html index f1fd8eddf..788f4b49b 100644 --- a/projects/ui/src/lib/components/po-accordion/po-accordion-item-header/po-accordion-item-header.component.html +++ b/projects/ui/src/lib/components/po-accordion/po-accordion-item-header/po-accordion-item-header.component.html @@ -1,5 +1,6 @@
diff --git a/projects/ui/src/lib/components/po-disclaimer-group/po-disclaimer-group-base.component.spec.ts b/projects/ui/src/lib/components/po-disclaimer-group/po-disclaimer-group-base.component.spec.ts index 152a75f97..8fbb40d1b 100644 --- a/projects/ui/src/lib/components/po-disclaimer-group/po-disclaimer-group-base.component.spec.ts +++ b/projects/ui/src/lib/components/po-disclaimer-group/po-disclaimer-group-base.component.spec.ts @@ -225,32 +225,6 @@ describe('PoDisclaimerGroupBaseComponent:', () => { expect(component.removeAll.emit).toHaveBeenCalledWith(validDisclaimers); }); - it('onCloseAction: should remove disclaimer and emit current disclaimers', fakeAsync(() => { - spyOn(component.change, 'emit'); - - const disclaimerToRemove = { value: 'north', label: 'Region', property: 'region', hideClose: false }; - const currentDisclaimers = [component.disclaimers[0], component.disclaimers[1]]; - - component.onCloseAction(disclaimerToRemove); - - tick(); - - expect(component.disclaimers).toEqual(currentDisclaimers); - expect(component.change.emit).toHaveBeenCalledWith(component.disclaimers); - })); - - it('onCloseAction: should emit removedDisclaimer and currentDisclaimers in remove action', () => { - spyOn(component.remove, 'emit'); - - const removedDisclaimer = { value: 'north', label: 'Region', property: 'region', hideClose: false }; - const currentDisclaimers = [component.disclaimers[0], component.disclaimers[1]]; - - component.onCloseAction(removedDisclaimer); - - expect(component.disclaimers).toEqual(currentDisclaimers); - expect(component.remove.emit).toHaveBeenCalledWith({ currentDisclaimers, removedDisclaimer }); - }); - it('checkDisclaimers: should return only valid disclaimers.', () => { const checkedDisclaimers = component['checkDisclaimers']([...validDisclaimers]); diff --git a/projects/ui/src/lib/components/po-disclaimer-group/po-disclaimer-group-base.component.ts b/projects/ui/src/lib/components/po-disclaimer-group/po-disclaimer-group-base.component.ts index b87bcf65a..10447011f 100644 --- a/projects/ui/src/lib/components/po-disclaimer-group/po-disclaimer-group-base.component.ts +++ b/projects/ui/src/lib/components/po-disclaimer-group/po-disclaimer-group-base.component.ts @@ -1,8 +1,8 @@ -import { DoCheck, EventEmitter, Input, IterableDiffers, Output, Directive, ChangeDetectorRef } from '@angular/core'; +import { ChangeDetectorRef, Directive, DoCheck, EventEmitter, Input, IterableDiffers, Output } from '@angular/core'; -import { convertToBoolean, isKeyCodeEnter, uuid } from '../../utils/util'; -import { PoLanguageService } from '../../services/po-language/po-language.service'; import { poLocaleDefault } from '../../services/po-language/po-language.constant'; +import { PoLanguageService } from '../../services/po-language/po-language.service'; +import { convertToBoolean, isKeyCodeEnter, uuid } from '../../utils/util'; import { PoDisclaimer } from '../po-disclaimer/po-disclaimer.interface'; @@ -140,16 +140,6 @@ export class PoDisclaimerGroupBaseComponent implements DoCheck { this.checkChanges(); } - onCloseAction(disclaimer) { - this.removeDisclaimer(disclaimer); - - this.emitChangeDisclaimers(); - this.remove.emit({ - removedDisclaimer: { ...disclaimer }, - currentDisclaimers: [...this.disclaimers] - }); - } - isRemoveAll() { return !this.hideRemoveAll && this.disclaimers.filter(c => !c.hideClose).length > 1; } @@ -175,11 +165,19 @@ export class PoDisclaimerGroupBaseComponent implements DoCheck { this.removeAll.emit([...removeItems]); } - private removeDisclaimer(disclaimer: any) { + protected removeDisclaimer(disclaimer: any) { const itemIndex = this.disclaimers.findIndex(d => d['$id'] === disclaimer['$id']); this.disclaimers.splice(itemIndex, 1); } + protected emitChangeDisclaimers() { + setTimeout(() => { + this.change.emit(this.disclaimers); + }); + this.previousDisclaimers = [...this._disclaimers]; + this.changeDetector?.detectChanges(); + } + private checkChanges() { if (this.differ) { const changes = this.differ.diff(this.disclaimers); @@ -224,12 +222,4 @@ export class PoDisclaimerGroupBaseComponent implements DoCheck { disclaimer.property !== this.previousDisclaimers[index].property ); } - - private emitChangeDisclaimers() { - setTimeout(() => { - this.change.emit(this.disclaimers); - }); - this.previousDisclaimers = [...this._disclaimers]; - this.changeDetector?.detectChanges(); - } } diff --git a/projects/ui/src/lib/components/po-disclaimer-group/po-disclaimer-group.component.html b/projects/ui/src/lib/components/po-disclaimer-group/po-disclaimer-group.component.html index 810c98341..3ff2e3746 100644 --- a/projects/ui/src/lib/components/po-disclaimer-group/po-disclaimer-group.component.html +++ b/projects/ui/src/lib/components/po-disclaimer-group/po-disclaimer-group.component.html @@ -10,14 +10,12 @@ > - - +
diff --git a/projects/ui/src/lib/components/po-disclaimer-group/po-disclaimer-group.component.spec.ts b/projects/ui/src/lib/components/po-disclaimer-group/po-disclaimer-group.component.spec.ts index bf93a10ff..4aa97ffa9 100644 --- a/projects/ui/src/lib/components/po-disclaimer-group/po-disclaimer-group.component.spec.ts +++ b/projects/ui/src/lib/components/po-disclaimer-group/po-disclaimer-group.component.spec.ts @@ -1,4 +1,4 @@ -import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; +import { ComponentFixture, fakeAsync, flush, TestBed, tick } from '@angular/core/testing'; import { NO_ERRORS_SCHEMA } from '@angular/core'; import { configureTestSuite } from './../../util-test/util-expect.spec'; @@ -51,16 +51,8 @@ describe('PoDisclaimerGroupComponent:', () => { }); }); - it('should be created with 3 disclaimers and default removeAll', () => { - expect(nativeElement.querySelectorAll('po-disclaimer').length).toBe(3); - expect(nativeElement.querySelectorAll('po-tag').length).toBe(1); - }); - - it('should be created with 3 disclaimers and without removeAll disclaimer', () => { - component.hideRemoveAll = true; - fixture.detectChanges(); - expect(nativeElement.querySelectorAll('po-disclaimer').length).toBe(3); - expect(nativeElement.querySelector('.po-disclaimer-danger')).toBeFalsy(); + it('should be created with 3 tags plus tag default removeAll', () => { + expect(nativeElement.querySelectorAll('po-tag').length).toBe(4); }); it('should hide disclaimer-group if there are no disclaimers', () => { @@ -82,7 +74,7 @@ describe('PoDisclaimerGroupComponent:', () => { component.onCloseAction(disclaimers[0]); fixture.detectChanges(); - expect(nativeElement.querySelectorAll('po-disclaimer').length).toBe(2); + expect(nativeElement.querySelectorAll('po-tag').length).toBe(2); }); it('should remove all disclaimers', () => { @@ -92,13 +84,241 @@ describe('PoDisclaimerGroupComponent:', () => { expect(nativeElement.querySelectorAll('po-disclaimer').length).toBe(0); }); + it('should call handleKeyboardNavigationTag after changes', fakeAsync(() => { + const changes: any = { + disclaimers: ['test'] + }; + spyOn(component, 'handleKeyboardNavigationTag'); + + component.ngOnChanges(changes); + tick(); + + expect(component.handleKeyboardNavigationTag).toHaveBeenCalled(); + })); + + it('onCloseAction: should remove disclaimer and emit current disclaimers', fakeAsync(() => { + spyOn(component.change, 'emit'); + spyOn(component, 'focusOnNextTag'); + + const disclaimerToRemove = { value: 'north', label: 'Region', property: 'region', hideClose: false }; + const currentDisclaimers = [component.disclaimers[0], component.disclaimers[1]]; + + component.onCloseAction(disclaimerToRemove); + + tick(); + + expect(component.disclaimers).toEqual(currentDisclaimers); + expect(component.change.emit).toHaveBeenCalledWith(component.disclaimers); + + tick(301); + + expect(component.focusOnNextTag).toHaveBeenCalled(); + })); + + it('onCloseAction: should emit removedDisclaimer and currentDisclaimers in remove action', () => { + spyOn(component.remove, 'emit'); + + const removedDisclaimer = { value: 'north', label: 'Region', property: 'region', hideClose: false }; + const currentDisclaimers = [component.disclaimers[0], component.disclaimers[1]]; + + component.onCloseAction(removedDisclaimer); + + expect(component.disclaimers).toEqual(currentDisclaimers); + expect(component.remove.emit).toHaveBeenCalledWith({ currentDisclaimers, removedDisclaimer }); + }); + + it('should handleKeyDown correctly for Space key', () => { + const event = new KeyboardEvent('keydown', { code: 'Space' }); + + spyOn(event, 'preventDefault'); + spyOn(event, 'stopPropagation'); + + component['handleKeyDown'](event, [], 0); + + expect(event.preventDefault).toHaveBeenCalled(); + expect(event.stopPropagation).toHaveBeenCalled(); + }); + + it('should handleKeyDown correctly for ArrowLeft key', () => { + const event = new KeyboardEvent('keydown', { key: 'ArrowLeft' }); + spyOn(component as any, 'handleArrowLeft'); + + component['handleKeyDown'](event, [], 0); + + expect(component['handleArrowLeft']).toHaveBeenCalled(); + }); + + it('should handleKeyDown correctly for ArrowRight key', () => { + const event = new KeyboardEvent('keydown', { key: 'ArrowRight' }); + spyOn(component as any, 'handleArrowRight'); + + component['handleKeyDown'](event, [], 0); + + expect(component['handleArrowRight']).toHaveBeenCalled(); + }); + + it('should call setTabIndex in next tag if index is 1', () => { + const tagRemoveElements = [ + document.createElement('div'), + document.createElement('div'), + document.createElement('div') + ]; + + const indexArrow = 1; + + spyOn(component, 'setTabIndex' as any); + spyOn(tagRemoveElements[indexArrow + 1], 'focus'); + + component['handleArrowRight'](tagRemoveElements, indexArrow); + + expect(component['setTabIndex']).toHaveBeenCalledWith(tagRemoveElements[indexArrow], -1); + expect(tagRemoveElements[indexArrow + 1].focus).toHaveBeenCalled(); + expect(component['setTabIndex']).toHaveBeenCalledWith(tagRemoveElements[indexArrow + 1], 0); + }); + + it('should call setTabIndex in previous tag if index is 1', () => { + const tagRemoveElements = [ + document.createElement('div'), + document.createElement('div'), + document.createElement('div') + ]; + + const indexArrow = 1; + + spyOn(component, 'setTabIndex' as any); + spyOn(tagRemoveElements[indexArrow - 1], 'focus'); + + component['handleArrowLeft'](tagRemoveElements, indexArrow); + + expect(component['setTabIndex']).toHaveBeenCalledWith(tagRemoveElements[indexArrow], -1); + expect(tagRemoveElements[indexArrow - 1].focus).toHaveBeenCalled(); + expect(component['setTabIndex']).toHaveBeenCalledWith(tagRemoveElements[indexArrow - 1], 0); + }); + + it('should focus on the previous element if the tag length is equal to the closed index', () => { + const tagRemoveElements = [ + document.createElement('div'), + document.createElement('div'), + document.createElement('div') + ]; + const indexClosed = 3; + spyOn(tagRemoveElements[indexClosed - 1], 'focus'); + + component['focusOnRemoveTag'](tagRemoveElements, indexClosed); + + expect(tagRemoveElements[indexClosed - 1].focus).toHaveBeenCalled(); + }); + + it('should focus on the current element if the tag length is not equal to the closed index', () => { + const tagRemoveElements = [ + document.createElement('div'), + document.createElement('div'), + document.createElement('div') + ]; + const indexClosed = 1; + spyOn(tagRemoveElements[indexClosed], 'focus'); + + component['focusOnRemoveTag'](tagRemoveElements, indexClosed); + + expect(tagRemoveElements[indexClosed].focus).toHaveBeenCalled(); + }); + + it('should focus in previous tag if remove next tag ', () => { + const tagRemoveElements = [ + document.createElement('div'), + document.createElement('div'), + document.createElement('div') + ]; + + const initialIndex = 3; + + spyOn(component, 'setTabIndex' as any); + + component['initializeTagRemoveElements'](tagRemoveElements, initialIndex); + + expect(component['setTabIndex']).toHaveBeenCalledWith(tagRemoveElements[initialIndex - 1], 0); + }); + + it('should add keydown event listeners', () => { + const tagRemoveElements = [document.createElement('div')]; + const initialIndex = 0; + const fakeKeyboardEvent = new KeyboardEvent('keydown'); + + spyOn(component as any, 'setTabIndex'); + spyOn(component as any, 'handleKeyDown'); + + component['initializeTagRemoveElements'](tagRemoveElements, initialIndex); + + expect(component['setTabIndex']).toHaveBeenCalledWith(tagRemoveElements[0], 0); + + tagRemoveElements[0].dispatchEvent(fakeKeyboardEvent); + + expect(component['handleKeyDown']).toHaveBeenCalled(); + }); + + it('should add blur event listeners and call setTabIndex', () => { + const tagRemoveElements = [document.createElement('div'), document.createElement('div')]; + const initialIndex = 0; + + spyOn(component as any, 'setTabIndex'); + + component['initializeTagRemoveElements'](tagRemoveElements, initialIndex); + + tagRemoveElements[0].focus(); + tagRemoveElements[0].dispatchEvent(new Event('blur')); + + expect(component['setTabIndex']).toHaveBeenCalledWith(tagRemoveElements[0], -1); + expect(component['setTabIndex']).toHaveBeenCalledWith(tagRemoveElements[1], 0); + }); + + it('should set tab index to 0 for the previous element when initialIndex is not 0', () => { + const tagRemoveElements = [document.createElement('div'), document.createElement('div')]; + const initialIndex = 1; + + spyOn(component as any, 'setTabIndex'); + + component['initializeTagRemoveElements'](tagRemoveElements, initialIndex); + + expect(component['setTabIndex']).toHaveBeenCalledWith(tagRemoveElements[0], 0); + }); + + it('focusOnNextTag: should select attribute unselected with index 0', () => { + const tagsFake = document.createElement('div'); + tagsFake.innerHTML = ` +
+
+
+ `; + + spyOn(component, 'focusOnRemoveTag'); + + component['focusOnNextTag'](0, 'enter'); + + expect(component['focusOnRemoveTag']).toHaveBeenCalled(); + }); + + it('focusOnNextTag: should select attribute unselected whitout index', () => { + const tagsFake = document.createElement('div'); + tagsFake.innerHTML = ` +
+
+
+ `; + + spyOn(component, 'focusOnRemoveTag'); + + component['focusOnNextTag'](null, 'enter'); + + expect(component['focusOnRemoveTag']).toHaveBeenCalled(); + }); + describe('Templates:', () => { it(`should set tabindex to 0 if have a disclaimer with 'hideClose'.`, () => { component.disclaimers = [{ value: 'po', hideClose: false }]; fixture.detectChanges(); - expect(nativeElement.querySelector('.po-disclaimer-remove[tabindex="0"]')).toBeTruthy(); + expect(nativeElement.querySelector('.po-tag-remove[tabindex="0"]')).toBeTruthy(); }); it(`shouldn't set tabindex if disclaimer doesn't have 'hideClose'.`, () => { diff --git a/projects/ui/src/lib/components/po-disclaimer-group/po-disclaimer-group.component.ts b/projects/ui/src/lib/components/po-disclaimer-group/po-disclaimer-group.component.ts index 324a7e208..c4037f327 100644 --- a/projects/ui/src/lib/components/po-disclaimer-group/po-disclaimer-group.component.ts +++ b/projects/ui/src/lib/components/po-disclaimer-group/po-disclaimer-group.component.ts @@ -1,8 +1,20 @@ -import { Component, IterableDiffers, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { + AfterViewInit, + ChangeDetectionStrategy, + ChangeDetectorRef, + Component, + ElementRef, + IterableDiffers, + OnChanges, + SimpleChanges, + inject +} from '@angular/core'; import { PoLanguageService } from '../../services/po-language/po-language.service'; +import { Subscription, fromEvent } from 'rxjs'; import { PoDisclaimerGroupBaseComponent } from './po-disclaimer-group-base.component'; +import { PoDisclaimer } from '../po-disclaimer/po-disclaimer.interface'; /** * @docsExtends PoDisclaimerGroupBaseComponent @@ -31,7 +43,11 @@ import { PoDisclaimerGroupBaseComponent } from './po-disclaimer-group-base.compo templateUrl: './po-disclaimer-group.component.html', changeDetection: ChangeDetectionStrategy.OnPush }) -export class PoDisclaimerGroupComponent extends PoDisclaimerGroupBaseComponent { +export class PoDisclaimerGroupComponent extends PoDisclaimerGroupBaseComponent implements AfterViewInit, OnChanges { + private subscription: Subscription = new Subscription(); + + private el = inject(ElementRef); + constructor( differs: IterableDiffers, languageService: PoLanguageService, @@ -39,4 +55,122 @@ export class PoDisclaimerGroupComponent extends PoDisclaimerGroupBaseComponent { ) { super(differs, languageService, changeDetector); } + + ngAfterViewInit(): void { + this.handleKeyboardNavigationTag(); + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes.disclaimers) { + setTimeout(() => { + this.handleKeyboardNavigationTag(); + }); + } + } + + onCloseAction(disclaimer: PoDisclaimer, event?) { + const index = this.disclaimers.findIndex(option => option.value === disclaimer.value); + + this.removeDisclaimer(disclaimer); + + this.emitChangeDisclaimers(); + this.remove.emit({ + removedDisclaimer: { ...disclaimer }, + currentDisclaimers: [...this.disclaimers] + }); + + setTimeout(() => { + this.focusOnNextTag(index, event); + }, 300); + } + + focusOnNextTag(indexClosed: number, clickOrEnter: string) { + if (clickOrEnter === 'enter') { + const tagRemoveElements: NodeListOf = this.el.nativeElement.querySelectorAll('.po-tag-remove'); + indexClosed = indexClosed || indexClosed === 0 ? indexClosed : tagRemoveElements.length; + this.focusOnRemoveTag(tagRemoveElements, indexClosed); + } else { + indexClosed = 0; + } + this.handleKeyboardNavigationTag(indexClosed); + } + + handleKeyboardNavigationTag(initialIndex = 0) { + this.subscription.unsubscribe(); + this.subscription = new Subscription(); + const tagRemoveElements: NodeListOf = this.el.nativeElement.querySelectorAll('.po-tag-remove'); + this.initializeTagRemoveElements(tagRemoveElements, initialIndex); + } + + private handleArrowLeft(tagRemoveElements, index) { + if (index > 0) { + this.setTabIndex(tagRemoveElements[index], -1); + tagRemoveElements[index - 1].focus(); + this.setTabIndex(tagRemoveElements[index - 1], 0); + } + } + + private handleArrowRight(tagRemoveElements, index) { + if (index < tagRemoveElements.length - 1) { + this.setTabIndex(tagRemoveElements[index], -1); + tagRemoveElements[index + 1].focus(); + this.setTabIndex(tagRemoveElements[index + 1], 0); + } + } + + private setTabIndex(element, tabIndex) { + element.setAttribute('tabindex', tabIndex); + } + + private initializeTagRemoveElements(tagRemoveElements, initialIndex) { + tagRemoveElements.forEach((tagRemoveElement, index) => { + if (index === initialIndex) { + this.setTabIndex(tagRemoveElements[initialIndex], 0); + } else if (tagRemoveElements.length === initialIndex) { + this.setTabIndex(tagRemoveElements[initialIndex - 1], 0); + } else { + this.setTabIndex(tagRemoveElement, -1); + } + + this.subscription.add( + fromEvent(tagRemoveElement, 'keydown').subscribe((event: KeyboardEvent) => { + this.handleKeyDown(event, tagRemoveElements, index); + }) + ); + + if (index !== 0) { + this.subscription.add( + fromEvent(tagRemoveElements, 'blur').subscribe(() => { + this.setTabIndex(tagRemoveElements[index], -1); + this.setTabIndex(tagRemoveElements[0], 0); + }) + ); + } + }); + } + + private handleKeyDown(event: KeyboardEvent, tagRemoveElements, index: number) { + const KEY_SPACE = 'Space'; + const KEY_ARROW_LEFT = 'ArrowLeft'; + const KEY_ARROW_RIGHT = 'ArrowRight'; + + if (event.code === KEY_SPACE) { + event.preventDefault(); + event.stopPropagation(); + } + + if (event.key === KEY_ARROW_LEFT) { + this.handleArrowLeft(tagRemoveElements, index); + } else if (event.key === KEY_ARROW_RIGHT) { + this.handleArrowRight(tagRemoveElements, index); + } + } + + private focusOnRemoveTag(tag: any, indexClosed: number) { + if (tag.length === indexClosed) { + tag[indexClosed - 1]?.focus(); + } else { + tag[indexClosed]?.focus(); + } + } } diff --git a/projects/ui/src/lib/components/po-dynamic/po-dynamic-field-force-component.enum.ts b/projects/ui/src/lib/components/po-dynamic/po-dynamic-field-force-component.enum.ts index db89e8666..b3749c85c 100644 --- a/projects/ui/src/lib/components/po-dynamic/po-dynamic-field-force-component.enum.ts +++ b/projects/ui/src/lib/components/po-dynamic/po-dynamic-field-force-component.enum.ts @@ -1,3 +1,18 @@ +/** + * @usedBy PoDynamicFormComponent + * + * @description + * + * Enum para definição do tipo de componente a ser renderizado. + */ +export enum ForceBooleanComponentEnum { + /** Força a renderização de um po-switch */ + switch = 'switch', + + /** Força a renderização de um po-checkbox */ + checkbox = 'checkbox' +} + /** * @usedBy PoDynamicFormComponent * diff --git a/projects/ui/src/lib/components/po-dynamic/po-dynamic-form/po-dynamic-form-field.interface.ts b/projects/ui/src/lib/components/po-dynamic/po-dynamic-form/po-dynamic-form-field.interface.ts index f0702d3ce..c9c60ca28 100644 --- a/projects/ui/src/lib/components/po-dynamic/po-dynamic-form/po-dynamic-form-field.interface.ts +++ b/projects/ui/src/lib/components/po-dynamic/po-dynamic-form/po-dynamic-form-field.interface.ts @@ -17,7 +17,7 @@ import { PoLookupAdvancedFilter } from '../../po-field/po-lookup/interfaces/po-l import { PoLookupColumn } from '../../po-field/po-lookup/interfaces/po-lookup-column.interface'; import { PoMultiselectOption } from '../../po-field/po-multiselect/po-multiselect-option.interface'; import { PoSelectOption } from '../../po-field/po-select/po-select-option.interface'; -import { ForceOptionComponentEnum } from '../po-dynamic-field-force-component.enum'; +import { ForceBooleanComponentEnum, ForceOptionComponentEnum } from '../po-dynamic-field-force-component.enum'; import { PoDynamicField } from '../po-dynamic-field.interface'; @@ -507,6 +507,15 @@ export interface PoDynamicFormField extends PoDynamicField { * `url + ?page=1&pageSize=20&name=Tony%20Stark,Peter%20Parker,Gohan` */ advancedFilters?: Array; + + /** + * Valores aceitos: + * - ForceBooleanComponentEnum.switch + * - ForceBooleanComponentEnum.checkbox + * + */ + forceBooleanComponentType?: ForceBooleanComponentEnum; + /** * pode ser utilizada em conjunto com a propriedade `options` forçando o componente a renderizar um `po-select` ou `po-radio-group`. * diff --git a/projects/ui/src/lib/components/po-dynamic/po-dynamic-form/po-dynamic-form-fields/po-dynamic-form-fields-base.component.spec.ts b/projects/ui/src/lib/components/po-dynamic/po-dynamic-form/po-dynamic-form-fields/po-dynamic-form-fields-base.component.spec.ts index 6df657f10..37f23e66b 100644 --- a/projects/ui/src/lib/components/po-dynamic/po-dynamic-form/po-dynamic-form-fields/po-dynamic-form-fields-base.component.spec.ts +++ b/projects/ui/src/lib/components/po-dynamic/po-dynamic-form/po-dynamic-form-fields/po-dynamic-form-fields-base.component.spec.ts @@ -7,7 +7,7 @@ import * as PoDynamicUtil from '../../po-dynamic.util'; import { PoDynamicFieldType } from '../../po-dynamic-field-type.enum'; import { PoDynamicFormFieldsBaseComponent } from './po-dynamic-form-fields-base.component'; import { PoDynamicFormField } from '../po-dynamic-form-field.interface'; -import { ForceOptionComponentEnum } from '../../po-dynamic-field-force-component.enum'; +import { ForceBooleanComponentEnum, ForceOptionComponentEnum } from '../../po-dynamic-field-force-component.enum'; describe('PoDynamicFormFieldsBaseComponent:', () => { let component: PoDynamicFormFieldsBaseComponent; @@ -629,6 +629,16 @@ describe('PoDynamicFormFieldsBaseComponent:', () => { expect(component['getComponentControl'](field)).toBe(expectedValue); }); + it('should return checkbox if `forceBooleanComponentType` is checkbox', () => { + const expectedValue = ForceBooleanComponentEnum.checkbox; + const field: PoDynamicFormField = { + property: 'test', + forceBooleanComponentType: ForceBooleanComponentEnum.checkbox + }; + + expect(component['getComponentControl'](field)).toBe(expectedValue); + }); + it('should return select if `forceOptionsComponentType` is select', () => { const expectedValue = ForceOptionComponentEnum.select; const field: PoDynamicFormField = { @@ -650,10 +660,10 @@ describe('PoDynamicFormFieldsBaseComponent:', () => { ] }; - spyOn(component, 'verifyforceOptionComponent').and.callThrough(); + spyOn(component, 'verifyForceOptionComponent').and.callThrough(); expect(component['getComponentControl'](field)).toBe(expectedValue); - expect(component['verifyforceOptionComponent']).toHaveBeenCalled(); + expect(component['verifyForceOptionComponent']).toHaveBeenCalled(); }); it('shouldn`t return select if `forceOptionsComponentType` is select but optionsMulti is true', () => { @@ -682,10 +692,10 @@ describe('PoDynamicFormFieldsBaseComponent:', () => { ] }; - spyOn(component, 'verifyforceOptionComponent').and.callThrough(); + spyOn(component, 'verifyForceOptionComponent').and.callThrough(); expect(component['getComponentControl'](field)).toBe(expectedValue); - expect(component['verifyforceOptionComponent']).toHaveBeenCalled(); + expect(component['verifyForceOptionComponent']).toHaveBeenCalled(); }); it('should return `upload` if type is `upload` and has a `url`', () => { diff --git a/projects/ui/src/lib/components/po-dynamic/po-dynamic-form/po-dynamic-form-fields/po-dynamic-form-fields-base.component.ts b/projects/ui/src/lib/components/po-dynamic/po-dynamic-form/po-dynamic-form-fields/po-dynamic-form-fields-base.component.ts index 04d1dd0e6..25220260e 100644 --- a/projects/ui/src/lib/components/po-dynamic/po-dynamic-form/po-dynamic-form-fields/po-dynamic-form-fields-base.component.ts +++ b/projects/ui/src/lib/components/po-dynamic/po-dynamic-form/po-dynamic-form-fields/po-dynamic-form-fields-base.component.ts @@ -150,7 +150,13 @@ export class PoDynamicFormFieldsBaseComponent { private getComponentControl(field: PoDynamicFormField = {}) { const type = field && field.type ? field.type.toLocaleLowerCase() : 'string'; - const forceOptionComponent = this.verifyforceOptionComponent(field); + const { forceBooleanComponentType } = field; + const forceOptionComponent = this.verifyForceOptionComponent(field); + + if (forceBooleanComponentType) { + return forceBooleanComponentType; + } + if (forceOptionComponent) { const { forceOptionsComponentType } = field; return forceOptionsComponentType; @@ -257,7 +263,7 @@ export class PoDynamicFormFieldsBaseComponent { return url && type === 'upload'; } - private verifyforceOptionComponent(field: PoDynamicFormField) { + private verifyForceOptionComponent(field: PoDynamicFormField) { const { optionsMulti, optionsService, forceOptionsComponentType } = field; if (forceOptionsComponentType && !optionsMulti && !optionsService) { diff --git a/projects/ui/src/lib/components/po-dynamic/po-dynamic-form/po-dynamic-form-fields/po-dynamic-form-fields.component.html b/projects/ui/src/lib/components/po-dynamic/po-dynamic-form/po-dynamic-form-fields/po-dynamic-form-fields.component.html index 39c3bc808..f50f9fce8 100644 --- a/projects/ui/src/lib/components/po-dynamic/po-dynamic-form/po-dynamic-form-fields/po-dynamic-form-fields.component.html +++ b/projects/ui/src/lib/components/po-dynamic/po-dynamic-form/po-dynamic-form-fields/po-dynamic-form-fields.component.html @@ -198,6 +198,20 @@ > + + + +
+
{ expect(newField.value).toEqual(listName); }); + it('transformArrayValue: should return a concatenated string of multiple properties from an array of objects', () => { + const inputArray = [ + { id: 1, name: 'Company1', ssn: '261-81-7609' }, + { id: 2, name: 'Company2', ssn: '527-84-6773' } + ]; + const field = { + property: 'company', + label: 'Company', + fieldLabel: 'name', + fieldValue: 'id', + format: ['id', 'name', 'ssn'] + }; + + const result = component['transformArrayValue'](inputArray, field); + + expect(result).toBe('1 - Company1 - 261-81-7609, 2 - Company2 - 527-84-6773'); + }); + + it('transformArrayValue: should return a concatenated string of properties from a single object', () => { + const inputArray = [{ id: 1, name: 'Company1', ssn: '261-81-7609' }]; + const field = { + property: 'company', + label: 'Company', + fieldLabel: 'name', + fieldValue: 'id', + format: ['id', 'name', 'ssn'] + }; + + const result = component['transformArrayValue'](inputArray, field); + + expect(result).toBe('1 - Company1 - 261-81-7609'); + }); + it(`createField: should call 'transformFieldLabel' and return a fieldLabel property`, () => { const field = { property: 'name', label: 'Nome', fieldLabel: 'title', fieldValue: 'id' }; component.value = { name: 'Test Name', title: 'Title Test', id: 123 }; diff --git a/projects/ui/src/lib/components/po-dynamic/po-dynamic-view/po-dynamic-view-base.component.ts b/projects/ui/src/lib/components/po-dynamic/po-dynamic-view/po-dynamic-view-base.component.ts index faf3ae98b..03c934252 100644 --- a/projects/ui/src/lib/components/po-dynamic/po-dynamic-view/po-dynamic-view-base.component.ts +++ b/projects/ui/src/lib/components/po-dynamic/po-dynamic-view/po-dynamic-view-base.component.ts @@ -259,21 +259,27 @@ export class PoDynamicViewBaseComponent { private transformArrayValue(valueProperty: any, field: PoDynamicViewField) { const valueArray = Array.isArray(valueProperty) ? valueProperty : [valueProperty]; - const arrayWithLabel = valueArray.map(item => ({ - value: item[field.fieldValue] || item.value, - label: item[field.fieldLabel] || item.label - })); - - const labels = arrayWithLabel.map(optionValue => { - if (optionValue.label) { - const labelTranformed = this.transformValue(field.type, optionValue.label, field.format); - if (field.concatLabelValue && optionValue.value) { - return `${labelTranformed} - ${optionValue.value}`; - } else { - return labelTranformed; + let labels: Array; + + if (Array.isArray(field.format)) { + labels = valueArray.map(objectData => this.formatField(objectData, field.format)); + } else { + const arrayWithLabel = valueArray.map(item => ({ + value: item[field.fieldValue] || item.value, + label: item[field.fieldLabel] || item.label + })); + + labels = arrayWithLabel.map(optionValue => { + if (optionValue.label) { + const labelTranformed = this.transformValue(field.type, optionValue.label, field.format); + if (field.concatLabelValue && optionValue.value) { + return `${labelTranformed} - ${optionValue.value}`; + } else { + return labelTranformed; + } } - } - }); + }); + } if (labels[0] !== undefined && labels.join()) { return labels.join(', '); @@ -318,4 +324,20 @@ export class PoDynamicViewBaseComponent { return transformedValue; } + + private formatField(objectSelected, properties) { + let formattedField; + if (Array.isArray(properties)) { + for (const property of properties) { + if (objectSelected && objectSelected[property]) { + if (!formattedField) { + formattedField = objectSelected[property]; + } else { + formattedField += ' - ' + objectSelected[property]; + } + } + } + } + return formattedField; + } } diff --git a/projects/ui/src/lib/components/po-dynamic/po-dynamic-view/po-dynamic-view-field.interface.ts b/projects/ui/src/lib/components/po-dynamic/po-dynamic-view/po-dynamic-view-field.interface.ts index 89f5ad624..77544219a 100644 --- a/projects/ui/src/lib/components/po-dynamic/po-dynamic-view/po-dynamic-view-field.interface.ts +++ b/projects/ui/src/lib/components/po-dynamic/po-dynamic-view/po-dynamic-view-field.interface.ts @@ -96,26 +96,31 @@ export interface PoDynamicViewField extends PoDynamicField { isArrayOrObject?: boolean; /** - * Formato de exibição do valor do campo. - * - * Aplicado para casos específicos de acordo com o tipo do campo. - * - * **types**: - * - `currency`: Aceita valores definidos para a propriedade `currencyCode` do - * [**CurrencyPipe**](https://angular.io/api/common/CurrencyPipe) - * + Exemplos: 'BRL', 'USD'. - * - `date`: Aceita valores definidos para a propriedade `format` do [**DatePipe**](https://angular.io/api/common/DatePipe) - * e também aceita os caracteres de dia(dd), mês(MM) e ano (yyyy ou yy), - * caso não seja informado um formato o mesmo será 'dd/MM/yyyy'. Exemplos: 'dd/MM/yyyy', 'dd-MM-yy', 'mm/dd/yyyy'. - * - `time`: Aceita apenas os caracteres de hora(HH), minutos(mm), segundos(ss) e - * milisegundos(f-ffffff), os milisegundos são opcionais, caso não seja informado um formato o mesmo será - * 'HH:mm:ss'. Exemplos: 'HH:mm', 'HH:mm:ss.ffffff', 'HH:mm:ss.ff', 'mm:ss.fff'. - * - `number`: Aceita valores definidos para a propriedade `digitsInfo` do [**DecimalPipe**](https://angular.io/api/common/DecimalPipe) - * para formatação, e caso não seja informado, o número será exibido na sua forma original. - * - * + Exemplo: com o valor de entrada: `50` e a valor para formatação: `'1.2-5'` o resultado será: `50.00`. + * Define o formato de exibição para o valor de um campo. + * + * - Quando `format` é uma `string`, o formato aplicado depende da propriedade **type** segue como usar cada tipo: + * - `currency`: Utiliza códigos de moeda definidos pelo [CurrencyPipe](https://angular.io/api/common/CurrencyPipe). + * Exemplos: Use 'BRL' para Real Brasileiro e 'USD' para Dólar Americano. + * - `date`: Adota formatos de data especificados pelo [DatePipe](https://angular.io/api/common/DatePipe). + * Suporta formatos personalizados, como dia (dd), mês (MM) e ano (yyyy ou yy). + * Formato padrão é 'dd/MM/yyyy'. Exemplos: 'dd/MM/yyyy', 'dd-MM-yy', 'mm/dd/yyyy'. + * - `time`: Aceita formatos de tempo, incluindo hora (HH), minutos (mm), segundos (ss) e opcionalmente + * milisegundos (f-ffffff). Formato padrão é 'HH:mm:ss'. Exemplos: 'HH:mm', 'HH:mm:ss.ffffff', 'HH:mm:ss.ff'. + * - `number`: Usa especificações do [DecimalPipe](https://angular.io/api/common/DecimalPipe) para formatação numérica. + * Na ausência de um formato específico, o número é exibido como fornecido. + * Exemplo: Entrada `50`, formato `'1.2-5'`, resulta em `50.00`. + * + * - Quando `format` é um `Array`: + * - Cada elemento do array representa uma propriedade do objeto. + * - Os valores dessas propriedades são concatenados, separados pelo padrão ' - '. + * - Exemplo: Para `format: ["id", "name"]` e um objeto `{ id: 1, name: 'Carlos Diego' }`, + * o resultado será `'1 - Carlos Diego'`. + * + * @example Para formatar um campo de moeda, use format: "BRL". + * Para um campo de data, use format: "dd/MM/yyyy". + * Para combinar propriedades de um objeto em um campo, use format: ["id", "name"]. */ - format?: string; + format?: string | Array; /** * Informa a ordem de exibição do campo. @@ -230,4 +235,10 @@ export interface PoDynamicViewField extends PoDynamicField { * [guia de API do PO UI](https://po-ui.io/guides/api). */ searchService?: string | PoDynamicViewRequest; + + /** Texto exibido quando o valor do componente for *true*. */ + booleanTrue?: string; + + /** Texto exibido quando o valor do componente for *false*. */ + booleanFalse?: string; } diff --git a/projects/ui/src/lib/components/po-dynamic/po-dynamic-view/po-dynamic-view.component.spec.ts b/projects/ui/src/lib/components/po-dynamic/po-dynamic-view/po-dynamic-view.component.spec.ts index 62039a399..25e5f3caf 100644 --- a/projects/ui/src/lib/components/po-dynamic/po-dynamic-view/po-dynamic-view.component.spec.ts +++ b/projects/ui/src/lib/components/po-dynamic/po-dynamic-view/po-dynamic-view.component.spec.ts @@ -247,32 +247,75 @@ describe('PoDynamicViewComponent:', () => { expect(component['getVisibleFields']).toHaveBeenCalled(); }); - it(`setFieldValue: should return the label of the selected option if options exist and a match is found`, () => { - const field = { - value: 'value1', - options: [ - { value: 'value1', label: 'label1' }, - { value: 'value2', label: 'label2' }, - { value: 'value3', label: 'label3' } - ] - }; + describe('setFieldValue:', () => { + it(`should return the label of the selected option if options exist and a match is found`, () => { + const field = { + value: 'value1', + options: [ + { value: 'value1', label: 'label1' }, + { value: 'value2', label: 'label2' }, + { value: 'value3', label: 'label3' } + ] + }; + + field.value = 'value2'; + expect(component.setFieldValue(field)).toEqual('label2'); + }); - field.value = 'value2'; - expect(component.setFieldValue(field)).toEqual('label2'); - }); + it(`should return the field value if options exist but no match is found'`, () => { + const field = { + value: 'value1', + options: [ + { value: 'value1', label: 'label1' }, + { value: 'value2', label: 'label2' }, + { value: 'value3', label: 'label3' } + ] + }; + + field.value = 'value4'; + expect(component.setFieldValue(field)).toEqual('value4'); + }); + it('should return the value of booleanTrue when the field value is true', () => { + const field = { + property: 'active', + type: 'boolean', + value: true, + booleanTrue: 'Ativo', + booleanFalse: 'Inativo' + }; + expect(component.setFieldValue(field)).toEqual('Ativo'); + }); - it(`setFieldValue: should return the field value if options exist but no match is found'`, () => { - const field = { - value: 'value1', - options: [ - { value: 'value1', label: 'label1' }, - { value: 'value2', label: 'label2' }, - { value: 'value3', label: 'label3' } - ] - }; + it('should return the value of booleanFalse when the field value is false', () => { + const field = { + property: 'active', + type: 'boolean', + value: false, + booleanTrue: 'Ativo', + booleanFalse: 'Inativo' + }; + expect(component.setFieldValue(field)).toEqual('Inativo'); + }); - field.value = 'value4'; - expect(component.setFieldValue(field)).toEqual('value4'); + it('should return "True" when the field value is true and booleanTrue is undefined', () => { + const field = { + property: 'active', + type: 'boolean', + value: true, + booleanFalse: 'Inativo' + }; + expect(component.setFieldValue(field)).toEqual(true); + }); + + it('should return "False" when the field value is false and booleanFalse is undefined', () => { + const field = { + property: 'active', + type: 'boolean', + value: false, + booleanTrue: 'Ativo' + }; + expect(component.setFieldValue(field)).toEqual(false); + }); }); }); diff --git a/projects/ui/src/lib/components/po-dynamic/po-dynamic-view/po-dynamic-view.component.ts b/projects/ui/src/lib/components/po-dynamic/po-dynamic-view/po-dynamic-view.component.ts index 6e1cc778e..d6a0d26a6 100644 --- a/projects/ui/src/lib/components/po-dynamic/po-dynamic-view/po-dynamic-view.component.ts +++ b/projects/ui/src/lib/components/po-dynamic/po-dynamic-view/po-dynamic-view.component.ts @@ -66,6 +66,8 @@ export class PoDynamicViewComponent extends PoDynamicViewBaseComponent implement if (field.options) { const selectedOption = field.options.find(option => option.value === field.value); return selectedOption ? selectedOption.label : field.value; + } else if (field.type === 'boolean' && 'booleanTrue' in field && 'booleanFalse' in field) { + return field.value ? field.booleanTrue : field.booleanFalse; } else { return field.value; } diff --git a/projects/ui/src/lib/components/po-dynamic/po-dynamic-view/samples/sample-po-dynamic-view-employee-on-load/sample-po-dynamic-view-employee-on-load.component.ts b/projects/ui/src/lib/components/po-dynamic/po-dynamic-view/samples/sample-po-dynamic-view-employee-on-load/sample-po-dynamic-view-employee-on-load.component.ts index 3cbb1dd78..e869bc3b7 100644 --- a/projects/ui/src/lib/components/po-dynamic/po-dynamic-view/samples/sample-po-dynamic-view-employee-on-load/sample-po-dynamic-view-employee-on-load.component.ts +++ b/projects/ui/src/lib/components/po-dynamic/po-dynamic-view/samples/sample-po-dynamic-view-employee-on-load/sample-po-dynamic-view-employee-on-load.component.ts @@ -70,7 +70,7 @@ export class SamplePoDynamicViewEmployeeOnLoadComponent implements OnInit { private _newService = inject(SamplePoDynamicViewEmployeeOnLoadService); ngOnInit(): void { - this._newService.setConfig('https://po-sample-api.fly.dev/v1/hotels', { id: 1485976673002 }); + this._newService.setConfig('https://po-sample-api.onrender.com/v1/hotels', { id: 1485976673002 }); } customEmployeeData() { diff --git a/projects/ui/src/lib/components/po-field/po-combo/po-combo.component.spec.ts b/projects/ui/src/lib/components/po-field/po-combo/po-combo.component.spec.ts index 3476fe40f..236867d06 100644 --- a/projects/ui/src/lib/components/po-field/po-combo/po-combo.component.spec.ts +++ b/projects/ui/src/lib/components/po-field/po-combo/po-combo.component.spec.ts @@ -634,6 +634,15 @@ describe('PoComboComponent:', () => { expect(component.isFiltering).toBe(false); }); + it('should call controlComboVisibility(false) when keyCode tab is pressed and shiftKey is true', () => { + const event = { ...fakeEvent, keyCode: 9, shiftKey: true }; + spyOn(component, 'controlComboVisibility'); + + component.onKeyDown(event); + + expect(component.controlComboVisibility).toHaveBeenCalledWith(false); + }); + it(`should call 'controlComboVisibility', 'updateComboList' and 'updateSelectedValue' with 'selectedView' and 'true' if selectedView.label is not equal inputValue, typed 'enter', 'selectedView' is truthy and 'comboOpen' is true `, () => { const event = { ...fakeEvent, keyCode: 13, target: { value: 'lab' } }; diff --git a/projects/ui/src/lib/components/po-field/po-combo/po-combo.component.ts b/projects/ui/src/lib/components/po-field/po-combo/po-combo.component.ts index 5ad0bcbcf..b53f07381 100644 --- a/projects/ui/src/lib/components/po-field/po-combo/po-combo.component.ts +++ b/projects/ui/src/lib/components/po-field/po-combo/po-combo.component.ts @@ -227,6 +227,11 @@ export class PoComboComponent extends PoComboBaseComponent implements AfterViewI const key = event.keyCode; const inputValue = event.target.value; + if (event.shiftKey && key === PoKeyCodeEnum.tab) { + this.controlComboVisibility(false); + return; + } + // busca um registro quando acionar o tab if (this.service && key === PoKeyCodeEnum.tab && inputValue && !this.disabledTabFilter) { this.controlComboVisibility(false); diff --git a/projects/ui/src/lib/components/po-field/po-combo/samples/sample-po-combo-heroes-reactive-form/sample-po-combo-heroes-reactive-form.component.html b/projects/ui/src/lib/components/po-field/po-combo/samples/sample-po-combo-heroes-reactive-form/sample-po-combo-heroes-reactive-form.component.html index 531ab8624..52504c1b7 100644 --- a/projects/ui/src/lib/components/po-field/po-combo/samples/sample-po-combo-heroes-reactive-form/sample-po-combo-heroes-reactive-form.component.html +++ b/projects/ui/src/lib/components/po-field/po-combo/samples/sample-po-combo-heroes-reactive-form/sample-po-combo-heroes-reactive-form.component.html @@ -6,7 +6,7 @@ formControlName="hero" p-field-label="nickname" p-field-value="name" - p-filter-service="https://po-sample-api.fly.dev/v1/heroes" + p-filter-service="https://po-sample-api.onrender.com/v1/heroes" p-label="Search a Hero" p-sort (p-change)="onChangeHero($event)" diff --git a/projects/ui/src/lib/components/po-field/po-combo/samples/sample-po-combo-heroes-reactive-form/sample-po-combo-heroes-reactive-form.component.ts b/projects/ui/src/lib/components/po-field/po-combo/samples/sample-po-combo-heroes-reactive-form/sample-po-combo-heroes-reactive-form.component.ts index 209e48c43..506b776c0 100644 --- a/projects/ui/src/lib/components/po-field/po-combo/samples/sample-po-combo-heroes-reactive-form/sample-po-combo-heroes-reactive-form.component.ts +++ b/projects/ui/src/lib/components/po-field/po-combo/samples/sample-po-combo-heroes-reactive-form/sample-po-combo-heroes-reactive-form.component.ts @@ -1,6 +1,6 @@ +import { HttpClient } from '@angular/common/http'; import { Component, OnInit } from '@angular/core'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; -import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs'; @@ -35,6 +35,6 @@ export class SamplePoComboHeroesReactiveFormComponent implements OnInit { } private getHero(heroName: string) { - return this.http.get(`https://po-sample-api.fly.dev/v1/heroes/${heroName}`); + return this.http.get(`https://po-sample-api.onrender.com/v1/heroes/${heroName}`); } } diff --git a/projects/ui/src/lib/components/po-field/po-combo/samples/sample-po-combo-heroes/sample-po-combo-heroes.component.html b/projects/ui/src/lib/components/po-field/po-combo/samples/sample-po-combo-heroes/sample-po-combo-heroes.component.html index 202089b25..215fde6e1 100644 --- a/projects/ui/src/lib/components/po-field/po-combo/samples/sample-po-combo-heroes/sample-po-combo-heroes.component.html +++ b/projects/ui/src/lib/components/po-field/po-combo/samples/sample-po-combo-heroes/sample-po-combo-heroes.component.html @@ -5,7 +5,7 @@ [(ngModel)]="heroName" p-field-label="nickname" p-field-value="name" - p-filter-service="https://po-sample-api.fly.dev/v1/heroes" + p-filter-service="https://po-sample-api.onrender.com/v1/heroes" p-label="Search a Hero" p-sort (p-change)="onChangeHero($event)" diff --git a/projects/ui/src/lib/components/po-field/po-combo/samples/sample-po-combo-heroes/sample-po-combo-heroes.component.ts b/projects/ui/src/lib/components/po-field/po-combo/samples/sample-po-combo-heroes/sample-po-combo-heroes.component.ts index 9cfb13988..92c07f8f5 100644 --- a/projects/ui/src/lib/components/po-field/po-combo/samples/sample-po-combo-heroes/sample-po-combo-heroes.component.ts +++ b/projects/ui/src/lib/components/po-field/po-combo/samples/sample-po-combo-heroes/sample-po-combo-heroes.component.ts @@ -1,5 +1,5 @@ -import { Component } from '@angular/core'; import { HttpClient } from '@angular/common/http'; +import { Component } from '@angular/core'; import { Observable } from 'rxjs'; @@ -26,6 +26,6 @@ export class SamplePoComboHeroesComponent { } private getHero(heroName: string) { - return this.http.get(`https://po-sample-api.fly.dev/v1/heroes/${heroName}`); + return this.http.get(`https://po-sample-api.onrender.com/v1/heroes/${heroName}`); } } diff --git a/projects/ui/src/lib/components/po-field/po-combo/samples/sample-po-combo-hotels/sample-po-combo-hotels.component.html b/projects/ui/src/lib/components/po-field/po-combo/samples/sample-po-combo-hotels/sample-po-combo-hotels.component.html index 928ff7938..dd15ed245 100644 --- a/projects/ui/src/lib/components/po-field/po-combo/samples/sample-po-combo-hotels/sample-po-combo-hotels.component.html +++ b/projects/ui/src/lib/components/po-field/po-combo/samples/sample-po-combo-hotels/sample-po-combo-hotels.component.html @@ -63,7 +63,7 @@ p-field-value="value" p-label="Search a hotel" p-sort - p-filter-service="https://po-sample-api.fly.dev/v1/hotels" + p-filter-service="https://po-sample-api.onrender.com/v1/hotels" [p-filter-params]="filterParams" > diff --git a/projects/ui/src/lib/components/po-field/po-combo/samples/sample-po-combo-infinity-scroll/sample-po-combo-infinity-scroll.component.html b/projects/ui/src/lib/components/po-field/po-combo/samples/sample-po-combo-infinity-scroll/sample-po-combo-infinity-scroll.component.html index 5ee2e8f9c..e2b3e26cb 100644 --- a/projects/ui/src/lib/components/po-field/po-combo/samples/sample-po-combo-infinity-scroll/sample-po-combo-infinity-scroll.component.html +++ b/projects/ui/src/lib/components/po-field/po-combo/samples/sample-po-combo-infinity-scroll/sample-po-combo-infinity-scroll.component.html @@ -1,7 +1,7 @@
diff --git a/projects/ui/src/lib/components/po-field/po-combo/samples/sample-po-combo-transfer/sample-po-combo-transfer.component.html b/projects/ui/src/lib/components/po-field/po-combo/samples/sample-po-combo-transfer/sample-po-combo-transfer.component.html index 9125efa06..93d6a75a0 100644 --- a/projects/ui/src/lib/components/po-field/po-combo/samples/sample-po-combo-transfer/sample-po-combo-transfer.component.html +++ b/projects/ui/src/lib/components/po-field/po-combo/samples/sample-po-combo-transfer/sample-po-combo-transfer.component.html @@ -20,7 +20,7 @@ [(ngModel)]="contact" p-field-value="id" p-field-label="name" - p-filter-service="https://po-sample-api.fly.dev/v1/people" + p-filter-service="https://po-sample-api.onrender.com/v1/people" p-icon="po-icon-user" p-label="To contact" p-placeholder="Select a contact" diff --git a/projects/ui/src/lib/components/po-field/po-lookup/samples/sample-po-lookup-basic/sample-po-lookup-basic.component.html b/projects/ui/src/lib/components/po-field/po-lookup/samples/sample-po-lookup-basic/sample-po-lookup-basic.component.html index 2288a039f..a763872a1 100644 --- a/projects/ui/src/lib/components/po-field/po-lookup/samples/sample-po-lookup-basic/sample-po-lookup-basic.component.html +++ b/projects/ui/src/lib/components/po-field/po-lookup/samples/sample-po-lookup-basic/sample-po-lookup-basic.component.html @@ -2,7 +2,7 @@ name="lookup" p-field-label="label" p-field-value="value" - p-filter-service="https://po-sample-api.fly.dev/v1/heroes" + p-filter-service="https://po-sample-api.onrender.com/v1/heroes" p-label="PO Lookup" > diff --git a/projects/ui/src/lib/components/po-field/po-lookup/samples/sample-po-lookup-labs/sample-po-lookup-labs.component.html b/projects/ui/src/lib/components/po-field/po-lookup/samples/sample-po-lookup-labs/sample-po-lookup-labs.component.html index 307f90105..3e990d361 100644 --- a/projects/ui/src/lib/components/po-field/po-lookup/samples/sample-po-lookup-labs/sample-po-lookup-labs.component.html +++ b/projects/ui/src/lib/components/po-field/po-lookup/samples/sample-po-lookup-labs/sample-po-lookup-labs.component.html @@ -81,7 +81,7 @@ name="filterService" [(ngModel)]="filterService" p-clean - p-help="https://po-sample-api.fly.dev/v1/people" + p-help="https://po-sample-api.onrender.com/v1/people" p-label="Filter Service" > diff --git a/projects/ui/src/lib/components/po-field/po-lookup/samples/sample-po-lookup-multiple/sample-po-lookup-multiple.component.html b/projects/ui/src/lib/components/po-field/po-lookup/samples/sample-po-lookup-multiple/sample-po-lookup-multiple.component.html index c16be3ead..736f9ba11 100644 --- a/projects/ui/src/lib/components/po-field/po-lookup/samples/sample-po-lookup-multiple/sample-po-lookup-multiple.component.html +++ b/projects/ui/src/lib/components/po-field/po-lookup/samples/sample-po-lookup-multiple/sample-po-lookup-multiple.component.html @@ -5,7 +5,7 @@ [(ngModel)]="multiLookup" p-field-label="label" p-field-value="value" - p-filter-service="https://po-sample-api.fly.dev/v1/heroes" + p-filter-service="https://po-sample-api.onrender.com/v1/heroes" p-label="Search a Hero" [p-multiple]="true" (p-change)="changeOptions($event)" diff --git a/projects/ui/src/lib/components/po-field/po-lookup/samples/sample-po-lookup-multiple/sample-po-lookup-multiple.service.ts b/projects/ui/src/lib/components/po-field/po-lookup/samples/sample-po-lookup-multiple/sample-po-lookup-multiple.service.ts index 136c9441f..dbbff2f78 100644 --- a/projects/ui/src/lib/components/po-field/po-lookup/samples/sample-po-lookup-multiple/sample-po-lookup-multiple.service.ts +++ b/projects/ui/src/lib/components/po-field/po-lookup/samples/sample-po-lookup-multiple/sample-po-lookup-multiple.service.ts @@ -11,6 +11,6 @@ export class SamplePoLookupMultipleService { getHeroes(data): Observable { const values = data?.length ? data.toString() : data; - return this.http.get(`https://po-sample-api.fly.dev/v1/heroes?value=${values}`).pipe(pluck('items')); + return this.http.get(`https://po-sample-api.onrender.com/v1/heroes?value=${values}`).pipe(pluck('items')); } } diff --git a/projects/ui/src/lib/components/po-field/po-lookup/samples/sample-po-lookup.service.ts b/projects/ui/src/lib/components/po-field/po-lookup/samples/sample-po-lookup.service.ts index 89167e4d3..ddc6b3368 100644 --- a/projects/ui/src/lib/components/po-field/po-lookup/samples/sample-po-lookup.service.ts +++ b/projects/ui/src/lib/components/po-field/po-lookup/samples/sample-po-lookup.service.ts @@ -7,7 +7,7 @@ import { PoLookupFilter, PoLookupFilteredItemsParams } from '@po-ui/ng-component @Injectable() export class SamplePoLookupService implements PoLookupFilter { - private url = 'https://po-sample-api.fly.dev/v1/heroes'; + private url = 'https://po-sample-api.onrender.com/v1/heroes'; constructor(private httpClient: HttpClient) {} diff --git a/projects/ui/src/lib/components/po-field/po-multiselect/po-multiselect.component.spec.ts b/projects/ui/src/lib/components/po-field/po-multiselect/po-multiselect.component.spec.ts index c2a45e490..48d607be3 100644 --- a/projects/ui/src/lib/components/po-field/po-multiselect/po-multiselect.component.spec.ts +++ b/projects/ui/src/lib/components/po-field/po-multiselect/po-multiselect.component.spec.ts @@ -241,7 +241,7 @@ describe('PoMultiselectComponent:', () => { expect(component.controlDropdownVisibility).not.toHaveBeenCalled(); }); - it('should return when event keyCode is PoKeyCodeEnum.tab and visibleTags.length > 1', () => { + it('should return when event keyCode is PoKeyCodeEnum.tab', () => { const event = new KeyboardEvent('keydown', { keyCode: PoKeyCodeEnum.tab }); const tagRemovable = document.createElement('span'); tagRemovable.setAttribute('class', 'po-tag-remove'); @@ -253,13 +253,13 @@ describe('PoMultiselectComponent:', () => { expect(component.visibleTags.length).toEqual(2); }); - it('should return when event keyCode is PoKeyCodeEnum.tab and visibleTags.length < 1', () => { - const event = new KeyboardEvent('keydown', { keyCode: PoKeyCodeEnum.tab }); - component.visibleTags = []; + it('should call controlDropdownVisibility(false) when keyCode tab is pressed and shiftKey is true', () => { + const event = { keyCode: PoKeyCodeEnum.tab, shiftKey: true }; + spyOn(component, 'controlDropdownVisibility'); component.onKeyDown(event); - expect(component.visibleTags.length).toEqual(0); + expect(component.controlDropdownVisibility).toHaveBeenCalledWith(false); }); it('should call preventDefault and controlDropdownVisibility(true) when keyCode space is pressed', () => { diff --git a/projects/ui/src/lib/components/po-field/po-multiselect/po-multiselect.component.ts b/projects/ui/src/lib/components/po-field/po-multiselect/po-multiselect.component.ts index a95499ba6..8d31707ec 100644 --- a/projects/ui/src/lib/components/po-field/po-multiselect/po-multiselect.component.ts +++ b/projects/ui/src/lib/components/po-field/po-multiselect/po-multiselect.component.ts @@ -138,6 +138,7 @@ export class PoMultiselectComponent private initCalculateItems = true; private isCalculateVisibleItems: boolean = true; private cacheOptions: Array; + private focusOnTag = false; constructor( private renderer: Renderer2, @@ -314,10 +315,12 @@ export class PoMultiselectComponent } onKeyDown(event?: any) { - if ( - (event.keyCode === PoKeyCodeEnum.tab && this.visibleTags.length > 1) || - (event.keyCode === PoKeyCodeEnum.tab && this.visibleTags.length < 1) - ) { + if (event.shiftKey && event.keyCode === PoKeyCodeEnum.tab && !this.focusOnTag) { + this.controlDropdownVisibility(false); + } + this.focusOnTag = false; + + if (event.keyCode === PoKeyCodeEnum.tab) { return; } @@ -553,6 +556,7 @@ export class PoMultiselectComponent const KEY_SPACE = 'Space'; const KEY_ARROW_LEFT = 'ArrowLeft'; const KEY_ARROW_RIGHT = 'ArrowRight'; + this.focusOnTag = true; if (event.code === KEY_SPACE) { event.preventDefault(); diff --git a/projects/ui/src/lib/components/po-field/po-multiselect/samples/sample-po-multiselect-heroes/sample-po-multiselect-heroes.service.ts b/projects/ui/src/lib/components/po-field/po-multiselect/samples/sample-po-multiselect-heroes/sample-po-multiselect-heroes.service.ts index 23bfde3c4..a62d3eae7 100644 --- a/projects/ui/src/lib/components/po-field/po-multiselect/samples/sample-po-multiselect-heroes/sample-po-multiselect-heroes.service.ts +++ b/projects/ui/src/lib/components/po-field/po-multiselect/samples/sample-po-multiselect-heroes/sample-po-multiselect-heroes.service.ts @@ -4,7 +4,7 @@ import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; -import { PoMultiselectOption, PoMultiselectFilter } from '@po-ui/ng-components'; +import { PoMultiselectFilter, PoMultiselectOption } from '@po-ui/ng-components'; @Injectable() export class SamplePoMultiselectHeroesService implements PoMultiselectFilter { @@ -14,13 +14,13 @@ export class SamplePoMultiselectHeroesService implements PoMultiselectFilter { const params = { filter: value }; return this.http - .get(`https://po-sample-api.fly.dev/v1/heroes?page=1&pageSize=10`, { params }) + .get(`https://po-sample-api.onrender.com/v1/heroes?page=1&pageSize=10`, { params }) .pipe(map((response: { items: Array }) => response.items)); } getObjectsByValues(value: Array): Observable> { return this.http - .get(`https://po-sample-api.fly.dev/v1/heroes/?value=${value.toString()}`) + .get(`https://po-sample-api.onrender.com/v1/heroes/?value=${value.toString()}`) .pipe(map((response: { items: Array }) => response.items)); } } diff --git a/projects/ui/src/lib/components/po-field/po-multiselect/samples/sample-po-multiselect-labs/sample-po-multiselect-labs.component.html b/projects/ui/src/lib/components/po-field/po-multiselect/samples/sample-po-multiselect-labs/sample-po-multiselect-labs.component.html index bbce7de6c..fbaf907e6 100644 --- a/projects/ui/src/lib/components/po-field/po-multiselect/samples/sample-po-multiselect-labs/sample-po-multiselect-labs.component.html +++ b/projects/ui/src/lib/components/po-field/po-multiselect/samples/sample-po-multiselect-labs/sample-po-multiselect-labs.component.html @@ -91,7 +91,7 @@ name="filterService" [(ngModel)]="filterService" p-clean - p-help="https://po-sample-api.fly.dev/v1/heroes" + p-help="https://po-sample-api.onrender.com/v1/heroes" p-label="Filter Service" > diff --git a/projects/ui/src/lib/components/po-field/po-select/po-select.component.html b/projects/ui/src/lib/components/po-field/po-select/po-select.component.html index 59d2fb0aa..38d94946e 100644 --- a/projects/ui/src/lib/components/po-field/po-select/po-select.component.html +++ b/projects/ui/src/lib/components/po-field/po-select/po-select.component.html @@ -17,19 +17,23 @@ [required]="required" (change)="onSelectChange($event.target.value)" > - - - + + + + + + + + +