diff --git a/.github/workflows/.deploy.yml b/.github/workflows/.deploy.yml index 0b4957b..bdc6d46 100644 --- a/.github/workflows/.deploy.yml +++ b/.github/workflows/.deploy.yml @@ -109,9 +109,7 @@ jobs: --set global.autoscaling=${{ inputs.autoscaling }} \ --set-string global.repository=${{ github.repository }} \ --set-string global.secrets.databasePassword=${{ secrets.DB_PASSWORD }} \ - --set-string backend.containers[0].tag="${{ env.package_tag }}" \ - --set-string backend.initContainers[0].tag="${{ env.package_tag }}" \ - --set-string frontend.containers[0].tag="${{ env.package_tag }}" \ + --set-string global.tag="${{ env.package_tag }}" \ --install --wait --atomic ${{ env.repo_release }} \ --timeout ${{ inputs.timeout-minutes }}m \ --values ${{ inputs.values }} . diff --git a/.github/workflows/pr-open.yml b/.github/workflows/pr-open.yml index bd027c7..2b46d38 100644 --- a/.github/workflows/pr-open.yml +++ b/.github/workflows/pr-open.yml @@ -53,7 +53,7 @@ jobs: packages: write strategy: matrix: - package: [migrations, backend, frontend] + package: [workflows, frontend] # frontend is backend/frontend combined into single deployment. timeout-minutes: 10 steps: - uses: bcgov-nr/action-builder-ghcr@v2.0.0 @@ -74,4 +74,4 @@ jobs: autoscaling: false tag: ${{ github.event.number }} release: ${{ github.event.number }} - triggers: ('backend/' 'frontend/' 'migrations/' 'charts/') + triggers: ('backend/' 'workflows/' 'charts/') diff --git a/.gitignore b/.gitignore index 4298d01..c9d65a3 100644 --- a/.gitignore +++ b/.gitignore @@ -112,6 +112,7 @@ test-report.xml .volumes .idea *.iml +!frontend/app/bin **/bin **/build **/dist diff --git a/backend/package.json b/backend/package.json index 8365a02..cb11f86 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,5 +1,6 @@ { - "author": "BC Government Forestry Suite of Applications Starter Template", + "name": "nr-data-access-api", + "author": "NRIDS Architecture and Devops", "license": "Apache-2.0", "main": "index.js", "scripts": { diff --git a/charts/nr-data-access/charts/crunchy-postgres/Chart.yaml b/charts/nr-data-access/charts/crunchy-postgres/Chart.yaml new file mode 100644 index 0000000..f6c5862 --- /dev/null +++ b/charts/nr-data-access/charts/crunchy-postgres/Chart.yaml @@ -0,0 +1,26 @@ +apiVersion: v2 +name: crunchy-postgres +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.5.1 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. + +# Crunchy Postgres Operator version +appVersion: "5.0.4" diff --git a/charts/nr-data-access/charts/crunchy-postgres/templates/Postgres.yaml b/charts/nr-data-access/charts/crunchy-postgres/templates/Postgres.yaml new file mode 100644 index 0000000..a06410c --- /dev/null +++ b/charts/nr-data-access/charts/crunchy-postgres/templates/Postgres.yaml @@ -0,0 +1,164 @@ +apiVersion: postgres-operator.crunchydata.com/v1beta1 +kind: PostgresCluster +metadata: + name: {{ template "crunchy-postgres.fullname" . }} + labels: {{ include "crunchy-postgres.labels" . | nindent 4 }} +spec: + metadata: + labels: {{ include "crunchy-postgres.labels" . | nindent 6 }} + {{ if .Values.crunchyImage }} + image: {{ .Values.crunchyImage }} + {{ end }} + imagePullPolicy: {{.Values.imagePullPolicy}} + postgresVersion: {{ .Values.postgresVersion }} + {{ if .Values.postGISVersion }} + postGISVersion: {{ .Values.postGISVersion | quote }} + {{ end }} + postgresVersion: {{ .Values.postgresVersion }} + + {{ if .Values.pgmonitor.enabled }} + + monitoring: + pgmonitor: + # this stuff is for the "exporter" container in the "postgres-cluster-ha" set of pods + exporter: + {{ if .Values.pgmonitor.exporter.image}} + image: {{ .Values.pgmonitor.exporter.image}} + {{ end }} + resources: + requests: + cpu: {{ .Values.pgmonitor.exporter.requests.cpu }} + memory: {{ .Values.pgmonitor.exporter.requests.memory }} + limits: + cpu: {{ .Values.pgmonitor.exporter.limits.cpu }} + memory: {{ .Values.pgmonitor.exporter.limits.memory }} + + {{ end }} + + instances: + - name: {{ .Values.instances.name }} + replicas: {{ .Values.instances.replicas }} + resources: + requests: + cpu: {{ .Values.instances.requests.cpu }} + memory: {{ .Values.instances.requests.memory }} + limits: + cpu: {{ .Values.instances.limits.cpu }} + memory: {{ .Values.instances.limits.memory }} + sidecars: + replicaCertCopy: + resources: + requests: + cpu: {{ .Values.instances.replicaCertCopy.requests.cpu }} + memory: {{ .Values.instances.replicaCertCopy.requests.memory }} + limits: + cpu: {{ .Values.instances.replicaCertCopy.limits.cpu }} + memory: {{ .Values.instances.replicaCertCopy.limits.memory }} + dataVolumeClaimSpec: + accessModes: + - "ReadWriteOnce" + resources: + requests: + storage: {{ .Values.instances.dataVolumeClaimSpec.storage }} + storageClassName: {{ .Values.instances.dataVolumeClaimSpec.storageClassName }} + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 1 + podAffinityTerm: + topologyKey: kubernetes.io/hostname + labelSelector: + matchLabels: + postgres-operator.crunchydata.com/cluster: + {{ template "crunchy-postgres.fullname" . }} + postgres-operator.crunchydata.com/instance-set: {{ .Values.instances.name }}-ha + + + + users: + {{- toYaml .Values.users | nindent 4 }} + + + backups: + pgbackrest: + {{ if .Values.pgBackRest.image }} + image: {{ .Values.pgBackRest.image }} + {{ end }} + global: + repo1-retention-full: {{ .Values.pgBackRest.retention | quote }} + repo1-retention-full-type: {{ .Values.pgBackRest.retentionFullType }} + repos: + - name: repo1 + schedules: + full: {{ .Values.pgBackRest.repos.schedules.full }} + incremental: {{ .Values.pgBackRest.repos.schedules.incremental }} + volume: + volumeClaimSpec: + accessModes: + - {{ .Values.pgBackRest.repos.volume.accessModes }} + resources: + requests: + storage: {{ .Values.pgBackRest.repos.volume.storage }} + storageClassName: {{ .Values.pgBackRest.repos.volume.storageClassName }} + + # this stuff is for the "pgbackrest" container (the only non-init container) in the "postgres-crunchy-repo-host" pod + repoHost: + resources: + requests: + cpu: {{ .Values.pgBackRest.repoHost.requests.cpu }} + memory: {{ .Values.pgBackRest.repoHost.requests.memory }} + limits: + cpu: {{ .Values.pgBackRest.repoHost.limits.cpu }} + memory: {{ .Values.pgBackRest.repoHost.limits.memory }} + sidecars: + # this stuff is for the "pgbackrest" container in the "postgres-crunchy-ha" set of pods + pgbackrest: + resources: + requests: + cpu: {{ .Values.pgBackRest.sidecars.requests.cpu }} + memory: {{ .Values.pgBackRest.sidecars.requests.memory }} + limits: + cpu: {{ .Values.pgBackRest.sidecars.limits.cpu }} + memory: {{ .Values.pgBackRest.sidecars.limits.memory }} + + patroni: + dynamicConfiguration: + postgresql: + pg_hba: + - {{ .Values.patroni.postgresql.pg_hba}} + parameters: + shared_buffers: {{ .Values.patroni.postgresql.parameters.shared_buffers }} + wal_buffers: {{ .Values.patroni.postgresql.parameters.wal_buffers }} + min_wal_size: {{ .Values.patroni.postgresql.parameters.min_wal_size }} + max_wal_size: {{ .Values.patroni.postgresql.parameters.max_wal_size }} + max_slot_wal_keep_size: {{ .Values.patroni.postgresql.parameters.max_slot_wal_keep_size }} + + proxy: + pgBouncer: + config: + global: + client_tls_sslmode: disable + {{ if .Values.proxy.pgBouncer.image }} + image: {{ .Values.proxy.pgBouncer.image }} + {{ end }} + replicas: {{ .Values.proxy.pgBouncer.replicas }} + # these resources are for the "pgbouncer" container in the "postgres-crunchy-ha-pgbouncer" set of pods + # there is a sidecar in these pods which are not mentioned here, but the requests/limits are teeny weeny by default so no worries there. + resources: + requests: + cpu: {{ .Values.proxy.pgBouncer.requests.cpu }} + memory: {{ .Values.proxy.pgBouncer.requests.memory }} + limits: + cpu: {{ .Values.proxy.pgBouncer.limits.cpu }} + memory: {{ .Values.proxy.pgBouncer.limits.memory }} + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 1 + podAffinityTerm: + topologyKey: kubernetes.io/hostname + labelSelector: + matchLabels: + postgres-operator.crunchydata.com/cluster: + {{ .Values.instances.name }} + postgres-operator.crunchydata.com/role: pgbouncer diff --git a/charts/nr-data-access/charts/crunchy-postgres/templates/_helpers.tpl b/charts/nr-data-access/charts/crunchy-postgres/templates/_helpers.tpl new file mode 100644 index 0000000..584e9ad --- /dev/null +++ b/charts/nr-data-access/charts/crunchy-postgres/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "crunchy-postgres.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "crunchy-postgres.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "crunchy-postgres.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "crunchy-postgres.labels" -}} +helm.sh/chart: {{ include "crunchy-postgres.chart" . }} +{{ include "crunchy-postgres.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "crunchy-postgres.selectorLabels" -}} +app.kubernetes.io/name: {{ include "crunchy-postgres.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "crunchy-postgres.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "crunchy-postgres.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/charts/nr-data-access/templates/secret.yaml b/charts/nr-data-access/templates/secret.yaml index beb6119..306603b 100644 --- a/charts/nr-data-access/templates/secret.yaml +++ b/charts/nr-data-access/templates/secret.yaml @@ -13,12 +13,13 @@ metadata: name: {{ .Release.Name }} labels: {{- include "selectorLabels" . | nindent 4 }} data: - databasePassword: {{ $databasePassword | b64enc | quote }} - postgres-password: {{ $databasePassword | b64enc | quote }} - password: {{ $databasePassword | b64enc | quote }} - databaseUser: {{ $databaseUser | b64enc | quote }} - databaseName: {{ $databaseName | b64enc | quote }} - databaseURL: {{ $databaseURL | b64enc | quote }} - databaseJDBCURL: {{ $databaseJDBCURL | b64enc | quote }} - databaseJDBCURLNoCreds: {{ $databaseJDBCURLNoCreds | b64enc | quote }} + SERVER_KC_CLIENTID: {{ .Values.global.secrets.SERVER_KC_CLIENTID | b64enc | quote }} + SERVER_KC_CLIENTSECRET: {{ .Values.global.secrets.SERVER_KC_CLIENTSECRET | b64enc | quote }} + SC_CS_CHES_CLIENT_ID: {{ .Values.global.secrets.SC_CS_CHES_CLIENT_ID | b64enc | quote }} + SC_CS_CHES_CLIENT_SECRET: {{ .Values.global.secrets.SC_CS_CHES_CLIENT_SECRET | b64enc | quote }} + SC_CS_CDOGS_CLIENT_ID: {{ .Values.global.secrets.SC_CS_CDOGS_CLIENT_ID | b64enc | quote }} + SC_CS_CDOGS_CLIENT_SECRET: {{ .Values.global.secrets.SC_CS_CDOGS_CLIENT_SECRET | b64enc | quote }} + FILES_OBJECTSTORAGE_ACCESSKEYID: {{ .Values.global.secrets.FILES_OBJECTSTORAGE_ACCESSKEYID | b64enc | quote }} + FILES_OBJECTSTORAGE_SECRETACCESSKEY: {{ .Values.global.secrets.FILES_OBJECTSTORAGE_SECRETACCESSKEY | b64enc | quote }} + APITOKEN: {{ .Values.global.secrets.APITOKEN | b64enc | quote }} {{- end }} diff --git a/charts/nr-data-access/values.yaml b/charts/nr-data-access/values.yaml index c6f5bc9..9b92666 100644 --- a/charts/nr-data-access/values.yaml +++ b/charts/nr-data-access/values.yaml @@ -6,51 +6,65 @@ global: tag: ~ autoscaling: true secrets: - enabled: true - databasePassword: ~ - databaseUser: ~ - databaseName: ~ + enabled: false + databasePassword: default + databaseUser: default + databaseName: default + SERVER_KC_CLIENTID: default + SERVER_KC_CLIENTSECRET: default + SC_CS_CHES_CLIENT_ID: default + SC_CS_CHES_CLIENT_SECRET: default + SC_CS_CDOGS_CLIENT_ID: default + SC_CS_CDOGS_CLIENT_SECRET: default + FILES_OBJECTSTORAGE_ACCESSKEYID: default + FILES_OBJECTSTORAGE_SECRETACCESSKEY: default + FILES_OBJECTSTORAGE_BUCKET: default + APITOKEN: default annotation: helm.sh/policy: "keep" domain: "apps.silver.devops.gov.bc.ca" # it is required, apps.silver.devops.gov.bc.ca for silver cluster openshiftImageRegistry: "image-registry.openshift-image-registry.svc:5000" - databaseAlias: bitnami-pg # this is the alias for bitnami postgres, change it based on db type(crunchy,patroni...) and alias used in the chart. - -backend: + podAnnotations: | + app.kubernetes.io/timestamp: {{now | toString }} +workflows: enabled: true deployment: # can be either a statefulSet or a deployment not both enabled: true containers: - - name: backend + - name: workflows registry: '{{ .Values.global.registry }}' repository: '{{ .Values.global.repository }}' # example, it includes registry and repository - image: backend # the exact component name, be it backend, api-1 etc... + image: workflows # the exact component name, be it backend, api-1 etc... tag: '{{ .Values.global.tag }}' # the tag of the image, it can be latest, 1.0.0 etc..., or the sha256 hash env: fromGlobalSecret: - - name: POSTGRES_PASSWORD - key: password - - name: POSTGRES_USER - key: databaseUser - name: POSTGRES_DATABASE - key: databaseName - fromValues: + secretName: '{{ .Release.Name }}-crunchy-pguser-nrdataacessworkflows' + key: dbname - name: POSTGRES_HOST - value: '{{ .Release.Name }}-{{.Values.global.databaseAlias}}' + secretName: '{{ .Release.Name }}-crunchy-pguser-nrdataacessworkflows' + key: pgbouncer-host + - name: POSTGRES_USER + secretName: '{{ .Release.Name }}-crunchy-pguser-nrdataacessworkflows' + key: user + - name: POSTGRES_PASSWORD + secretName: '{{ .Release.Name }}-crunchy-pguser-nrdataacessworkflows' + key: password + ports: - name: http containerPort: 3000 protocol: TCP resources: # this is optional limits: - cpu: 250m - memory: 250Mi - requests: cpu: 100m memory: 150Mi + requests: + cpu: 30m + memory: 50Mi readinessProbe: httpGet: - path: /api + path: /q/health port: 3000 scheme: HTTP initialDelaySeconds: 5 @@ -62,133 +76,80 @@ backend: successThreshold: 1 failureThreshold: 3 httpGet: - path: /api + path: /q/health port: 3000 scheme: HTTP initialDelaySeconds: 15 periodSeconds: 30 timeoutSeconds: 5 - initContainers: - - name: database-migrations - registry: '{{ .Values.global.registry }}' - repository: '{{ .Values.global.repository }}' # example, it includes registry and repository - image: migrations - tag: '{{ .Values.global.tag }}' - env: - fromGlobalSecret: - - name: FLYWAY_PASSWORD - key: databasePassword - - name: FLYWAY_URL - key: databaseJDBCURLNoCreds - - name: FLYWAY_USER - key: databaseUser - fromValues: - - name: FLYWAY_BASELINE_ON_MIGRATE - value: "true" - - name: FLYWAY_DEFAULT_SCHEMA - value: "USERS" - resources: - limits: - cpu: 500m - memory: 250Mi - requests: - cpu: 200m - memory: 150Mi - autoscaling: - enabled: true - minReplicas: 3 - maxReplicas: 7 - targetCPUUtilizationPercentage: 80 # this percentage from request cpu - behavior: - scaleDown: - stabilizationWindowSeconds: 300 - policies: - - type: Percent - value: 10 - periodSeconds: 60 - - type: Pods - value: 2 - periodSeconds: 60 - selectPolicy: Min - scaleUp: - stabilizationWindowSeconds: 0 - policies: - - type: Percent - value: 100 - periodSeconds: 30 - - type: Pods - value: 2 - periodSeconds: 30 - selectPolicy: Max - vault: - enabled: false - entrypoint: ~ # the entrypoint for vault, this is the override of container command. - role: ~ #licenseplate-prod or licenseplate-nonprod - secretPaths: # the paths where secrets live. dev/api-1, dev/api-2, test/api-1 etc... - - dev/api-1 - - dev/api-2 - - test/api-1 - - test/api-2 - - prod/api-1 - - prod/api-2 - resources: - limits: - cpu: 50m - memory: 50Mi - requests: - cpu: 50m - memory: 25Mi - service: - enabled: true - type: ClusterIP - ports: - - name: http - port: 80 - targetPort: 3000 # the container port where the application is listening on - protocol: TCP - nodeSelector: { } - tolerations: [ ] - affinity: { } frontend: - enabled: true + enabled: false deployment: # can be either a statefulSet or a deployment not both enabled: true configmap: enabled: true data: # below is just for example. - config.js: |- - const envConfig = (() => { - return { - "VITE_DEPLOY_ENVIRONMENT":"{{ .Release.Name }}-{{ .Release.Namespace }}" - }; - })(); - config.prod.js: |- - const envConfig = (() => { - return { - "VITE_DEPLOY_ENVIRONMENT":"static" - }; - })(); + VITE_CONTACT: 'omprakash.2.mishra@gov.bc.ca' + VITE_HOWTOURL: 'https://howto.gov.bc.ca' + VITE_CHEFSTOURURL: 'https://chefstour.gov.bc.ca' + FRONTEND_APIPATH: api/v1 + VITE_FRONTEND_BASEPATH: /app + FRONTEND_BASEPATH: /app + FRONTEND_ENV: dev + FRONTEND_KC_REALM: chefs + FRONTEND_KC_SERVERURL: https://dev.loginproxy.gov.bc.ca/auth + SC_CS_CHES_ENDPOINT: https://ches-dev.api.gov.bc.ca/api + SC_CS_CDOGS_ENDPOINT: https://cdogs-dev.api.gov.bc.ca/api + SC_CS_CHES_TOKEN_ENDPOINT: https://dev.loginproxy.gov.bc.ca/auth/realms/comsvcauth/protocol/openid-connect/token + SC_CS_CDOGS_TOKEN_ENDPOINT: https://dev.loginproxy.gov.bc.ca/auth/realms/comsvcauth/protocol/openid-connect/token + SERVER_APIPATH: /api/v1 + SERVER_BASEPATH: /app + SERVER_BODYLIMIT: 30mb + SERVER_KC_REALM: standard + SERVER_KC_SERVERURL: https://dev.loginproxy.gov.bc.ca/auth + SERVER_LOGLEVEL: http + SERVER_PORT: 8080 + FILES_UPLOADS_DIR: + FILES_UPLOADS_ENABLED: true + FILES_UPLOADS_FILECOUNT: 1 + FILES_UPLOADS_FILEKEY: files + FILES_UPLOADS_FILEMAXSIZE: 25MB + FILES_UPLOADS_FILEMINSIZE: 0KB + FILES_UPLOADS_PATH: files + FILES_PERMANENT: objectStorage + FILES_LOCALSTORAGE_PATH: + FILES_OBJECTSTORAGE_BUCKET: '{{ .Values.global.FILES_OBJECTSTORAGE_BUCKET }}' + FILES_OBJECTSTORAGE_ENDPOINT: https://nrs.objectstore.gov.bc.ca + FILES_OBJECTSTORAGE_KEY: '{{ .Values.global.secrets.FILES_OBJECTSTORAGE_ACCESSKEYID }}' + NODE_ENV: production + VITE_CHEFS_GEO_ADDRESS_APIURL: https://geocoder.api.gov.bc.ca/addresses.json + VITE_CHEFS_ADVANCE_GEO_ADDRESS_APIURL: https://geocoder.api.gov.bc.ca/addresses.json + VITE_BC_GEO_ADDRESS_APIURL: https://geocoder.api.gov.bc.ca/addresses.json containers: - name: frontend registry: '{{ .Values.global.registry }}' repository: '{{ .Values.global.repository }}' # example, it includes registry and repository image: frontend # the exact component name, be it backend, api-1 etc... tag: '{{ .Values.global.tag }}' # the tag of the image, it can be latest, 1.0.0 etc..., or the sha256 hash - securityContext: - capabilities: - add: [ "NET_BIND_SERVICE" ] + envFrom: + - configMapRef: + - secretRef: env: - fromValues: - - name: BACKEND_URL - value: "http://{{ .Release.Name }}-backend" - - name: LOG_LEVEL - value: "info" - fromLocalConfigmap: # just for example purpose. - - name: frontend-configmap - key: config.js - - name: frontend-prod-configmap - key: config.prod.js + fromGlobalSecret: + - name: DB_DATABASE + secretName: '{{ .Release.Name }}-crunchy-pguser-nrdataaccessfrontend' + key: dbname + - name: DB_HOST + secretName: '{{ .Release.Name }}-crunchy-pguser-nrdataaccessfrontend' + key: pgbouncer-host + - name: DB_USERNAME + secretName: '{{ .Release.Name }}-crunchy-pguser-nrdataaccessfrontend' + key: user + - name: DB_PASSWORD + secretName: '{{ .Release.Name }}-crunchy-pguser-nrdataaccessfrontend' + key: password + ports: - name: http containerPort: 3000 @@ -263,22 +224,32 @@ frontend: targetPort: http # look at line#164 refer to the name. crunchy: # enable it for TEST and PROD, for PR based pipelines simply use single postgres - enabled: false - - crunchyImage: artifacts.developer.gov.bc.ca/bcgov-docker-local/crunchy-postgres-gis:ubi8-15.2-3.3-0 + enabled: true + users: + - name: postgres + databases: + - postgres + - name: nrdataaccessfrontend + databases: + - nrdataaccessfrontend + - name: nrdataacessworkflows + databases: + - nrdataacessworkflows + - name: nrdataacessreporting + databases: + - nrdataacessreporting postgresVersion: 15 - postGISVersion: '3.3' imagePullPolicy: Always instances: name: ha # high availability - replicas: 1 # 2 or 3 for high availability in TEST and PROD. + replicas: 2 # 2 or 3 for high availability in TEST and PROD. metadata: annotations: prometheus.io/scrape: 'true' prometheus.io/port: '9187' dataVolumeClaimSpec: - storage: 120Mi + storage: 420Mi storageClassName: netapp-block-standard requests: cpu: 25m @@ -295,7 +266,6 @@ crunchy: # enable it for TEST and PROD, for PR based pipelines simply use single memory: 64Mi pgBackRest: - enabled: false image: # it's not necessary to specify an image as the images specified in the Crunchy Postgres Operator will be pulled by default retention: "1" # Ideally a larger number such as 30 backups/days # If retention-full-type set to 'count' then the oldest backups will expire when the number of backups reach the number defined in retention @@ -357,111 +327,52 @@ crunchy: # enable it for TEST and PROD, for PR based pipelines simply use single cpu: 50m memory: 128Mi -bitnami-pg: +keycloak: enabled: true - image: - registry: ghcr.io - repository: bcgov/nr-containers/bitnami/postgresql - tag: 15.5.0 - auth: - existingSecret: '{{ .Release.Name }}' - username: 'quickstart' - database: quickstart - shmVolume: + podSecurityContext: enabled: false - backup: + containerSecurityContext: enabled: false - cronjob: - containerSecurityContext: { } - podSecurityContext: - enabled: false - storage: - size: 200Mi - primary: - persistence: - enabled: true - storageClass: netapp-file-standard - accessModes: - - ReadWriteOnce - size: 100Mi - containerSecurityContext: - enabled: false - podSecurityContext: - enabled: false - initdb: - scripts: # remove the below script, if POSTGIS is not required. - postgis.sh: | - #!/bin/sh - PGPASSWORD=$POSTGRES_PASSWORD psql -U postgres -d postgres -c "CREATE EXTENSION postgis;" - resources: - requests: - cpu: 50m - memory: 150Mi - limits: - cpu: 150m - memory: 250Mi - -backup: - enabled: true - pvc: + livenessProbe: enabled: true - size: 256Mi - storageClassName: netapp-file-standard - accessModes: ReadWriteOnce - cronjob: + initialDelaySeconds: 300 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 30 + successThreshold: 1 + readinessProbe: enabled: true - volumes: - - name: "{{.Release.Name}}-backup" - persistentVolumeClaim: - claimName: "{{.Release.Name}}-backup" - restartPolicy: "Never" - schedule: "0 0 * * *" - concurrencyPolicy: "Replace" - failedJobsHistoryLimit: 7 - successfulJobsHistoryLimit: 30 - startingDeadlineSeconds: 3600 - containers: - - name: backup - registry: 'docker.io' - repository: 'bcgovimages' # example, it includes registry and repository - image: backup-container # the exact component name, be it backend, api-1 etc... - tag: latest # the tag of the image, it can be latest, 1.0.0 etc..., or the sha256 hash - command: - - "/bin/bash" - - "-c" - - "/backup.sh -1" - volumeMounts: - - mountPath: "/backups/" - name: "{{.Release.Name}}-backup" - env: - fromValues: - - name: BACKUP_DIR - value: "/backups/" - - name: BACKUP_STRATEGY - value: "rolling" - - name: NUM_BACKUPS - value: '5' - - name: DAILY_BACKUPS - value: '7' - - name: WEEKLY_BACKUPS - value: '4' - - name: MONTHLY_BACKUPS - value: '1' - - name: DATABASE_SERVICE_NAME # depends on which chart being used, adjust accordingly. - value: '{{.Release.Name}}-{{.Values.global.databaseAlias}}' - - name: DEFAULT_PORT - value: "5432" - fromGlobalSecret: - - name: DATABASE_PASSWORD - key: password - - name: POSTGRESQL_DATABASE - key: databaseName - - name: DATABASE_USER - key: databaseUser + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 50 + successThreshold: 1 + resources: + requests: + cpu: 100m + memory: 300Mi + limits: + cpu: 250m + memory: 500Mi + postgresql: + enabled: true + shmVolume: + enabled: false + primary: + podSecurityContext: + enabled: false + containerSecurityContext: + enabled: + false resources: - limits: - cpu: 50m - memory: 256Mi requests: - cpu: 20m - memory: 128Mi + cpu: 100m + memory: 250Mi + limits: + cpu: 250m + memory: 500Mi + persistence: + size: 150Mi + storageClass: netapp-block-standard + + diff --git a/docker-compose.yml b/docker-compose.yml index d758cfa..c067bf7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -25,6 +25,33 @@ services: test: ["CMD", "pg_isready", "-U", *POSTGRES_USER] ports: ["5432:5432"] + chefs-keycloak: + image: quay.io/keycloak/keycloak:18.0 + volumes: + - type: bind + source: ./realm-export.json + target: /tmp/realm-export.json + read_only: true + ports: + - 8082:8082 + environment: + - DB_VENDOR=POSTGRES + - DB_ADDR=database + - DB_USER=postgres + - DB_PASSWORD=default + - KEYCLOAK_ADMIN=admin + - KEYCLOAK_ADMIN_PASSWORD=admin + - KEYCLOAK_HTTPS_REQUIRED=false + depends_on: + - database + restart: unless-stopped + command: + - "start-dev" + - "--http-port=8082" + - "-Dkeycloak.migration.action=import" + - "-Dkeycloak.migration.provider=singleFile" + - "-Dkeycloak.migration.file=/tmp/realm-export.json" + - "-Dkeycloak.migration.strategy=OVERWRITE_EXISTING" migrations: image: flyway/flyway:9-alpine container_name: migrations diff --git a/frontend/.codeclimate.yml b/frontend/.codeclimate.yml new file mode 100644 index 0000000..c81eb79 --- /dev/null +++ b/frontend/.codeclimate.yml @@ -0,0 +1,63 @@ +version: "2" +exclude_patterns: + - config/ + - "**/db/" + - dist/ + - features/ + - "**/node_modules/" + - script/ + - "**/spec/" + - "**/test/" + - "**/tests/" + - Tests/ + - "**/vendor/" + - "**/*_test.go" + - "**/*.d.ts" +plugins: + csslint: + enabled: true + editorconfig: + enabled: true + checks: + END_OF_LINE: + enabled: false + INDENTATION_SPACES: + enabled: false + INDENTATION_SPACES_AMOUNT: + enabled: false + TRAILINGSPACES: + enabled: false + eslint: + enabled: true + channel: "eslint-8" + config: + config: app/.eslintrc.js + fixme: + enabled: true + git-legal: + enabled: true + markdownlint: + enabled: true + checks: + MD002: + enabled: false + MD013: + enabled: false + MD029: + enabled: false + MD046: + enabled: false + nodesecurity: + enabled: true + sass-lint: + enabled: true +checks: + method-complexity: + config: + threshold: 6 + method-lines: + config: + threshold: 40 + file-lines: + config: + threshold: 500 diff --git a/frontend/.dockerignore b/frontend/.dockerignore index a5712a1..d95ee2a 100644 --- a/frontend/.dockerignore +++ b/frontend/.dockerignore @@ -1,6 +1,42 @@ +# Editor directories and files +.DS_Store +.gradle +.nyc_output +.scannerwork +build coverage -.vscode -.idea dist +files +**/e2e/videos node_modules -cypress +# Ignore only top-level package-lock.json +/package-lock.json + +# Ignore Helm subcharts +charts/**/charts +Chart.lock + +# local env files +local.* +local-*.* +.env.local +.env.*.local + +# Log files +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Editor directories and files +.idea +.vscode +*.iml +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? +*.mp4 + +# temp office files +~$* diff --git a/frontend/.editorconfig b/frontend/.editorconfig new file mode 100644 index 0000000..782e534 --- /dev/null +++ b/frontend/.editorconfig @@ -0,0 +1,25 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.html] +indent_style = space +indent_size = 2 + +[*.{css,js,json,jsx,scss,ts,tsx,vue}] +indent_style = space +indent_size = 2 + +[.{babelrc,eslintrc}] +indent_style = space +indent_size = 2 + +# ignore patterns +[*.{gif,ico}] +end_of_line = unset +insert_final_newline = unset +trim_trailing_whitespace = unset diff --git a/frontend/.eslintignore b/frontend/.eslintignore deleted file mode 100644 index 7d455ee..0000000 --- a/frontend/.eslintignore +++ /dev/null @@ -1,7 +0,0 @@ -.husky/ -.vscode/ -.yarn/ -coverage/ -dist/ -public/assets/ -tsconfig.*.json diff --git a/frontend/.eslintrc.yml b/frontend/.eslintrc.yml deleted file mode 100644 index f088349..0000000 --- a/frontend/.eslintrc.yml +++ /dev/null @@ -1,75 +0,0 @@ -env: - browser: true - es2021: true - node: true - -extends: - - 'eslint:recommended' - - 'plugin:react/recommended' - - 'plugin:@typescript-eslint/recommended' - - 'prettier' - - 'plugin:prettier/recommended' - -parser: '@typescript-eslint/parser' - -parserOptions: - ecmaFeatures: - jsx: true - ecmaVersion: 12 - sourceType: module - project: './frontend/tsconfig.json' - -plugins: - - 'react' - - 'react-hooks' - - '@typescript-eslint' - - 'prettier' - - 'cypress' - -settings: - react: - version: 'detect' - -rules: - # General ESLint rules - 'no-console': 'off' - 'no-debugger': 'warn' - 'no-unused-vars': 'off' - 'no-empty': ['error', { allowEmptyCatch: true }] - 'no-undef': 'off' - 'no-use-before-define': 'off' - 'no-restricted-imports': [ - 'error', - { - paths: [ - { - name: 'react', - importNames: ['default'], - message: "Please import from 'react/jsx-runtime' instead.", - }, - ], - }, - ] - - # React rules - 'react/jsx-uses-react': 'off' - 'react/react-in-jsx-scope': 'off' - 'react/prop-types': 'off' - 'react/display-name': 'off' - 'react-hooks/rules-of-hooks': 'error' - 'react-hooks/exhaustive-deps': 'warn' - - # TypeScript rules - '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }] - '@typescript-eslint/explicit-module-boundary-types': 'off' - '@typescript-eslint/no-empty-interface': 'off' - '@typescript-eslint/no-explicit-any': 'off' - '@typescript-eslint/no-non-null-assertion': 'off' - '@typescript-eslint/ban-types': 'off' - '@typescript-eslint/no-use-before-define': ['error', { functions: false }] - '@typescript-eslint/no-var-requires': 'off' - '@typescript-eslint/explicit-function-return-type': 'off' - '@typescript-eslint/consistent-type-imports': [ - 'error', - { prefer: 'type-imports' }, - ] diff --git a/frontend/.gitattributes b/frontend/.gitattributes new file mode 100644 index 0000000..fd57b60 --- /dev/null +++ b/frontend/.gitattributes @@ -0,0 +1,8 @@ +# Autodetect text files and forces unix eols, so Windows does not break them +* text=auto eol=lf + +# Force images/fonts to be handled as binaries +*.jpg binary +*.jpeg binary +*.gif binary +*.png binary diff --git a/frontend/.gitignore b/frontend/.gitignore index a547bf3..a66531d 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -1,24 +1,66 @@ -# Logs -logs -*.log +# Editor directories and files +.DS_Store +.gradle +.nyc_output +.scannerwork +build +coverage +dist +**/src/formio +**/cypress/**/screenshots +**/cypress/**/videos +node_modules + +# Ignore only top-level package-lock.json +/package-lock.json + + + + +# local env files +local.* +local-*.* +.env.local +.env.*.local +cypress.env.json + +# Log files npm-debug.log* yarn-debug.log* yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -dist-ssr -*.local # Editor directories and files -.vscode/* -!.vscode/extensions.json .idea -.DS_Store +*.iml *.suo *.ntvs* *.njsproj *.sln *.sw? +*.mp4 + +# Visual Studio Code -- generally ignore, but allow shared configuration +.vscode/* +!.vscode/launch.json +!.vscode/tasks.json +!.vscode/README.md + +# temp office files +~$* +*.*.bak + +# bddstack files +build +.settings +*.log +.DS_Store +*.ipr +*.iml +*.iws +.env +.idea +.project + +!app/frontend/.env +!local-infrastructure/.env +.history diff --git a/frontend/.prettierrc.yml b/frontend/.prettierrc.yml deleted file mode 100644 index 0de77c4..0000000 --- a/frontend/.prettierrc.yml +++ /dev/null @@ -1,22 +0,0 @@ -# .prettierrc.yml - -# Use single quotes instead of double quotes -singleQuote: true - -# Use 2 spaces for indentation -tabWidth: 2 - -# Use spaces instead of tabs -useTabs: false - -# Add a trailing comma to the last item in an object or array -trailingComma: 'all' - -# Print semicolons at the ends of statements -semi: false - -# Wrap prose-like comments as-is -proseWrap: 'always' - -# Format files with Unix-style line endings -endOfLine: 'lf' \ No newline at end of file diff --git a/frontend/.tool-versions b/frontend/.tool-versions new file mode 100644 index 0000000..343dc53 --- /dev/null +++ b/frontend/.tool-versions @@ -0,0 +1 @@ +nodejs 18.18.2 diff --git a/frontend/.vscode/extensions.json b/frontend/.vscode/extensions.json deleted file mode 100644 index c0a6e5a..0000000 --- a/frontend/.vscode/extensions.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"] -} diff --git a/frontend/CODE-OF-CONDUCT.md b/frontend/CODE-OF-CONDUCT.md new file mode 100644 index 0000000..6a0014e --- /dev/null +++ b/frontend/CODE-OF-CONDUCT.md @@ -0,0 +1,132 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +- Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +- The use of sexualized language or imagery, and sexual attention or advances of + any kind +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or email address, + without their explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +submit.digital@gov.bc.ca. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/frontend/COMPLIANCE.yaml b/frontend/COMPLIANCE.yaml new file mode 100644 index 0000000..3033f6f --- /dev/null +++ b/frontend/COMPLIANCE.yaml @@ -0,0 +1,11 @@ +name: compliance +description: | + This document is used to track a projects PIA and STRA + compliance. +spec: + - name: PIA + status: COMPLETED + last-updated: "2023-03-17T00:00:00.000Z" + - name: STRA + status: COMPLETED + last-updated: "2023-08-04T00:00:00.000Z" diff --git a/frontend/CONTRIBUTING.md b/frontend/CONTRIBUTING.md new file mode 100644 index 0000000..40bf0c0 --- /dev/null +++ b/frontend/CONTRIBUTING.md @@ -0,0 +1,23 @@ +# How to contribute + +This page describes how to contribute bug fixes and new features. It is a resource for application developers wanting to contribute code changes. + +## Before you begin + +The stability of the CHEFS application is of highest importance. + +- Code changes must not reduce the confidentiality, integrity, or availability of the application +- Please bring your change ideas to the team before starting work +- Contributors must follow the [Code of Conduct](CODE-OF-CONDUCT.md) +- Changes must include test coverage, documentation, and comments +- The repository guardians review all changes and may ask for revisions + +## Contributing code + +Government employees, public and members of the private sector are encouraged to contribute to the repository by **forking and submitting a pull request**. + +(If you are new to GitHub, you might start with a [basic tutorial](https://help.github.com/articles/set-up-git) and check out a more detailed guide to [pull requests](https://help.github.com/articles/using-pull-requests/).) + +All contributors retain the original copyright to their stuff, but by contributing to this project, you grant a world-wide, royalty-free, perpetual, irrevocable, non-exclusive, transferable license to all users **under the terms of the [license](./LICENSE) under which this project is distributed**. + +To set up CHEFS on your workstation, visit the [Developer](https://github.com/bcgov/common-hosted-form-service/wiki/Developer) Wiki page. diff --git a/frontend/Caddyfile b/frontend/Caddyfile deleted file mode 100644 index 2a88e9c..0000000 --- a/frontend/Caddyfile +++ /dev/null @@ -1,45 +0,0 @@ -{ - auto_https off - admin off -} -:3000 { - log { - output stdout - format console { - time_format iso8601 - level_format color - } - level {$LOG_LEVEL} - } - root * /srv - encode zstd gzip - file_server - @spa_router { - not path /api/* - file { - try_files {path} /index.html - } - } - rewrite @spa_router {http.matchers.file.relative} - # Proxy requests to API service - reverse_proxy /api/* {$BACKEND_URL} { - header_up Host {http.reverse_proxy.upstream.hostport} - header_up X-Real-IP {remote_host} - header_up X-Forwarded-For {remote_host} - } - header { - X-Frame-Options "SAMEORIGIN" - X-XSS-Protection "1;mode=block" - Cache-Control "no-store, no-cache, must-revalidate, proxy-revalidate" - X-Content-Type-Options "nosniff" - Strict-Transport-Security "max-age=31536000" - Content-Security-Policy "default-src 'self' https://spt.apps.gov.bc.ca data:; script-src 'self' 'unsafe-eval' https://www2.gov.bc.ca ;style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://use.fontawesome.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data: https://fonts.googleapis.com http://www.w3.org https://*.gov.bc.ca" - Referrer-Policy "same-origin" - Feature-Policy "fullscreen 'self'; camera 'none'; microphone 'none'" - } -} -:3001 { - handle /health { - respond "OK" - } -} diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 8ccde6f..3177917 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,25 +1,17 @@ -# Build static files -# Node Bullseye has npm -FROM node:20.10.0-bullseye-slim AS build +FROM docker.io/node:18.18.2-alpine -# Install packages, build and keep only prod packages -WORKDIR /app -COPY *.json *.ts index.html ./ -COPY ./src ./src -RUN npm ci --ignore-scripts --no-update-notifier --omit=dev && \ - npm run build - -# Deploy container -# Caddy serves static files -FROM caddy:2.7.6-alpine -RUN apk add --no-cache ca-certificates - -# Copy static files and run formatting -COPY --from=build /app/dist /srv -COPY Caddyfile /etc/caddy/Caddyfile -RUN caddy fmt --overwrite /etc/caddy/Caddyfile - -# Ports, health check and non-root user -EXPOSE 3000 3001 -HEALTHCHECK --interval=30s --timeout=3s CMD curl -f http://localhost/:3001/health -USER 1001 +ENV NO_UPDATE_NOTIFIER=true +WORKDIR /opt/app-root/src/app +COPY . /opt/app-root/src +RUN npm run all:ci \ + && npm run all:build \ + && npm run frontend:purge \ + && npm run components:clean \ + && npm run components:purge +EXPOSE 8000 +# Create the /.npm directory and grant access to group 0 to allow npm v9 to work +# See: https://docs.openshift.com/container-platform/4.11/openshift_images/create-images.html#use-uid_create-images +RUN mkdir /.npm +RUN chgrp -R 0 /.npm && \ + chmod -R g=u /.npm +CMD ["npm", "run", "start"] diff --git a/frontend/LICENSE b/frontend/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/frontend/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/frontend/README.md b/frontend/README.md new file mode 100644 index 0000000..30d0507 --- /dev/null +++ b/frontend/README.md @@ -0,0 +1,74 @@ +# Common Hosted Form Service [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE) [![img](https://img.shields.io/badge/Lifecycle-Stable-97ca00)](https://github.com/bcgov/repomountie/blob/master/doc/lifecycle-badges.md) + +![Tests](https://github.com/bcgov/common-hosted-form-service/workflows/Tests/badge.svg) +[![Maintainability](https://api.codeclimate.com/v1/badges/950b1d6c61567a1da227/maintainability)](https://codeclimate.com/github/bcgov/common-hosted-form-service/maintainability) +[![Test Coverage](https://api.codeclimate.com/v1/badges/950b1d6c61567a1da227/test_coverage)](https://codeclimate.com/github/bcgov/common-hosted-form-service/test_coverage) + +Create, edit and publish forms. + +## Directory Structure + + .github/ - PR and Issue templates + .vscode/ - Visual Studio Code's Launcher and Tasks + app/ - Application Root + ├── frontend/ - Frontend Root + │ ├── src/ - Vue.js frontend web application + │ └── tests/ - Vue.js frontend web application tests + ├── src/ - Node.js backend web application + │ ├── db/migrations - data migration scripts + │ ├── docs/ - OpenAPI 3.0 Specification + │ └── forms/ - Models, Controllers, Routes for the forms + └── tests/ - Node.js backend web application tests + components/ - Form.io Custom Components Library + openshift/ - OpenShift-deployment and shared pipeline files + tests/ - External test frameworks + ├── functional/ - Supporting functional tests + │ └── cypress/ - Cypress functional test suite + └── load/ - Supporting load tests + └── load-test/ - Chefs API load test suite + CODE-OF-CONDUCT.md - Code of Conduct + COMPLIANCE.yaml - BCGov PIA/STRA compliance status + CONTRIBUTING.md - Contributing Guidelines + LICENSE - License + SECURITY.md - Security Policy and Reporting + +## Documentation + +- [Application Readme](app/README.md) +- [Frontend Readme](app/frontend/README.md) +- [Openshift Readme](openshift/README.md) +- [Cypress Test Readme](tests/functional/cypress/README.md) +- [CHEFS Load Test Readme](tests/load/load-test/README.md) +- [Devops Tools Setup](https://github.com/bcgov/nr-showcase-devops-tools) +- [Security Reporting](SECURITY.md) +- [Product Roadmap](https://github.com/bcgov/common-hosted-form-service/wiki/Product-Roadmap) + +## Help, Problems, and Feature Requests + +Visit the [CHEFS Wiki](https://github.com/bcgov/common-hosted-form-service/wiki/) for help on using CHEFS. + +To report a problem with CHEFS please create a [GitHub Issue](https://github.com/bcgov/common-hosted-form-service/issues). + +Feature requests can be found in the [CHEFS Feedback](https://chefs-fider.apps.silver.devops.gov.bc.ca/) - vote for a feature you want in CHEFS, or add a new feature that hasn't been requested. + +## How to Contribute + +If you would like to contribute, please see our [contributing](CONTRIBUTING.md) guidelines. + +Please note that this project is released with a [Contributor Code of Conduct](CODE-OF-CONDUCT.md). By participating in this project you agree to abide by its terms. + +## License + + Copyright 2020 Province of British Columbia + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/frontend/SECURITY.md b/frontend/SECURITY.md new file mode 100644 index 0000000..7331f77 --- /dev/null +++ b/frontend/SECURITY.md @@ -0,0 +1,51 @@ +# Security Policies and Procedures + +This document outlines security procedures and general policies for the Common Hosted Form Service (CHEFS) project. + +- [Supported Versions](#supported-versions) +- [Reporting a Bug](#reporting-a-bug) +- [Disclosure Policy](#disclosure-policy) +- [Comments on this Policy](#comments-on-this-policy) + +## Supported Versions + +At this time, only the latest version of Common Hosted Form Service is supported. + +| Version | Supported | +| ------- | ------------------ | +| 1.4.x | :white_check_mark: | +| < 1.4 | :x: | + +## Reporting a Bug + +The `Forminators` team and community take all security bugs in `CHEFS` seriously. +Thank you for improving the security of `CHEFS`. We appreciate your efforts and +responsible disclosure and will make every effort to acknowledge your +contributions. + +Report security bugs by sending an email to . + +The `Forminators` team will acknowledge your email within 48 hours, and will send a +more detailed response within 48 hours indicating the next steps in handling +your report. After the initial reply to your report, the security team will +endeavor to keep you informed of the progress towards a fix and full +announcement, and may ask for additional information or guidance. + +Report security bugs in third-party modules to the person or team maintaining +the module. + +## Disclosure Policy + +When the security team receives a security bug report, they will assign it to a +primary handler. This person will coordinate the fix and release process, +involving the following steps: + +- Confirm the problem and determine the affected versions. +- Audit code to find any potential similar problems. +- Prepare fixes for all releases still under maintenance. These fixes will be + released as fast as possible. + +## Comments on this Policy + +If you have suggestions on how this process could be improved please submit a +pull request. diff --git a/frontend/_config.yml b/frontend/_config.yml new file mode 100644 index 0000000..277f1f2 --- /dev/null +++ b/frontend/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-cayman diff --git a/frontend/app/.editorconfig b/frontend/app/.editorconfig new file mode 100644 index 0000000..fe5cb88 --- /dev/null +++ b/frontend/app/.editorconfig @@ -0,0 +1,19 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.html] +indent_style = space +indent_size = 2 + +[*.{css,js,json,jsx,scss,ts,tsx,vue}] +indent_style = space +indent_size = 2 + +[.{babelrc,eslintrc}] +indent_style = space +indent_size = 2 diff --git a/frontend/app/.eslintignore b/frontend/app/.eslintignore new file mode 100644 index 0000000..eb53114 --- /dev/null +++ b/frontend/app/.eslintignore @@ -0,0 +1,4 @@ +dist +frontend +node_modules +public/js diff --git a/frontend/app/.eslintrc.js b/frontend/app/.eslintrc.js new file mode 100644 index 0000000..9ce52c1 --- /dev/null +++ b/frontend/app/.eslintrc.js @@ -0,0 +1,43 @@ +module.exports = { + root: true, + env: { + browser: true, + commonjs: true, + es6: true, + es2016: true, + es2017: true, + es2018: true, + es2019: true, + es2020: true, + es2021: true, + jest: true, + node: true, + }, + extends: ['eslint:recommended', 'plugin:prettier/recommended'], + plugins: ['prettier'], + globals: { + Atomics: 'readonly', + SharedArrayBuffer: 'readonly', + _: false, + }, + parserOptions: { + ecmaVersion: 12, + sourceType: 'module', + }, + rules: { + 'eol-last': ['error', 'always'], + 'prettier/prettier': 'error', + 'linebreak-style': ['error', 'unix'], + 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'warn', + 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'warn', + semi: ['error', 'always'], + }, + overrides: [ + { + files: ['**/__tests__/*.{j,t}s?(x)', '**/tests/unit/**/*.spec.{j,t}s?(x)'], + env: { + jest: true, + }, + }, + ], +}; diff --git a/frontend/app/.gitignore b/frontend/app/.gitignore new file mode 100644 index 0000000..d593e45 --- /dev/null +++ b/frontend/app/.gitignore @@ -0,0 +1,2 @@ +myfiles +myfiles/* diff --git a/frontend/app/.prettierignore b/frontend/app/.prettierignore new file mode 100644 index 0000000..2b8beb7 --- /dev/null +++ b/frontend/app/.prettierignore @@ -0,0 +1,5 @@ +dist +frontend +node_modules +public/js +src/db/* \ No newline at end of file diff --git a/frontend/app/.prettierrc b/frontend/app/.prettierrc new file mode 100644 index 0000000..8290e95 --- /dev/null +++ b/frontend/app/.prettierrc @@ -0,0 +1,6 @@ +{ + "semi": true, + "singleQuote": true, + "printWidth": 180, + "tabWidth": 2 +} diff --git a/frontend/app/README.md b/frontend/app/README.md new file mode 100644 index 0000000..127ba04 --- /dev/null +++ b/frontend/app/README.md @@ -0,0 +1,60 @@ +# Common Hosted Forms Application + +This node.js app hosts the Common Hosted Forms frontend. + +## Settings + +This app will require some configuration. The API will be locked down and require a valid JWT Token to access. We will need to configure the application to authenticate using the same Keycloak realm as the [frontend](frontend). + +## Super Quickstart + +Ensure that you have filled in all the appropriate configurations shown in [config/custom-environment-variables.json](config/custom-environment-variables.json) before proceeding. +You can configure your **database connection**, **front and back-end paths** and **authentication parameters** as well as **object storage** for file uploads with a local configuration file '/app/config/local.json' or [openshift config maps](../openshift/README.md). + +In general, most of these npm run scripts can be prepended with `all:` in order to run the same operation on both the application and the frontend sequentially. + +### Database Tasks + +Migrate Database + +``` sh +npm run migrate +``` + +Seed Database with Example Data + +``` sh +npm run seed:run +``` + +### Production Build and Run + +``` sh +npm run all:fresh-start +``` + +### Development Run + +``` sh +npm run serve +``` + +Start a new terminal + +``` sh +cd frontend +npm run serve +``` + +### Run application tests + +``` sh +npm run test +``` + +### Lints and fixes application files + +``` sh +npm run lint +npm run lint-fix +``` diff --git a/frontend/app/app.js b/frontend/app/app.js new file mode 100644 index 0000000..096ec3d --- /dev/null +++ b/frontend/app/app.js @@ -0,0 +1,216 @@ +const compression = require('compression'); +const config = require('config'); +const express = require('express'); +const path = require('path'); +const Problem = require('api-problem'); +const querystring = require('querystring'); + +const keycloak = require('./src/components/keycloak'); +const log = require('./src/components/log')(module.filename); +const httpLogger = require('./src/components/log').httpLogger; +const v1Router = require('./src/routes/v1'); + +const DataConnection = require('./src/db/dataConnection'); +const dataConnection = new DataConnection(); +const apiRouter = express.Router(); +const state = { + connections: { + data: false, + }, + ready: false, + shutdown: false, +}; +let probeId; +const app = express(); +app.use(compression()); +app.use(express.json({ limit: config.get('server.bodyLimit') })); +app.use(express.urlencoded({ extended: true })); + +// Skip if running tests +if (process.env.NODE_ENV !== 'test') { + // Initialize connections and exit if unsuccessful + initializeConnections(); + app.use(httpLogger); +} + +// Use Keycloak OIDC Middleware +app.use(keycloak.middleware()); + +// Block requests until service is ready +app.use((_req, res, next) => { + if (state.shutdown) { + new Problem(503, { details: 'Server is shutting down' }).send(res); + } else if (!state.ready) { + new Problem(503, { details: 'Server is not ready' }).send(res); + } else { + next(); + } +}); + +// Frontend configuration endpoint +apiRouter.use('/config', (_req, res, next) => { + try { + const frontend = config.get('frontend'); + // we will need to pass + const uploads = config.get('files.uploads'); + const feConfig = { ...frontend, uploads: uploads }; + res.status(200).json(feConfig); + } catch (err) { + next(err); + } +}); + +// Base API Directory +apiRouter.get('/api', (_req, res) => { + if (state.shutdown) { + throw new Error('Server shutting down'); + } else { + res.status(200).json('ok'); + } +}); + +// Host API endpoints +apiRouter.use(config.get('server.apiPath'), v1Router); +app.use(config.get('server.basePath'), apiRouter); + +// Host the static frontend assets +const staticFilesPath = config.get('frontend.basePath'); +app.use('/favicon.ico', (_req, res) => { + res.redirect(`${staticFilesPath}/favicon.ico`); +}); +app.use(staticFilesPath, express.static(path.join(__dirname, 'frontend/dist'))); + +// Handle 500 +// eslint-disable-next-line no-unused-vars +app.use((err, _req, res, _next) => { + if (err.stack) { + log.error(err); + } + + if (err instanceof Problem) { + // Attempt to reset DB connection if 5xx error + if (err.status >= 500 && !state.shutdown) dataConnection.resetConnection(); + err.send(res, null); + } else { + // Attempt to reset DB connection + if (!state.shutdown) dataConnection.resetConnection(); + new Problem(500, 'Server Error', { + detail: err.message ? err.message : err, + }).send(res); + } +}); + +// Handle 404 +app.use((req, res) => { + if (req.originalUrl.startsWith(`${config.get('server.basePath')}/api`)) { + // Return a 404 problem if attempting to access API + new Problem(404, 'Page Not Found', { + detail: req.originalUrl, + }).send(res); + } else { + // Redirect any non-API requests to static frontend with redirect breadcrumb + const query = querystring.stringify({ ...req.query, r: req.path }); + res.redirect(`${staticFilesPath}/?${query}`); + } +}); + +// Prevent unhandled errors from crashing application +process.on('unhandledRejection', (err) => { + if (err && err.stack) { + log.error(err); + } +}); + +// Graceful shutdown support +process.on('SIGTERM', shutdown); +process.on('SIGINT', shutdown); +process.on('SIGUSR1', shutdown); +process.on('SIGUSR2', shutdown); +process.on('exit', () => { + log.info('Exiting...'); +}); + +/** + * @function shutdown + * Shuts down this application after at least 3 seconds. + */ +function shutdown() { + log.info('Received kill signal. Shutting down...'); + // Wait 3 seconds before starting cleanup + if (!state.shutdown) setTimeout(cleanup, 3000); +} + +/** + * @function cleanup + * Cleans up connections in this application. + */ +function cleanup() { + log.info('Service no longer accepting traffic', { function: 'cleanup' }); + state.shutdown = true; + + log.info('Cleaning up...', { function: 'cleanup' }); + clearInterval(probeId); + + dataConnection.close(() => process.exit()); + + // Wait 10 seconds max before hard exiting + setTimeout(() => process.exit(), 10000); +} + +/** + * @function initializeConnections + * Initializes the database connections + * This will force the application to exit if it fails + */ +function initializeConnections() { + // Initialize connections and exit if unsuccessful + const tasks = [dataConnection.checkAll()]; + + Promise.all(tasks) + .then((results) => { + state.connections.data = results[0]; + + if (state.connections.data) log.info('DataConnection Reachable', { function: 'initializeConnections' }); + }) + .catch((error) => { + log.error(`Initialization failed: Database OK = ${state.connections.data}`, { function: 'initializeConnections' }); + log.error('Connection initialization failure', error.message, { function: 'initializeConnections' }); + if (!state.ready) { + process.exitCode = 1; + shutdown(); + } + }) + .finally(() => { + state.ready = Object.values(state.connections).every((x) => x); + if (state.ready) { + log.info('Service ready to accept traffic', { function: 'initializeConnections' }); + // Start periodic 10 second connection probe check + probeId = setInterval(checkConnections, 10000); + } + }); +} + +/** + * @function checkConnections + * Checks Database connectivity + * This will force the application to exit if a connection fails + */ +function checkConnections() { + const wasReady = state.ready; + if (!state.shutdown) { + const tasks = [dataConnection.checkConnection()]; + + Promise.all(tasks).then((results) => { + state.connections.data = results[0]; + state.ready = Object.values(state.connections).every((x) => x); + if (!wasReady && state.ready) log.info('Service ready to accept traffic', { function: 'checkConnections' }); + log.verbose(state); + if (!state.ready) { + process.exitCode = 1; + shutdown(); + } + }); + } +} + +module.exports = app; diff --git a/frontend/app/config/custom-environment-variables.json b/frontend/app/config/custom-environment-variables.json new file mode 100644 index 0000000..ca03470 --- /dev/null +++ b/frontend/app/config/custom-environment-variables.json @@ -0,0 +1,72 @@ +{ + "db": { + "database": "DB_DATABASE", + "host": "DB_HOST", + "password": "DB_PASSWORD", + "port": "DB_PORT", + "username": "DB_USERNAME" + }, + "files": { + "uploads": { + "dir": "FILES_UPLOADS_DIR", + "enabled": "FILES_UPLOADS_ENABLED", + "fileCount": "FILES_UPLOADS_FILECOUNT", + "fileKey": "FILES_UPLOADS_FILEKEY", + "fileMaxSize": "FILES_UPLOADS_FILEMAXSIZE", + "fileMinSize": "FILES_UPLOADS_FILEMINSIZE", + "path": "FILES_UPLOADS_PATH" + }, + "permanent": "FILES_PERMANENT", + "localStorage": { + "path": "FILES_LOCALSTORAGE_PATH" + }, + "objectStorage": { + "accessKeyId": "FILES_OBJECTSTORAGE_ACCESSKEYID", + "bucket": "FILES_OBJECTSTORAGE_BUCKET", + "endpoint": "FILES_OBJECTSTORAGE_ENDPOINT", + "key": "FILES_OBJECTSTORAGE_KEY", + "secretAccessKey": "FILES_OBJECTSTORAGE_SECRETACCESSKEY" + } + }, + "frontend": { + "adminDashboardUrl": "VITE_ADMIN_DASHBOARD_URL", + "apiPath": "FRONTEND_APIPATH", + "basePath": "VITE_FRONTEND_BASEPATH", + "keycloak": { + "clientId": "FRONTEND_KC_CLIENTID", + "realm": "FRONTEND_KC_REALM", + "serverUrl": "FRONTEND_KC_SERVERURL" + } + }, + "server": { + "apiPath": "SERVER_APIPATH", + "basePath": "SERVER_BASEPATH", + "bodyLimit": "SERVER_BODYLIMIT", + "keycloak": { + "clientId": "SERVER_KC_CLIENTID", + "clientSecret": "SERVER_KC_CLIENTSECRET", + "publicKey": "SERVER_KC_PUBLICKEY", + "realm": "SERVER_KC_REALM", + "serverUrl": "SERVER_KC_SERVERURL" + }, + "logFile": "SERVER_LOGFILE", + "logLevel": "SERVER_LOGLEVEL", + "port": "SERVER_PORT" + }, + "serviceClient": { + "commonServices": { + "ches": { + "endpoint": "SC_CS_CHES_ENDPOINT", + "tokenEndpoint": "SC_CS_CHES_TOKEN_ENDPOINT", + "clientId": "SC_CS_CHES_CLIENT_ID", + "clientSecret": "SC_CS_CHES_CLIENT_SECRET" + }, + "cdogs": { + "endpoint": "SC_CS_CDOGS_ENDPOINT", + "tokenEndpoint": "SC_CS_CDOGS_TOKEN_ENDPOINT", + "clientId": "SC_CS_CDOGS_CLIENT_ID", + "clientSecret": "SC_CS_CDOGS_CLIENT_SECRET" + } + } + } +} diff --git a/frontend/app/config/default.json b/frontend/app/config/default.json new file mode 100644 index 0000000..97491f8 --- /dev/null +++ b/frontend/app/config/default.json @@ -0,0 +1,88 @@ +{ + "db": { + "database": "chefs", + "host": "localhost", + "port": "5432", + "username": "app" + }, + "files": { + "uploads": { + "enabled": "true", + "fileCount": "1", + "fileKey": "files", + "fileMaxSize": "25MB", + "fileMaxSizeBytes": "25000000", + "fileMinSize": "0KB", + "path": "files" + }, + "permanent": "objectStorage", + "localStorage": { + "path": "" + }, + "objectStorage": { + "accessKeyId": "bcgov-citz-ccft", + "bucket": "chefs", + "endpoint": "https://commonservices.objectstore.gov.bc.ca", + "key": "chefs/dev/" + } + }, + "frontend": { + "adminDashboardUrl": "", + "apiPath": "api/v1", + "basePath": "/app", + "keycloak": { + "clientId": "chefs-frontend", + "realm": "chefs", + "serverUrl": "https://dev.loginproxy.gov.bc.ca/auth" + } + }, + "server": { + "apiPath": "/api/v1", + "basePath": "/app", + "bodyLimit": "30mb", + "keycloak": { + "clientId": "chefs", + "realm": "chefs", + "serverUrl": "https://dev.loginproxy.gov.bc.ca/auth" + }, + "logLevel": "http", + "port": "8080", + "rateLimit": { + "public": { + "windowMs": "60000", + "max": "60" + } + } + }, + "serviceClient": { + "commonServices": { + "ches": { + "endpoint": "https://ches-dev.api.gov.bc.ca/api", + "tokenEndpoint": "https://dev.loginproxy.gov.bc.ca/auth/realms/comsvcauth/protocol/openid-connect/token", + "clientId": "CHES_CLIENT_ID", + "clientSecret": "CHES_CLIENT_SECRET" + }, + "cdogs": { + "endpoint": "https://cdogs-dev.api.gov.bc.ca/api", + "tokenEndpoint": "https://dev.loginproxy.gov.bc.ca/auth/realms/comsvcauth/protocol/openid-connect/token", + "clientId": "CDOGS_CLIENT_ID", + "clientSecret": "CDOGS_CLIENT_SECRET" + } + } + }, + "customBcAddressFormioComponent": { + "apikey": "xxxxxxxxxxxxxxx", + "bcAddressURL": "https://geocoder.api.gov.bc.ca/addresses.json", + "queryParameters": { + "echo": false, + "brief": true, + "minScore": 55, + "onlyCivic": true, + "maxResults": 15, + "autocomplete": true, + "matchAccuracy": 100, + "matchPrecision": "occupant, unit, site, civic_number, intersection, block, street, locality, province", + "precisionPoints": 100 + } + } +} diff --git a/frontend/app/config/production.json b/frontend/app/config/production.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/frontend/app/config/production.json @@ -0,0 +1 @@ +{} diff --git a/frontend/app/config/test.json b/frontend/app/config/test.json new file mode 100644 index 0000000..23510c2 --- /dev/null +++ b/frontend/app/config/test.json @@ -0,0 +1,40 @@ +{ + "db": { + "username": "username", + "password": "password" + }, + "files": { + "uploads": { + "enabled": "true", + "fileCount": "1", + "fileKey": "files", + "fileMaxSize": "1MB", + "fileMinSize": "0KB", + "path": "files" + }, + "permanent": "localStorage", + "localStorage" : { + "path": "" + }, + "objectStorage": { + "accessKeyId": "nr-iit-showcase", + "bucket": "egejyy", + "endpoint": "https://nrs.objectstore.gov.bc.ca", + "key": "chefs/dev/", + "secretAccessKey": "THIS_IS_NOT_A_KEY" + } + }, + "server": { + "emailRecipients": "foo@bar.com,baz@boo.com", + "keycloak": { + "clientSecret": "password" + }, + "logLevel": "silent" + }, + "serviceClient": { + "commonServices": { + "username": "username", + "password": "password" + } + } +} diff --git a/frontend/app/frontend/.browserslistrc b/frontend/app/frontend/.browserslistrc new file mode 100644 index 0000000..9dee646 --- /dev/null +++ b/frontend/app/frontend/.browserslistrc @@ -0,0 +1,3 @@ +> 1% +last 2 versions +not ie <= 8 diff --git a/frontend/app/frontend/.eslintignore b/frontend/app/frontend/.eslintignore new file mode 100644 index 0000000..28445e1 --- /dev/null +++ b/frontend/app/frontend/.eslintignore @@ -0,0 +1,6 @@ +coverage +dist +node_modules +public/js +src/formio +tests \ No newline at end of file diff --git a/frontend/app/frontend/.eslintrc.cjs b/frontend/app/frontend/.eslintrc.cjs new file mode 100644 index 0000000..6c65c59 --- /dev/null +++ b/frontend/app/frontend/.eslintrc.cjs @@ -0,0 +1,79 @@ +module.exports = { + root: true, + env: { + browser: true, + commonjs: true, + es6: true, + jest: true, + node: true, + }, + extends: [ + 'eslint:recommended', + 'plugin:vue/vue3-recommended', + 'eslint-config-prettier', + 'plugin:prettier/recommended', + 'plugin:vuetify/base', + ], + plugins: ['vuetify', 'prettier'], + globals: { + Atomics: 'readonly', + SharedArrayBuffer: 'readonly', + _: false, + }, + parserOptions: { + sourceType: 'module', + ecmaVersion: 2020, + }, + rules: { + 'prettier/prettier': 'error', + 'no-unused-vars': ['error', { argsIgnorePattern: '^_' }], + 'eol-last': ['error', 'always'], + 'linebreak-style': ['error', 'unix'], + 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'warn', + 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'warn', + semi: ['error', 'always'], + 'vue/html-closing-bracket-newline': [ + 'off', + { + singleline: 'never', + multiline: 'never', + }, + ], + 'vue/max-attributes-per-line': [ + 'off', + { + singleline: 1, + multiline: { + max: 1, + allowFirstLine: true, + }, + }, + ], + 'vue/multi-word-component-names': 'off', + 'vue/no-multi-spaces': [ + 'error', + { + ignoreProperties: false, + }, + ], + 'vue/no-spaces-around-equal-signs-in-attribute': ['error'], + 'vuetify/no-deprecated-classes': 'error', + 'vuetify/grid-unknown-attributes': 'error', + /* This needs to be removed during testing, we need it in production to ignore the v-data-table + but there may be more Vuetify components that are deprecated or in labs */ + 'vuetify/no-deprecated-components': 'off', + 'vue/v-on-event-hyphenation': 'off', + 'vue/no-v-html': 'off', + }, + overrides: [ + { + files: [ + '**/__tests__/*.{j,t}s?(x)', + '**/tests/unit/**/*.spec.{j,t}s?(x)', + ], + env: { + jest: true, + }, + }, + ], +}; diff --git a/frontend/app/frontend/.gitignore b/frontend/app/frontend/.gitignore new file mode 100644 index 0000000..57a089e --- /dev/null +++ b/frontend/app/frontend/.gitignore @@ -0,0 +1,29 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +.env +.env.development +.env.production +.env* +.vscode \ No newline at end of file diff --git a/frontend/app/frontend/.prettierignore b/frontend/app/frontend/.prettierignore new file mode 100644 index 0000000..3598c30 --- /dev/null +++ b/frontend/app/frontend/.prettierignore @@ -0,0 +1 @@ +tests \ No newline at end of file diff --git a/frontend/app/frontend/.prettierrc b/frontend/app/frontend/.prettierrc new file mode 100644 index 0000000..a4538ba --- /dev/null +++ b/frontend/app/frontend/.prettierrc @@ -0,0 +1,5 @@ +{ + "semi": true, + "singleQuote": true, + "printWidth": 80 +} diff --git a/frontend/app/frontend/LICENSE b/frontend/app/frontend/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/frontend/app/frontend/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/frontend/app/frontend/README.md b/frontend/app/frontend/README.md new file mode 100644 index 0000000..f3d9227 --- /dev/null +++ b/frontend/app/frontend/README.md @@ -0,0 +1,57 @@ +# CHEFS Frontend + +This is the CHEFS frontend. It implements a Vue frontend with Keycloak authentication support. + +## Configuration + +The CHEFS frontend will require some configuration. The API it invokes will be locked down and require a valid JWT Token to access. We will need to configure the application to authenticate using the same Keycloak realm as the [app](../). Note that the Vue Skeleton frontend is currently designed to expect all associated resources to be relative to the original access path. + +## Super Quickstart + +Ensure that you have filled in all the appropriate configurations following [../config/custom-environment-variables.json](../config/custom-environment-variables.json) before proceeding. Other environment variables such as the app title and contact information must be configured using the Vue environment files [.env](.env), [.env.development](.env.development), [.env.test](.env.test). + +Entries in the JSON file are deployed with the application. Entries in the .env files are per-environment. + +### Required .env variables + +| Name | Description | Example | +| ------------------------- | --------------------------------- | --------------------------- | +| VITE_TITLE | The application title | Common Hosted Forms Service | +| VITE_CONTACT | Contact information such as email | submit.digital@gov.bc.ca | +| VITE_FRONTEND_BASEPATH | The path to the Vue application | /app | +| VITE_CHEFSTOURURL | The URL to the CHEFS tour video | https://www.youtube.com/embed/obOhyYusMjM | +| VITE_HOWTOURL | The URL to the CHEFS how to video | https://www.youtube.com/playlist?list=PL9CV_8JBQHirsQAShw45PZeU1CkU88Q53 | + +### Project setup + +```sh +npm install +``` + +### Compiles and hot-reloads for development + +```sh +npm run serve +``` + +### Compiles and minifies for production + +```sh +npm run build +``` + +### Run your unit tests + +```sh +npm run test:unit +``` + +### Lints and fixes files + +```sh +npm run lint +``` + +### Customize configuration + +See [Configuration Reference](https://cli.vuejs.org/config/). diff --git a/frontend/app/frontend/component-update.js b/frontend/app/frontend/component-update.js new file mode 100644 index 0000000..80020a4 --- /dev/null +++ b/frontend/app/frontend/component-update.js @@ -0,0 +1,163 @@ +// This script attempts to gracefully rebuild and update @bcgov/formio if necessary +const fs = require('fs'); +const path = require('path'); + +const COMPONENTS_DIR = '../../components'; +const FORMIO_DIR = 'src/formio'; +const TITLE = '@bcgov/formio'; + +try { + const args = process.argv.slice(2); + switch (args[0]) { + case 'build': + buildComponents(); + break; + case 'clean': + cleanComponents(); + break; + case 'deploy': + deployComponents(); + break; + case 'purge': + console.log(`Purging "${FORMIO_DIR}"...`); // eslint-disable-line no-console + if (fs.existsSync(FORMIO_DIR)) fs.rmSync(FORMIO_DIR, { recursive: true }); + break; + default: + if (!fs.existsSync(FORMIO_DIR) || !fs.readdirSync(FORMIO_DIR).length) { + console.log(`${TITLE} not found under "${FORMIO_DIR}"`); // eslint-disable-line no-console + buildComponents(); + deployComponents(); + } else if ( + fs.statSync(FORMIO_DIR).mtime < fs.statSync(COMPONENTS_DIR).mtime + ) { + console.log(`${TITLE} "${COMPONENTS_DIR}" directory has been modified`); // eslint-disable-line no-console + buildComponents(); + deployComponents(); + } else { + console.log(`${TITLE} is present and up to date`); // eslint-disable-line no-console + } + } +} catch (err) { + console.error(err.message); // eslint-disable-line no-console + console.log(`An error occured while managing ${TITLE}`); // eslint-disable-line no-console + process.exit(1); +} + +// +// Task Functions +// + +/** + * @function buildComponents + * @description Rebuild `@bcgov/formio` library + */ +function buildComponents() { + if (!fs.existsSync(`${COMPONENTS_DIR}/node_modules`)) { + console.warn(`${TITLE} missing dependencies. Reinstalling...`); // eslint-disable-line no-console + runSync('npm ci', COMPONENTS_DIR); + } + console.log(`Rebuilding ${TITLE}...`); // eslint-disable-line no-console + runSync('npm run build', COMPONENTS_DIR); + console.log(`${TITLE} has been rebuilt`); // eslint-disable-line no-console +} + +/** + * @function cleanComponents + * @description Clean `@bcgov/formio` library directory + */ +function cleanComponents() { + console.log(`Cleaning ${TITLE}...`); // eslint-disable-line no-console + if (fs.existsSync(`${COMPONENTS_DIR}/coverage`)) + fs.rmSync(`${COMPONENTS_DIR}/coverage`, { recursive: true }); + if (fs.existsSync(`${COMPONENTS_DIR}/dist`)) + fs.rmSync(`${COMPONENTS_DIR}/dist`, { recursive: true }); + if (fs.existsSync(`${COMPONENTS_DIR}/lib`)) + fs.rmSync(`${COMPONENTS_DIR}/lib`, { recursive: true }); + console.log(`${TITLE} has been cleaned`); // eslint-disable-line no-console +} + +/** + * @function deployComponents + * @description Redeploy `@bcgov/formio` library + */ +function deployComponents() { + console.log(`Redeploying ${TITLE}...`); // eslint-disable-line no-console + if (fs.existsSync(FORMIO_DIR)) fs.rmSync(FORMIO_DIR, { recursive: true }); + copyDirRecursiveSync(`${COMPONENTS_DIR}/lib`, FORMIO_DIR); + console.log(`${TITLE} has been redeployed`); // eslint-disable-line no-console +} + +// +// Helper Functions +// + +/** + * @function runSync + * @description Execute a single shell command where `cmd` is a string + * @param {string} cmd Shell command to run + * @param {string} [cwd] Working directory of the command to run + */ +function runSync(cmd, cwd = undefined) { + const { spawnSync } = require('child_process'); + const parts = cmd.split(/\s+/g); + const opts = { stdio: 'inherit', shell: true }; + if (cwd) opts.cwd = cwd; + + const p = spawnSync(parts[0], parts.slice(1), opts); + if (p.status) { + throw new Error(`Command "${cmd}" exited with status code "${p.status}"`); + } + if (p.signal) { + throw new Error(`Command "${cmd}" exited with signal "${p.signal}"`); + } +} + +/** + * @function copyFileSync + * @description Copies `source` file to `target` file + * @param {string} source Source file location + * @param {string} target Target file location + */ +function copyFileSync(source, target) { + let targetFile = target; + + // If target is a directory, a new file with the same name will be created + if (fs.existsSync(target)) { + if (fs.lstatSync(target).isDirectory()) { + targetFile = path.join(target, path.basename(source)); + } + } + + fs.writeFileSync(targetFile, fs.readFileSync(source)); +} + +/** + * @function copyDirRecursiveSync + * @description Recursively copies `source` directory contents to `target` directory + * @param {string} source Source directory location + * @param {string} target Target directory location + */ +function copyDirRecursiveSync(source, target) { + let files = []; + + // Check if folder needs to be created or integrated + const targetFolder = path.join(target, path.basename(source)); + if (!fs.existsSync(targetFolder)) { + fs.mkdirSync(targetFolder, { recursive: true }); + } + + // Copy + if (fs.lstatSync(source).isDirectory()) { + files = fs.readdirSync(source); + files.forEach((file) => { + const curSource = path.join(source, file); + if (fs.lstatSync(curSource).isDirectory()) { + copyDirRecursiveSync(curSource, targetFolder); + } else { + copyFileSync(curSource, targetFolder); + } + }); + } +} + +module.exports = { runSync, copyFileSync, copyDirRecursiveSync }; diff --git a/frontend/app/frontend/index.html b/frontend/app/frontend/index.html new file mode 100644 index 0000000..9aa04bb --- /dev/null +++ b/frontend/app/frontend/index.html @@ -0,0 +1,22 @@ + + + + + + + + Common Hosted Forms Service + + + + + +
+ + + diff --git a/frontend/app/frontend/jsconfig.json b/frontend/app/frontend/jsconfig.json new file mode 100644 index 0000000..8bdfb15 --- /dev/null +++ b/frontend/app/frontend/jsconfig.json @@ -0,0 +1,3 @@ +{ + "allowJs": true +} diff --git a/frontend/app/frontend/package-lock.json b/frontend/app/frontend/package-lock.json new file mode 100644 index 0000000..c52bd9d --- /dev/null +++ b/frontend/app/frontend/package-lock.json @@ -0,0 +1,5493 @@ +{ + "name": "common-hosted-form-service-frontend", + "version": "1.5.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "common-hosted-form-service-frontend", + "version": "1.5.0", + "license": "Apache-2.0", + "dependencies": { + "@bcgov/bc-sans": "^1.0.1", + "@formio/vue": "github:formio/vue#v5.0.0-rc.2", + "@fortawesome/fontawesome-svg-core": "^6.4.2", + "@fortawesome/free-solid-svg-icons": "^6.4.2", + "@fortawesome/vue-fontawesome": "^3.0.3", + "axios": "^1.4.0", + "bootstrap-scss": "^5.3.1", + "crypto-js": "^4.1.1", + "fast-json-patch": "^3.1.1", + "font-awesome": "^4.7.0", + "formiojs": "^4.14.13", + "keycloak-js": "^21.1.1", + "lodash": "^4.17.21", + "mitt": "^3.0.0", + "moment": "^2.29.4", + "nprogress": "^0.2.0", + "pinia": "^2.1.4", + "qrcode.vue": "^3.4.0", + "uuid": "^9.0.0", + "vue": "^3.3.4", + "vue-i18n": "^9.2.2", + "vue-json-pretty": "^2.2.4", + "vue-router": "^4.2.2", + "vue3-clipboard": "^1.0.0", + "vuetify": "^3.3.11" + }, + "devDependencies": { + "@mdi/font": "^7.2.96", + "@pinia/testing": "^0.1.2", + "@vitejs/plugin-vue": "^4.1.0", + "@vitest/coverage-v8": "^0.32.0", + "@vue/test-utils": "^2.3.2", + "axios-mock-adapter": "^1.21.5", + "eslint": "^8.40.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-vue": "^9.13.0", + "eslint-plugin-vuetify": "^2.0.0-beta.4", + "happy-dom": "^9.20.3", + "jsdom": "^22.1.0", + "prettier": "^2.8.8", + "sass": "^1.62.1", + "terser": "^5.17.4", + "vite": "^4.3.2", + "vite-plugin-eslint": "^1.8.1", + "vite-plugin-vuetify": "^1.0.2", + "vitest": "^0.32.2" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.5.tgz", + "integrity": "sha512-DFZMC9LJUG9PLOclRC32G63UXwzqS2koQC8dkx+PLdmt1xSePYpbT/NbsrJy8Q/muXz7o/h/d4A7Fuyixm559Q==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.5.tgz", + "integrity": "sha512-ecjvYlnAaZ/KVneE/OdKYBYfgXV3Ptu6zQWmgEF7vwKhQnvVS6bjMD2XYgj+SNvQ1GfK/pjgokfPkC/2CO8CuA==", + "dependencies": { + "regenerator-runtime": "^0.13.11" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcgov/bc-sans": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@bcgov/bc-sans/-/bc-sans-1.0.1.tgz", + "integrity": "sha512-4suRUBFeHcuFkwXXJu9pKJNB5Z2G3bpuLEHIq203KVCKC8KrsnqvsyUOf645TypgLwqOTOYCETiXYzfxF4gLAw==" + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "node_modules/@esbuild/android-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", + "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", + "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", + "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", + "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", + "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", + "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", + "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", + "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", + "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", + "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", + "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", + "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", + "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", + "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", + "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", + "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", + "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", + "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", + "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", + "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", + "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", + "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", + "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", + "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.5.2", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.43.0.tgz", + "integrity": "sha512-s2UHCoiXfxMvmfzqoN+vrQ84ahUSYde9qNO1MdxmoEhyHWsfmwOpFlwYV+ePJEVc7gFnATGUi376WowX1N7tFg==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@formio/bootstrap3": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/@formio/bootstrap3/-/bootstrap3-2.12.2.tgz", + "integrity": "sha512-Y1WD/U22HHKRl1MzUt65bXeFHYO9Wlt+wefRqXFrOhIgbmkfTjCx6e0n2b8t/IYz9FUMg+/GTKdqaBrTZgjrTA==", + "dependencies": { + "resize-observer-polyfill": "^1.5.1" + } + }, + "node_modules/@formio/choices.js": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@formio/choices.js/-/choices.js-9.0.1.tgz", + "integrity": "sha512-+JQRWH0yhaeemVJGE1L4oPe9KPFhipzDlms3Pd31gePXpy8q7Mf3Is54/f0fc88+mWeMjK4GyIhcKIKmuGx5Xw==", + "dependencies": { + "deepmerge": "^4.2.0", + "fuse.js": "^3.4.5", + "redux": "^4.0.4" + } + }, + "node_modules/@formio/semantic": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@formio/semantic/-/semantic-2.6.0.tgz", + "integrity": "sha512-RwMEVXkyz+B6RivflrrKIqvvnGR/eZDLQs74u67StcrzO6n3/5D2J8XqTQRSUzQzr5QV6Wq0eZ51z/+mGm6THw==" + }, + "node_modules/@formio/text-mask-addons": { + "version": "3.8.0-formio.2", + "resolved": "https://registry.npmjs.org/@formio/text-mask-addons/-/text-mask-addons-3.8.0-formio.2.tgz", + "integrity": "sha512-H4Sm+1Sx59jbrlKxtKbzethhp5OIcP8Oi4JBpsvH/SB8P/KCRmtjKbN5ACqURnXmYtBHLJC6Yr9KZibOVRGxpA==" + }, + "node_modules/@formio/vanilla-text-mask": { + "version": "5.1.1-formio.1", + "resolved": "https://registry.npmjs.org/@formio/vanilla-text-mask/-/vanilla-text-mask-5.1.1-formio.1.tgz", + "integrity": "sha512-rYBlvIPMNUd6sAaduOaiIwI4vfTAjHDRonko2qJn2RP1O//TQ7rcFIPYVYePJZ4OtOpwHiHAvAIh79McphZotQ==" + }, + "node_modules/@formio/vue": { + "version": "5.0.0-rc.2", + "resolved": "git+ssh://git@github.com/formio/vue.git#82bdecc878cbe00614765ecc84ee78ab1be06b8e", + "license": "MIT", + "peerDependencies": { + "formiojs": "^4.14.9", + "vue": "^3.0.9" + } + }, + "node_modules/@fortawesome/fontawesome-common-types": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.2.tgz", + "integrity": "sha512-1DgP7f+XQIJbLFCTX1V2QnxVmpLdKdzzo2k8EmvDOePfchaIGQ9eCHj2up3/jNEbZuBqel5OxiaOJf37TWauRA==", + "hasInstallScript": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/fontawesome-svg-core": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.4.2.tgz", + "integrity": "sha512-gjYDSKv3TrM2sLTOKBc5rH9ckje8Wrwgx1CxAPbN5N3Fm4prfi7NsJVWd1jklp7i5uSCVwhZS5qlhMXqLrpAIg==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.4.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-solid-svg-icons": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.4.2.tgz", + "integrity": "sha512-sYwXurXUEQS32fZz9hVCUUv/xu49PEJEyUOsA51l6PU/qVgfbTb2glsTEaJngVVT8VqBATRIdh7XVgV1JF1LkA==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.4.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/vue-fontawesome": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@fortawesome/vue-fontawesome/-/vue-fontawesome-3.0.3.tgz", + "integrity": "sha512-KCPHi9QemVXGMrfuwf3nNnNo129resAIQWut9QTAMXmXqL2ErABC6ohd2yY5Ipq0CLWNbKHk8TMdTXL/Zf3ZhA==", + "peerDependencies": { + "@fortawesome/fontawesome-svg-core": "~1 || ~6", + "vue": ">= 3.0.0 < 4" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", + "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@intlify/core-base": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-9.2.2.tgz", + "integrity": "sha512-JjUpQtNfn+joMbrXvpR4hTF8iJQ2sEFzzK3KIESOx+f+uwIjgw20igOyaIdhfsVVBCds8ZM64MoeNSx+PHQMkA==", + "dependencies": { + "@intlify/devtools-if": "9.2.2", + "@intlify/message-compiler": "9.2.2", + "@intlify/shared": "9.2.2", + "@intlify/vue-devtools": "9.2.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@intlify/devtools-if": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@intlify/devtools-if/-/devtools-if-9.2.2.tgz", + "integrity": "sha512-4ttr/FNO29w+kBbU7HZ/U0Lzuh2cRDhP8UlWOtV9ERcjHzuyXVZmjyleESK6eVP60tGC9QtQW9yZE+JeRhDHkg==", + "dependencies": { + "@intlify/shared": "9.2.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@intlify/message-compiler": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.2.2.tgz", + "integrity": "sha512-IUrQW7byAKN2fMBe8z6sK6riG1pue95e5jfokn8hA5Q3Bqy4MBJ5lJAofUsawQJYHeoPJ7svMDyBaVJ4d0GTtA==", + "dependencies": { + "@intlify/shared": "9.2.2", + "source-map": "0.6.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@intlify/shared": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.2.2.tgz", + "integrity": "sha512-wRwTpsslgZS5HNyM7uDQYZtxnbI12aGiBZURX3BTR9RFIKKRWpllTsgzHWvj3HKm3Y2Sh5LPC1r0PDCKEhVn9Q==", + "engines": { + "node": ">= 14" + } + }, + "node_modules/@intlify/vue-devtools": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/@intlify/vue-devtools/-/vue-devtools-9.2.2.tgz", + "integrity": "sha512-+dUyqyCHWHb/UcvY1MlIpO87munedm3Gn6E9WWYdWrMuYLcoIoOEVDWSS8xSwtlPU+kA+MEQTP6Q1iI/ocusJg==", + "dependencies": { + "@intlify/core-base": "9.2.2", + "@intlify/shared": "9.2.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.3.tgz", + "integrity": "sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", + "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@mdi/font": { + "version": "7.2.96", + "resolved": "https://registry.npmjs.org/@mdi/font/-/font-7.2.96.tgz", + "integrity": "sha512-e//lmkmpFUMZKhmCY9zdjRe4zNXfbOIJnn6xveHbaV2kSw5aJ5dLXUxcRt1Gxfi7ZYpFLUWlkG2MGSFAiqAu7w==", + "dev": true + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pinia/testing": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@pinia/testing/-/testing-0.1.2.tgz", + "integrity": "sha512-8EyBaVFtv682tBiF810u81vAJ1ykwnaldkVDU52oqtVbh5FUj5dSCSM9+MtRM/tZkq0AulwMK4BnBktqwsnEnw==", + "dev": true, + "dependencies": { + "vue-demi": ">=0.14.5" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "pinia": ">=2.1.2" + } + }, + "node_modules/@pinia/testing/node_modules/vue-demi": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.5.tgz", + "integrity": "sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA==", + "dev": true, + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", + "integrity": "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==", + "dev": true, + "dependencies": { + "estree-walker": "^2.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/@sphinxxxx/color-conversion": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@sphinxxxx/color-conversion/-/color-conversion-2.2.2.tgz", + "integrity": "sha512-XExJS3cLqgrmNBIP3bBw6+1oQ1ksGjFh0+oClDKFYpCCqx/hlqwWO5KO/S63fzUo67SxI9dMrF0y5T/Ey7h8Zw==" + }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@types/chai": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz", + "integrity": "sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==", + "dev": true + }, + "node_modules/@types/chai-subset": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@types/chai-subset/-/chai-subset-1.3.3.tgz", + "integrity": "sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==", + "dev": true, + "dependencies": { + "@types/chai": "*" + } + }, + "node_modules/@types/eslint": { + "version": "8.40.2", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.40.2.tgz", + "integrity": "sha512-PRVjQ4Eh9z9pmmtaq8nTjZjQwKFk7YIHIud3lRoKRBgUQjgjRmoGxxGEPXQkF+lH7QkHJRNr5F4aBgYCW0lqpQ==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", + "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", + "dev": true + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", + "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.3.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.1.tgz", + "integrity": "sha512-EhcH/wvidPy1WeML3TtYFGR83UzjxeWRen9V402T8aUGYsCHOmfoisV3ZSg03gAFIbLq8TnWOJ0f4cALtnSEUg==", + "dev": true + }, + "node_modules/@vitejs/plugin-vue": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.2.3.tgz", + "integrity": "sha512-R6JDUfiZbJA9cMiguQ7jxALsgiprjBeHL5ikpXfJCH62pPHtI+JdJ5xWj6Ev73yXSlYl86+blXn1kZHQ7uElxw==", + "dev": true, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@vitest/coverage-v8": { + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-0.32.2.tgz", + "integrity": "sha512-/+V3nB3fyeuuSeKxCfi6XmWjDIxpky7AWSkGVfaMjAk7di8igBwRsThLjultwIZdTDH1RAxpjmCXEfSqsMFZOA==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.1", + "@bcoe/v8-coverage": "^0.2.3", + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.1", + "istanbul-reports": "^3.1.5", + "magic-string": "^0.30.0", + "picocolors": "^1.0.0", + "std-env": "^3.3.2", + "test-exclude": "^6.0.0", + "v8-to-istanbul": "^9.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "vitest": ">=0.32.0 <1" + } + }, + "node_modules/@vitest/expect": { + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.32.2.tgz", + "integrity": "sha512-6q5yzweLnyEv5Zz1fqK5u5E83LU+gOMVBDuxBl2d2Jfx1BAp5M+rZgc5mlyqdnxquyoiOXpXmFNkcGcfFnFH3Q==", + "dev": true, + "dependencies": { + "@vitest/spy": "0.32.2", + "@vitest/utils": "0.32.2", + "chai": "^4.3.7" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.32.2.tgz", + "integrity": "sha512-06vEL0C1pomOEktGoLjzZw+1Fb+7RBRhmw/06WkDrd1akkT9i12su0ku+R/0QM69dfkIL/rAIDTG+CSuQVDcKw==", + "dev": true, + "dependencies": { + "@vitest/utils": "0.32.2", + "concordance": "^5.0.4", + "p-limit": "^4.0.0", + "pathe": "^1.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@vitest/runner/node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@vitest/snapshot": { + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.32.2.tgz", + "integrity": "sha512-JwhpeH/PPc7GJX38vEfCy9LtRzf9F4er7i4OsAJyV7sjPwjj+AIR8cUgpMTWK4S3TiamzopcTyLsZDMuldoi5A==", + "dev": true, + "dependencies": { + "magic-string": "^0.30.0", + "pathe": "^1.1.0", + "pretty-format": "^27.5.1" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.32.2.tgz", + "integrity": "sha512-Q/ZNILJ4ca/VzQbRM8ur3Si5Sardsh1HofatG9wsJY1RfEaw0XKP8IVax2lI1qnrk9YPuG9LA2LkZ0EI/3d4ug==", + "dev": true, + "dependencies": { + "tinyspy": "^2.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.32.2.tgz", + "integrity": "sha512-lnJ0T5i03j0IJaeW73hxe2AuVnZ/y1BhhCOuIcl9LIzXnbpXJT9Lrt6brwKHXLOiA7MZ6N5hSJjt0xE1dGNCzQ==", + "dev": true, + "dependencies": { + "diff-sequences": "^29.4.3", + "loupe": "^2.3.6", + "pretty-format": "^27.5.1" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.4.tgz", + "integrity": "sha512-cquyDNvZ6jTbf/+x+AgM2Arrp6G4Dzbb0R64jiG804HRMfRiFXWI6kqUVqZ6ZR0bQhIoQjB4+2bhNtVwndW15g==", + "dependencies": { + "@babel/parser": "^7.21.3", + "@vue/shared": "3.3.4", + "estree-walker": "^2.0.2", + "source-map-js": "^1.0.2" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.4.tgz", + "integrity": "sha512-wyM+OjOVpuUukIq6p5+nwHYtj9cFroz9cwkfmP9O1nzH68BenTTv0u7/ndggT8cIQlnBeOo6sUT/gvHcIkLA5w==", + "dependencies": { + "@vue/compiler-core": "3.3.4", + "@vue/shared": "3.3.4" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.3.4.tgz", + "integrity": "sha512-6y/d8uw+5TkCuzBkgLS0v3lSM3hJDntFEiUORM11pQ/hKvkhSKZrXW6i69UyXlJQisJxuUEJKAWEqWbWsLeNKQ==", + "dependencies": { + "@babel/parser": "^7.20.15", + "@vue/compiler-core": "3.3.4", + "@vue/compiler-dom": "3.3.4", + "@vue/compiler-ssr": "3.3.4", + "@vue/reactivity-transform": "3.3.4", + "@vue/shared": "3.3.4", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.0", + "postcss": "^8.1.10", + "source-map-js": "^1.0.2" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.4.tgz", + "integrity": "sha512-m0v6oKpup2nMSehwA6Uuu+j+wEwcy7QmwMkVNVfrV9P2qE5KshC6RwOCq8fjGS/Eak/uNb8AaWekfiXxbBB6gQ==", + "dependencies": { + "@vue/compiler-dom": "3.3.4", + "@vue/shared": "3.3.4" + } + }, + "node_modules/@vue/devtools-api": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.5.0.tgz", + "integrity": "sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==" + }, + "node_modules/@vue/reactivity": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.4.tgz", + "integrity": "sha512-kLTDLwd0B1jG08NBF3R5rqULtv/f8x3rOFByTDz4J53ttIQEDmALqKqXY0J+XQeN0aV2FBxY8nJDf88yvOPAqQ==", + "dependencies": { + "@vue/shared": "3.3.4" + } + }, + "node_modules/@vue/reactivity-transform": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.3.4.tgz", + "integrity": "sha512-MXgwjako4nu5WFLAjpBnCj/ieqcjE2aJBINUNQzkZQfzIZA4xn+0fV1tIYBJvvva3N3OvKGofRLvQIwEQPpaXw==", + "dependencies": { + "@babel/parser": "^7.20.15", + "@vue/compiler-core": "3.3.4", + "@vue/shared": "3.3.4", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.0" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.3.4.tgz", + "integrity": "sha512-R+bqxMN6pWO7zGI4OMlmvePOdP2c93GsHFM/siJI7O2nxFRzj55pLwkpCedEY+bTMgp5miZ8CxfIZo3S+gFqvA==", + "dependencies": { + "@vue/reactivity": "3.3.4", + "@vue/shared": "3.3.4" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.3.4.tgz", + "integrity": "sha512-Aj5bTJ3u5sFsUckRghsNjVTtxZQ1OyMWCr5dZRAPijF/0Vy4xEoRCwLyHXcj4D0UFbJ4lbx3gPTgg06K/GnPnQ==", + "dependencies": { + "@vue/runtime-core": "3.3.4", + "@vue/shared": "3.3.4", + "csstype": "^3.1.1" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.3.4.tgz", + "integrity": "sha512-Q6jDDzR23ViIb67v+vM1Dqntu+HUexQcsWKhhQa4ARVzxOY2HbC7QRW/ggkDBd5BU+uM1sV6XOAP0b216o34JQ==", + "dependencies": { + "@vue/compiler-ssr": "3.3.4", + "@vue/shared": "3.3.4" + }, + "peerDependencies": { + "vue": "3.3.4" + } + }, + "node_modules/@vue/shared": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.4.tgz", + "integrity": "sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==" + }, + "node_modules/@vue/test-utils": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@vue/test-utils/-/test-utils-2.3.2.tgz", + "integrity": "sha512-hJnVaYhbrIm0yBS0+e1Y0Sj85cMyAi+PAbK4JHqMRUZ6S622Goa+G7QzkRSyvCteG8wop7tipuEbHoZo26wsSA==", + "dev": true, + "dependencies": { + "js-beautify": "1.14.6" + }, + "optionalDependencies": { + "@vue/compiler-dom": "^3.0.1", + "@vue/server-renderer": "^3.0.1" + }, + "peerDependencies": { + "@vue/compiler-dom": "^3.0.1", + "@vue/server-renderer": "^3.0.1", + "vue": "^3.0.1" + } + }, + "node_modules/@vuetify/loader-shared": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@vuetify/loader-shared/-/loader-shared-1.7.1.tgz", + "integrity": "sha512-kLUvuAed6RCvkeeTNJzuy14pqnkur8lTuner7v7pNE/kVhPR97TuyXwBSBMR1cJeiLiOfu6SF5XlCYbXByEx1g==", + "devOptional": true, + "dependencies": { + "find-cache-dir": "^3.3.2", + "upath": "^2.0.1" + }, + "peerDependencies": { + "vue": "^3.0.0", + "vuetify": "^3.0.0-beta.4" + } + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "dev": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/atoa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atoa/-/atoa-1.0.0.tgz", + "integrity": "sha512-VVE1H6cc4ai+ZXo/CRWoJiHXrA1qfA31DPnx6D20+kSI547hQN5Greh51LQ1baMRMfxO5K5M4ImMtZbZt2DODQ==" + }, + "node_modules/autocompleter": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/autocompleter/-/autocompleter-6.1.3.tgz", + "integrity": "sha512-Pjb5R5r+S0/zDFudLP9a8CW7/xMc7O/uVCtaTf3f+RdNLAQQ5oUG018c3IRdDJMRVvT+OeZ1NYQoUH5GHlORKQ==" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axios": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", + "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axios-mock-adapter": { + "version": "1.21.5", + "resolved": "https://registry.npmjs.org/axios-mock-adapter/-/axios-mock-adapter-1.21.5.tgz", + "integrity": "sha512-5NI1V/VK+8+JeTF8niqOowuysA4b8mGzdlMN/QnTnoXbYh4HZSNiopsDclN2g/m85+G++IrEtUdZaQ3GnaMsSA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "is-buffer": "^2.0.5" + }, + "peerDependencies": { + "axios": ">= 0.17.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/blueimp-md5": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/blueimp-md5/-/blueimp-md5-2.19.0.tgz", + "integrity": "sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==", + "dev": true + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/bootstrap-scss": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/bootstrap-scss/-/bootstrap-scss-5.3.1.tgz", + "integrity": "sha512-WEhEFkHTSjaeA7gQ6Eizn50nDM+q8nzaQX52yoQMrnqwY/0rhE+VvC6sD2XKI8KFAxQpK0Jbrg/ggQ6smaXsCA==" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-cookies": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browser-cookies/-/browser-cookies-1.2.0.tgz", + "integrity": "sha512-cg2WuoOJo+F+g2XjEaP8nmeRp1vDHjt7sqpKJMsTNXKrpyIBNVslYJeehvs6FEddj8usV2+qyRSBEX244yN5/g==" + }, + "node_modules/browser-md5-file": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/browser-md5-file/-/browser-md5-file-1.1.1.tgz", + "integrity": "sha512-9h2UViTtZPhBa7oHvp5mb7MvJaX5OKEPUsplDwJ800OIV+In7BOR3RXOMB78obn2iQVIiS3WkVLhG7Zu1EMwbw==", + "dependencies": { + "spark-md5": "^2.0.2" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chai": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", + "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^4.1.2", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/clipboard": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.11.tgz", + "integrity": "sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==", + "dependencies": { + "good-listener": "^1.2.2", + "select": "^1.1.2", + "tiny-emitter": "^2.0.0" + } + }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "devOptional": true + }, + "node_modules/compare-versions": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-4.1.4.tgz", + "integrity": "sha512-FemMreK9xNyL8gQevsdRMrvO4lFCkQP7qbuktn1q8ndcNk1+0mz7lgE7b/sNvbhVgY4w6tMN1FDp6aADjqw2rw==" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/concordance": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/concordance/-/concordance-5.0.4.tgz", + "integrity": "sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw==", + "dev": true, + "dependencies": { + "date-time": "^3.1.0", + "esutils": "^2.0.3", + "fast-diff": "^1.2.0", + "js-string-escape": "^1.0.1", + "lodash": "^4.17.15", + "md5-hex": "^3.0.1", + "semver": "^7.3.2", + "well-known-symbols": "^2.0.0" + }, + "engines": { + "node": ">=10.18.0 <11 || >=12.14.0 <13 || >=14" + } + }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/contra": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/contra/-/contra-1.9.4.tgz", + "integrity": "sha512-N9ArHAqwR/lhPq4OdIAwH4e1btn6EIZMAz4TazjnzCiVECcWUPTma+dRAM38ERImEJBh8NiCCpjoQruSZ+agYg==", + "dependencies": { + "atoa": "1.0.0", + "ticky": "1.0.1" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "node_modules/core-js": { + "version": "3.31.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.31.0.tgz", + "integrity": "sha512-NIp2TQSGfR6ba5aalZD+ZQ1fSxGhDo/s1w0nx3RYzf2pnJxt7YynxFlFScP6eV7+GZsKO95NSjGxyJsU3DZgeQ==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crossvent": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/crossvent/-/crossvent-1.5.5.tgz", + "integrity": "sha512-MY4xhBYEnVi+pmTpHCOCsCLYczc0PVtGdPBz6NXNXxikLaUZo4HdAeUb1UqAo3t3yXAloSelTmfxJ+/oUqkW5w==", + "dependencies": { + "custom-event": "^1.0.0" + } + }, + "node_modules/crypto-js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" + }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssstyle": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz", + "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==", + "dev": true, + "dependencies": { + "rrweb-cssom": "^0.6.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/csstype": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" + }, + "node_modules/custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==" + }, + "node_modules/custom-event-polyfill": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/custom-event-polyfill/-/custom-event-polyfill-1.0.7.tgz", + "integrity": "sha512-TDDkd5DkaZxZFM8p+1I3yAlvM3rSr1wbrOliG4yJiwinMZN8z/iGL7BTlDkrJcYTmgUSb4ywVCc3ZaUtOtC76w==" + }, + "node_modules/data-urls": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz", + "integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==", + "dev": true, + "dependencies": { + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^12.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/data-urls/node_modules/tr46": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", + "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "dev": true, + "dependencies": { + "punycode": "^2.3.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/data-urls/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/data-urls/node_modules/whatwg-url": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz", + "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==", + "dev": true, + "dependencies": { + "tr46": "^4.1.1", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/date-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/date-time/-/date-time-3.1.0.tgz", + "integrity": "sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==", + "dev": true, + "dependencies": { + "time-zone": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "devOptional": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", + "dev": true + }, + "node_modules/deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-equal": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.1.tgz", + "integrity": "sha512-lKdkdV6EOGoVn65XaOsPdH4rMxTZOnmFyuIkMjM1i5HHCbfjC97dawgTAy0deYNfuqUqW+Q5VrVaQYtUpSd6yQ==", + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.2", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.0", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.2", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.0", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegate": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", + "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==" + }, + "node_modules/dialog-polyfill": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/dialog-polyfill/-/dialog-polyfill-0.5.6.tgz", + "integrity": "sha512-ZbVDJI9uvxPAKze6z146rmfUZjBqNEwcnFTVamQzXH+svluiV7swmVIGr7miwADgfgt1G2JQIytypM9fbyhX4w==" + }, + "node_modules/diff-sequences": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", + "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/domexception": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", + "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", + "dev": true, + "dependencies": { + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/domexception/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/dompurify": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.5.tgz", + "integrity": "sha512-jggCCd+8Iqp4Tsz0nIvpcb22InKEBrGz5dw3EQJMs8HPJDsKbFIO3STYtAvCfDx26Muevn1MHVI0XxjgFfmiSA==" + }, + "node_modules/downloadjs": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/downloadjs/-/downloadjs-1.4.7.tgz", + "integrity": "sha512-LN1gO7+u9xjU5oEScGFKvXhYf7Y/empUIIEAGBs1LzUq/rg5duiDrkuH5A2lQGd5jfMOb9X9usDa2oVXwJ0U/Q==" + }, + "node_modules/dragula": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/dragula/-/dragula-3.7.3.tgz", + "integrity": "sha512-/rRg4zRhcpf81TyDhaHLtXt6sEywdfpv1cRUMeFFy7DuypH2U0WUL0GTdyAQvXegviT4PJK4KuMmOaIDpICseQ==", + "dependencies": { + "contra": "1.9.4", + "crossvent": "1.5.5" + } + }, + "node_modules/editorconfig": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", + "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", + "dev": true, + "dependencies": { + "commander": "^2.19.0", + "lru-cache": "^4.1.5", + "semver": "^5.6.0", + "sigmund": "^1.0.1" + }, + "bin": { + "editorconfig": "bin/editorconfig" + } + }, + "node_modules/editorconfig/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/esbuild": { + "version": "0.17.19", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", + "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", + "devOptional": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.17.19", + "@esbuild/android-arm64": "0.17.19", + "@esbuild/android-x64": "0.17.19", + "@esbuild/darwin-arm64": "0.17.19", + "@esbuild/darwin-x64": "0.17.19", + "@esbuild/freebsd-arm64": "0.17.19", + "@esbuild/freebsd-x64": "0.17.19", + "@esbuild/linux-arm": "0.17.19", + "@esbuild/linux-arm64": "0.17.19", + "@esbuild/linux-ia32": "0.17.19", + "@esbuild/linux-loong64": "0.17.19", + "@esbuild/linux-mips64el": "0.17.19", + "@esbuild/linux-ppc64": "0.17.19", + "@esbuild/linux-riscv64": "0.17.19", + "@esbuild/linux-s390x": "0.17.19", + "@esbuild/linux-x64": "0.17.19", + "@esbuild/netbsd-x64": "0.17.19", + "@esbuild/openbsd-x64": "0.17.19", + "@esbuild/sunos-x64": "0.17.19", + "@esbuild/win32-arm64": "0.17.19", + "@esbuild/win32-ia32": "0.17.19", + "@esbuild/win32-x64": "0.17.19" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.43.0.tgz", + "integrity": "sha512-aaCpf2JqqKesMFGgmRPessmVKjcGXqdlAYLLC3THM8t5nBRZRQ+st5WM/hoJXkdioEXLLbXgclUpM0TXo5HX5Q==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.0.3", + "@eslint/js": "8.43.0", + "@humanwhocodes/config-array": "^0.11.10", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.0", + "eslint-visitor-keys": "^3.4.1", + "espree": "^9.5.2", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz", + "integrity": "sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", + "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "eslint": ">=7.28.0", + "prettier": ">=2.0.0" + }, + "peerDependenciesMeta": { + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-vue": { + "version": "9.15.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-9.15.0.tgz", + "integrity": "sha512-XYzpK6e2REli100+6iCeBA69v6Sm0D/yK2FZP+fCeNt0yH/m82qZQq+ztseyV0JsKdhFysuSEzeE1yCmSC92BA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.3.0", + "natural-compare": "^1.4.0", + "nth-check": "^2.0.1", + "postcss-selector-parser": "^6.0.9", + "semver": "^7.3.5", + "vue-eslint-parser": "^9.3.0", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-plugin-vuetify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-vuetify/-/eslint-plugin-vuetify-2.0.2.tgz", + "integrity": "sha512-PzZQzvfqATOYIVrccs7LpKbQD2GAASFwa2A5hcOhzndierTAhh7uOgyofb4FhhGUVs921Ya0ytL/lonngBHNIA==", + "dev": true, + "dependencies": { + "eslint-plugin-vue": "^9.6.0", + "requireindex": "^1.2.0" + }, + "peerDependencies": { + "eslint": "^8.0.0", + "vuetify": "^3.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", + "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", + "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", + "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", + "dev": true, + "dependencies": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, + "node_modules/fast-json-patch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz", + "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fetch-ponyfill": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/fetch-ponyfill/-/fetch-ponyfill-7.1.0.tgz", + "integrity": "sha512-FhbbL55dj/qdVO3YNK7ZEkshvj3eQ7EuIGV2I6ic/2YiocvyWv+7jg2s4AyS0wdRU75s3tA8ZxI/xPigb0v5Aw==", + "dependencies": { + "node-fetch": "~2.6.1" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "devOptional": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/font-awesome": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz", + "integrity": "sha512-U6kGnykA/6bFmg1M/oT9EkFeIYv7JlX3bozwQJWiiLz6L0w3F5vBVPxHlwyX/vtNq1ckcpRKOB9f2Qal/VtFpg==", + "engines": { + "node": ">=0.10.3" + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/formiojs": { + "version": "4.14.13", + "resolved": "https://registry.npmjs.org/formiojs/-/formiojs-4.14.13.tgz", + "integrity": "sha512-x8ZFYexjc6hYL9sVT6vv6YUId9adq8g84sOB92ZH6MEOw3OyDfaTzVUrb4oo7zlEHZw2UC4CNKrIHoXffwYN3Q==", + "dependencies": { + "@formio/bootstrap3": "^2.12.2", + "@formio/choices.js": "^9.0.1", + "@formio/semantic": "^2.6.0", + "@formio/text-mask-addons": "^3.8.0-formio.2", + "@formio/vanilla-text-mask": "^5.1.1-formio.1", + "autocompleter": "^6.1.2", + "browser-cookies": "^1.2.0", + "browser-md5-file": "^1.1.1", + "compare-versions": "^4.1.3", + "core-js": "^3.21.1", + "custom-event-polyfill": "^1.0.7", + "dialog-polyfill": "^0.5.6", + "dompurify": "^2.3.4", + "downloadjs": "^1.4.7", + "dragula": "^3.7.3", + "eventemitter3": "^4.0.7", + "fast-deep-equal": "^3.1.3", + "fast-json-patch": "^3.1.0", + "fetch-ponyfill": "^7.1.0", + "i18next": "^21.6.0", + "idb": "^6.1.5", + "ismobilejs": "^1.1.1", + "json-logic-js": "^2.0.0", + "jstimezonedetect": "^1.0.7", + "jwt-decode": "^3.1.2", + "lodash": "^4.17.21", + "moment": "^2.29.4", + "moment-timezone": "^0.5.40", + "native-promise-only": "^0.8.1", + "quill": "^2.0.0-dev.3", + "resize-observer-polyfill": "^1.5.1", + "signature_pad": "^4.0.4", + "string-hash": "^1.1.3", + "tippy.js": "^6.3.7", + "uuid": "^8.3.2", + "vanilla-picker": "^2.12.1" + } + }, + "node_modules/formiojs/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/fuse.js": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-3.6.1.tgz", + "integrity": "sha512-hT9yh/tiinkmirKrlv4KWOjztdoZo1mx9Qh4KvWqC7isoXwdUY3PNWUxceF4/qO9R6riA2C29jdTOeQOIROjgw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/good-listener": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", + "integrity": "sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==", + "dependencies": { + "delegate": "^3.1.2" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/happy-dom": { + "version": "9.20.3", + "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-9.20.3.tgz", + "integrity": "sha512-eBsgauT435fXFvQDNcmm5QbGtYzxEzOaX35Ia+h6yP/wwa4xSWZh1CfP+mGby8Hk6Xu59mTkpyf72rUXHNxY7A==", + "dev": true, + "dependencies": { + "css.escape": "^1.5.1", + "entities": "^4.5.0", + "iconv-lite": "^0.6.3", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0" + } + }, + "node_modules/happy-dom/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "dev": true, + "dependencies": { + "whatwg-encoding": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/i18next": { + "version": "21.10.0", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-21.10.0.tgz", + "integrity": "sha512-YeuIBmFsGjUfO3qBmMOc0rQaun4mIpGKET5WDwvu8lU7gvwpcariZLNtL0Fzj+zazcHUrlXHiptcFhBMFaxzfg==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "dependencies": { + "@babel/runtime": "^7.17.2" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/idb": { + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/idb/-/idb-6.1.5.tgz", + "integrity": "sha512-IJtugpKkiVXQn5Y+LteyBCNk1N8xpGV3wWZk9EVtZWH8DYkjBn0bX1XnGP9RkyZF0sAcywa6unHqSWKe7q4LGw==" + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/immutable": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz", + "integrity": "sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dependencies": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "engines": { + "node": ">=4" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", + "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/ismobilejs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ismobilejs/-/ismobilejs-1.1.1.tgz", + "integrity": "sha512-VaFW53yt8QO61k2WJui0dHf4SlL8lxBofUuUmwBo0ljPk0Drz2TiuDW4jo3wDcv41qy/SxrJ+VAzJ/qYqsmzRw==" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/js-beautify": { + "version": "1.14.6", + "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.14.6.tgz", + "integrity": "sha512-GfofQY5zDp+cuHc+gsEXKPpNw2KbPddreEo35O6jT6i0RVK6LhsoYBhq5TvK4/n74wnA0QbK8gGd+jUZwTMKJw==", + "dev": true, + "dependencies": { + "config-chain": "^1.1.13", + "editorconfig": "^0.15.3", + "glob": "^8.0.3", + "nopt": "^6.0.0" + }, + "bin": { + "css-beautify": "js/bin/css-beautify.js", + "html-beautify": "js/bin/html-beautify.js", + "js-beautify": "js/bin/js-beautify.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/js-sha256": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz", + "integrity": "sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==" + }, + "node_modules/js-string-escape": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", + "integrity": "sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "22.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz", + "integrity": "sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==", + "dev": true, + "dependencies": { + "abab": "^2.0.6", + "cssstyle": "^3.0.0", + "data-urls": "^4.0.0", + "decimal.js": "^10.4.3", + "domexception": "^4.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.4", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.6.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.2", + "w3c-xmlserializer": "^4.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^12.0.1", + "ws": "^8.13.0", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/tr46": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", + "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "dev": true, + "dependencies": { + "punycode": "^2.3.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/jsdom/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/jsdom/node_modules/whatwg-url": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz", + "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==", + "dev": true, + "dependencies": { + "tr46": "^4.1.1", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/json-logic-js": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/json-logic-js/-/json-logic-js-2.0.2.tgz", + "integrity": "sha512-ZBtBdMJieqQcH7IX/LaBsr5pX+Y5JIW+EhejtM3Ffg2jdN9Iwf+Ht6TbHnvAZ/YtwyuhPaCBlnvzrwVeWdvGDQ==" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/jsonc-parser": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "dev": true + }, + "node_modules/jstimezonedetect": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/jstimezonedetect/-/jstimezonedetect-1.0.7.tgz", + "integrity": "sha512-ARADHortktl9IZ1tr4GHwGPIAzgz3mLNCbR/YjWtRtc/O0o634O3NeFlpLjv95EvuDA5dc8z6yfgbS8nUc4zcQ==" + }, + "node_modules/jwt-decode": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", + "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" + }, + "node_modules/keycloak-js": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/keycloak-js/-/keycloak-js-21.1.1.tgz", + "integrity": "sha512-Viyhf0SOpu2jM/A33vpigSCFLo8l4yg8lqzaGyxXoZ3nGO9lo68B2LwJBDtgpzqDUh8DK//yCOzdWuR2CT4keA==", + "dependencies": { + "base64-js": "^1.5.1", + "js-sha256": "^0.9.0" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/local-pkg": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz", + "integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/loupe": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", + "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.0" + } + }, + "node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/magic-string": { + "version": "0.30.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.0.tgz", + "integrity": "sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ==", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.13" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "devOptional": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "devOptional": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/md5-hex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-3.0.1.tgz", + "integrity": "sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw==", + "dev": true, + "dependencies": { + "blueimp-md5": "^2.10.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mitt": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.0.tgz", + "integrity": "sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ==" + }, + "node_modules/mlly": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.3.0.tgz", + "integrity": "sha512-HT5mcgIQKkOrZecOjOX3DJorTikWXwsBfpcr/MGBkhfWcjiqvnaL/9ppxvIUXfjT6xt4DVIAsN9fMUz1ev4bIw==", + "dev": true, + "dependencies": { + "acorn": "^8.8.2", + "pathe": "^1.1.0", + "pkg-types": "^1.0.3", + "ufo": "^1.1.2" + } + }, + "node_modules/moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "engines": { + "node": "*" + } + }, + "node_modules/moment-timezone": { + "version": "0.5.43", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.43.tgz", + "integrity": "sha512-72j3aNyuIsDxdF1i7CEgV2FfxM1r6aaqJyLB2vwb33mXYyoyLly+F1zbWqhA3/bVIoJ4szlUoMbUnVdid32NUQ==", + "dependencies": { + "moment": "^2.29.4" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "devOptional": true + }, + "node_modules/nanoid": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/native-promise-only": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz", + "integrity": "sha512-zkVhZUA3y8mbz652WrL5x0fB0ehrBkulWT3TomAQ9iDtyXZvzKeEA6GPxAItBYeNYl5yngKRX612qHOhvMkDeg==" + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/nopt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", + "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "dev": true, + "dependencies": { + "abbrev": "^1.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nprogress": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", + "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==" + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/nwsapi": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.5.tgz", + "integrity": "sha512-6xpotnECFy/og7tKSBVmUNft7J3jyXAka4XvG6AUhFWRz+Q/Ljus7znJAA3bxColfQLdS+XsjoodtJfCgeTEFQ==", + "dev": true + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "devOptional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parchment": { + "version": "2.0.0-dev.2", + "resolved": "https://registry.npmjs.org/parchment/-/parchment-2.0.0-dev.2.tgz", + "integrity": "sha512-4fgRny4pPISoML08Zp7poi52Dff3E2G1ORTi2D/acJ/RiROdDAMDB6VcQNfBcmehrX5Wixp6dxh6JjLyE5yUNQ==" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "devOptional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.1.tgz", + "integrity": "sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==", + "dev": true + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pinia": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.1.4.tgz", + "integrity": "sha512-vYlnDu+Y/FXxv1ABo1vhjC+IbqvzUdiUC3sfDRrRyY2CQSrqqaa+iiHmqtARFxJVqWQMCJfXx1PBvFs9aJVLXQ==", + "dependencies": { + "@vue/devtools-api": "^6.5.0", + "vue-demi": ">=0.14.5" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "@vue/composition-api": "^1.4.0", + "typescript": ">=4.4.4", + "vue": "^2.6.14 || ^3.3.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/pinia/node_modules/vue-demi": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.5.tgz", + "integrity": "sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA==", + "hasInstallScript": true, + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "devOptional": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "devOptional": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "devOptional": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "devOptional": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "devOptional": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-types": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz", + "integrity": "sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==", + "dev": true, + "dependencies": { + "jsonc-parser": "^3.2.0", + "mlly": "^1.2.0", + "pathe": "^1.1.0" + } + }, + "node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.13", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", + "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", + "dev": true + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qrcode.vue": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/qrcode.vue/-/qrcode.vue-3.4.0.tgz", + "integrity": "sha512-4XeImbv10Fin16Fl2DArCMhGyAdvIg2jb7vDT+hZiIAMg/6H6mz9nUZr/dR8jBcun5VzNzkiwKhiqOGbloinwA==", + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/quill": { + "version": "2.0.0-dev.4", + "resolved": "https://registry.npmjs.org/quill/-/quill-2.0.0-dev.4.tgz", + "integrity": "sha512-9WmMVCEIhf3lDdhzl+i+GBDeDl0BFi65waC4Im8Y4HudEJ9kEEb1lciAz9A8pcDmLMjiMbvz84lNt/U5OBS8Vg==", + "dependencies": { + "clone": "^2.1.2", + "deep-equal": "^2.0.2", + "eventemitter3": "^4.0.0", + "extend": "^3.0.2", + "parchment": "2.0.0-dev.2", + "quill-delta": "4.2.1" + } + }, + "node_modules/quill-delta": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-4.2.1.tgz", + "integrity": "sha512-Y2nksOj6Q+4hizre8n0dml76vLNGK4/y86EoI1d7rv6EL1bx7DPDYRmqQMPu1UqFQO/uQuVHQ3fOmm4ZSzWrfA==", + "dependencies": { + "deep-equal": "^1.0.1", + "extend": "^3.0.2", + "fast-diff": "1.2.0" + } + }, + "node_modules/quill-delta/node_modules/deep-equal": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", + "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "dependencies": { + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.1", + "is-regex": "^1.0.4", + "object-is": "^1.0.1", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.2.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/quill-delta/node_modules/fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==" + }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/redux": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", + "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", + "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/requireindex": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", + "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==", + "dev": true, + "engines": { + "node": ">=0.10.5" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "node_modules/resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "3.25.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.25.1.tgz", + "integrity": "sha512-tywOR+rwIt5m2ZAWSe5AIJcTat8vGlnPFAv15ycCrw33t6iFsXZ6mzHVFh2psSjxQPmI+xgzMZZizUAukBI4aQ==", + "devOptional": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/rrweb-cssom": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", + "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==", + "dev": true + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/sass": { + "version": "1.63.4", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.63.4.tgz", + "integrity": "sha512-Sx/+weUmK+oiIlI+9sdD0wZHsqpbgQg8wSwSnGBjwb5GwqFhYNwwnI+UWZtLjKvKyFlKkatRK235qQ3mokyPoQ==", + "dev": true, + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/select": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", + "integrity": "sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA==" + }, + "node_modules/semver": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.2.tgz", + "integrity": "sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true + }, + "node_modules/sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha512-fCvEXfh6NWpm+YSuY2bpXb/VIihqWA6hLsgboC+0nl71Q7N7o2eaCW8mJa/NLvQhs6jpd3VZV4UiUQlV6+lc8g==", + "dev": true + }, + "node_modules/signature_pad": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/signature_pad/-/signature_pad-4.1.5.tgz", + "integrity": "sha512-VOE846UbQMeLBbcR08KwjwE1wNLgp3gqC7yr/AELkgSMs/BdRpxIZna6K5XyZJpA7IWq9GiInw1C8PLm57VO6Q==" + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/spark-md5": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/spark-md5/-/spark-md5-2.0.2.tgz", + "integrity": "sha512-9WfT+FYBEvlrOOBEs484/zmbtSX4BlGjzXih1qIEWA1yhHbcqgcMHkiwXoWk2Sq1aJjLpcs6ZKV7JxrDNjIlNg==" + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true + }, + "node_modules/std-env": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.3.3.tgz", + "integrity": "sha512-Rz6yejtVyWnVjC1RFvNmYL10kgjC49EOghxWn0RFqlCHGFpQx+Xe7yW3I4ceK1SGrWIGMjD5Kbue8W/udkbMJg==", + "dev": true + }, + "node_modules/stop-iteration-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "dependencies": { + "internal-slot": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string-hash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", + "integrity": "sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==" + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-literal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.0.1.tgz", + "integrity": "sha512-QZTsipNpa2Ppr6v1AmJHESqJ3Uz247MUS0OjrnnZjFAvEoWqxuyFuXn2xLgMtRnijJShAa1HL0gtJyUs7u7n3Q==", + "dev": true, + "dependencies": { + "acorn": "^8.8.2" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, + "node_modules/terser": { + "version": "5.18.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.18.1.tgz", + "integrity": "sha512-j1n0Ao919h/Ai5r43VAnfV/7azUYW43GPxK7qSATzrsERfW7+y2QW9Cp9ufnRF5CQUWbnLSo7UJokSWCqg4tsQ==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/ticky": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ticky/-/ticky-1.0.1.tgz", + "integrity": "sha512-RX35iq/D+lrsqhcPWIazM9ELkjOe30MSeoBHQHSsRwd1YuhJO5ui1K1/R0r7N3mFvbLBs33idw+eR6j+w6i/DA==" + }, + "node_modules/time-zone": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/time-zone/-/time-zone-1.0.0.tgz", + "integrity": "sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/tiny-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" + }, + "node_modules/tinybench": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.5.0.tgz", + "integrity": "sha512-kRwSG8Zx4tjF9ZiyH4bhaebu+EDz1BOx9hOigYHlUW4xxI/wKIUQUqo018UlU4ar6ATPBsaMrdbKZ+tmPdohFA==", + "dev": true + }, + "node_modules/tinypool": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.5.0.tgz", + "integrity": "sha512-paHQtnrlS1QZYKF/GnLoOM/DN9fqaGOFbCbxzAhwniySnzl9Ebk8w73/dd34DAhe/obUbPAOldTyYXQZxnPBPQ==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.1.1.tgz", + "integrity": "sha512-XPJL2uSzcOyBMky6OFrusqWlzfFrXtE0hPuMgW8A2HmaqrPo4ZQHRN/V0QXN3FSjKxpsbRrFc5LI7KOwBsT1/w==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tippy.js": { + "version": "6.3.7", + "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz", + "integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==", + "dependencies": { + "@popperjs/core": "^2.9.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "dev": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ufo": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.1.2.tgz", + "integrity": "sha512-TrY6DsjTQQgyS3E3dBaOXf0TpPD8u9FVrVYmKVegJuFw51n/YB9XPt+U6ydzFG5ZIN7+DIjPbNmXoBj9esYhgQ==", + "dev": true + }, + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/upath": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz", + "integrity": "sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==", + "devOptional": true, + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/uuid": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-to-istanbul": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", + "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/vanilla-picker": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/vanilla-picker/-/vanilla-picker-2.12.1.tgz", + "integrity": "sha512-2qrEP9VYylKXbyzXKsbu2dferBTvqnlsr29XjHwFE+/MEp0VNj6oEUESLDtKZ7DWzGdSv1x/+ujqFZF+KsO3cg==", + "dependencies": { + "@sphinxxxx/color-conversion": "^2.2.2" + } + }, + "node_modules/vite": { + "version": "4.3.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz", + "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==", + "devOptional": true, + "dependencies": { + "esbuild": "^0.17.5", + "postcss": "^8.4.23", + "rollup": "^3.21.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.32.2.tgz", + "integrity": "sha512-dTQ1DCLwl2aEseov7cfQ+kDMNJpM1ebpyMMMwWzBvLbis8Nla/6c9WQcqpPssTwS6Rp/+U6KwlIj8Eapw4bLdA==", + "dev": true, + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.3.4", + "mlly": "^1.2.0", + "pathe": "^1.1.0", + "picocolors": "^1.0.0", + "vite": "^3.0.0 || ^4.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": ">=v14.18.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vite-plugin-eslint": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/vite-plugin-eslint/-/vite-plugin-eslint-1.8.1.tgz", + "integrity": "sha512-PqdMf3Y2fLO9FsNPmMX+//2BF5SF8nEWspZdgl4kSt7UvHDRHVVfHvxsD7ULYzZrJDGRxR81Nq7TOFgwMnUang==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^4.2.1", + "@types/eslint": "^8.4.5", + "rollup": "^2.77.2" + }, + "peerDependencies": { + "eslint": ">=7", + "vite": ">=2" + } + }, + "node_modules/vite-plugin-eslint/node_modules/rollup": { + "version": "2.79.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", + "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/vite-plugin-vuetify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/vite-plugin-vuetify/-/vite-plugin-vuetify-1.0.2.tgz", + "integrity": "sha512-MubIcKD33O8wtgQXlbEXE7ccTEpHZ8nPpe77y9Wy3my2MWw/PgehP9VqTp92BLqr0R1dSL970Lynvisx3UxBFw==", + "devOptional": true, + "dependencies": { + "@vuetify/loader-shared": "^1.7.1", + "debug": "^4.3.3", + "upath": "^2.0.1" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "vite": "^2.7.0 || ^3.0.0 || ^4.0.0", + "vuetify": "^3.0.0-beta.4" + } + }, + "node_modules/vitest": { + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.32.2.tgz", + "integrity": "sha512-hU8GNNuQfwuQmqTLfiKcqEhZY72Zxb7nnN07koCUNmntNxbKQnVbeIS6sqUgR3eXSlbOpit8+/gr1KpqoMgWCQ==", + "dev": true, + "dependencies": { + "@types/chai": "^4.3.5", + "@types/chai-subset": "^1.3.3", + "@types/node": "*", + "@vitest/expect": "0.32.2", + "@vitest/runner": "0.32.2", + "@vitest/snapshot": "0.32.2", + "@vitest/spy": "0.32.2", + "@vitest/utils": "0.32.2", + "acorn": "^8.8.2", + "acorn-walk": "^8.2.0", + "cac": "^6.7.14", + "chai": "^4.3.7", + "concordance": "^5.0.4", + "debug": "^4.3.4", + "local-pkg": "^0.4.3", + "magic-string": "^0.30.0", + "pathe": "^1.1.0", + "picocolors": "^1.0.0", + "std-env": "^3.3.2", + "strip-literal": "^1.0.1", + "tinybench": "^2.5.0", + "tinypool": "^0.5.0", + "vite": "^3.0.0 || ^4.0.0", + "vite-node": "0.32.2", + "why-is-node-running": "^2.2.2" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": ">=v14.18.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@vitest/browser": "*", + "@vitest/ui": "*", + "happy-dom": "*", + "jsdom": "*", + "playwright": "*", + "safaridriver": "*", + "webdriverio": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "playwright": { + "optional": true + }, + "safaridriver": { + "optional": true + }, + "webdriverio": { + "optional": true + } + } + }, + "node_modules/vue": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.3.4.tgz", + "integrity": "sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==", + "dependencies": { + "@vue/compiler-dom": "3.3.4", + "@vue/compiler-sfc": "3.3.4", + "@vue/runtime-dom": "3.3.4", + "@vue/server-renderer": "3.3.4", + "@vue/shared": "3.3.4" + } + }, + "node_modules/vue-eslint-parser": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-9.3.1.tgz", + "integrity": "sha512-Clr85iD2XFZ3lJ52/ppmUDG/spxQu6+MAeHXjjyI4I1NUYZ9xmenQp4N0oaHJhrA8OOxltCVxMRfANGa70vU0g==", + "dev": true, + "dependencies": { + "debug": "^4.3.4", + "eslint-scope": "^7.1.1", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.6" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/vue-i18n": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-9.2.2.tgz", + "integrity": "sha512-yswpwtj89rTBhegUAv9Mu37LNznyu3NpyLQmozF3i1hYOhwpG8RjcjIFIIfnu+2MDZJGSZPXaKWvnQA71Yv9TQ==", + "dependencies": { + "@intlify/core-base": "9.2.2", + "@intlify/shared": "9.2.2", + "@intlify/vue-devtools": "9.2.2", + "@vue/devtools-api": "^6.2.1" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "node_modules/vue-json-pretty": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/vue-json-pretty/-/vue-json-pretty-2.2.4.tgz", + "integrity": "sha512-JX80b3QDrspcH43C53CdtYeq/froApQGSV5y43bEMWFj2LGOxB96aH1VmvrFA21nD1WTP6nwfFMQqGXuS4jyFQ==", + "engines": { + "node": ">= 10.0.0", + "npm": ">= 5.0.0" + }, + "peerDependencies": { + "vue": ">=3.0.0" + } + }, + "node_modules/vue-router": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.2.2.tgz", + "integrity": "sha512-cChBPPmAflgBGmy3tBsjeoe3f3VOSG6naKyY5pjtrqLGbNEXdzCigFUHgBvp9e3ysAtFtEx7OLqcSDh/1Cq2TQ==", + "dependencies": { + "@vue/devtools-api": "^6.5.0" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/vue3-clipboard": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/vue3-clipboard/-/vue3-clipboard-1.0.0.tgz", + "integrity": "sha512-GUqKh1oO79xDpq0z+cCv/NDVTpcJGNDzeNgT3PmTdTp/WJh3gcTrDqIYKycKhzMFOtIFJ7hO/+usgyWtT+fNhA==", + "dependencies": { + "clipboard": "^2.0.6" + }, + "peerDependencies": { + "vue": "^3.0.0" + } + }, + "node_modules/vuetify": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/vuetify/-/vuetify-3.3.11.tgz", + "integrity": "sha512-hlbSgxXCcEu4VelJMRHKhvLpaitLsruHvdvolbqbCS6Z64XoulUDw3CQ9ay6WGBL7uckmop0bUYidD2d8mN0UQ==", + "engines": { + "node": "^12.20 || >=14.13" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/johnleider" + }, + "peerDependencies": { + "typescript": ">=4.7", + "vite-plugin-vuetify": "^1.0.0-alpha.12", + "vue": "^3.2.0", + "vue-i18n": "^9.0.0", + "webpack-plugin-vuetify": "^2.0.0-alpha.11" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + }, + "vite-plugin-vuetify": { + "optional": true + }, + "vue-i18n": { + "optional": true + }, + "webpack-plugin-vuetify": { + "optional": true + } + } + }, + "node_modules/w3c-xmlserializer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", + "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", + "dev": true, + "dependencies": { + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/well-known-symbols": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/well-known-symbols/-/well-known-symbols-2.0.0.tgz", + "integrity": "sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "dev": true, + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dependencies": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/why-is-node-running": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz", + "integrity": "sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==", + "dev": true, + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/ws": { + "version": "8.13.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", + "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, + "node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", + "dev": true + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/frontend/app/frontend/package.json b/frontend/app/frontend/package.json new file mode 100644 index 0000000..ec47c5b --- /dev/null +++ b/frontend/app/frontend/package.json @@ -0,0 +1,80 @@ +{ + "name": "common-hosted-form-service-frontend", + "version": "1.5.0", + "private": true, + "license": "Apache-2.0", + "scripts": { + "serve": "vite", + "preserve": "node ./component-update.js", + "build": "vite build", + "build:watch": "vite build --watch", + "preview": "vite preview", + "prebuild": "node ./component-update.js", + "build:formio": "node ./component-update.js build", + "deploy:formio": "node ./component-update.js deploy", + "test": "npm run test:unit", + "test:unit": "vitest", + "test:coverage": "vitest run --coverage", + "test:watch": "vitest watch", + "lint": "eslint \"src/**/*.{js,vue}\"", + "lint:fix": "eslint --fix \"src/**/*.{js,vue}\"", + "prettier": "prettier --check \"src/**/*.{js,vue,css,scss}\"", + "prettier:fix": "prettier --write \"src/**/*.{js,vue,css,scss}\"", + "pretest": "npm run lint", + "clean": "rm -rf coverage dist **/e2e/videos", + "clean:formio": "node ./component-update.js clean", + "purge": "rm -rf src/formio node_modules", + "purge:formio": "node ./component-update.js purge", + "rebuild": "npm run clean && npm run build", + "reinstall": "npm run purge && npm install" + }, + "dependencies": { + "@bcgov/bc-sans": "^1.0.1", + "@formio/vue": "github:formio/vue#v5.0.0-rc.2", + "@fortawesome/fontawesome-svg-core": "^6.4.2", + "@fortawesome/free-solid-svg-icons": "^6.4.2", + "@fortawesome/vue-fontawesome": "^3.0.3", + "axios": "^1.4.0", + "bootstrap-scss": "^5.3.1", + "crypto-js": "^4.1.1", + "fast-json-patch": "^3.1.1", + "font-awesome": "^4.7.0", + "formiojs": "^4.14.13", + "keycloak-js": "^21.1.1", + "lodash": "^4.17.21", + "mitt": "^3.0.0", + "moment": "^2.29.4", + "nprogress": "^0.2.0", + "pinia": "^2.1.4", + "qrcode.vue": "^3.4.0", + "uuid": "^9.0.0", + "vue": "^3.3.4", + "vue-i18n": "^9.2.2", + "vue-json-pretty": "^2.2.4", + "vue-router": "^4.2.2", + "vue3-clipboard": "^1.0.0", + "vuetify": "^3.3.11" + }, + "devDependencies": { + "@mdi/font": "^7.2.96", + "@pinia/testing": "^0.1.2", + "@vitejs/plugin-vue": "^4.1.0", + "@vitest/coverage-v8": "^0.32.0", + "@vue/test-utils": "^2.3.2", + "axios-mock-adapter": "^1.21.5", + "eslint": "^8.40.0", + "eslint-config-prettier": "^8.8.0", + "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-vue": "^9.13.0", + "eslint-plugin-vuetify": "^2.0.0-beta.4", + "happy-dom": "^9.20.3", + "jsdom": "^22.1.0", + "prettier": "^2.8.8", + "sass": "^1.62.1", + "terser": "^5.17.4", + "vite": "^4.3.2", + "vite-plugin-eslint": "^1.8.1", + "vite-plugin-vuetify": "^1.0.2", + "vitest": "^0.32.2" + } +} diff --git a/frontend/app/frontend/public/favicon.ico b/frontend/app/frontend/public/favicon.ico new file mode 100644 index 0000000..1841396 Binary files /dev/null and b/frontend/app/frontend/public/favicon.ico differ diff --git a/frontend/app/frontend/public/index.html b/frontend/app/frontend/public/index.html new file mode 100644 index 0000000..5e1d6e9 --- /dev/null +++ b/frontend/app/frontend/public/index.html @@ -0,0 +1,21 @@ + + + + + + + + + <%= process.env.VUE_APP_TITLE %> + + + + +
+ + + + diff --git a/frontend/app/frontend/src/App.vue b/frontend/app/frontend/src/App.vue new file mode 100644 index 0000000..d5c3e87 --- /dev/null +++ b/frontend/app/frontend/src/App.vue @@ -0,0 +1,44 @@ + + + + + diff --git a/frontend/app/frontend/src/assets/images/bc_logo.svg b/frontend/app/frontend/src/assets/images/bc_logo.svg new file mode 100644 index 0000000..5ba3bb5 --- /dev/null +++ b/frontend/app/frontend/src/assets/images/bc_logo.svg @@ -0,0 +1 @@ +bc_logo diff --git a/frontend/app/frontend/src/assets/images/bc_logo_print.svg b/frontend/app/frontend/src/assets/images/bc_logo_print.svg new file mode 100644 index 0000000..aae06ff --- /dev/null +++ b/frontend/app/frontend/src/assets/images/bc_logo_print.svg @@ -0,0 +1 @@ +bc_logo_print diff --git a/frontend/app/frontend/src/assets/images/bc_logo_square.svg b/frontend/app/frontend/src/assets/images/bc_logo_square.svg new file mode 100644 index 0000000..8d228dc --- /dev/null +++ b/frontend/app/frontend/src/assets/images/bc_logo_square.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/app/frontend/src/assets/images/drag-drop-demo.gif b/frontend/app/frontend/src/assets/images/drag-drop-demo.gif new file mode 100644 index 0000000..935f0e3 Binary files /dev/null and b/frontend/app/frontend/src/assets/images/drag-drop-demo.gif differ diff --git a/frontend/app/frontend/src/assets/scss/style.scss b/frontend/app/frontend/src/assets/scss/style.scss new file mode 100644 index 0000000..c707c01 --- /dev/null +++ b/frontend/app/frontend/src/assets/scss/style.scss @@ -0,0 +1,547 @@ +@import url('https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900'); +@import url('https://fonts.googleapis.com/css?family=Material+Icons'); +@import '@mdi/font/css/materialdesignicons.css'; +@import '~font-awesome/css/font-awesome.min.css'; +@import '~formiojs/dist/formio.builder.min.css'; +@import 'vue-json-pretty/lib/styles.css'; + +// Override bootstrap default value +$enable-smooth-scroll: false; +@import 'bootstrap-scss/bootstrap.scss'; // TODO: import this only for form designer/renderer formio components + +// Variables +$bcgov-blue: #003366; +$bcgov-blue-secondary: #38598a; +$bcgov-orange: #fcba19; +$bcgov-grey: #efefef; +$bcgov-font: #313132; +$bcgov-error: #d8292f; +$bcgov-link: #1a5a96; +$bcgov-link-hover: #3b99fc; +$bcgov-input-placeholder: #606060; +$bcgov-font-error: #a12622; +$bcgov-font-warning: #6c4a00; +$bcgov-font-success: #2d4821; +$bcgov-alert-error: #f2dede; +$bcgov-alert-warning: #f9f1c6; +$bcgov-alert-info: #d9eaf7; +$bcgov-alert-success: #dff0d8; + +// Sticky Footer +body { + display: flex; + flex-direction: column; + & > .v-content { + flex: 1 0 auto; + } +} + +// Typography +.v-application { + font-family: -apple-system, BlinkMacSystemFont, BCSans, Roboto, Verdana, Arial, + sans-serif !important; + line-height: 1.4; + font-size: 0.875rem; +} + +h1 { + font-size: 1.9em; +} +h2 { + font-size: 1.7em; +} +h3 { + font-size: 1.3em; +} +h4 { + font-size: 1.05em; +} + +h1, +h2, +h3, +h4, +h5 { + color: $bcgov-font; + line-height: 1.2; + font-weight: bold; +} + +p { + color: $bcgov-font; + line-height: 1.7; +} + +// links +a { + color: $bcgov-link; + &:hover { + color: $bcgov-link-hover; + } +} + +// Horizontal Rule +hr { + margin-bottom: 1em; + .orange { + border-top: 2px solid $bcgov-orange; + } +} + +// General Transition Animation Behavior +.component-fade-enter-active, +.component-fade-leave-active { + transition: opacity 0.3s ease; +} +.component-fade-enter, +.component-fade-leave-to { + opacity: 0; +} + +// Anchor and Tab Behavior +a, +.v-tab { + text-decoration: none; + &:hover { + text-decoration: underline; + button, + .v-icon { + text-decoration: none; + } + } +} + +.v-btn { + span > span { + font-weight: bold; + } + + &:hover { + opacity: 0.8; + span > span { + text-decoration: underline; + } + } + &.v-btn--disabled { + color: #777; + } + + &.v-btn--outlined { + border: 2px solid #fff; + &.v-btn--disabled { + border-color: rgba(0, 0, 0, 0.26); + } + } +} + +.v-tooltip > .v-overlay__content { + background: rgba(97, 97, 97, .9) !important; +} + +// Customized expand/collapse section +.nrmc-expand-collapse { + width: 100%; + min-height: 50px; + + .v-expansion-panel--active { + margin-bottom: 20px; + } + + .v-expansion-panel--active > .v-expansion-panel-title { + min-height: 50px; + } + + .v-expansion-panel-title { + padding: 10px; + background-color: $bcgov-grey; + .icon { + order: 0; + } + + .header { + order: 1; + display: flex; + align-items: center; + justify-content: space-between; + flex: 1 auto; + } + } +} + +///////////////////////////////// +/// override formio styles: +///////////////////////////////// + +// override formio form designer +.form-designer, +// override form viewer +.form-wrapper, +// override preview panel in form builder component editor modal +.component-preview { + // layout + div[class^='col-']:nth-child(n + 1) { + padding-top: 0; // make nested columns line up vertically alongside components in non-nested adjacent columns + } + + // tabs, cards, headings etc.. + .card-header { + font-weight: bold; + color: $bcgov-font; + opacity: 1; + .fa-minus-square-o::before, + .fa-plus-square-o::before { + font-size: 130%; + color: black; + } + .fa-minus-square-o::before { + content: '\f106'; + } + .fa-plus-square-o::before { + content: '\f107'; + } + } + + // tabs component + .formio-component-simpletabs { + & > .card { + border: 0; + + & > .card-body { + border-style: solid; + border-color: rgba(0, 0, 0, 0.125); + border-width: 0 1px 1px 1px; + border-radius: 0; + } + } + & > .card > .card-header { + background: none; + + .nav-item { + background-color: $bcgov-grey; + margin-right: 3px; + + .nav-link { + @extend a; + font-weight: normal; + + &.active { + color: $bcgov-font; + background: white; + + &:hover { + color: $bcgov-font; + cursor: default; + text-decoration: none; + } + } + } + } + } + } + + // form inputs + .form-control { + // placeholder text to match bcgov + &::placeholder, + .choices__placeholder { + color: $bcgov-input-placeholder; + opacity: inherit; + } + + &:not(.is-invalid) { + // input borders to match bcgov (exclude invalid fields that should be red) + border: 1px solid $bcgov-input-placeholder; + } + } + + // remove alert icons from invalid fields + .form-control.is-invalid, + .was-validated .form-control:invalid { + background-image: none; + } + + // add rounded corners to Date / Time Component input groups and red border if invalid + .input-group > .flatpickr-input.form-control { + & + .form-control.input { + border-top-left-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; + } + // if validation error make borders red; + &.is-invalid + .form-control.input { + border: 1px solid #dc3545; + + &:focus { + border-color: #dc3545; + -webkit-box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); + } + } + } + + // buttons + + .btn { + @extend .v-btn; + } + + .btn.btn-primary { + background-color: $bcgov-blue; + border: none; + color: white; + + &:hover { + background-color: $bcgov-blue; + text-decoration: underline; + } + + &:disabled, + &[disabled='disabled'], + &[disabled='disabled'] &:hover { + @extend .v-btn--disabled; + cursor: default; + text-decoration: none; + background-color: rgba(0, 0, 0, 0.12); + opacity: 1; + color: rgba(0, 0, 0, 0.26) !important; + } + } + + // formio submit buttons + .formio-component-button .btn { + text-transform: uppercase; + padding: 8px 16px; + line-height: 21px; + font-weight: 700; + letter-spacing: 0.0892857143em; + font-size: 0.875rem; + } + + // add margin to create space between the button and form.io inputs + .formio-component-button { + margin-top: 1rem; + } + + // tooltips + .tooltip-inner { + background-color: #606060; + border-radius: 3px; + box-shadow: 0 2px 8px 0 rgba(175, 175, 175, 0.5); + font-size: 0.85em; + } + + // validation messages and help text + .form-text { + font-size: 0.85em; + } + .invalid-feedback { + font-size: 100%; // reset this wrapper + } + .form-text.error { + background: none !important; + color: $bcgov-error; + } + + // hide asterisks after input in Data Grid when labels appear as table headers + .formio-component-datagrid { + label.field-required.control-label--hidden::after { + content: ''; + } + } + + // dropdowns + .choices__list--dropdown { + .choices__item { + &:not(.is-selected) { + color: $bcgov-font; + } + &:hover { + background-color: $bcgov-link-hover; + color: white; + } + } + } + + .choices__list--multiple { + .choices__item { + margin-bottom: 0; + font-size: 90%; + } + .choices__item, + .choices__button { + background-color: white; + color: $bcgov-link; + border-color: $bcgov-link; + &:hover { + background-color: $bcgov-link-hover; + border-color: $bcgov-link-hover; + color: white; + } + } + } + + // hide 'X' (button that removes selected option) on dropdown, when placeholder exists and no selectiuon has been made + .choices__placeholder button { + display: none; + } + + // radio buttons and checkboxes + .form-radio { + .form-check { + margin-bottom: 5px; + .form-check-label { + font-size: 1em; + + .form-check-input { + transform: scale(1.3); + } + span { + margin-left: 5px; + } + } + } + } + + // form builder misc. + .drag-and-drop-alert.alert-info { + border: 2px dashed grey; + background-color: transparent; + color: grey; + padding: 30px; + } +} + +///////////////////////////////// +// override Formio form designer +///////////////////////////////// + +.form-designer { + .formio-component-submit .btn.btn-primary, + .formio-component-submit .btn.btn-primary:hover { + @extend :disabled; + background-color: rgba(0, 0, 0, 0.12); + } + // the drag/drop area needs to line up with vuetify v-application ul styles... + .formio-component-file .fileSelector { + margin-left: 24px; + } +} + +.formcomponents { + .builder-sidebar { + .form-builder-panel { + .formcomponent.btn-block { + width: 100%; + } + } + } +} + +.form-wrapper { + // the drag/drop area needs to line up with vuetify v-application ul styles... + .formio-component-file { + .fileSelector { + margin-left: 24px; + } + .file { + .row { + margin-left: 24px; + } + } + } +} + +// allow dropdowns to continue expanding downwards within a modal +.formio-dialog-content { + .component-edit-container { + overflow: visible; + + .choices__list.choices__list--dropdown { + overflow: auto; + + div.choices__list { + max-height: 175px; + } + } + } +} + +// formio component buttons +.btn-primary.formcomponent.drag-copy, +.btn-primary.formcomponent.drag-copy:hover, +.formcomponent.drag-copy:active { + background-color: #e4f2ff; + color: #003366; + font-size: 0.8rem; + border: none; +} +.drag-container .btn-primary.formcomponent.drag-copy { + opacity: 0.3; + color: white; + background: $bcgov-blue; +} + +.info-helper { + color: #00000061; + margin-top: 2px; +} + +.info-helper:hover { + color: #01254a; +} + +.v-tooltip > .v-overlay__content { + pointer-events: auto !important; //Have to replace Tooltips default behaviour pointer-events: none as we have some tooltips with External Links. +} + +.preview_info_link_field_white { + color: white !important; + text-decoration: underline; +} +.center_vertical_content { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + min-height: 300px; +} + +.label .v-label { + right: 0 !important; + left: auto !important; +} + + +.label span { + margin-right:30px; +} + +.flex-xs-column-reverse { + flex-direction: column-reverse; +} + +.flex-xs-column { + flex-direction: column; +} + +.dir-rtl { + direction: rtl !important; + text-align: right; +} + +.dir-ltl { + direction: ltr !important; + text-align: left; +} + +.v-skeleton-loader { + background: none !important; + display: block !important; +} + +.submissions-table tbody tr:nth-child(odd) td { + background-color: #f5f5f5 !important; +} + +.v-table.v-table--hover > .v-table__wrapper > table > tbody > tr:hover td { + background-color: #eee !important; +} diff --git a/frontend/app/frontend/src/components/admin/AddOwner.vue b/frontend/app/frontend/src/components/admin/AddOwner.vue new file mode 100644 index 0000000..99be2c6 --- /dev/null +++ b/frontend/app/frontend/src/components/admin/AddOwner.vue @@ -0,0 +1,67 @@ + + + diff --git a/frontend/app/frontend/src/components/admin/AdminFormsTable.vue b/frontend/app/frontend/src/components/admin/AdminFormsTable.vue new file mode 100644 index 0000000..b4bc007 --- /dev/null +++ b/frontend/app/frontend/src/components/admin/AdminFormsTable.vue @@ -0,0 +1,189 @@ + + + + diff --git a/frontend/app/frontend/src/components/admin/AdminPage.vue b/frontend/app/frontend/src/components/admin/AdminPage.vue new file mode 100644 index 0000000..1cb573c --- /dev/null +++ b/frontend/app/frontend/src/components/admin/AdminPage.vue @@ -0,0 +1,74 @@ + + + diff --git a/frontend/app/frontend/src/components/admin/AdminUsersTable.vue b/frontend/app/frontend/src/components/admin/AdminUsersTable.vue new file mode 100644 index 0000000..1c2933c --- /dev/null +++ b/frontend/app/frontend/src/components/admin/AdminUsersTable.vue @@ -0,0 +1,143 @@ + + + + diff --git a/frontend/app/frontend/src/components/admin/AdminVersions.vue b/frontend/app/frontend/src/components/admin/AdminVersions.vue new file mode 100644 index 0000000..d49d07f --- /dev/null +++ b/frontend/app/frontend/src/components/admin/AdminVersions.vue @@ -0,0 +1,175 @@ + + + + + diff --git a/frontend/app/frontend/src/components/admin/AdministerForm.vue b/frontend/app/frontend/src/components/admin/AdministerForm.vue new file mode 100644 index 0000000..112525b --- /dev/null +++ b/frontend/app/frontend/src/components/admin/AdministerForm.vue @@ -0,0 +1,195 @@ + + + diff --git a/frontend/app/frontend/src/components/admin/AdministerUser.vue b/frontend/app/frontend/src/components/admin/AdministerUser.vue new file mode 100644 index 0000000..f91cf4a --- /dev/null +++ b/frontend/app/frontend/src/components/admin/AdministerUser.vue @@ -0,0 +1,48 @@ + + + diff --git a/frontend/app/frontend/src/components/admin/Dashboard.vue b/frontend/app/frontend/src/components/admin/Dashboard.vue new file mode 100644 index 0000000..2a04b51 --- /dev/null +++ b/frontend/app/frontend/src/components/admin/Dashboard.vue @@ -0,0 +1,16 @@ + + + diff --git a/frontend/app/frontend/src/components/admin/Developer.vue b/frontend/app/frontend/src/components/admin/Developer.vue new file mode 100644 index 0000000..4431df4 --- /dev/null +++ b/frontend/app/frontend/src/components/admin/Developer.vue @@ -0,0 +1,98 @@ + + + diff --git a/frontend/app/frontend/src/components/admin/FormComponentsProactiveHelp.vue b/frontend/app/frontend/src/components/admin/FormComponentsProactiveHelp.vue new file mode 100644 index 0000000..844c89b --- /dev/null +++ b/frontend/app/frontend/src/components/admin/FormComponentsProactiveHelp.vue @@ -0,0 +1,213 @@ + + + + + diff --git a/frontend/app/frontend/src/components/base/BaseAuthButton.vue b/frontend/app/frontend/src/components/base/BaseAuthButton.vue new file mode 100644 index 0000000..65ee0c5 --- /dev/null +++ b/frontend/app/frontend/src/components/base/BaseAuthButton.vue @@ -0,0 +1,35 @@ + + + diff --git a/frontend/app/frontend/src/components/base/BaseCopyToClipboard.vue b/frontend/app/frontend/src/components/base/BaseCopyToClipboard.vue new file mode 100644 index 0000000..ec453f1 --- /dev/null +++ b/frontend/app/frontend/src/components/base/BaseCopyToClipboard.vue @@ -0,0 +1,71 @@ + + + diff --git a/frontend/app/frontend/src/components/base/BaseDialog.vue b/frontend/app/frontend/src/components/base/BaseDialog.vue new file mode 100644 index 0000000..0df2fbb --- /dev/null +++ b/frontend/app/frontend/src/components/base/BaseDialog.vue @@ -0,0 +1,196 @@ + + + + + diff --git a/frontend/app/frontend/src/components/base/BaseFilter.vue b/frontend/app/frontend/src/components/base/BaseFilter.vue new file mode 100644 index 0000000..b6b7402 --- /dev/null +++ b/frontend/app/frontend/src/components/base/BaseFilter.vue @@ -0,0 +1,192 @@ + + + + + diff --git a/frontend/app/frontend/src/components/base/BaseImagePopout.vue b/frontend/app/frontend/src/components/base/BaseImagePopout.vue new file mode 100644 index 0000000..68a719b --- /dev/null +++ b/frontend/app/frontend/src/components/base/BaseImagePopout.vue @@ -0,0 +1,53 @@ + + + + + diff --git a/frontend/app/frontend/src/components/base/BaseInfoCard.vue b/frontend/app/frontend/src/components/base/BaseInfoCard.vue new file mode 100644 index 0000000..9985f89 --- /dev/null +++ b/frontend/app/frontend/src/components/base/BaseInfoCard.vue @@ -0,0 +1,32 @@ + + + diff --git a/frontend/app/frontend/src/components/base/BaseInternationalization.vue b/frontend/app/frontend/src/components/base/BaseInternationalization.vue new file mode 100644 index 0000000..204cf10 --- /dev/null +++ b/frontend/app/frontend/src/components/base/BaseInternationalization.vue @@ -0,0 +1,83 @@ + + + + + diff --git a/frontend/app/frontend/src/components/base/BaseNotificationBar.vue b/frontend/app/frontend/src/components/base/BaseNotificationBar.vue new file mode 100644 index 0000000..34090f9 --- /dev/null +++ b/frontend/app/frontend/src/components/base/BaseNotificationBar.vue @@ -0,0 +1,88 @@ + + + + + diff --git a/frontend/app/frontend/src/components/base/BaseNotificationContainer.vue b/frontend/app/frontend/src/components/base/BaseNotificationContainer.vue new file mode 100644 index 0000000..4c8c95a --- /dev/null +++ b/frontend/app/frontend/src/components/base/BaseNotificationContainer.vue @@ -0,0 +1,37 @@ + + + + + diff --git a/frontend/app/frontend/src/components/base/BasePanel.vue b/frontend/app/frontend/src/components/base/BasePanel.vue new file mode 100644 index 0000000..106fc31 --- /dev/null +++ b/frontend/app/frontend/src/components/base/BasePanel.vue @@ -0,0 +1,29 @@ + + + diff --git a/frontend/app/frontend/src/components/base/BasePrintButton.vue b/frontend/app/frontend/src/components/base/BasePrintButton.vue new file mode 100644 index 0000000..655aabb --- /dev/null +++ b/frontend/app/frontend/src/components/base/BasePrintButton.vue @@ -0,0 +1,22 @@ + + + diff --git a/frontend/app/frontend/src/components/base/BaseSecure.vue b/frontend/app/frontend/src/components/base/BaseSecure.vue new file mode 100644 index 0000000..0a27df9 --- /dev/null +++ b/frontend/app/frontend/src/components/base/BaseSecure.vue @@ -0,0 +1,101 @@ + + + diff --git a/frontend/app/frontend/src/components/base/BaseStepper.vue b/frontend/app/frontend/src/components/base/BaseStepper.vue new file mode 100644 index 0000000..df720f5 --- /dev/null +++ b/frontend/app/frontend/src/components/base/BaseStepper.vue @@ -0,0 +1,123 @@ + + + + + + +step diff --git a/frontend/app/frontend/src/components/bcgov/BCGovAlertBanner.vue b/frontend/app/frontend/src/components/bcgov/BCGovAlertBanner.vue new file mode 100644 index 0000000..b6848a8 --- /dev/null +++ b/frontend/app/frontend/src/components/bcgov/BCGovAlertBanner.vue @@ -0,0 +1,79 @@ + + + + + diff --git a/frontend/app/frontend/src/components/bcgov/BCGovFooter.vue b/frontend/app/frontend/src/components/bcgov/BCGovFooter.vue new file mode 100644 index 0000000..58f0ace --- /dev/null +++ b/frontend/app/frontend/src/components/bcgov/BCGovFooter.vue @@ -0,0 +1,99 @@ + + + + + diff --git a/frontend/app/frontend/src/components/bcgov/BCGovHeader.vue b/frontend/app/frontend/src/components/bcgov/BCGovHeader.vue new file mode 100644 index 0000000..58310aa --- /dev/null +++ b/frontend/app/frontend/src/components/bcgov/BCGovHeader.vue @@ -0,0 +1,124 @@ + + + + + diff --git a/frontend/app/frontend/src/components/bcgov/BCGovNavBar.vue b/frontend/app/frontend/src/components/bcgov/BCGovNavBar.vue new file mode 100644 index 0000000..9a988fc --- /dev/null +++ b/frontend/app/frontend/src/components/bcgov/BCGovNavBar.vue @@ -0,0 +1,141 @@ + + + + + diff --git a/frontend/app/frontend/src/components/designer/FloatButton.vue b/frontend/app/frontend/src/components/designer/FloatButton.vue new file mode 100644 index 0000000..54e4e5b --- /dev/null +++ b/frontend/app/frontend/src/components/designer/FloatButton.vue @@ -0,0 +1,573 @@ + + + + + diff --git a/frontend/app/frontend/src/components/designer/FormDesigner.vue b/frontend/app/frontend/src/components/designer/FormDesigner.vue new file mode 100644 index 0000000..413f732 --- /dev/null +++ b/frontend/app/frontend/src/components/designer/FormDesigner.vue @@ -0,0 +1,830 @@ + + + + + diff --git a/frontend/app/frontend/src/components/designer/FormDisclaimer.vue b/frontend/app/frontend/src/components/designer/FormDisclaimer.vue new file mode 100644 index 0000000..5d24303 --- /dev/null +++ b/frontend/app/frontend/src/components/designer/FormDisclaimer.vue @@ -0,0 +1,45 @@ + + + diff --git a/frontend/app/frontend/src/components/designer/FormSettings.vue b/frontend/app/frontend/src/components/designer/FormSettings.vue new file mode 100644 index 0000000..634d3c2 --- /dev/null +++ b/frontend/app/frontend/src/components/designer/FormSettings.vue @@ -0,0 +1,51 @@ + + + diff --git a/frontend/app/frontend/src/components/designer/FormViewer.vue b/frontend/app/frontend/src/components/designer/FormViewer.vue new file mode 100644 index 0000000..e4c6c93 --- /dev/null +++ b/frontend/app/frontend/src/components/designer/FormViewer.vue @@ -0,0 +1,1259 @@ + + + + + diff --git a/frontend/app/frontend/src/components/designer/FormViewerActions.vue b/frontend/app/frontend/src/components/designer/FormViewerActions.vue new file mode 100644 index 0000000..0e7e350 --- /dev/null +++ b/frontend/app/frontend/src/components/designer/FormViewerActions.vue @@ -0,0 +1,170 @@ + + + diff --git a/frontend/app/frontend/src/components/designer/FormViewerMultiUpload.vue b/frontend/app/frontend/src/components/designer/FormViewerMultiUpload.vue new file mode 100644 index 0000000..4a638e0 --- /dev/null +++ b/frontend/app/frontend/src/components/designer/FormViewerMultiUpload.vue @@ -0,0 +1,813 @@ + + + + + diff --git a/frontend/app/frontend/src/components/designer/FormsTable.vue b/frontend/app/frontend/src/components/designer/FormsTable.vue new file mode 100644 index 0000000..51bf826 --- /dev/null +++ b/frontend/app/frontend/src/components/designer/FormsTable.vue @@ -0,0 +1,230 @@ + + + + + diff --git a/frontend/app/frontend/src/components/designer/settings/FormAccessSettings.vue b/frontend/app/frontend/src/components/designer/settings/FormAccessSettings.vue new file mode 100644 index 0000000..d20c820 --- /dev/null +++ b/frontend/app/frontend/src/components/designer/settings/FormAccessSettings.vue @@ -0,0 +1,192 @@ + + + diff --git a/frontend/app/frontend/src/components/designer/settings/FormFunctionalitySettings.vue b/frontend/app/frontend/src/components/designer/settings/FormFunctionalitySettings.vue new file mode 100644 index 0000000..d9b6a98 --- /dev/null +++ b/frontend/app/frontend/src/components/designer/settings/FormFunctionalitySettings.vue @@ -0,0 +1,265 @@ + + + diff --git a/frontend/app/frontend/src/components/designer/settings/FormGeneralSettings.vue b/frontend/app/frontend/src/components/designer/settings/FormGeneralSettings.vue new file mode 100644 index 0000000..48a7c34 --- /dev/null +++ b/frontend/app/frontend/src/components/designer/settings/FormGeneralSettings.vue @@ -0,0 +1,66 @@ + + + diff --git a/frontend/app/frontend/src/components/designer/settings/FormScheduleSettings.vue b/frontend/app/frontend/src/components/designer/settings/FormScheduleSettings.vue new file mode 100644 index 0000000..e526c5d --- /dev/null +++ b/frontend/app/frontend/src/components/designer/settings/FormScheduleSettings.vue @@ -0,0 +1,781 @@ + + + diff --git a/frontend/app/frontend/src/components/designer/settings/FormSubmissionSettings.vue b/frontend/app/frontend/src/components/designer/settings/FormSubmissionSettings.vue new file mode 100644 index 0000000..4c22551 --- /dev/null +++ b/frontend/app/frontend/src/components/designer/settings/FormSubmissionSettings.vue @@ -0,0 +1,137 @@ + + + diff --git a/frontend/app/frontend/src/components/forms/ExportSubmissions.vue b/frontend/app/frontend/src/components/forms/ExportSubmissions.vue new file mode 100644 index 0000000..8b7cecf --- /dev/null +++ b/frontend/app/frontend/src/components/forms/ExportSubmissions.vue @@ -0,0 +1,659 @@ + + + + + diff --git a/frontend/app/frontend/src/components/forms/FormSubmission.vue b/frontend/app/frontend/src/components/forms/FormSubmission.vue new file mode 100644 index 0000000..c29070f --- /dev/null +++ b/frontend/app/frontend/src/components/forms/FormSubmission.vue @@ -0,0 +1,272 @@ + + + + + diff --git a/frontend/app/frontend/src/components/forms/PrintOptions.vue b/frontend/app/frontend/src/components/forms/PrintOptions.vue new file mode 100644 index 0000000..4c568fc --- /dev/null +++ b/frontend/app/frontend/src/components/forms/PrintOptions.vue @@ -0,0 +1,277 @@ + + + diff --git a/frontend/app/frontend/src/components/forms/RequestReceipt.vue b/frontend/app/frontend/src/components/forms/RequestReceipt.vue new file mode 100644 index 0000000..4526164 --- /dev/null +++ b/frontend/app/frontend/src/components/forms/RequestReceipt.vue @@ -0,0 +1,145 @@ + + + diff --git a/frontend/app/frontend/src/components/forms/SubmissionsTable.vue b/frontend/app/frontend/src/components/forms/SubmissionsTable.vue new file mode 100644 index 0000000..01cecca --- /dev/null +++ b/frontend/app/frontend/src/components/forms/SubmissionsTable.vue @@ -0,0 +1,933 @@ + + + + + diff --git a/frontend/app/frontend/src/components/forms/manage/AddTeamMember.vue b/frontend/app/frontend/src/components/forms/manage/AddTeamMember.vue new file mode 100644 index 0000000..cd1bdbb --- /dev/null +++ b/frontend/app/frontend/src/components/forms/manage/AddTeamMember.vue @@ -0,0 +1,304 @@ + + + + + diff --git a/frontend/app/frontend/src/components/forms/manage/ApiKey.vue b/frontend/app/frontend/src/components/forms/manage/ApiKey.vue new file mode 100644 index 0000000..75782ec --- /dev/null +++ b/frontend/app/frontend/src/components/forms/manage/ApiKey.vue @@ -0,0 +1,237 @@ + + + diff --git a/frontend/app/frontend/src/components/forms/manage/EmailManagement.vue b/frontend/app/frontend/src/components/forms/manage/EmailManagement.vue new file mode 100644 index 0000000..f49f214 --- /dev/null +++ b/frontend/app/frontend/src/components/forms/manage/EmailManagement.vue @@ -0,0 +1,84 @@ + + + diff --git a/frontend/app/frontend/src/components/forms/manage/EmailTemplate.vue b/frontend/app/frontend/src/components/forms/manage/EmailTemplate.vue new file mode 100644 index 0000000..8278152 --- /dev/null +++ b/frontend/app/frontend/src/components/forms/manage/EmailTemplate.vue @@ -0,0 +1,126 @@ + + + diff --git a/frontend/app/frontend/src/components/forms/manage/ManageForm.vue b/frontend/app/frontend/src/components/forms/manage/ManageForm.vue new file mode 100644 index 0000000..4f6621b --- /dev/null +++ b/frontend/app/frontend/src/components/forms/manage/ManageForm.vue @@ -0,0 +1,282 @@ + + + + + diff --git a/frontend/app/frontend/src/components/forms/manage/ManageFormActions.vue b/frontend/app/frontend/src/components/forms/manage/ManageFormActions.vue new file mode 100644 index 0000000..2bb31ac --- /dev/null +++ b/frontend/app/frontend/src/components/forms/manage/ManageFormActions.vue @@ -0,0 +1,169 @@ + + + diff --git a/frontend/app/frontend/src/components/forms/manage/ManageLayout.vue b/frontend/app/frontend/src/components/forms/manage/ManageLayout.vue new file mode 100644 index 0000000..b599e6d --- /dev/null +++ b/frontend/app/frontend/src/components/forms/manage/ManageLayout.vue @@ -0,0 +1,81 @@ + + + + + diff --git a/frontend/app/frontend/src/components/forms/manage/ManageVersions.vue b/frontend/app/frontend/src/components/forms/manage/ManageVersions.vue new file mode 100644 index 0000000..9f64adf --- /dev/null +++ b/frontend/app/frontend/src/components/forms/manage/ManageVersions.vue @@ -0,0 +1,553 @@ + + + + + diff --git a/frontend/app/frontend/src/components/forms/manage/ShareForm.vue b/frontend/app/frontend/src/components/forms/manage/ShareForm.vue new file mode 100644 index 0000000..562f42e --- /dev/null +++ b/frontend/app/frontend/src/components/forms/manage/ShareForm.vue @@ -0,0 +1,191 @@ + + + + + diff --git a/frontend/app/frontend/src/components/forms/manage/Subscription.vue b/frontend/app/frontend/src/components/forms/manage/Subscription.vue new file mode 100644 index 0000000..eb1e292 --- /dev/null +++ b/frontend/app/frontend/src/components/forms/manage/Subscription.vue @@ -0,0 +1,165 @@ + + + diff --git a/frontend/app/frontend/src/components/forms/manage/TeamManagement.vue b/frontend/app/frontend/src/components/forms/manage/TeamManagement.vue new file mode 100644 index 0000000..9457d63 --- /dev/null +++ b/frontend/app/frontend/src/components/forms/manage/TeamManagement.vue @@ -0,0 +1,699 @@ + + + + diff --git a/frontend/app/frontend/src/components/forms/submission/AuditHistory.vue b/frontend/app/frontend/src/components/forms/submission/AuditHistory.vue new file mode 100644 index 0000000..f0ea401 --- /dev/null +++ b/frontend/app/frontend/src/components/forms/submission/AuditHistory.vue @@ -0,0 +1,121 @@ + + + diff --git a/frontend/app/frontend/src/components/forms/submission/DeleteSubmission.vue b/frontend/app/frontend/src/components/forms/submission/DeleteSubmission.vue new file mode 100644 index 0000000..e64e050 --- /dev/null +++ b/frontend/app/frontend/src/components/forms/submission/DeleteSubmission.vue @@ -0,0 +1,95 @@ + + + diff --git a/frontend/app/frontend/src/components/forms/submission/ManageSubmissionUsers.vue b/frontend/app/frontend/src/components/forms/submission/ManageSubmissionUsers.vue new file mode 100644 index 0000000..3a371a3 --- /dev/null +++ b/frontend/app/frontend/src/components/forms/submission/ManageSubmissionUsers.vue @@ -0,0 +1,421 @@ + + + diff --git a/frontend/app/frontend/src/components/forms/submission/MySubmissionsActions.vue b/frontend/app/frontend/src/components/forms/submission/MySubmissionsActions.vue new file mode 100644 index 0000000..f267e37 --- /dev/null +++ b/frontend/app/frontend/src/components/forms/submission/MySubmissionsActions.vue @@ -0,0 +1,152 @@ + + + diff --git a/frontend/app/frontend/src/components/forms/submission/MySubmissionsTable.vue b/frontend/app/frontend/src/components/forms/submission/MySubmissionsTable.vue new file mode 100644 index 0000000..346ff8b --- /dev/null +++ b/frontend/app/frontend/src/components/forms/submission/MySubmissionsTable.vue @@ -0,0 +1,450 @@ + + + + + diff --git a/frontend/app/frontend/src/components/forms/submission/NotesPanel.vue b/frontend/app/frontend/src/components/forms/submission/NotesPanel.vue new file mode 100644 index 0000000..ad761fa --- /dev/null +++ b/frontend/app/frontend/src/components/forms/submission/NotesPanel.vue @@ -0,0 +1,165 @@ + + + + + diff --git a/frontend/app/frontend/src/components/forms/submission/StatusPanel.vue b/frontend/app/frontend/src/components/forms/submission/StatusPanel.vue new file mode 100644 index 0000000..a2dd925 --- /dev/null +++ b/frontend/app/frontend/src/components/forms/submission/StatusPanel.vue @@ -0,0 +1,515 @@ + + + + + diff --git a/frontend/app/frontend/src/components/forms/submission/StatusTable.vue b/frontend/app/frontend/src/components/forms/submission/StatusTable.vue new file mode 100644 index 0000000..b71d6c0 --- /dev/null +++ b/frontend/app/frontend/src/components/forms/submission/StatusTable.vue @@ -0,0 +1,94 @@ + + + + + diff --git a/frontend/app/frontend/src/components/forms/submission/UserDuplicateSubmission.vue b/frontend/app/frontend/src/components/forms/submission/UserDuplicateSubmission.vue new file mode 100644 index 0000000..47a4ad1 --- /dev/null +++ b/frontend/app/frontend/src/components/forms/submission/UserDuplicateSubmission.vue @@ -0,0 +1,51 @@ + + + diff --git a/frontend/app/frontend/src/components/forms/submission/UserSubmission.vue b/frontend/app/frontend/src/components/forms/submission/UserSubmission.vue new file mode 100644 index 0000000..004c5cf --- /dev/null +++ b/frontend/app/frontend/src/components/forms/submission/UserSubmission.vue @@ -0,0 +1,74 @@ + + + diff --git a/frontend/app/frontend/src/components/infolinks/GeneralLayout.vue b/frontend/app/frontend/src/components/infolinks/GeneralLayout.vue new file mode 100644 index 0000000..7d5d51c --- /dev/null +++ b/frontend/app/frontend/src/components/infolinks/GeneralLayout.vue @@ -0,0 +1,272 @@ + + + + + diff --git a/frontend/app/frontend/src/components/infolinks/ProactiveHelpDialog.vue b/frontend/app/frontend/src/components/infolinks/ProactiveHelpDialog.vue new file mode 100644 index 0000000..d2236fb --- /dev/null +++ b/frontend/app/frontend/src/components/infolinks/ProactiveHelpDialog.vue @@ -0,0 +1,393 @@ + + + + + diff --git a/frontend/app/frontend/src/components/infolinks/ProactiveHelpPreviewDialog.vue b/frontend/app/frontend/src/components/infolinks/ProactiveHelpPreviewDialog.vue new file mode 100644 index 0000000..08c423d --- /dev/null +++ b/frontend/app/frontend/src/components/infolinks/ProactiveHelpPreviewDialog.vue @@ -0,0 +1,141 @@ + + + + diff --git a/frontend/app/frontend/src/favicon.ico b/frontend/app/frontend/src/favicon.ico new file mode 100644 index 0000000..1841396 Binary files /dev/null and b/frontend/app/frontend/src/favicon.ico differ diff --git a/frontend/app/frontend/src/filters/index.js b/frontend/app/frontend/src/filters/index.js new file mode 100644 index 0000000..e029060 --- /dev/null +++ b/frontend/app/frontend/src/filters/index.js @@ -0,0 +1,29 @@ +import moment from 'moment'; + +// +// Date format Filters {{ expression | filter }} +// + +/** + * @function formatDate + * Converts a date to an 'MMMM D YYYY' formatted string + * @param {Date} value A date object + * @returns {String} A string representation of `value` + */ +export function formatDate(value) { + if (value) { + return moment(String(value)).format('MMMM D YYYY'); + } +} + +/** + * @function formatDateLong + * Converts a date to a 'YYYY-MM-DD hh:mm:ss a' formatted string + * @param {Date} value A date object + * @returns {String} A string representation of `value` + */ +export function formatDateLong(value) { + if (value) { + return moment(String(value)).format('YYYY-MM-DD hh:mm:ss a'); + } +} diff --git a/frontend/app/frontend/src/internationalization/index.js b/frontend/app/frontend/src/internationalization/index.js new file mode 100644 index 0000000..4b91482 --- /dev/null +++ b/frontend/app/frontend/src/internationalization/index.js @@ -0,0 +1,54 @@ +import { createI18n } from 'vue-i18n'; + +import ar from '~/internationalization/trans/chefs/ar'; +import de from '~/internationalization/trans/chefs/de'; +import en from '~/internationalization/trans/chefs/en'; +import es from '~/internationalization/trans/chefs/es'; +import fa from '~/internationalization/trans/chefs/fa'; +import fr from '~/internationalization/trans/chefs/fr'; +import hi from '~/internationalization/trans/chefs/hi'; +import it from '~/internationalization/trans/chefs/it'; +import ja from '~/internationalization/trans/chefs/ja'; +import ko from '~/internationalization/trans/chefs/ko'; +import pa from '~/internationalization/trans/chefs/pa'; +import pt from '~/internationalization/trans/chefs/pt'; +import ru from '~/internationalization/trans/chefs/ru'; +import tl from '~/internationalization/trans/chefs/tl'; +import uk from '~/internationalization/trans/chefs/uk'; +import vi from '~/internationalization/trans/chefs/vi'; +import zh from '~/internationalization/trans/chefs/zh'; +import zhTW from '~/internationalization/trans/chefs/zhTW'; + +const messages = { + ar: ar, + de: de, + en: en, + es: es, + fa: fa, + fr: fr, + hi: hi, + it: it, + ja: ja, + ko: ko, + pa: pa, + pt: pt, + ru: ru, + tl: tl, + uk: uk, + vi: vi, + zh: zh, + zhTW: zhTW, +}; + +// Create VueI18n instance with options +const instance = createI18n({ + legacy: false, // set to false to use Composition API + locale: 'en', // set locale + fallbackLocale: 'en', + messages, // set locale messages + globalInjection: true, +}); + +export default instance; + +export const i18n = instance.global; diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/ar/ar.json b/frontend/app/frontend/src/internationalization/trans/chefs/ar/ar.json new file mode 100644 index 0000000..e04fc26 --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/ar/ar.json @@ -0,0 +1,995 @@ +{ + "date": { + "date": "yyyy-mm-dd" + }, + "emailManagement": { + "emailManagement": "إدارة البريد الإلكتروني", + "manageForm": "إدارة النموذج", + "submissionConfirmation": "تأكيد تقديم" + }, + "emailTemplate": { + "body": "جسم", + "save": "يحفظ", + "saveEmailTemplateConsoleErrMsg": "خطأ في تحديث قالب البريد الإلكتروني للنموذج {formId}: {error}", + "saveEmailTemplateErrMsg": "حدث خطأ أثناء محاولة تحديث قالب البريد الإلكتروني.", + "subject": "موضوع", + "title": "عنوان", + "validBodyRequired": "الرجاء إدخال نص للبريد الإلكتروني", + "validSubjectRequired": "الرجاء إدخال سطر الموضوع للبريد الإلكتروني", + "validTitleRequired": "الرجاء إدخال عنوان للبريد الإلكتروني" + }, + "formsTable": { + "myForms": "نماذجي", + "createNewForm": "قم بإنشاء نموذج جديد", + "search": "يبحث", + "manage": "يدير", + "submissions": "التقديمات", + "formTitle": "عنوان النموذج", + "viewForm": "مشاهدة النموذج", + "description": "وصف", + "Description": "وصف:", + "action": "أجراءات", + "loadingText": "جاري التحميل الرجاءالانتظار" + }, + "manageLayout": { + "manageForm": "إدارة النموذج" + }, + "preview": { + "preview": "معاينة", + "previewToolTip": "يعرض هذا معاينة لتصميم إصدار النموذج وسلوكه كما يراه مقدموه. لا يمكنك تقديم النموذج من هذه الصفحة." + }, + "shareForm": { + "shareForm": "نموذج المشاركة", + "shareLink": "رابط المشاركة", + "copyQRCode": "انسخ الرابط أدناه أو قم بتنزيل رمز الاستجابة السريعة.", + "warningMessage": "لا توجد نسخة منشورة من النموذج في الوقت الحالي. لن يمكن الوصول إلى الرابط أدناه حتى يتم نشر نسخة.", + "openThisForm": "افتح هذا النموذج", + "downloadQRCode": "تنزيل QR Code", + "close": "يغلق", + "copyURLToClipboard": "انسخ URL إلى الحافظة" + }, + "manageFormActions": { + "emailManagement": "إدارة البريد الإلكتروني", + "viewSubmissions": "مشاهدة عمليات الإرسال", + "teamManagement": "ادارة فريق", + "deleteForm": "حذف النموذج", + "confirmDeletion": "تأكيد الحذف", + "deleteMessageA": "هل أنت متأكد أنك ترغب في حذف", + "deleteMessageB": "لن يمكن الوصول إلى هذا النموذج بعد الآن.", + "delete": "يمسح" + }, + "manageForm": { + "formSettings": "إعدادات النموذج", + "apiKey": "مفتاح API", + "updated": "محدث", + "created": "مخلوق", + "formDesignHistory": "تاريخ تصميم النموذج", + "totalVersions": "إجمالي الإصدارات", + "status": "حالة", + "update": "تحديث", + "cancel": "يلغي", + "eventSubscription": "اشتراك الحدث" + }, + "formSettings": { + "pressToAddMultiEmail": "اضغط على مفتاح الإدخال أو ، أو مسافة لإضافة عناوين بريد إلكتروني متعددة", + "allowMultiDraft": "السماح بتحميل مسودة متعددة", + "formTitle": "عنوان النموذج", + "formDescription": "وصف النموذج", + "formAccess": "الوصول إلى النموذج", + "info": "إذا كنت ستستخدم هذا النموذج لجمع معلومات من عامة الناس حول مواضيع تهم الجمهور بشكل عام ، فأنت مطالب بالاتصال بـ GCPE حتى يمكن إدراج مشاركتك في", + "important": "مهم", + "idimNotifyA": "يجب عليك إخطار فريق إدارة معلومات الهوية (IDIM) عن طريق البريد الإلكتروني", + "idimNotifyB": "نيتك في الاستفادة من BCeID للتحقق من هويات مقدمي النموذج.", + "referenceGuideA": "يرجى الرجوع إلى", + "referenceGuideB": "دليل المستخدم", + "referenceGuideC": "لمزيد من التفاصيل", + "specificTeamMembers": "أعضاء الفريق المحدد", + "formFunctionality": "وظيفة الشكل", + "formSubmissinScheduleMsg": "سيكون جدول تقديم النموذج متاحًا في \"إعدادات النموذج\" بعد نشر النموذج.", + "formSubmissionsSchedule": "جدول تقديم النموذج", + "experimental": "تجريبي", + "learnMore": "يتعلم أكثر", + "afterSubmission": "بعد التقديم", + "submissionConfirmation": "إظهار تفاصيل تأكيد الإرسال", + "theConfirmationID": "معرف التأكيد", + "infoB": "خيار للمستخدم إرسال بريد إلكتروني لتأكيد الإرسال", + "loginRequired": "تسجيل الدخول مطلوب", + "canSaveAndEditDraftLabel": "يمكن للمرسلين حفظ المسودات وتحريرها", + "canUpdateStatusAsReviewer": "يمكن للمراجعين تحديث حالة هذا النموذج (أي مُرسَل ، مُعين ، مكتمل)", + "submitterCanCopyExistingSubmissn": "يمكن للمرسلين نسخ إرسال موجود", + "submissionConfirmationToolTip": "يتحكم تحديد هذا الخيار في ما سيراه المستخدم المرسل لهذا النموذج عند الإرسال الناجح.
إذا تم تحديده ، فسيتم عرضه", + "emailNotificatnToTeam": "أرسل إلى فريقي إشعارًا بالبريد الإلكتروني", + "emailNotificatnToTeamToolTip": "أرسل إشعارًا إلى عنوان بريدك الإلكتروني المحدد عندما يرسل أي مستخدم هذا النموذج", + "notificationEmailAddrs": "عناوين البريد الإلكتروني الخاصة بالإشعار", + "addMoreValidEmailAddrs": "أضف عنوان بريد إلكتروني واحدًا أو أكثر", + "formScheduleSettings": "إعدادات جدول النموذج", + "opensubmissions": "فتح عمليات الإرسال", + "submissionsDeadline": "ما هي المدة التي تريدها لتلقي الطلبات؟", + "keepSubmissnOpenTilUnplished": "ابق مفتوحًا حتى يتم إلغاء نشره يدويًا", + "submissionsClosingDate": "جدولة موعد إغلاق", + "submissionPeriod": "قم بإعداد فترة التقديم", + "closeSubmissions": "إغلاق عمليات الإرسال", + "keepOpenFor": "ابق مفتوحا", + "period": "فترة", + "allowLateSubmissions": "السماح بالتقديم المتأخر", + "allowLateSubmissionsInfoTip": "إذا تم تحديده ، سيتمكن المرسلون من إرسال البيانات بعد تاريخ الإغلاق.", + "afterCloseDateFor": "بعد تاريخ الاغلاق ل", + "repeatPeriod": "كرر الفترة", + "every": "كل", + "repeatUntil": "كرر حتى", + "summary": "ملخص", + "submissionsOpenDateRange": "سيتم فتح هذا النموذج لتقديم الطلبات من", + "to": "ل", + "scheduleRepetition": "الجدول الزمني سوف يتكرر كل", + "allowLateSubmissnInterval": "السماح بتقديم الطلبات المتأخرة لـ", + "until": "حتى", + "datesOfSubmissnInfo": "وفقًا للإعدادات ، فهذه هي التواريخ المتاحة لتقديم الطلبات:", + "formOpenInterval": "سيتم فتح هذا النموذج لتقديم الطلبات من", + "allowDateSubmissionDate": "مع السماح بالتقديم المتأخر حتى", + "customClosingMessage": "تعيين رسالة ختامية مخصصة", + "customClosingMessageToolTip": "تسمح لك بإضافة رسالة مخصصة للمستخدمين عند زيارتهم لنموذج مغلق.", + "closingMessage": "رسالة ختامية", + "sendReminderEmail": "إرسال بريد إلكتروني للتذكير", + "autoReminderNotificatn": "تفعيل إشعار التذكير التلقائي", + "autoReminderNotificatnToolTip": "إرسال رسائل بريد إلكتروني للتذكير مع رابط النموذج خلال فترة التقديم.", + "selectLoginType": "الرجاء تحديد نوع تسجيل دخول واحد", + "formDescriptnMaxChars": "يجب أن يتكون وصف النموذج من 255 حرفًا أو أقل", + "formTitlemaxChars": "يجب أن يتكون عنوان النموذج من 255 حرفًا أو أقل", + "formTitleReq": "عنوان النموذج مطلوب", + "atLeastOneEmailReq": "الرجاء إدخال عنوان بريد إلكتروني واحد على الأقل", + "validEmailRequired": "الرجاء إدخال جميع عناوين البريد الإلكتروني الصحيحة", + "fieldRequired": "هذه الخانة مطلوبه.", + "correctDateFormat": "يجب أن يكون التاريخ في الشكل الصحيح. أي. yyyy-mm-dd", + "dateDiffMsg": "يجب أن يكون تاريخ التقديم إغلاق أكبر من تاريخ التقديم المفتوح.", + "valueMustBeNumber": "يجب أن تكون القيمة رقمًا. أي. 1،2،3،5،99", + "selectAnOptions": "الرجاء تحديد خيار واحد على الأقل", + "validInterval": "يجب أن يكون هذا الفاصل الزمني صالحًا.", + "fieldRequiredAndInterval": "هذا الحقل مطلوب ويجب أن يكون فترة.", + "dateGrtOpenSubmissnDate": "كرر حتى التاريخ يجب أن يكون أكبر من تاريخ التقديم المفتوح", + "public": "عام (مجهول)", + "allowEventSubscription": "السماح بالاشتراك في الحدث", + "eventSubscription": "اشتراك الحدث", + "validEndpointRequired": "الرجاء إدخال نقطة نهاية https://", + "validBearerTokenRequired": "89abddfb-2cff-4fda-83e6-13221f0c3d4f أدخل مثال رمز حامل صالح" + }, + "subscribeEvent": { + "eventType": "نوع الحدث", + "endpointUrl": "عنوان URL لنقطة النهاية", + "eventSubmission": "استسلام", + "eventAssignment": "تكليف", + "eventStatusChange": "تغيير الوضع", + "endpointToken": "رمز نقطة النهاية", + "urlPlaceholder": "https://endpoint.gov.bc.ca/api/v1/", + "save": "يحفظ", + "text": "نص", + "password": "كلمة المرور", + "hideSecret": "إخفاء السر", + "showSecret": "إظهار السر", + "key": "مفتاح", + "saveSettingsErrMsg": "حدث خطأ أثناء محاولة تحديث إعدادات هذا النموذج.", + "updateSettingsConsoleErrMsg": "خطأ في تحديث إعدادات النموذج {formId}: {error}" + }, + "apiKey": { + "disclaimer": "تنصل", + "infoA": "تأكد من تخزين سر مفتاح واجهة برمجة التطبيقات في مكان آمن (أي مخزن المفاتيح).", + "infoB": "يمنحك مفتاح API وصولاً غير مقيد إلى النموذج الخاص بك. لا تعطي مفتاح API الخاص بك لأي شخص.", + "infoC": "يجب استخدام مفتاح API فقط لتفاعلات النظام المؤتمتة. لا تستخدم مفتاح API الخاص بك للوصول المستند إلى المستخدم", + "deleteKey": "مفتاح الحذف", + "apiKey": "مفتاح API", + "hideSecret": "إخفاء السر", + "showSecret": "إظهار السر", + "sCTC": "تم نسخ السر إلى الحافظة", + "cSTC": "نسخ السر إلى الحافظة", + "key": "مفتاح", + "confirmDeletion": "تأكيد الحذف", + "deleteMsg": "هل أنت متأكد من رغبتك في حذف مفتاح API الخاص بك؟", + "delete": "يمسح", + "confirmKeyGen": "تأكيد إنشاء المفتاح", + "createAPIKey": "إنشاء مفتاح API لهذا النموذج؟
تأكد من اتباع إخلاء المسؤولية في هذه الصفحة.", + "regenerateAPIKey": "إعادة إنشاء مفتاح API؟
ستؤدي المتابعة إلى حذف الوصول الحالي لمفتاح واجهة برمجة التطبيقات .", + "formOwnerKeyAcess": "يجب أن تكون مالك النموذج لإدارة مفاتيح API.", + "regenerate": "تجديد", + "generate": "يولد", + "secret": "سر" + }, + "manageVersions": { + "important": "مهم!", + "infoA": "إذا لم تكن هناك إصدارات منشورة ، فلن يتمكن المستخدمون من الوصول إلى هذا النموذج حتى يتم تعيين إصدار منشور. بمجرد نشر الإصدار ، لم يعد هذا الإصدار قابلاً للتحرير. يجب عليك إنشاء إصدار جديد بناءً على أحد إصدارات النموذج السابقة لمتابعة التحرير.", + "infoB": "ملاحظة: يمكن نشر نسخة واحدة فقط.", + "version": "إصدار", + "draft": "مسودة", + "clickToPreview": "انقر لمعاينة", + "editVersion": "تحرير الإصدار", + "exportDesign": "تصميم التصدير", + "infoC": "يرجى نشر أو حذف أحدث نسخة مسودة قبل بدء إصدار جديد.", + "deleteVersion": "حذف الإصدار", + "draftAlreadyExists": "المسودة موجودة بالفعل", + "infoD": "يرجى تعديل المسودة الحالية أو نشرها أو حذفها قبل بدء مسودة جديدة.", + "publishVersion": "نشر الإصدار", + "unpublishVersion": "نسخة غير منشورة", + "infoE": "سيؤدي إلغاء نشر هذا النموذج إلى إخراج النموذج من التداول حتى يتم نشر النسخة مرة أخرى.", + "confirmDeletion": "تأكيد الحذف", + "infoF": "هل أنت متأكد أنك تريد حذف هذا الإصدار؟", + "delete": "يمسح", + "status": "حالة", + "dateCreated": "تاريخ الإنشاء", + "createdBy": "انشأ من قبل", + "actions": "أجراءات", + "published": "نشرت", + "unpublished": "غير منشورة", + "useVersionInfo": "استخدم الإصدار {version} كأساس لإصدار جديد", + "publishingVersionInfo": "سيؤدي هذا إلى جعل الإصدار {version} من النموذج الخاص بك مباشرًا." + }, + "addOwner": { + "infoA": "يجب أن يتم ذلك فقط في حالة أن مالك النموذج الحالي لم يعد نشطًا أو كان خارج الاتصال في حدث ذي أولوية. وبخلاف ذلك ، اطلب من المالك الحالي أو مسؤول الفريق للنموذج القيام بذلك بنفسه.", + "hint": "للعثور على معرّف المستخدم المطلوب ، يمكنك الانتقال إلى علامة التبويب \"المستخدمون\" في بوابة المسؤول والبحث عنها.", + "addowner": "إضافة مالك", + "label": "معرف المستخدم (الدليل)" + }, + "adminFormsTable": { + "showDeletedForms": "إظهار النماذج المحذوفة", + "search": "يبحث", + "loadingText": "نص التحميل", + "noDataText": "لا توجد نماذج في نظامك", + "admin": "مسؤل", + "launch": "يطلق", + "formTitle": "عنوان النموذج", + "created": "مخلوق", + "deleted": "تم الحذف", + "actions": "أجراءات", + "delete": "يمسح" + }, + "administerForm": { + "deleted": "تم الحذف", + "restoreForm": "قم باستعادة هذا النموذج", + "formDetails": "تفاصيل النموذج", + "apiKeyDetails": "تفاصيل مفتاح API", + "deleteApiKey": "حذف مفتاح API", + "formUsers": "مستخدمي النموذج", + "formVersions": "إصدارات النموذج", + "assignANewOwner": "تعيين مالك جديد", + "restoring": "استعادة", + "restore": "يعيد", + "toActiveState": "إلى الحالة النشطة", + "confirmDeletion": "تأكيد الحذف", + "confirmDeletionMsg": "هل أنت متأكد أنك تريد حذف مفتاح API هذا؟", + "delete": "يمسح", + "confirmRestore": "تأكيد الاستعادة" + }, + "administerUser": { + "userDetails": "بيانات المستخدم", + "openSSOConsole": "افتح وحدة تحكم الدخول الموحّد (SSO)" + }, + "adminPage": { + "forms": "نماذج", + "users": "المستخدمون", + "developer": "مطور", + "infoLinks": "روابط المعلومات", + "metrics": "المقاييس" + }, + "adminUsersTable": { + "search": "يبحث", + "loadingText": "جاري التحميل الرجاءالانتظار", + "admin": "مسؤل", + "fullName": "الاسم الكامل", + "userID": "معرف المستخدم", + "created": "مخلوق", + "actions": "أجراءات" + }, + "adminVersions": { + "exportDesign": "تصميم التصدير", + "versions": "إصدارات", + "status": "حالة", + "created": "مخلوق", + "lastUpdated": "آخر تحديث", + "actions": "أجراءات", + "published": "نشرت", + "unpublished": "غير منشورة", + "version": "الإصدار {versionNo}", + "notificationMsg": "حدث خطأ أثناء تحميل تصميم النموذج." + }, + "developer": { + "user": "مستخدم", + "name": "اسم", + "userName": "اسم المستخدم", + "JWTContents": "محتويات JWT", + "JWTContentsSBTxt": "تم نسخ محتويات JWT إلى الحافظة", + "JWTContentsTTTxt": "انسخ محتويات JWT إلى الحافظة", + "JWTToken": "JWT Token", + "JWTTokenSBTxt": "تم نسخ JWT Token إلى الحافظة", + "JWTTokenTTTxt": "انسخ JWT Token إلى الحافظة", + "chefsAPI": "CHEFS API", + "RBACSBTxt": "تم نسخ استجابة RBAC إلى الحافظة", + "RBACTTTxt": "نسخ استجابة RBAC إلى الحافظة", + "notificationMsg": "فشل الحصول على مستخدم من RBAC ، راجع وحدة التحكم", + "notificationConsErr": "خطأ في الحصول على مستخدم من RBAC" + }, + "baseAuthButton": { + "logout": "تسجيل خروج", + "login": "تسجيل الدخول" + }, + "baseDialog": { + "defaultText": "النص الافتراضي", + "ok": "نعم", + "continue": "يكمل", + "cancel": "يلغي", + "custom": "مخصص" + }, + "baseSecure": { + "about": "عن", + "loginInfo": "يجب عليك تسجيل الدخول لاستخدام هذه الميزة.", + "login": "تسجيل الدخول", + "401NotAuthorized": "401: غير مصرح به. :", + "401ErrorMsg": "لم يتم إعداد حسابك بشكل صحيح.
الرجاء التواصل", + "403Forbidden": "403 ممنوع. :", + "403ErrorMsg": "تتطلب هذه الصفحة مصادقة {idp}.", + "401UnAuthorized": "401: غير مصرح به. :", + "401UnAuthorizedErrMsg": "ليس لديك الصلاحية لدخول هذه الصفحة." + }, + "formDesigner": { + "formDesign": "تصميم النموذج", + "exportDesign": "تصميم التصدير", + "importDesign": "تصميم الاستيراد", + "important": "مهم", + "formDesignInfoA": "استخدم زر حفظ التصميم عند الانتهاء من بناء هذا النموذج.", + "formDesignInfoB": "يتم توفير زر إرسال للمستخدم لإرسال هذا النموذج وسيتم تنشيطه بعد حفظه.", + "formLoadErrMsg": "حدث خطأ أثناء تحميل تصميم النموذج.", + "formLoadConsoleErrMsg": "خطأ في تحميل مخطط النموذج {formId} (الإصدار: {versionId} المسودة: {draftId}): {error}", + "formSchemaImportErrMsg": "حدث خطأ أثناء استيراد مخطط النموذج.", + "formSchemaImportConsoleErrMsg": "خطأ في استيراد مخطط النموذج: {error}", + "formDesignSaveErrMsg": "حدث خطأ أثناء محاولة حفظ تصميم النموذج هذا. إذا كنت بحاجة إلى التحديث أو المغادرة للمحاولة مرة أخرى لاحقًا ، فيمكنك تصدير التصميم الحالي على الصفحة لحفظه في وقت لاحق.", + "formDesignSaveConsoleErrMsg": "خطأ في تحديث أو إنشاء النموذج (FormID: {formId} ، versionId: {versionId} ، draftId: {draftId}) خطأ: {error}", + "collapse": "ينهار", + "actions": "أجراءات", + "version": "إصدار", + "save": "يحفظ", + "saving": "إنقاذ", + "notSaved": "يتم حفظ", + "fieldnameError": "لا يمكنك استخدام الكلمة الأساسية `form` كاسم حقل {label}." + }, + "formViewerMultiUpload": { + "important": "مهم", + "uploadSucessMsg": "لضمان تحميل مسودات متعددة بنجاح ، يرجى تنزيل النموذج المقدم واستخدامه.", + "confirmDownload": "هل تريد تحميله؟", + "jsonFileUpload": "حدد ملف JSON للتحميل", + "dragNDrop": "أو اسحبه وأفلته هنا", + "chooseAFile": "اختيار ملف", + "downloadDraftSubmns": "يرجى تنزيل مسودة تقرير التقديم والتأكد من إدخال البيانات بشكل صحيح.", + "downloadReport": "تحميل التقرير", + "doYouWantToDownload": "هل تريد تحميله؟", + "uploadNewFile": "تحميل ملف جديد", + "uploadMultipleFileErr": "عذرا ، يمكنك تحميل ملف واحد فقط", + "dragMultipleFileErr": "عذرا ، يمكنك سحب ملف واحد فقط", + "fileFormatErr": "عذرا ، نحن نقبل ملفات json فقط", + "fileSizeErr": "الحد الأقصى لحجم الملف المسموح به هو 5 ميغا بايت", + "parseJsonErr": "لا يمكننا تحليل بيانات json من الملف", + "jsonObjNotArray": "تنسيق ملف json خاطئ", + "jsonObjNotArrayConsErr": "حدث خطأ غير متوقع.", + "jsonArrayEmpty": "ملف json هذا فارغ.", + "errorWhileValidate": "هناك خطأ في هذا الملف", + "errWhileCheckValidity": "هناك خطأ في هذا الملف", + "errAfterValidate": "تم العثور على بعض الأخطاء ، انظر أدناه لمزيد من المعلومات.", + "fileIsEmpty": "هذا الملف فارغ.", + "download": "تحميل" + }, + "formDisclaimer": { + "disclaimerAndStatement": "إخلاء المسؤولية وبيان المسؤولية لمصممي النماذج:", + "privacyLaw": "تقع على عاتقك مسؤولية الامتثال لقوانين الخصوصية التي تحكم جمع معلومات التعريف الشخصية واستخدامها والكشف عنها.", + "disclosure": "لا يمنح الوصول إلى أداة مصمم النماذج هذه إذنًا بطبيعته لجمع أو استخدام أو الكشف عن أي معلومات تعريف شخصية.", + "consent": "تقع على عاتقك مسؤولية الحصول على الموافقة لجمع المعلومات وفقًا لما يقتضيه القانون.", + "formIntention": "قبل نشر النموذج أو توزيعه ، يتعين عليك مناقشة نية النموذج مع", + "privacyOfficer": "مسؤول الخصوصية بالوزارة", + "assement": "واستكمال التقييمات كما هو مطلوب." + }, + "requestReceipt": { + "emailPriority": "أولوية البريد الإلكتروني", + "emailReceipt": "إرسال إيصال هذا الإرسال بالبريد الإلكتروني", + "high": "عالي", + "low": "قليل", + "normal": "طبيعي", + "send": "يرسل", + "sendToEmailAddress": "أرسل إلى عنوان البريد الإلكتروني", + "emailSent": "تم إرسال بريد إلكتروني إلى {to}.", + "sendingEmailErrMsg": "حدث خطأ أثناء محاولة إرسال البريد الإلكتروني الخاص بك.", + "sendingEmailConsErrMsg": "فشل تأكيد البريد الإلكتروني إلى {to}: {error}", + "emailRequired": "البريد الالكتروني مطلوب" + }, + "submissionsTable": { + "noMatchingRecordText": "لم يتم العثور على سجلات مطابقة", + "submissions": "التقديمات", + "submissionsTable": "الجدول", + "selectColumns": "حدد الأعمدة", + "manageForm": "إدارة النموذج", + "submissionsToFiles": "تصدير عمليات الإرسال إلى الملفات", + "showDeletedSubmissions": "إظهار عمليات الإرسال المحذوفة", + "showMySubmissions": "عرض عمليات الإرسال الخاصة بي", + "search": "يبحث", + "loadingText": "جاري التحميل الرجاءالانتظار", + "noDataText": "لا توجد عمليات إرسال لهذا النموذج", + "delSelectedSubmissions": "حذف عمليات الإرسال المحددة", + "resSelectedSubmissions": "استعادة عمليات الإرسال المحددة", + "yes": "نعم", + "no": "لا", + "viewSubmission": "عرض التقديم", + "deleteSubmission": "حذف التقديم", + "restore": "يعيد", + "confirmDeletion": "تأكيد الحذف", + "delete": "يمسح", + "confirmRestoration": "تأكيد الاستعادة", + "searchSubmissionFields": "البحث في حقول التقديم", + "save": "يحفظ", + "searchTitle": "ابحث عن الأعمدة وحددها لإظهارها أسفل لوحة التحكم", + "status": "حالة", + "submitter": "المرسل", + "submissionDate": "تاريخ التقديم", + "event": "حدث", + "view": "منظر", + "lateSubmission": "تسليم متأخر", + "confirmationID": "معرف التأكيد", + "multiDelWarning": "هل أنت متأكد أنك تريد حذف عمليات الإرسال المختارة؟", + "singleDelWarning": "هل أنت متأكد أنك ترغب في حذف هذا الإرسال؟", + "multiRestoreWarning": "هل أنت متأكد أنك تريد استعادة هذه الإرسالات؟", + "singleRestoreWarning": "هل أنت متأكد أنك ترغب في استعادة هذا الإرسال؟" + }, + "auditHistory": { + "viewEditHistory": "عرض محفوظات التحرير", + "editHistory": "تحرير المحفوظات", + "auditLogMsg": "هذا سجل تدقيق لمن أجرى تغييرات على هذا الإرسال بعد الإرسال الأصلي.", + "loadingText": "جاري التحميل الرجاءالانتظار", + "close": "يغلق", + "userName": "اسم المستخدم", + "date": "تاريخ", + "errorMsg": "حدث خطأ أثناء محاولة جلب المحفوظات.", + "consoleErrMsg": "خطأ في الحصول على سجل التدقيق لـ" + }, + "deleteSubmission": { + "deleteThis": "امسح هذه", + "draft": "مسودة", + "submission": "استسلام", + "confirmDeletion": "تأكيد الحذف", + "deleteWarning": "هل أنت متأكد أنك ترغب في حذف هذا", + "drafts": "مسودة", + "formSubmission": "تقديم النموذج", + "delete": "يمسح" + }, + "manageSubmissionUsers": { + "manageTeamMembers": "إدارة أعضاء الفريق", + "add": "يضيف", + "draftFormInvite": "يمكنك فقط دعوة أعضاء الفريق وإدارتهم عندما يكون هذا النموذج مسودة", + "submissionTeamMembers": "أعضاء الفريق لهذا التقديم", + "actions": "أجراءات", + "close": "يغلق", + "remove": "يزيل", + "userNotFoundErrMsg": "لا يمكنك العثور على شخص ما؟ ربما لم يقوموا بتسجيل الدخول إلى CHEFS.
يرجى إرسال رابط إلى CHEFS واطلب منهم تسجيل الدخول.", + "name": "اسم", + "username": "اسم المستخدم", + "email": "بريد إلكتروني", + "removeUserWarningMsg1": "هل أنت متأكد أنك ترغب في الإزالة", + "removeUserWarningMsg2": "لم يعد لديهم أذونات لهذا الإرسال.", + "userExistInListMsg": "المستخدم {username} موجود بالفعل في قائمة أعضاء الفريق.", + "getSubmissionUsersErr": "حدث خطأ أثناء محاولة جلب المستخدمين لهذا الإرسال.", + "getSubmissionUsersConsoleErr": "خطأ في الحصول على مستخدمين لـ {submitId}: {error}", + "sentInviteEmailTo": "أرسلت دعوة البريد الإلكتروني إلى", + "sentUninvitedEmailTo": "أرسل بريدًا إلكترونيًا غير مدعو إلى", + "updateUserErrMsg": "حدث خطأ أثناء محاولة تحديث المستخدمين لهذا الإرسال.", + "updateUserConsoleErrMsg": "خطأ في تعيين أذونات المستخدم. Sub: {submitId} المستخدم: {userId} خطأ: {error}", + "searchInputLength": "يجب أن يكون إدخال البحث عن اسم المستخدم / البريد الإلكتروني BCeID أكبر من 6 أحرف.", + "exactBCEIDSearch": "يجب أن تكون عمليات البحث في البريد الإلكتروني عن BCeID دقيقة.", + "getUsersErrMsg": "خطأ في الحصول على المستخدمين: {error}", + "exactEmailOrUsername": "أدخل البريد الإلكتروني أو اسم المستخدم بالضبط.", + "requiredFiled": "أدخل اسمًا أو بريدًا إلكترونيًا أو اسم مستخدم" + }, + "mySubmissionsActions": { + "viewThisSubmission": "مشاهدة هذا التقديم", + "copyThisSubmission": "انسخ هذا التقديم", + "editThisDraft": "تحرير هذه المسودة" + }, + "mySubmissionsTable": { + "noMatchingRecordText": "لم يتم العثور على سجلات مطابقة", + "previousSubmissions": "عمليات الإرسال السابقة", + "selectColumns": "حدد الأعمدة", + "createNewSubmission": "إنشاء إرسال جديد", + "search": "يبحث", + "loadingText": "جاري التحميل الرجاءالانتظار", + "noDataText": "ليس لديك إرسالات", + "searchSubmissionFields": "البحث في حقول التقديم", + "save": "يحفظ", + "filterTitle": "ابحث عن الأعمدة وحددها لإظهارها أسفل لوحة التحكم", + "confirmationId": "معرف التأكيد", + "actions": "أجراءات", + "createdBy": "انشأ من قبل", + "statusUpdatedBy": "تم تحديث الحالة بواسطة", + "status": "حالة", + "submissionDate": "تاريخ التقديم", + "draftUpdatedBy": "تم تحديث المسودة بواسطة", + "draftLastEdited": "آخر تعديل للمسودة", + "createLateSubmissn": "إنشاء تقديم متأخر", + "formLoading": "يرجى الانتظار حتى يتم تحميل النموذج !!!", + "pleaseConfirm": "يرجى تأكيد", + "wantToSaveDraft": "هل تريد حفظ المسودة؟", + "yes": "نعم", + "no": "لا", + "multiDraftUploadSuccess": "لقد نجح تحميل المسودة المتعددة!", + "failedResSubmissn": "فشل الرد من نقطة نهاية الإرسال. رمز الاستجابة: {status}", + "errSubmittingForm": "حدث خطأ أثناء إرسال هذا النموذج", + "errorSavingFile": "خطأ في حفظ الملفات. اسم الملف: {fileName}. خطأ: {error}", + "submittingDraftErrMsg": "حدث خطأ أثناء حفظ المسودة", + "submittingDraftConsErrMsg": "خطأ في حفظ المسودة. معرف التقديم: {submitId}. خطأ: {error}" + }, + "notesPanel": { + "addNewNote": "أضف ملاحظة جديدة", + "cancel": "يلغي", + "addNote": "اضف ملاحظة", + "noResponseErr": "لا توجد بيانات استجابة من API أثناء إرسال النموذج", + "errorMesg": "حدث خطأ أثناء محاولة إضافة الملاحظة.", + "consoleErrMsg": "خطأ في إضافة الملاحظة:", + "fetchErrMsg": "حدث خطأ أثناء محاولة جلب الملاحظات لهذا الإرسال.", + "fetchConsoleErrMsg": "خطأ في إضافة الملاحظة:", + "notes": "ملحوظات", + "note": "ملحوظة", + "maxChars": "4000 حرف كحد أقصى" + }, + "statusPanel": { + "currentStatus": "الحالة الحالية:", + "assignedTo": "مخصص ل:", + "assignOrUpdateStatus": "تعيين أو تحديث الحالة", + "display": "عرض", + "statusIsRequired": "الحالة مطلوبة", + "assignTo": "يسند إلى", + "noDataText": "لم يتم العثور على مراجعي النموذج مع البحث. قم بإضافة مراجعي النموذج في صفحة الإدارة.", + "assigneeIsRequired": "مطلوب الوكيل", + "assignToMe": "تعيين لي", + "recipientEmail": "البريد الإلكتروني المستلم", + "attachCommentToEmail": "إرفاق تعليق بالبريد الإلكتروني", + "emailComment": "التعليق بالبريد الإلكتروني", + "maxChars": "4000 حرف كحد أقصى", + "viewHistory": "عرض السجل", + "statusHistory": "محفوظات الحالة", + "close": "يغلق", + "addNoteNoReponserErr": "لا توجد بيانات استجابة من API أثناء إرسال ملاحظة لتحديث الحالة", + "addNoteConsoleErrMsg": "خطأ في تحديث الحالة: {error}", + "addNoteErrMsg": "حدث خطأ أثناء محاولة تحديث الحالة", + "updtSubmissionsStatusErr": "لا توجد بيانات استجابة من API أثناء إرسال نموذج تحديث الحالة", + "noStatus": "لا توجد حالة", + "noStatusesFound": "لم يتم العثور على حالات", + "statusCodesErr": "خطأ في العثور على رموز الحالة", + "notifyErrorCode": "حدث خطأ أثناء إحضار الحالة لهذا الإرسال.", + "notifyConsoleErrorCode": "خطأ في الحصول على الحالات:", + "fetchSubmissionUsersErr": "حدث خطأ أثناء محاولة جلب رسائل البريد الإلكتروني للمستلمين لهذا الإرسال.", + "fetchSubmissionUsersConsErr": "خطأ في الحصول على رسائل البريد الإلكتروني للمستلم لـ", + "assignSubmissnToFormReviewer": "يمكن تعيين التقديمات لمراجعي النموذج.
لإضافة المزيد من أعضاء الفريق كمراجعين للنموذج ، انتقل إلى صفحة الإدارة لهذا النموذج.", + "update": "تحديث", + "revise": "يراجع", + "complete": "مكتمل", + "assign": "تعيين" + }, + "statusTable": { + "loadingText": "جاري التحميل الرجاءالانتظار", + "status": "حالة", + "dateStatusChanged": "تاريخ الحالة تغيرت", + "assignee": "الوكيل", + "updatedBy": "تم التحديث بواسطة", + "getSubmissionStatusErr": "حدث خطأ أثناء محاولة جلب الحالات.", + "getSubmissionStatusConsErr": "خطأ في إضافة الملاحظة:" + }, + "exportSubmissions": { + "exportSubmissionsToFile": "تصدير التقديمات إلى ملف", + "viewSubmissions": "مشاهدة عمليات الإرسال", + "fileType": "نوع الملف", + "json": "جسون", + "csv": "CSV", + "formVersion": "نسخة النموذج", + "versionIsRequired": "الإصدار مطلوب.", + "dataFields": "حقول البيانات", + "searchFields": "البحث في الحقول", + "selectedForExports": "المختار للتصدير", + "submissionDate": "تاريخ التقديم", + "all": "الجميع", + "selectDateRange": "حدد النطاق الزمني", + "SelectdateRange": "حدد النطاق الزمني", + "from": "من", + "to": "ل", + "CSVFormat": "تنسيق CSV", + "multiRowPerSubmissionA": "1 - صفوف متعددة لكل إرسال مع مسافات بادئة", + "multiRowPerSubmissionB": "2 - صفوف متعددة لكل إرسال", + "singleRowPerSubmission": "3 - صف واحد لكل تقديم", + "unformatted": "4 - غير منسق", + "fileNameAndType": "اسم الملف ونوعه", + "export": "يصدّر", + "noResponseDataErr": "لا توجد بيانات استجابة من استدعاء exportSubmissions", + "apiCallErrorMsg": "حدث خطأ أثناء محاولة تصدير عمليات الإرسال لهذا النموذج.", + "apiCallConsErrorMsg": "إرسال خطأ في تصدير", + "selectAllFields": "حدد كل الحقول", + "emailSentMsg": "سيتم إرسال بريد إلكتروني إلى {email} يحتوي على رابط لتنزيل بياناتك عندما تكون جاهزة", + "exportInProgress": "التصدير قيد التقدم", + "of": "ل" + }, + "printOptions": { + "submitButtonTxt": "أرسل إلى CDOGS وقم بالتنزيل", + "templatePrint": "طباعة القالب", + "uploadTemplateFile": "تحميل ملف القالب", + "downloadOptions": "خيارات التنزيل", + "print": "مطبعة", + "browserPrint": "طباعة المتصفح", + "pageFromBrowser": "الصفحة من متصفحك", + "uploadA": "تحميل أ", + "uploadB": "للحصول على نسخة منظمة", + "docGrnSucess": "تم إنشاء المستند بنجاح", + "failedDocGenErrMsg": "فشل إنشاء المستند", + "failedDocGenConsErrMsg": "خطأ في إرسال النموذج: {error}", + "cDogsTemplate": "قالب CDOGS" + }, + "proactiveHelpDialog": { + "componentInfoLink": "رابط معلومات المكون", + "learnMoreLinkTxt": "تعرف على المزيد لا يمكن أن يكون حقل الارتباط فارغًا.", + "largeImgTxt": "صورة كبيرة. لا يمكن أن يكون حجم الصورة أكبر من .5 ميغا بايت", + "componentName": "اسم المكون:", + "learnMoreLink": "تعلم المزيد الارتباط:", + "clickToEnableLink": "انقر لتمكين الارتباط", + "clickToDisableLink": "انقر لتعطيل الارتباط", + "imageUpload": "تحميل الصور:", + "cancel": "يلغي", + "save": "يحفظ", + "description": "وصف" + }, + "proactiveHelpPreviewDialog": { + "learnMore": "يتعلم أكثر" + }, + "preview": { + "preview": "معاينة", + "previewToolTip": "يعرض هذا معاينة لتصميم إصدار النموذج وسلوكه كما يراه مقدموه. لا يمكنك تقديم النموذج من هذه الصفحة." + }, + "generalLayout": { + "loadingText": "جاري التحميل الرجاءالانتظار", + "preview": "معاينة", + "published": "نشرت", + "unpublished": "غير منشورة", + "edit": "يحرر", + "formTitle": "عنوان النموذج", + "actions": "أجراءات" + }, + "formSubmission": { + "editThisSubmission": "تحرير هذا الإرسال", + "submission": "استسلام", + "alertInfo": "بعد التحرير ، أعد إرسال النموذج لحفظ التغييرات.", + "viewAllSubmissions": "عرض جميع عمليات الإرسال", + "submitted": "مُقَدَّم:", + "confirmationID": "معرف التأكيد:", + "submittedBy": "مقدم من:", + "cancel": "يلغي", + "status": "حالة", + "updatedAt": "معدل", + "updatedBy": "تم التعديل بواسطة" + }, + "teamManagement": { + "noMatchingRecordText": "لم يتم العثور على سجلات مطابقة", + "teamManagement": "ادارة فريق", + "selectColumns": "حدد الأعمدة", + "manageForm": "إدارة النموذج", + "search": "يبحث", + "loadingText": "جاري التحميل الرجاءالانتظار", + "noDataText": "فشل تحميل بيانات دور الفريق", + "removeSelectedUsers": "إزالة المستخدمين المختارين", + "removeThisUser": "قم بإزالة هذا المستخدم", + "confirmRemoval": "تأكيد الإزالة", + "remove": "يزيل", + "searchTeamManagementFields": "البحث في حقول إدارة الفريق", + "save": "يحفظ", + "teamMebersTitle": "ابحث عن الأعمدة وحددها لإظهارها أسفل لوحة التحكم", + "fullName": "الاسم الكامل", + "username": "اسم المستخدم", + "identityProvider": "مزود الهوية", + "delSelectedMembersWarning": "هل أنت متأكد أنك تريد إزالة الأعضاء المختارين؟", + "delSelectedMemberWarning": "هل أنت متأكد أنك تريد إزالة العضو المختار؟", + "idpMessage": "موجود بالفعل في الفريق.", + "formOwnerErrMsg": "يجب أن يكون هناك دائمًا مالك نموذج واحد على الأقل", + "formOwnerConsoleErrMsg": "لا يمكن إزالة {userId} لأنهم المالك الوحيد المتبقي لهذا النموذج.", + "insufficientPermissnMsg": "أذونات غير كافية لإدارة الفريق", + "getUserErrMsg": "خطأ في الحصول على مستخدمي النموذج:", + "getRolesErrMsg": "خطأ في الحصول على قائمة الأدوار:", + "formOwnerRemovalWarning": "لا يمكن الإزالة لأنهم المالك الوحيد المتبقي لهذا النموذج.", + "removeUsersErrMsg": "حدث خطأ أثناء محاولة حذف المستخدمين المحددين", + "removeUserConsoleErrMsg": "خطأ في حذف المستخدمين من النموذج {formId}: {error}", + "updUserRolesErrMsg": "حدث خطأ أثناء محاولة تحديث كافة أدوار المستخدم", + "updUserRolesConsoleErrMsg": "خطأ في تعيين كافة أدوار المستخدم للنموذج {formId}: {error}", + "setUserFormsErrMsg": "حدث خطأ أثناء محاولة تحديث الأدوار للمستخدم", + "setUserFormsConsoleErrMsg": "خطأ في تعيين أدوار المستخدم للنموذج {formId}: {error}" + }, + "floatButton": { + "publish": "ينشر", + "manage": "يدير", + "redo": "إعادة", + "undo": "الغاء التحميل", + "preview": "معاينة", + "bottom": "قاع", + "top": "قمة", + "actions": "أجراءات", + "collapse": "ينهار", + "saved": "أنقذ", + "save": "يحفظ", + "saving": "إنقاذ", + "notSaved": "يتم حفظ" + }, + "formViewer": { + "lateFormSubmissions": "انتهت فترة تقديم النموذج! لا يزال بإمكانك إنشاء إرسال متأخر بالنقر فوق الزر أدناه.", + "createLateSubmission": "إنشاء تقديم متأخر", + "draftSaved": "تم حفظ المسودة", + "saving": "إنقاذ", + "pleaseConfirm": "يرجى تأكيد", + "submitFormWarningMsg": "هل أنت متأكد أنك ترغب في تقديم النموذج الخاص بك؟", + "submit": "يُقدِّم", + "wantToSaveDraft": "هل تريد حفظ المسودة؟", + "version": "الإصدار: {version}", + "formScheduleExpireMessage": "إرسال النموذج غير متاح لأن فترة التقديم المجدولة قد انتهت.", + "getUsersSubmissionsErrMsg": "حدث خطأ أثناء إحضار الإرسال لهذا النموذج", + "getUsersSubmissionsConsoleErrMsg": "خطأ في تحميل بيانات إرسال النموذج {SubmitId}: {error}", + "multiDraftUploadSuccess": "لقد نجح تحميل المسودة المتعددة!", + "readVersionErrMsg": "لا يوجد مخطط في الاستجابة. معرف الإصدار: {versionId}", + "readDraftErrMsg": "لا يوجد مخطط في الاستجابة. معرّف المسودة: {draftId}", + "alertRouteMsg": "لم يقم مالك النموذج بنشر النموذج ، وهو غير متاح لعمليات الإرسال.", + "fecthingFormErrMsg": "حدث خطأ أثناء جلب هذا النموذج", + "fecthingFormConsoleErrMsg": "خطأ في تحميل مخطط النموذج {versionId}: {error}", + "savingDraftErrMsg": "حدث خطأ أثناء حفظ المسودة", + "savingDraftConsoleErrMsg": "خطأ في حفظ المسودة. معرف التقديم: {submitId}. خطأ: {error}", + "submissionsPreviewAlert": "الإرسال معطل أثناء معاينة النموذج", + "submissionsSubmitErrMsg": "خطأ في إرسال النموذج: {errors}", + "sendSubmissionErrMsg": "فشل الرد من نقطة نهاية الإرسال. رمز الاستجابة: {status}", + "errMsg": "حدث خطأ أثناء إرسال هذا النموذج", + "customEventAlert": "أحداث الزر المخصص غير مدعومة حتى الآن. نوع الحدث: {event}", + "formLoading": "يرجى الانتظار حتى يتم تحميل النموذج !!!", + "yes": "نعم", + "no": "لا", + "failedResSubmissn": "فشل الرد من نقطة نهاية الإرسال. رمز الاستجابة: {status}", + "errSubmittingForm": "حدث خطأ أثناء إرسال هذا النموذج", + "errorSavingFile": "خطأ في حفظ الملفات. اسم الملف: {fileName}. خطأ: {error}", + "submittingDraftErrMsg": "حدث خطأ أثناء حفظ المسودة", + "submittingDraftConsErrMsg": "خطأ في حفظ المسودة. معرف التقديم: {submitId}. خطأ: {error}", + "formDraftAccessErrMsg": "تم إرسال طلب التقديم بالفعل ، مع إعادة التوجيه إلى صفحة العرض" + }, + "bCGovFooter": { + "home": "بيت", + "about": "حول gov.bc.ca", + "disclaimer": "تنصل", + "privacy": "خصوصية", + "accessibility": "إمكانية الوصول", + "copyRight": "حقوق النشر", + "contactUs": "اتصل بنا" + }, + "bCGovNavBar": { + "about": "عن", + "myForms": "نماذجي", + "createNewForm": "قم بإنشاء نموذج جديد", + "help": "يساعد", + "feedback": "تعليق", + "admin": "مسؤل" + }, + "homePage": { + "title": "أنشئ النماذج وانشرها واستقبل عمليات الإرسال باستخدام Common Hosted Forms Service.", + "subTitle": "كل قبل الميلاد يمكن لموظفي الحكومة أو المتعاقدين الذين لديهم حساب IDIR استخدام نسختنا المستضافة من Common Hosted Forms Service (CHEFS) لإنشاء النماذج.", + "takeATourOfChefs": "قم بجولة في CHEFS لرؤيتها أثناء العمل.", + "logInToGetStarted": "سجل الدخول لتبدأ", + "loginToStart": "قم بتسجيل الدخول باستخدام IDIR للبدء", + "login": "تسجيل الدخول", + "createFormLabel": "قم بإنشاء نموذج", + "manageAccessTitle": "إدارة الوصول إلى النموذج الخاص بك", + "manageAccessSub1": "يتيح لك CHEFS إنشاء نماذج عامة ، أو يمكنك إدارة الوصول من خلال مصادقة IDIR أو BCeID.", + "manageAccessSub2": "يمكنك أيضًا تعيين أدوار لفريقك لإدارة جميع عمليات الإرسال الخاصة بك.", + "createCustomFormTitle": "قم بإنشاء نماذج مخصصة باستخدام أداة إنشاء النماذج CHEFS", + "createCustomFormSub1": "مع CHEFS ، يمكنك إنشاء نماذج آمنة بواجهة سحب وإفلات سهلة. يمكنك إضافة مكونات النموذج وإعادة ترتيبها وإفلاتها في تكوينات تخطيطات مختلفة.", + "chefsHowToTitle": "فيديوهات شيفس إرشادية", + "chefsHowToSub": "سيقدم لك دليل البدء السريع بعض الوظائف الأساسية لـ CHEFS.", + "getStartedToChefs": "ابدأ باستخدام CHEFS", + "createOnlineTitle": "قم بإنشاء نماذج عبر الإنترنت لجمع المعلومات من عملائك وتحسين سير العمل الخاص بك.", + "getStarted": "البدء" + }, + "baseStepper": { + "designForm": "نموذج التصميم", + "setUpForm": "قم بإعداد النموذج", + "manageForm": "إدارة النموذج" + }, + + "create": { + "formSettings": "إعدادات النموذج", + "disclaimer": "تنصل", + "disclaimerStmt": "أوافق على إخلاء المسؤولية وبيان المسؤولية لمصممي النماذج", + "continue": "يكمل", + "back": "خلف", + "confirmPageNav": "هل تريد حقًا مغادرة هذه الصفحة؟ لن يتم حفظ التغييرات التي قمت بها.", + "agreementErrMsg": "يجب أن توافق على إخلاء مسؤولية الخصوصية الموضح أعلاه." + }, + "addTeamMember": { + "cantFindChefsUsers": "لا يمكنك العثور على شخص ما؟ ربما لم يقوموا بتسجيل الدخول إلى CHEFS.
يرجى إرسال رابط إلى CHEFS واطلب منهم تسجيل الدخول.", + "cancel": "يلغي", + "add": "يضيف", + "mustSelectAUser": "يجب تحديد دور واحد على الأقل لإضافة هذا المستخدم.", + "addNewMember": "أضف عضو جديد", + "enterUsername": "أدخل اسمًا أو بريدًا إلكترونيًا أو اسم مستخدم", + "enterExactUsername": "أدخل البريد الإلكتروني أو اسم المستخدم بالضبط", + "BCeIDInputSearchMaxLen": "يجب أن يكون إدخال البحث عن اسم المستخدم / البريد الإلكتروني BCeID أكبر من 6 أحرف.", + "BCeIDMustBeExact": "يجب أن تكون عمليات البحث في البريد الإلكتروني عن BCeID دقيقة.", + "errorGettingUsers": "خطأ في الحصول على المستخدمين {error}" + }, + "baseFilter": { + "cancel": "يلغي", + "columnName": "اسم العمود", + "exampleText": "نص مثال", + "exampleText2": "نص مثال 2", + "filterPlaceholderTxt": "تصفية نص العنصر النائب", + "filter": "منقي", + "value": "قيمة", + "resetColumns": "إعادة تعيين الأعمدة" + }, + "formViewerActions": { + "viewMyDraftOrSubmissions": "عرض المسودة / التقديمات الخاصة بي", + "saveAsADraft": "احفظ كمسودة", + "editThisDraft": "قم بتحرير هذه المسودة", + "switchSingleSubmssn": "التبديل إلى الإرسال الفردي", + "switchMultiSubmssn": "التبديل إلى تقديمات متعددة" + }, + "baseCopyToClipboard": { + "linkToClipboard": "تم نسخ الرابط إلى الحافظة", + "copyToClipboard": "نسخ إلى الحافظة", + "errCopyToClipboard": "خطأ في محاولة النسخ إلى الحافظة." + }, + "sucess": { + "sucessFormSubmissn": "تم تسليم إستمارتك بنجاح", + "keepRecord": "إذا كنت ترغب في الاحتفاظ بسجل لهذا الإرسال ، فيمكنك الاحتفاظ بما يلي", + "confirmationId": "معرف التأكيد" + }, + "bcGovAlertBanner": { + "defaultErrMsg": "خطأ: حدث خطأ ما", + "error": "خطأ" + }, + "permissionUtils": { + "formNotAvailable": "النموذج غير متوفر حاليا. قد يكون هذا بسبب ارتباط غير صحيح ، أو ربما تم حذف النموذج من قبل مالكه.", + "missingFormIdAndSubmssId": "تفتقد الخيارات إلى كل من formId ومعرّف الإرسال", + "loadingFormErrMsg": "حدث خطأ أثناء تحميل هذا النموذج.", + "loadingForm": "خطأ أثناء تحميل {options}: {error}", + "idpHintMsg": "يتطلب هذا النموذج مصادقة {idpHint}. الرجاء إعادة تسجيل الدخول وحاول مرة أخرى.", + "formIdpMissMatch": "عدم تطابق IDP للنموذج. يتطلب النموذج {idpHint} لكن المستخدم لديه {userIdp}." + }, + "download": { + "chefsDataExport": "تصدير بيانات CHEFS", + "preparingForDownloading": "جاري التحضير للتنزيل ...", + "downloadInfoA": "إذا لم يتم تنزيل ملفك تلقائيًا", + "downloadInfoB": "اضغط هنا للمحاولة مرة أخرى" + }, + "history": { + "submissnHistory": "تاريخ التقديم الخاص بك (يتم تحديده لاحقًا)" + }, + "error": { + "logout": "تسجيل خروج" + }, + "login": { + "authenticateWith": "المصادقة مع:", + "alreadyLoggedIn": "قمت بتسجيل الدخول بالفعل", + "home": "بيت", + "about": "عن" + }, + "notFound": { + "about": "عن", + "pageNotFound": "404: الصفحة غير موجودة. :(" + }, + "store": { + "admin": { + "addFormOwnerRole": "تمت إضافة دور المالك لهذا النموذج إلى {fullName}", + "addRowError": "حدث خطأ أثناء إضافة الدور.", + "addRowConsoleErr": "خطأ في إضافة المستخدم {userId} إلى النموذج {formId}: {error}", + "apiKeyDelMsg": "تم حذف مفتاح API لهذا النموذج.", + "errDeletingApiKey": "حدث خطأ أثناء محاولة حذف مفتاح API.", + "consErrDeletingApiKey": "خطأ في حذف مفتاح API للنموذج {formId}: {error}", + "fecthingFormsErrMsg": "حدث خطأ أثناء إحضار النماذج.", + "fecthingFormsConsErrMsg": "خطأ في الحصول على بيانات نموذج المسؤول: {error}", + "fecthingFormErrMsg": "حدث خطأ أثناء جلب هذا النموذج.", + "fecthingFormConsErrMsg": "خطأ في الحصول على بيانات نموذج المسؤول {formId}: {error}", + "fecthFormUserRolesErrMsg": "حدث خطأ أثناء جلب نموذج أدوار المستخدم.", + "fecthFormUserRolesConsErrMsg": "خطأ في الحصول على بيانات أدوار المشرف: {error}", + "fecthApiDetailsErrMsg": "حدث خطأ أثناء جلب تفاصيل واجهة برمجة التطبيقات لهذا النموذج.", + "fecthApiDetailsConsErrMsg": "خطأ في الحصول على تفاصيل واجهة برمجة تطبيقات المشرف من بيانات النموذج {formId}: {error}", + "restoreFormErrMsg": "حدث خطأ أثناء استعادة هذا النموذج.", + "restoreFormConsErrMsg": "خطأ في استعادة بيانات النموذج {formId}: {error}", + "getUsersErrMsg": "حدث خطأ أثناء جلب المستخدمين.", + "getUsersConsErrMsg": "خطأ في الحصول على بيانات المستخدمين المسؤولين: {error}", + "getUserErrMsg": "حدث خطأ أثناء جلب هذا المستخدم.", + "getUserConsErrMsg": "خطأ في الحصول على بيانات المستخدم الإداري {userId}: {error}", + "storingFCHelpInfoErrMsg": "حدث خطأ أثناء تخزين معلومات تعليمات مكون النموذج", + "storingFCHelpInfoConsErrMsg": "خطأ في الحصول على معلومات تعليمات مكون النموذج: {error}", + "gettingFCImgUrlErrMsg": "حدث خطأ أثناء الحصول على عنوان url للصورة", + "gettingFCImgUrlConsErrMsg": "خطأ في الحصول على عنوان url للصورة: {error}", + "updatingFCStatusErrMsg": "حدث خطأ أثناء تحديث حالة النشر", + "updatingFCStatusConsErrMsg": "خطأ في تحديث حالة النشر: {error}", + "fecthingFormBuilderCompsErrMsg": "حدث خطأ أثناء إحضار مكونات أداة إنشاء النماذج", + "fecthingFormBuilderCompsConsErrMsg": "خطأ في الحصول على مكونات منشئ النموذج: {error}" + }, + "form": { + "fetchEmailTemplatesConsErrMsg": "خطأ في تحميل قوالب البريد الإلكتروني لـ {formId}: {error}", + "fetchEmailTemplatesErrMsg": "حدث خطأ أثناء جلب نماذج البريد الإلكتروني لهذا النموذج", + "getCurrUserFormsErrMsg": "حدث خطأ أثناء إحضار النماذج الخاصة بك.", + "getCurrUserFormsConsErrMsg": "خطأ في الحصول على بيانات المستخدم: {error}", + "getUserFormPermErrMsg": "حدث خطأ أثناء جلب بيانات المستخدم الخاصة بك لهذا النموذج.", + "getUserFormPermConsErrMsg": "خطأ في الحصول على بيانات المستخدم باستخدام formID {formId}: {error}", + "getUserFormRolesErrmsg": "حدث خطأ أثناء جلب بيانات المستخدم الخاصة بك لهذا النموذج.", + "getUserFormRolesConsErrmsg": "خطأ في الحصول على بيانات المستخدم باستخدام formID {formId}: {error}", + "updCurrUserFormPrefErrMsg": "حدث خطأ أثناء حفظ تفضيلاتك لهذا النموذج.", + "updCurrUserFormPrefConsErrMsg": "خطأ في تحديث تفضيلات نموذج المستخدم باستخدام formID {formId} ، وتفضيلات {preferences}: {error}", + "getCurrUserFormPrefErrMsg": "حدث خطأ أثناء جلب تفضيلاتك لهذا النموذج.", + "getCurrUserFormPrefConsErrMsg": "خطأ في الحصول على تفضيلات نموذج المستخدم باستخدام formID {formId}: {error}", + "delCurrformNotiMsg": "تم حذف النموذج {name} بنجاح.", + "delCurrFormConsErMsg": "خطأ في حذف النموذج {id}: {error}", + "delDraftErrMsg": "حدث خطأ أثناء حذف هذه المسودة.", + "delDraftConsErrMsg": "خطأ في حذف {draftId}: {error}", + "fecthDraftErrMsg": "حدث خطأ أثناء البحث عن مسودات لهذا النموذج.", + "fecthDraftConsErrMsg": "خطأ في الحصول على مسودات للنموذج {formId}: {error}", + "fecthFormErrMsg": "حدث خطأ أثناء جلب هذا النموذج.", + "fecthFormConsErrMsg": "خطأ في الحصول على النموذج {formId}: {error}", + "fetchFormFieldsErrMsg": "حدث خطأ أثناء جلب قائمة الحقول لهذا النموذج.", + "fetchFormFieldsConsErrMsg": "خطأ في الحصول على النموذج {formId}: {error}", + "publishDraftErrMsg": "حدث خطأ أثناء النشر.", + "publishDraftConsErrMsg": "خطأ في نشر $ {draftId}: {error}", + "toggleVersnPublConsErrMsg": "خطأ في toggleVersionPublish {versionId} {publish}: {error}", + "updateEmailTemplateConsErrMsg": "خطأ في تحديث قوالب البريد الإلكتروني للنموذج {formId}: {error}", + "updateEmailTemplateErrMsg": "حدث خطأ أثناء تحديث قوالب البريد الإلكتروني لهذا النموذج.", + "updateFormErrMsg": "حدث خطأ أثناء تحديث إعدادات هذا النموذج.", + "updateFormConsErrMsg": "خطأ في تحديث النموذج {id}: {error}", + "deleteSubmissionNotifyMsg": "تم حذف الإرسال بنجاح.", + "deleteSubmissionErrMsg": "حدث خطأ أثناء حذف هذا الإرسال.", + "deleteSubmissionConsErrMsg": "خطأ في حذف الإرسال {submitId}: {error}", + "deleteSubmissionsNotifyMsg": "تم حذف عمليات الإرسال بنجاح.", + "deleteSubmissionsErrMsg": "حدث خطأ أثناء حذف عمليات الإرسال المحددة.", + "deleteSubmissionsConsErrMsg": "خطأ في حذف عمليات الإرسال: {error}", + "restoreSubmissionsNotiMsg": "تمت استعادة التقديمات بنجاح.", + "restoreSubmissionsErrMsg": "حدث خطأ أثناء استعادة هذا الإرسال.", + "restoreSubmissionsConsErrMsg": "خطأ في استعادة عمليات الإرسال: {error}", + "restoreSubmissionNotiMsg": "تمت استعادة الإرسال بنجاح.", + "restoreSubmissionErrMsg": "حدث خطأ أثناء استعادة هذا الإرسال.", + "restoreSubmissionConsErrMsg": "خطأ في استعادة الإرسال {deliveryId}: {error}", + "fecthSubmissnUsersErrMsg": "حدث خطأ أثناء جلب البريد الإلكتروني للمستلم لهذا الإرسال.", + "fecthSubmissnUsersConsErrMsg": "خطأ في الحصول على البريد الإلكتروني للمستلم للإرسال {formSubmissionId}: {error}", + "fetchSubmissnErrMsg": "حدث خطأ أثناء جلب هذا الإرسال.", + "fetchSubmissnConsErrMsg": "خطأ في الحصول على الإرسال {SubmitId}: {error}", + "fetchFormCSVExptFieldsErrMsg": "حدث خطأ أثناء جلب قائمة الحقول لهذا النموذج.", + "fetchFormCSVExptFieldsConsErrMsg": "خطأ في الحصول على النموذج {formId}: {error}", + "fetchSubmissnsErrMsg": "حدث خطأ أثناء جلب عمليات الإرسال لهذا النموذج.", + "fetchSubmissnsConsErrMsg": "خطأ في الحصول على عمليات الإرسال لـ {formId}: {error}", + "fetchVersionErrMsg": "حدث خطأ أثناء جلب هذا النموذج.", + "fetchVersionConsErrMsg": "خطأ في الحصول على الإصدار {versionId} للنموذج {formId}: {error}", + "deleteApiKeyNotifyMsg": "تم حذف مفتاح API لهذا النموذج.", + "deleteApiKeyErrMsg": "حدث خطأ أثناء محاولة حذف مفتاح API.", + "deleteApiKeyConsErrMsg": "خطأ في حذف مفتاح API للنموذج {formId}: {error}", + "generateApiKeyNotifyMsg": "تم إنشاء مفتاح API لهذا النموذج.", + "generateApiKeyErrMsg": "حدث خطأ أثناء محاولة إنشاء مفتاح API.", + "generateApiKeyConsErrMsg": "خطأ في إنشاء مفتاح API للنموذج {formId}: {error}", + "readApiKeyErrMsg": "حدث خطأ أثناء محاولة جلب مفتاح API.", + "readApiKeyConsErrMsg": "خطأ في الحصول على مفتاح API للنموذج {formId}: {error}.", + "getFCPHImageUrlErrMsg": "حدث خطأ أثناء الحصول على عنوان url للصورة", + "getFCPHImageUrlConsErrMsg": "خطأ في الحصول على عنوان url للصورة: {error}", + "listFCPHErrMsg": "حدث خطأ أثناء إحضار مكونات أداة إنشاء النماذج", + "listFCPHConsErrMsg": "خطأ في الحصول على مكونات منشئ النموذج: {error}", + "downloadFileErrMsg": "حدث خطأ أثناء تنزيل الملف", + "downloadFileConsErrMsg": "خطأ في تنزيل الملف: خطأ", + "readSubscriptionSettingsErrMsg": "حدث خطأ أثناء محاولة جلب إعدادات الاشتراك.", + "readSubscriptionSettingsConsErrMsg": "خطأ في الحصول على إعدادات الاشتراك للنموذج {formId}: {error}.", + "saveSubscriptionSettingsNotifyMsg": "تم حفظ إعدادات الاشتراك لهذا النموذج.", + "saveSubscriptionSettingsErrMsg": "حدث خطأ أثناء محاولة حفظ إعدادات الاشتراك.", + "saveSubscriptionSettingsConsErrMsg": "خطأ في حفظ إعدادات الاشتراك للنموذج {formId}: {error}" + } + }, + "admin": { + "root": { + "admin": "مسؤل" + }, + "form": { + "administerForm": "إدارة النموذج" + }, + "user": { + "administerUser": "إدارة المستخدم" + } + }, + "user": { + "root": { + "myForms": "نماذجي", + "history": "تاريخ", + "user": "مستخدم" + } + } +} diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/ar/index.js b/frontend/app/frontend/src/internationalization/trans/chefs/ar/index.js new file mode 100644 index 0000000..f91956d --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/ar/index.js @@ -0,0 +1,4 @@ +import ar from '~/internationalization/trans/chefs/ar/ar.json'; +export default { + trans: ar, +}; diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/de/de.json b/frontend/app/frontend/src/internationalization/trans/chefs/de/de.json new file mode 100644 index 0000000..e155eeb --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/de/de.json @@ -0,0 +1,995 @@ +{ + "date": { + "date": "jjjj-mm-tt" + }, + "emailManagement": { + "emailManagement": "E-Mail-Management", + "manageForm": "Formular verwalten", + "submissionConfirmation": "Einreichungsbestätigung" + }, + "emailTemplate": { + "body": "Körper", + "save": "Speichern", + "saveEmailTemplateConsoleErrMsg": "Fehler beim Aktualisieren der E-Mail-Vorlage für Formular {formId}: {error}", + "saveEmailTemplateErrMsg": "Beim Versuch, die E-Mail-Vorlage zu aktualisieren, ist ein Fehler aufgetreten.", + "subject": "Thema", + "title": "Titel", + "validBodyRequired": "Bitte geben Sie einen Text für die E-Mail ein", + "validSubjectRequired": "Bitte geben Sie eine Betreffzeile für die E-Mail ein", + "validTitleRequired": "Bitte geben Sie einen Titel für die E-Mail ein" + }, + "formsTable": { + "myForms": "Meine Formulare", + "createNewForm": "Erstellen Sie ein neues Formular", + "search": "Suchen", + "manage": "Verwalten", + "submissions": "Einsendungen", + "formTitle": "Formulartitel", + "viewForm": "Formular anzeigen", + "description": "Beschreibung", + "Description": "Beschreibung:", + "action": "Aktionen", + "loadingText": "Laden, bitte warten" + }, + "preview": { + "preview": "Vorschau", + "previewToolTip": "Dies zeigt eine Vorschau des Designs und Verhaltens der Formularversion, wie es Ihren Einsendern angezeigt wird. Sie können das Formular nicht von dieser Seite aus senden." + }, + "manageLayout": { + "manageForm": "Formular verwalten" + }, + "shareForm": { + "shareForm": "Formular teilen", + "shareLink": "Einen Link teilen", + "copyQRCode": "Kopieren Sie den Link unten oder laden Sie den QR-Code herunter.", + "warningMessage": "Derzeit gibt es keine veröffentlichte Version des Formulars. Der Link unten ist erst erreichbar, wenn eine Version veröffentlicht wird.", + "openThisForm": "Öffnen Sie dieses Formular", + "downloadQRCode": "Laden Sie den QR-Code herunter", + "close": "Schließen", + "copyURLToClipboard": "URL in die Zwischenablage kopieren" + }, + "manageFormActions": { + "emailManagement": "E-Mail-Management", + "viewSubmissions": "Einsendungen anzeigen", + "teamManagement": "Team Management", + "deleteForm": "Formular löschen", + "confirmDeletion": "Löschung bestätigen", + "deleteMessageA": "Sind Sie sicher, dass Sie löschen möchten?", + "deleteMessageB": "Dieses Formular wird nicht mehr zugänglich sein.", + "delete": "Löschen" + }, + "manageForm": { + "formSettings": "Formulareinstellungen", + "apiKey": "API-Schlüssel", + "updated": "Aktualisiert", + "created": "Erstellt", + "formDesignHistory": "Geschichte des Formulardesigns", + "totalVersions": "Gesamtversionen", + "status": "Status", + "update": "Aktualisieren", + "cancel": "Stornieren", + "eventSubscription": "Ereignisabonnement" + }, + "formSettings": { + "pressToAddMultiEmail": "Drücken Sie die Eingabetaste oder die Leertaste oder , um mehrere E-Mail-Adressen hinzuzufügen", + "allowMultiDraft": "Erlauben Sie das Hochladen mehrerer Entwürfe", + "formTitle": "Formulartitel", + "formDescription": "Formularbeschreibung", + "formAccess": "Formularzugriff", + "info": "Wenn Sie dieses Formular verwenden, um Informationen von der Öffentlichkeit zu Themen zu sammeln, die für die Öffentlichkeit von allgemeinem Interesse sind, müssen Sie sich an die GCPE wenden, damit Ihr Engagement auf aufgeführt werden kann", + "important": "WICHTIG", + "idimNotifyA": "Sie müssen das Identity Information Management (IDIM)-Team per E-Mail benachrichtigen", + "idimNotifyB": "Ihre Absicht, BCeID zu nutzen, um die Identität Ihrer Formularabsender zu überprüfen.", + "referenceGuideA": "Bitte verweisen Sie auf unsere", + "referenceGuideB": "Benutzerhandbuch", + "referenceGuideC": "für mehr Details", + "specificTeamMembers": "Spezifische Teammitglieder", + "formFunctionality": "Formularfunktionalität", + "formSubmissinScheduleMsg": "Der Formulareinreichungsplan ist in den Formulareinstellungen verfügbar, nachdem das Formular veröffentlicht wurde.", + "formSubmissionsSchedule": "Zeitplan für Formulareinreichungen", + "experimental": "Experimental", + "learnMore": "Erfahren Sie mehr", + "afterSubmission": "Nach der Einreichung", + "submissionConfirmation": "Zeigen Sie die Details der Übermittlungsbestätigung an", + "theConfirmationID": "die Bestätigungs-ID", + "infoB": "die Option für den Benutzer, sich selbst eine Übermittlungsbestätigung per E-Mail zu senden", + "loginRequired": "Anmeldung erforderlich", + "canSaveAndEditDraftLabel": "Einreicher können Entwürfe speichern und bearbeiten", + "canUpdateStatusAsReviewer": "Prüfer können den Status dieses Formulars aktualisieren (z. B. „Eingereicht“, „Zugewiesen“, „Abgeschlossen“).", + "submitterCanCopyExistingSubmissn": "Einreicher können eine vorhandene Einreichung kopieren", + "submissionConfirmationToolTip": "Durch Auswahl dieser Option wird gesteuert, was der einreichende Benutzer dieses Formulars bei erfolgreicher Übermittlung sieht.
Wenn aktiviert, wird es angezeigt", + "emailNotificatnToTeam": "Senden Sie meinem Team eine Benachrichtigungs-E-Mail", + "emailNotificatnToTeamToolTip": "Senden Sie eine Benachrichtigung an Ihre angegebene E-Mail-Adresse, wenn ein Benutzer dieses Formular absendet", + "notificationEmailAddrs": "E-Mail-Adressen für Benachrichtigungen", + "addMoreValidEmailAddrs": "Fügen Sie eine oder mehrere gültige E-Mail-Adressen hinzu", + "formScheduleSettings": "Formularplaneinstellungen", + "opensubmissions": "Offene Einreichungen", + "submissionsDeadline": "Wie lange möchten Sie Einsendungen erhalten?", + "keepSubmissnOpenTilUnplished": "Offen bleiben, bis die Veröffentlichung manuell aufgehoben wird", + "submissionsClosingDate": "Vereinbaren Sie einen Abschlusstermin", + "submissionPeriod": "Legen Sie den Einreichungszeitraum fest", + "closeSubmissions": "Einreichungen schließen", + "keepOpenFor": "Offen bleiben für", + "period": "Zeitraum", + "allowLateSubmissions": "Erlauben Sie verspätete Einreichungen", + "allowLateSubmissionsInfoTip": "Wenn diese Option aktiviert ist, können Einreicher Daten nach dem Einsendeschluss einreichen.", + "afterCloseDateFor": "Nach Ablaufdatum für", + "repeatPeriod": "Zeitraum wiederholen", + "every": "Jeden", + "repeatUntil": "Wiederhole bis", + "summary": "Zusammenfassung", + "submissionsOpenDateRange": "Dieses Formular ist für Einsendungen geöffnet", + "to": "Zu", + "scheduleRepetition": "Der Zeitplan wiederholt sich alle", + "allowLateSubmissnInterval": "Zulassen verspäteter Einreichungen für", + "until": "bis", + "datesOfSubmissnInfo": "Gemäß den Einstellungen sind dies die verfügbaren Termine für Einreichungen:", + "formOpenInterval": "Dieses Formular ist für Einsendungen geöffnet", + "allowDateSubmissionDate": "mit der Möglichkeit einer verspäteten Einreichung bis", + "customClosingMessage": "Legen Sie eine benutzerdefinierte Abschlussnachricht fest", + "customClosingMessageToolTip": "Ermöglichen Sie das Hinzufügen einer benutzerdefinierten Nachricht für Ihre Benutzer, wenn diese ein geschlossenes Formular besuchen.", + "closingMessage": "Schlussnachricht", + "sendReminderEmail": "Erinnerungs-E-Mail SENDEN", + "autoReminderNotificatn": "Aktivieren Sie die automatische Erinnerungsbenachrichtigung", + "autoReminderNotificatnToolTip": "Senden Sie während des Einreichungszeitraums Erinnerungs-E-Mails mit dem Formularlink.", + "selectLoginType": "Bitte wählen Sie 1 Anmeldetyp aus", + "formDescriptnMaxChars": "Die Formularbeschreibung darf maximal 255 Zeichen lang sein", + "formTitlemaxChars": "Der Formulartitel darf maximal 255 Zeichen lang sein", + "formTitleReq": "Der Formulartitel ist erforderlich", + "atLeastOneEmailReq": "Bitte geben Sie mindestens eine E-Mail-Adresse ein", + "validEmailRequired": "Bitte geben Sie alle gültigen E-Mail-Adressen ein", + "fieldRequired": "Dieses Feld ist erforderlich.", + "correctDateFormat": "Das Datum muss im richtigen Format vorliegen. dh. jjjj-mm-tt", + "dateDiffMsg": "Das Datum der geschlossenen Einreichung sollte nach dem Datum der offenen Einreichung liegen.", + "valueMustBeNumber": "Der Wert muss eine Zahl sein. dh. 1,2,3,5,99", + "selectAnOptions": "Bitte wählen Sie mindestens 1 Option aus", + "validInterval": "Dies sollte ein gültiges Intervall sein.", + "fieldRequiredAndInterval": "Dieses Feld ist erforderlich und sollte ein Intervall sein.", + "dateGrtOpenSubmissnDate": "Das Datum „Wiederholen bis“ sollte größer sein als das Datum der offenen Einreichung", + "public": "Öffentlich (anonym)", + "allowEventSubscription": "Ereignisabonnement zulassen", + "eventSubscription": "Ereignisabonnement", + "validEndpointRequired": "Bitte geben Sie einen gültigen Endpunkt ein, beginnend mit https://", + "validBearerTokenRequired": "Bitte geben Sie ein gültiges Token ein. Beispiel: 89abddfb-2cff-4fda-83e6-13221f0c3d4f" + }, + "subscribeEvent": { + "eventType": "Ereignistyp", + "endpointUrl": "Endpunkt-URL", + "eventSubmission": "Eingabe", + "eventAssignment": "Zuordnung", + "eventStatusChange": "Statusänderung", + "endpointToken": "Endpunkttoken", + "urlPlaceholder": "https://endpoint.gov.bc.ca/api/v1/", + "save": "Speichern", + "text": "Text", + "password": "Passwort", + "hideSecret": "Geheimnis verbergen", + "showSecret": "Geheimnis anzeigen", + "key": "Taste", + "saveSettingsErrMsg": "Beim Versuch, die Einstellungen für dieses Formular zu aktualisieren, ist ein Fehler aufgetreten.", + "updateSettingsConsoleErrMsg": "Fehler beim Aktualisieren der Einstellungen für das Formular {formId}: {error}" + }, + "apiKey": { + "disclaimer": "Haftungsausschluss", + "infoA": "Stellen Sie sicher, dass Ihr API-Schlüsselgeheimnis an einem sicheren Ort (d. h. im Schlüsseltresor) gespeichert wird.", + "infoB": "Ihr API-Schlüssel gewährt uneingeschränkten Zugriff auf Ihr Formular. Geben Sie Ihren API-Schlüssel nicht an Dritte weiter.", + "infoC": "Der API-Schlüssel sollte NUR für automatisierte Systeminteraktionen verwendet werden. Verwenden Sie Ihren API-Schlüssel nicht für den benutzerbasierten Zugriff", + "deleteKey": "Schlüssel löschen", + "apiKey": "API-Schlüssel", + "hideSecret": "Geheimnis verbergen", + "showSecret": "Geheimnis anzeigen", + "sCTC": "Geheimnis in die Zwischenablage kopiert", + "cSTC": "Geheimnis in die Zwischenablage kopieren", + "key": "Taste", + "confirmDeletion": "Löschung bestätigen", + "deleteMsg": "Sind Sie sicher, dass Sie Ihren API-Schlüssel löschen möchten?", + "delete": "Löschen", + "confirmKeyGen": "Bestätigen Sie die Schlüsselgenerierung", + "createAPIKey": "Einen API-Schlüssel für dieses Formular erstellen?
Stellen Sie sicher, dass Sie den Haftungsausschluss auf dieser Seite befolgen.", + "regenerateAPIKey": "API-Schlüssel neu generieren?
Wenn Sie fortfahren, wird Ihr aktueller API-Schlüsselzugriff gelöscht .", + "formOwnerKeyAcess": "Sie müssen der Formulareigentümer sein, um API-Schlüssel verwalten zu können.", + "regenerate": "Regenerieren", + "generate": "Generieren", + "secret": "Geheimnis" + }, + "manageVersions": { + "important": "WICHTIG!", + "infoA": "Wenn keine veröffentlichten Versionen vorhanden sind, können Benutzer erst dann auf dieses Formular zugreifen, wenn eine veröffentlichte Version zugewiesen wurde. Sobald eine Version veröffentlicht ist, kann diese Version nicht mehr bearbeitet werden. Sie müssen eine neue Version basierend auf einer der vorherigen Formularversionen erstellen, um mit der Bearbeitung fortfahren zu können.", + "infoB": "Hinweis: Es kann nur eine Version veröffentlicht werden.", + "version": "Ausführung", + "draft": "Entwurf", + "clickToPreview": "Klicke für eine Vorschau", + "editVersion": "Version bearbeiten", + "exportDesign": "Design exportieren", + "infoC": "Bitte veröffentlichen oder löschen Sie Ihre neueste Entwurfsversion, bevor Sie mit einer neuen Version beginnen.", + "deleteVersion": "Version löschen", + "draftAlreadyExists": "Entwurf existiert bereits", + "infoD": "Bitte bearbeiten, veröffentlichen oder löschen Sie den vorhandenen Entwurf, bevor Sie mit einem neuen Entwurf beginnen.", + "publishVersion": "Version veröffentlichen", + "unpublishVersion": "Veröffentlichung der Version rückgängig machen", + "infoE": "Wenn Sie die Veröffentlichung dieses Formulars aufheben, wird das Formular aus dem Verkehr gezogen, bis eine Version erneut veröffentlicht wird.", + "confirmDeletion": "Löschung bestätigen", + "infoF": "Sind Sie sicher, dass Sie diese Version löschen möchten?", + "delete": "Löschen", + "status": "Status", + "dateCreated": "Datum erstellt", + "createdBy": "Erstellt von", + "actions": "Aktionen", + "published": "Veröffentlicht", + "unpublished": "Unveröffentlicht", + "useVersionInfo": "Verwenden Sie Version {version} als Basis für eine neue Version", + "publishingVersionInfo": "Dadurch wird die Version {version} Ihres Formulars live geschaltet." + }, + "addOwner": { + "infoA": "Dies sollte nur für den Fall erfolgen, dass der aktuelle Formulareigentümer nicht mehr aktiv ist oder bei einem vorrangigen Ereignis keinen Kontakt mehr hat. Andernfalls lassen Sie dies vom aktuellen Eigentümer oder einem Teamadministrator für das Formular selbst erledigen.", + "hint": "Um die benötigte Benutzer-ID zu finden, können Sie im Admin-Portal auf die Registerkarte „BENUTZER“ gehen und nach ihnen suchen.", + "addowner": "Besitzer hinzufügen", + "label": "Benutzer-ID (Guid)" + }, + "adminFormsTable": { + "showDeletedForms": "Gelöschte Formulare anzeigen", + "search": "Suchen", + "loadingText": "Ladetext", + "noDataText": "In Ihrem System sind keine Formulare vorhanden", + "admin": "Administrator", + "launch": "Start", + "formTitle": "Formulartitel", + "created": "Erstellt", + "deleted": "Gelöscht", + "actions": "Aktionen", + "delete": "Löschen" + }, + "administerForm": { + "deleted": "GELÖSCHT", + "restoreForm": "Stellen Sie dieses Formular wieder her", + "formDetails": "Formulardetails", + "apiKeyDetails": "Details zum API-Schlüssel", + "deleteApiKey": "API-Schlüssel löschen", + "formUsers": "Formularbenutzer", + "formVersions": "Formularversionen", + "assignANewOwner": "Weisen Sie einen neuen Eigentümer zu", + "restoring": "Wiederherstellen", + "restore": "Wiederherstellen", + "toActiveState": "in den aktiven Zustand", + "confirmDeletion": "Löschung bestätigen", + "confirmDeletionMsg": "Sind Sie sicher, dass Sie diesen API-Schlüssel löschen möchten?", + "delete": "Löschen", + "confirmRestore": "Bestätigen Sie die Wiederherstellung" + }, + "administerUser": { + "userDetails": "Nutzerdetails", + "openSSOConsole": "Öffnen Sie die SSO-Konsole" + }, + "adminPage": { + "forms": "Formen", + "users": "Benutzer", + "developer": "Entwickler", + "infoLinks": "Info-Links", + "metrics": "Metriken" + }, + "adminUsersTable": { + "search": "Suchen", + "loadingText": "Laden, bitte warten", + "admin": "Administrator", + "fullName": "Vollständiger Name", + "userID": "Benutzer-ID", + "created": "Erstellt", + "actions": "Aktionen" + }, + "adminVersions": { + "exportDesign": "Design exportieren", + "versions": "Versionen", + "status": "Status", + "created": "Erstellt", + "lastUpdated": "Letzte Aktualisierung", + "actions": "Aktionen", + "published": "Veröffentlicht", + "unpublished": "Unveröffentlicht", + "version": "Version {versionNo}", + "notificationMsg": "Beim Laden des Formularentwurfs ist ein Fehler aufgetreten." + }, + "developer": { + "user": "Benutzer", + "name": "Name", + "userName": "Nutzername", + "JWTContents": "JWT-Inhalte", + "JWTContentsSBTxt": "JWT-Inhalte in die Zwischenablage kopiert", + "JWTContentsTTTxt": "Kopieren Sie den JWT-Inhalt in die Zwischenablage", + "JWTToken": "JWT-Token", + "JWTTokenSBTxt": "JWT-Token in die Zwischenablage kopiert", + "JWTTokenTTTxt": "JWT-Token in die Zwischenablage kopieren", + "chefsAPI": "CHEFS-API", + "RBACSBTxt": "RBAC-Antwort in die Zwischenablage kopiert", + "RBACTTTxt": "Kopieren Sie die RBAC-Antwort in die Zwischenablage", + "notificationMsg": "Benutzer konnte nicht von RBAC abgerufen werden, siehe Konsole", + "notificationConsErr": "Fehler beim Abrufen des Benutzers von RBAC" + }, + "baseAuthButton": { + "logout": "Ausloggen", + "login": "Anmeldung" + }, + "baseDialog": { + "defaultText": "Standardtext", + "ok": "OK", + "continue": "Weitermachen", + "cancel": "Stornieren", + "custom": "Brauch" + }, + "baseSecure": { + "about": "Um", + "loginInfo": "Sie müssen angemeldet sein, um diese Funktion nutzen zu können.", + "login": "Anmeldung", + "401NotAuthorized": "401: nicht autorisiert. :", + "401ErrorMsg": "Ihr Konto ist nicht richtig eingerichtet.
Kontaktieren Sie bitte", + "403Forbidden": "403 Verboten. :", + "403ErrorMsg": "Diese Seite erfordert eine {idp}-Authentifizierung.", + "401UnAuthorized": "401 nicht Autorisiert. :", + "401UnAuthorizedErrMsg": "Sie haben keine Berechtigung, auf diese Seite zuzugreifen." + }, + "formDesigner": { + "formDesign": "Formulardesign", + "exportDesign": "Design exportieren", + "importDesign": "Design importieren", + "important": "WICHTIG", + "formDesignInfoA": "Verwenden Sie die Schaltfläche „DESIGN SPEICHERN“ , wenn Sie mit der Erstellung dieses Formulars fertig sind.", + "formDesignInfoB": "Die Schaltfläche SENDEN steht Ihrem Benutzer zum Absenden dieses Formulars zur Verfügung und wird nach dem Speichern aktiviert.", + "formLoadErrMsg": "Beim Laden des Formularentwurfs ist ein Fehler aufgetreten.", + "formLoadConsoleErrMsg": "Fehler beim Laden des Schemas des Formulars {formId} (Version: {versionId}, Entwurf: {draftId}): {error}", + "formSchemaImportErrMsg": "Beim Importieren des Formularschemas ist ein Fehler aufgetreten.", + "formSchemaImportConsoleErrMsg": "Fehler beim Importieren des Formularschemas: {error}", + "formDesignSaveErrMsg": "Beim Versuch, diesen Formularentwurf zu speichern, ist ein Fehler aufgetreten. Wenn Sie die Seite aktualisieren oder es später noch einmal versuchen möchten, können Sie das vorhandene Design auf der Seite exportieren, um es für später zu speichern.", + "formDesignSaveConsoleErrMsg": "Fehler beim Aktualisieren oder Erstellen des Formulars (FormID: {formId}, versionId: {versionId}, draftId: {draftId}) Fehler: {error}", + "collapse": "Zusammenbruch", + "actions": "Aktionen", + "version": "Ausführung", + "save": "Speichern", + "saving": "Sparen", + "notSaved": "Nicht gespeichert", + "fieldnameError": "Sie können das Schlüsselwort 'form' NICHT als {label}-Feldnamen verwenden" + }, + "formViewerMultiUpload": { + "important": "WICHTIG", + "uploadSucessMsg": "Um sicherzustellen, dass mehrere Entwürfe erfolgreich hochgeladen werden können, laden Sie bitte die bereitgestellte Vorlage herunter und verwenden Sie sie.", + "confirmDownload": "Möchten Sie es herunterladen?", + "jsonFileUpload": "Wählen Sie die JSON-Datei zum Hochladen aus", + "dragNDrop": "oder per Drag & Drop hierher ziehen", + "chooseAFile": "Wähle eine Datei", + "downloadDraftSubmns": "Bitte laden Sie den Entwurf des Einreichungsberichts herunter und stellen Sie sicher, dass die Daten korrekt eingegeben werden.", + "downloadReport": "Bericht herunterladen", + "doYouWantToDownload": "Möchten Sie es herunterladen?", + "uploadNewFile": "Neue Datei hochladen", + "uploadMultipleFileErr": "Leider können Sie nur eine Datei hochladen", + "dragMultipleFileErr": "Leider können Sie nur eine Datei ziehen", + "fileFormatErr": "Leider akzeptieren wir nur JSON-Dateien", + "fileSizeErr": "Die maximal zulässige Dateigröße beträgt 5 MB", + "parseJsonErr": "Wir können keine JSON-Daten aus der Datei analysieren", + "jsonObjNotArray": "Falsches JSON-Dateiformat", + "jsonObjNotArrayConsErr": "Ein unerwarteter Fehler ist aufgetreten.", + "jsonArrayEmpty": "Diese JSON-Datei ist leer.", + "errorWhileValidate": "Mit dieser Datei stimmt etwas nicht", + "errWhileCheckValidity": "Mit dieser Datei stimmt etwas nicht", + "errAfterValidate": "Es wurden einige Fehler gefunden. Weitere Informationen finden Sie weiter unten.", + "fileIsEmpty": "Diese Datei ist leer.", + "download": "Herunterladen" + }, + "formDisclaimer": { + "disclaimerAndStatement": "Haftungsausschluss und Haftungsausschluss für Form Designers:", + "privacyLaw": "Es liegt in Ihrer Verantwortung, die Datenschutzgesetze einzuhalten, die die Erhebung, Nutzung und Offenlegung personenbezogener Daten regeln.", + "disclosure": "Der Zugriff auf dieses Formulardesigner-Tool gewährt grundsätzlich keine Erlaubnis zur Erfassung, Nutzung oder Offenlegung personenbezogener Daten.", + "consent": "Es liegt in Ihrer Verantwortung, die gesetzlich vorgeschriebene Einwilligung zur Erhebung von Daten einzuholen.", + "formIntention": "Bevor Sie Ihr Formular veröffentlichen oder verteilen, müssen Sie die Absicht des Formulars mit Ihnen besprechen", + "privacyOfficer": "Datenschutzbeauftragter des Ministeriums", + "assement": "und bei Bedarf Beurteilungen durchzuführen." + }, + "requestReceipt": { + "emailPriority": "E-Mail-Priorität", + "emailReceipt": "Senden Sie eine Quittung für diese Einreichung per E-Mail", + "high": "Hoch", + "low": "Niedrig", + "normal": "Normal", + "send": "SCHICKEN", + "sendToEmailAddress": "An E-Mail-Adresse senden", + "emailSent": "Eine E-Mail wurde an {to} gesendet.", + "sendingEmailErrMsg": "Beim Versuch, Ihre E-Mail zu senden, ist ein Fehler aufgetreten.", + "sendingEmailConsErrMsg": "E-Mail-Bestätigung an {to} fehlgeschlagen: {error}", + "emailRequired": "E-Mail ist erforderlich" + }, + "submissionsTable": { + "noMatchingRecordText": "Keine übereinstimmenden Aufzeichnungen gefunden", + "submissions": "Einsendungen", + "submissionsTable": "Einreichungstabelle", + "selectColumns": "Wählen Sie Spalten aus", + "manageForm": "Formular verwalten", + "submissionsToFiles": "Einsendungen in Dateien exportieren", + "showDeletedSubmissions": "Gelöschte Einsendungen anzeigen", + "showMySubmissions": "Zeige meine Einsendungen", + "search": "Suchen", + "loadingText": "Laden, bitte warten", + "noDataText": "Für dieses Formular liegen keine Einsendungen vor", + "delSelectedSubmissions": "Ausgewählte Einreichungen löschen", + "resSelectedSubmissions": "Ausgewählte Übermittlungen wiederherstellen", + "yes": "JA", + "no": "NEIN", + "viewSubmission": "Einreichung anzeigen", + "deleteSubmission": "Einreichung löschen", + "restore": "Wiederherstellen", + "confirmDeletion": "Löschung bestätigen", + "delete": "Löschen", + "confirmRestoration": "Bestätigen Sie die Wiederherstellung", + "searchSubmissionFields": "Eingabefelder durchsuchen", + "save": "Speichern", + "searchTitle": "Suchen und wählen Sie Spalten aus, die unter Ihrem Dashboard angezeigt werden sollen", + "status": "Status", + "submitter": "Einsender", + "submissionDate": "Abgabetermin", + "event": "Fall", + "view": "Sicht", + "lateSubmission": "Verspätete Vorlage", + "confirmationID": "Bestätigungs-ID", + "multiDelWarning": "Sind Sie sicher, dass Sie ausgewählte Einreichungen löschen möchten?", + "singleDelWarning": "Sind Sie sicher, dass Sie diese Einreichung löschen möchten?", + "multiRestoreWarning": "Sind Sie sicher, dass Sie diese Übermittlungen wiederherstellen möchten?", + "singleRestoreWarning": "Sind Sie sicher, dass Sie diese Übermittlung wiederherstellen möchten?" + }, + "auditHistory": { + "viewEditHistory": "Bearbeitungsverlauf anzeigen", + "editHistory": "Verlauf bearbeiten", + "auditLogMsg": "Dies ist ein Prüfprotokoll darüber, wer nach der ursprünglichen Übermittlung Änderungen an dieser Übermittlung vorgenommen hat.", + "loadingText": "Laden, bitte warten", + "close": "Schließen", + "userName": "Nutzername", + "date": "Datum", + "errorMsg": "Beim Versuch, den Verlauf abzurufen, ist ein Fehler aufgetreten.", + "consoleErrMsg": "Fehler beim Abrufen des Prüfverlaufs für" + }, + "deleteSubmission": { + "deleteThis": "Lösch das", + "draft": "Entwurf", + "submission": "Vorlage", + "confirmDeletion": "Löschung bestätigen", + "deleteWarning": "Sind Sie sicher, dass Sie dies löschen möchten?", + "drafts": "Entwurf", + "formSubmission": "Formulareinreichung", + "delete": "Löschen" + }, + "manageSubmissionUsers": { + "manageTeamMembers": "Teammitglieder verwalten", + "add": "Hinzufügen", + "draftFormInvite": "Sie können Teammitglieder nur einladen und verwalten, während es sich bei diesem Formular um einen Entwurf handelt", + "submissionTeamMembers": "Teammitglieder für diese Einreichung", + "actions": "Aktionen", + "close": "Schließen", + "remove": "Entfernen", + "userNotFoundErrMsg": "Sie können niemanden finden? Möglicherweise haben sie sich nicht bei CHEFS angemeldet.
Bitte senden Sie ihnen einen Link zu CHEFS und bitten Sie sie, sich anzumelden.", + "name": "Name", + "username": "Nutzername", + "email": "Email", + "removeUserWarningMsg1": "Sind Sie sicher, dass Sie es entfernen möchten?", + "removeUserWarningMsg2": "Sie haben keine Berechtigungen mehr für diese Übermittlung.", + "userExistInListMsg": "Benutzer {username} ist bereits in der Liste der Teammitglieder.", + "getSubmissionUsersErr": "Beim Versuch, Benutzer für diese Übermittlung abzurufen, ist ein Fehler aufgetreten.", + "getSubmissionUsersConsoleErr": "Fehler beim Abrufen von Benutzern für {submissionId}: {error}", + "sentInviteEmailTo": "Einladungs-E-Mail an gesendet", + "sentUninvitedEmailTo": "Uneingeladene E-Mail an gesendet", + "updateUserErrMsg": "Beim Versuch, Benutzer für diese Übermittlung zu aktualisieren, ist ein Fehler aufgetreten.", + "updateUserConsoleErrMsg": "Fehler beim Festlegen der Benutzerberechtigungen. Sub: {submissionId} Benutzer: {userId} Fehler: {error}", + "searchInputLength": "Die Sucheingabe für BCeID-Benutzername/E-Mail-Adresse muss mehr als 6 Zeichen umfassen.", + "exactBCEIDSearch": "E-Mail-Suchen nach BCeID müssen genau sein.", + "getUsersErrMsg": "Fehler beim Abrufen von Benutzern: {error}", + "exactEmailOrUsername": "Geben Sie eine genaue E-Mail-Adresse oder einen Benutzernamen ein.", + "requiredFiled": "Geben Sie einen Namen, eine E-Mail-Adresse oder einen Benutzernamen ein" + }, + "mySubmissionsActions": { + "viewThisSubmission": "Diesen Beitrag ansehen", + "copyThisSubmission": "Kopieren Sie diese Einreichung", + "editThisDraft": "Bearbeiten Sie diesen Entwurf" + }, + "mySubmissionsTable": { + "noMatchingRecordText": "Keine übereinstimmenden Aufzeichnungen gefunden", + "previousSubmissions": "Frühere Einsendungen", + "selectColumns": "Wählen Sie Spalten aus", + "createNewSubmission": "Erstellen Sie eine neue Einreichung", + "search": "Suchen", + "loadingText": "Laden, bitte warten", + "noDataText": "Sie haben keine Einsendungen", + "searchSubmissionFields": "Eingabefelder durchsuchen", + "save": "Speichern", + "filterTitle": "Suchen und wählen Sie Spalten aus, die unter Ihrem Dashboard angezeigt werden sollen", + "confirmationId": "Bestätigungs-ID", + "actions": "Aktionen", + "createdBy": "Erstellt von", + "statusUpdatedBy": "Status aktualisiert von", + "status": "Status", + "submissionDate": "Abgabetermin", + "draftUpdatedBy": "Entwurf aktualisiert von", + "draftLastEdited": "Entwurf zuletzt bearbeitet", + "createLateSubmissn": "Erstellen Sie eine verspätete Einreichung", + "formLoading": "Bitte warten Sie, während das Formular geladen wird!!!", + "pleaseConfirm": "Bitte bestätigen", + "wantToSaveDraft": "Möchten Sie den Entwurf speichern?", + "yes": "Ja", + "no": "NEIN", + "multiDraftUploadSuccess": "Ihr mehrfacher Entwurfs-Upload war erfolgreich!", + "failedResSubmissn": "Fehlgeschlagene Antwort vom Übermittlungsendpunkt. Antwortcode: {status}", + "errSubmittingForm": "Beim Absenden dieses Formulars ist ein Fehler aufgetreten", + "errorSavingFile": "Fehler beim Speichern der Dateien. Dateiname: {fileName}. Fehler: {error}", + "submittingDraftErrMsg": "Beim Speichern eines Entwurfs ist ein Fehler aufgetreten", + "submittingDraftConsErrMsg": "Fehler beim Speichern des Entwurfs. Einreichungs-ID: {submissionId}. Fehler: {error}" + }, + "notesPanel": { + "addNewNote": "Neue Notiz hinzufügen", + "cancel": "Stornieren", + "addNote": "NOTIZ HINZUFÜGEN", + "noResponseErr": "Keine Antwortdaten von der API beim Absenden des Formulars", + "errorMesg": "Beim Versuch, die Notiz hinzuzufügen, ist ein Fehler aufgetreten.", + "consoleErrMsg": "Fehler beim Hinzufügen der Notiz:", + "fetchErrMsg": "Beim Versuch, Notizen für diese Übermittlung abzurufen, ist ein Fehler aufgetreten.", + "fetchConsoleErrMsg": "Fehler beim Hinzufügen der Notiz:", + "notes": "Anmerkungen", + "note": "Notiz", + "maxChars": "Maximal 4000 Zeichen" + }, + "statusPanel": { + "currentStatus": "Aktueller Status:", + "assignedTo": "Zugewiesen an:", + "assignOrUpdateStatus": "Status zuweisen oder aktualisieren", + "display": "Anzeige", + "statusIsRequired": "Status ist erforderlich", + "assignTo": "Zuweisen", + "noDataText": "Bei der Suche wurden keine Formularprüfer gefunden. Fügen Sie Formularprüfer auf der Seite „Verwalten“ hinzu.", + "assigneeIsRequired": "Bevollmächtigter ist erforderlich", + "assignToMe": "MIR ZUWEISEN", + "recipientEmail": "Empfänger E-Mail", + "attachCommentToEmail": "Kommentar an E-Mail anhängen", + "emailComment": "E-Mail-Kommentar", + "maxChars": "Maximal 4000 Zeichen", + "viewHistory": "SIEHE VERLAUF", + "statusHistory": "Statusverlauf", + "close": "SCHLIESSEN", + "addNoteNoReponserErr": "Keine Antwortdaten von der API beim Senden der Notiz zur Statusaktualisierung", + "addNoteConsoleErrMsg": "Fehler beim Aktualisieren des Status: {error}", + "addNoteErrMsg": "Beim Versuch, den Status zu aktualisieren, ist ein Fehler aufgetreten", + "updtSubmissionsStatusErr": "Keine Antwortdaten von der API beim Absenden des Statusaktualisierungsformulars", + "noStatus": "Kein Status", + "noStatusesFound": "Keine Status gefunden", + "statusCodesErr": "Fehler beim Finden von Statuscodes", + "notifyErrorCode": "Beim Abrufen des Status für diese Übermittlung ist ein Fehler aufgetreten.", + "notifyConsoleErrorCode": "Fehler beim Abrufen der Status:", + "fetchSubmissionUsersErr": "Beim Versuch, die Empfänger-E-Mails für diese Übermittlung abzurufen, ist ein Fehler aufgetreten.", + "fetchSubmissionUsersConsErr": "Fehler beim Abrufen der Empfänger-E-Mails für", + "assignSubmissnToFormReviewer": "Einreichungen können Formularprüfern zugewiesen werden.
Um weitere Teammitglieder als Formularprüfer hinzuzufügen, gehen Sie zur Seite „Verwalten“ für dieses Formular.", + "update": "AKTUALISIEREN", + "revise": "ÜBERARBEITEN", + "complete": "VOLLSTÄNDIG", + "assign": "ZUORDNEN" + }, + "statusTable": { + "loadingText": "Laden, bitte warten", + "status": "Status", + "dateStatusChanged": "Datum, Status geändert", + "assignee": "Bevollmächtigter", + "updatedBy": "Aktualisiert von", + "getSubmissionStatusErr": "Beim Versuch, Status abzurufen, ist ein Fehler aufgetreten.", + "getSubmissionStatusConsErr": "Fehler beim Hinzufügen der Notiz:" + }, + "exportSubmissions": { + "exportSubmissionsToFile": "Einreichungen in eine Datei exportieren", + "viewSubmissions": "Einsendungen anzeigen", + "fileType": "Dateityp", + "json": "JSON", + "csv": "CSV", + "formVersion": "Formularversion", + "versionIsRequired": "Version ist erforderlich.", + "dataFields": "Datenfelder", + "searchFields": "Suchfelder", + "selectedForExports": "für den Export ausgewählt", + "submissionDate": "Abgabetermin", + "all": "Alle", + "selectDateRange": "Wählen Sie Datumsbereich aus", + "SelectdateRange": "Wählen Sie den Datumsbereich aus", + "from": "Aus", + "to": "Zu", + "CSVFormat": "CSV-Format", + "multiRowPerSubmissionA": "1 – Mehrere Zeilen pro Einreichung mit Einrückungsräumen", + "multiRowPerSubmissionB": "2 – Mehrere Zeilen pro Einreichung", + "singleRowPerSubmission": "3 – Eine Zeile pro Einreichung", + "unformatted": "4 – Unformatiert", + "fileNameAndType": "Dateiname und -typ", + "export": "Export", + "noResponseDataErr": "Keine Daten als Antwort vom exportSubmissions-Aufruf", + "apiCallErrorMsg": "Beim Versuch, Einsendungen für dieses Formular zu exportieren, ist ein Fehler aufgetreten.", + "apiCallConsErrorMsg": "Fehler beim Exportieren von Übermittlungen für", + "selectAllFields": "Wählen Sie alle Felder aus", + "emailSentMsg": "Eine E-Mail mit einem Link zum Herunterladen Ihrer Daten wird an {email} gesendet, sobald diese fertig sind", + "exportInProgress": "Export läuft", + "of": "von" + }, + "printOptions": { + "submitButtonTxt": "An CDOGS senden und herunterladen", + "templatePrint": "Vorlagendruck", + "uploadTemplateFile": "Laden Sie die Vorlagendatei hoch", + "downloadOptions": "Download-Optionen", + "print": "Drucken", + "browserPrint": "Browserdruck", + "pageFromBrowser": "die Seite aus Ihrem Browser", + "uploadA": "Laden Sie eine hoch", + "uploadB": "eine strukturierte Version haben", + "docGrnSucess": "Dokument erfolgreich generiert", + "failedDocGenErrMsg": "Dokument konnte nicht generiert werden", + "failedDocGenConsErrMsg": "Fehler beim Senden der Vorlage: {error}", + "cDogsTemplate": "CDOGS-Vorlage" + }, + "proactiveHelpDialog": { + "componentInfoLink": "Link zu Komponenteninformationen", + "learnMoreLinkTxt": "Das Linkfeld für weitere Informationen darf nicht leer sein.", + "largeImgTxt": "Großes Bild. Die Bildgröße darf nicht größer als 0,5 MB sein", + "componentName": "Komponentenname:", + "learnMoreLink": "Link für weitere Informationen:", + "clickToEnableLink": "Klicken Sie, um den Link zu aktivieren", + "clickToDisableLink": "Klicken Sie hier, um den Link zu deaktivieren", + "imageUpload": "Bild-Upload:", + "cancel": "Stornieren", + "save": "Speichern", + "description": "Beschreibung" + }, + "proactiveHelpPreviewDialog": { + "learnMore": "Erfahren Sie mehr" + }, + "preview": { + "preview": "Vorschau", + "previewToolTip": "Dies zeigt eine Vorschau des Designs und Verhaltens der Formularversion, wie es Ihren Einsendern angezeigt wird. Sie können das Formular nicht von dieser Seite aus senden." + }, + "generalLayout": { + "loadingText": "Laden, bitte warten", + "preview": "VORSCHAU", + "published": "VERÖFFENTLICHT", + "unpublished": "UNVERÖFFENTLICHT", + "edit": "BEARBEITEN", + "formTitle": "Formulartitel", + "actions": "Aktionen" + }, + "formSubmission": { + "editThisSubmission": "Bearbeiten Sie diese Übermittlung", + "submission": "Vorlage", + "alertInfo": "Senden Sie das Formular nach der Bearbeitung erneut, um Ihre Änderungen zu speichern.", + "viewAllSubmissions": "Alle Einsendungen anzeigen", + "submitted": "Eingereicht:", + "confirmationID": "Bestätigungs-ID:", + "submittedBy": "Eingereicht von:", + "cancel": "STORNIEREN", + "status": "Status", + "updatedAt": "Geändert", + "updatedBy": "Angepasst von" + }, + "teamManagement": { + "noMatchingRecordText": "Keine übereinstimmenden Aufzeichnungen gefunden", + "teamManagement": "Team Management", + "selectColumns": "Wählen Sie Spalten aus", + "manageForm": "Formular verwalten", + "search": "Suchen", + "loadingText": "Laden, bitte warten", + "noDataText": "Teamrollendaten konnten nicht geladen werden", + "removeSelectedUsers": "Ausgewählte Benutzer entfernen", + "removeThisUser": "Entfernen Sie diesen Benutzer", + "confirmRemoval": "Bestätigen Sie das Entfernen", + "remove": "Entfernen", + "searchTeamManagementFields": "Durchsuchen Sie Teamverwaltungsfelder", + "save": "Speichern", + "teamMebersTitle": "Suchen und wählen Sie Spalten aus, die unter Ihrem Dashboard angezeigt werden sollen", + "fullName": "Vollständiger Name", + "username": "Nutzername", + "identityProvider": "Identitätsanbieter", + "delSelectedMembersWarning": "Sind Sie sicher, dass Sie die ausgewählten Mitglieder entfernen möchten?", + "delSelectedMemberWarning": "Sind Sie sicher, dass Sie das ausgewählte Mitglied entfernen möchten?", + "idpMessage": "ist bereits im Team.", + "formOwnerErrMsg": "Es muss immer mindestens ein Formulareigentümer vorhanden sein", + "formOwnerConsoleErrMsg": "{userId} kann nicht entfernt werden, da sie der einzige verbleibende Besitzer dieses Formulars ist.", + "insufficientPermissnMsg": "Unzureichende Berechtigungen zum Verwalten des Teams", + "getUserErrMsg": "Fehler beim Abrufen der Formularbenutzer:", + "getRolesErrMsg": "Fehler beim Abrufen der Rollenliste:", + "formOwnerRemovalWarning": "Kann nicht entfernt werden, da sie der einzige verbleibende Eigentümer dieses Formulars sind.", + "removeUsersErrMsg": "Beim Versuch, die ausgewählten Benutzer zu löschen, ist ein Fehler aufgetreten", + "removeUserConsoleErrMsg": "Fehler beim Löschen von Benutzern aus Formular {formId}: {error}", + "updUserRolesErrMsg": "Beim Versuch, alle Benutzerrollen zu aktualisieren, ist ein Fehler aufgetreten", + "updUserRolesConsoleErrMsg": "Fehler beim Festlegen aller Benutzerrollen für das Formular {formId}: {error}", + "setUserFormsErrMsg": "Beim Versuch, Rollen für einen Benutzer zu aktualisieren, ist ein Fehler aufgetreten", + "setUserFormsConsoleErrMsg": "Fehler beim Festlegen der Benutzerrollen für das Formular {formId}: {error}" + }, + "floatButton": { + "publish": "Veröffentlichen", + "manage": "Verwalten", + "redo": "Wiederholen", + "undo": "Rückgängig machen", + "preview": "Vorschau", + "bottom": "Unterseite", + "top": "Spitze", + "actions": "Aktionen", + "collapse": "Zusammenbruch", + "saved": "Gerettet", + "save": "Speichern", + "saving": "Sparen", + "notSaved": "Nicht gespeichert" + }, + "formViewer": { + "lateFormSubmissions": "Die Frist zum Einreichen des Formulars ist abgelaufen! Sie können dennoch eine verspätete Einreichung erstellen, indem Sie auf die Schaltfläche unten klicken.", + "createLateSubmission": "Erstellen Sie eine verspätete Einreichung", + "draftSaved": "Entwurf gespeichert", + "saving": "Sparen", + "pleaseConfirm": "Bitte bestätigen", + "submitFormWarningMsg": "Sind Sie sicher, dass Sie Ihr Formular absenden möchten?", + "submit": "Einreichen", + "wantToSaveDraft": "Möchten Sie den Entwurf speichern?", + "version": "Version: {version}", + "formScheduleExpireMessage": "Die Einreichung des Formulars ist nicht möglich, da die geplante Einreichungsfrist abgelaufen ist.", + "getUsersSubmissionsErrMsg": "Beim Abrufen der Übermittlung für dieses Formular ist ein Fehler aufgetreten", + "getUsersSubmissionsConsoleErrMsg": "Fehler beim Laden der Formularübermittlungsdaten {submissionId}: {error}", + "multiDraftUploadSuccess": "Ihr mehrfacher Entwurfs-Upload war erfolgreich!", + "readVersionErrMsg": "Kein Schema als Antwort. Versions-ID: {versionId}", + "readDraftErrMsg": "Kein Schema als Antwort. draftId: {draftId}", + "alertRouteMsg": "Der Formulareigentümer hat das Formular nicht veröffentlicht und es ist nicht für Übermittlungen verfügbar.", + "fecthingFormErrMsg": "Beim Abrufen dieses Formulars ist ein Fehler aufgetreten", + "fecthingFormConsoleErrMsg": "Fehler beim Laden des Formularschemas {versionId}: {error}", + "savingDraftErrMsg": "Beim Speichern eines Entwurfs ist ein Fehler aufgetreten", + "savingDraftConsoleErrMsg": "Fehler beim Speichern des Entwurfs. Einreichungs-ID: {submissionId}. Fehler: {error}", + "submissionsPreviewAlert": "Die Übermittlung wurde während der Formularvorschau deaktiviert", + "submissionsSubmitErrMsg": "Fehler beim Absenden des Formulars: {errors}", + "sendSubmissionErrMsg": "Fehlgeschlagene Antwort vom Übermittlungsendpunkt. Antwortcode: {status}", + "errMsg": "Beim Absenden dieses Formulars ist ein Fehler aufgetreten", + "customEventAlert": "Benutzerdefinierte Schaltflächenereignisse werden noch nicht unterstützt. Ereignistyp: {event}", + "formLoading": "Bitte warten Sie, während das Formular geladen wird!!!", + "yes": "Ja", + "no": "NEIN", + "failedResSubmissn": "Fehlgeschlagene Antwort vom Übermittlungsendpunkt. Antwortcode: {status}", + "errSubmittingForm": "Beim Absenden dieses Formulars ist ein Fehler aufgetreten", + "errorSavingFile": "Fehler beim Speichern der Dateien. Dateiname: {fileName}. Fehler: {error}", + "submittingDraftErrMsg": "Beim Speichern eines Entwurfs ist ein Fehler aufgetreten", + "submittingDraftConsErrMsg": "Fehler beim Speichern des Entwurfs. Einreichungs-ID: {submissionId}. Fehler: {error}", + "formDraftAccessErrMsg": "Die angeforderte Übermittlung wurde bereits übermittelt und wird zur Ansichtsseite weitergeleitet" + }, + "bCGovFooter": { + "home": "Heim", + "about": "Über gov.bc.ca", + "disclaimer": "Haftungsausschluss", + "privacy": "Privatsphäre", + "accessibility": "Barrierefreiheit", + "copyRight": "Urheberrechte ©", + "contactUs": "Kontaktiere uns" + }, + "bCGovNavBar": { + "about": "Um", + "myForms": "Meine Formulare", + "createNewForm": "Erstellen Sie ein neues Formular", + "help": "Hilfe", + "feedback": "Rückmeldung", + "admin": "Administrator" + }, + "homePage": { + "title": "Erstellen, veröffentlichen Sie Formulare und empfangen Sie Übermittlungen mit dem Common Hosted Forms Service.", + "subTitle": "Alle B.C. Regierungsmitarbeiter oder Auftragnehmer mit einem IDIR-Konto können unsere gehostete Version des Common Hosted Forms Service (CHEFS) zum Erstellen von Formularen verwenden.", + "takeATourOfChefs": "Machen Sie einen Rundgang durch CHEFS, um es in Aktion zu sehen.", + "logInToGetStarted": "Melden Sie sich an, um loszulegen", + "loginToStart": "Melden Sie sich mit IDIR an, um loszulegen", + "login": "Anmeldung", + "createFormLabel": "Erstellen Sie ein Formular", + "manageAccessTitle": "Verwalten Sie den Zugriff auf Ihr Formular", + "manageAccessSub1": "Mit CHEFS können Sie öffentliche Formulare erstellen oder den Zugriff über IDIR- oder BCeID-Authentifizierung verwalten.", + "manageAccessSub2": "Sie können Ihrem Team auch Rollen zuweisen, um alle Ihre Einreichungen zu verwalten.", + "createCustomFormTitle": "Erstellen Sie benutzerdefinierte Formulare mit dem CHEFS-Formular-Builder", + "createCustomFormSub1": "Mit CHEFS können Sie sichere Formulare mit einer intuitiven Drag-and-Drop-Oberfläche erstellen. Sie können Formularkomponenten hinzufügen, sie neu anordnen und in verschiedenen Layoutkonfigurationen ablegen.", + "chefsHowToTitle": "CHEFS-Anleitungsvideos", + "chefsHowToSub": "Unser Quickstart Guide führt Sie in einige Grundfunktionen von CHEFS ein.", + "getStartedToChefs": "Beginnen Sie mit der Nutzung von CHEFS", + "createOnlineTitle": "Erstellen Sie Online-Formulare, um Informationen von Ihren Kunden zu sammeln und Ihre Arbeitsabläufe zu verbessern.", + "getStarted": "Loslegen" + }, + "baseStepper": { + "designForm": "Designform", + "setUpForm": "Formular einrichten", + "manageForm": "Formular verwalten" + }, + "create": { + "formSettings": "Formulareinstellungen", + "disclaimer": "Haftungsausschluss", + "disclaimerStmt": "Ich stimme dem Haftungsausschluss und der Haftungserklärung von Form Designers zu", + "continue": "Weitermachen", + "back": "Zurück", + "confirmPageNav": "Möchten Sie diese Seite wirklich verlassen? Von Ihnen vorgenommene Änderungen werden nicht gespeichert.", + "agreementErrMsg": "Sie müssen dem oben aufgeführten Datenschutz-Haftungsausschluss zustimmen." + }, + "addTeamMember": { + "cantFindChefsUsers": "Sie können niemanden finden? Möglicherweise haben sie sich nicht bei CHEFS angemeldet.
Bitte senden Sie ihnen einen Link zu CHEFS und bitten Sie sie, sich anzumelden.", + "cancel": "Stornieren", + "add": "Hinzufügen", + "mustSelectAUser": "Sie müssen mindestens eine Rolle auswählen, um diesen Benutzer hinzuzufügen.", + "addNewMember": "Fügen Sie ein neues Mitglied hinzu", + "enterUsername": "Geben Sie einen Namen, eine E-Mail-Adresse oder einen Benutzernamen ein", + "enterExactUsername": "Geben Sie eine genaue E-Mail-Adresse oder einen Benutzernamen ein", + "BCeIDInputSearchMaxLen": "Die Sucheingabe für BCeID-Benutzername/E-Mail-Adresse muss mehr als 6 Zeichen umfassen.", + "BCeIDMustBeExact": "E-Mail-Suchen nach BCeID müssen genau sein.", + "errorGettingUsers": "Fehler beim Abrufen der Benutzer {error}" + }, + "baseFilter": { + "cancel": "Stornieren", + "columnName": "Spaltenname", + "exampleText": "Beispieltext", + "exampleText2": "Beispieltext 2", + "filterPlaceholderTxt": "Platzhaltertext filtern", + "filter": "Filter", + "value": "Wert", + "resetColumns": "Spalten zurücksetzen" + }, + "formViewerActions": { + "viewMyDraftOrSubmissions": "Meine Entwürfe/Einreichungen ansehen", + "saveAsADraft": "Als einen Entwurf sichern", + "editThisDraft": "Bearbeiten Sie diesen Entwurf", + "switchSingleSubmssn": "Wechseln Sie zur Einzeleinreichung", + "switchMultiSubmssn": "Wechseln Sie zu mehreren Einreichungen" + }, + "baseCopyToClipboard": { + "linkToClipboard": "Link in die Zwischenablage kopiert", + "copyToClipboard": "In die Zwischenablage kopieren", + "errCopyToClipboard": "Fehler beim Versuch, in die Zwischenablage zu kopieren." + }, + "sucess": { + "sucessFormSubmissn": "Ihr Formular wurde erfolgreich übermittelt", + "keepRecord": "Wenn Sie diese Einreichung protokollieren möchten, können Sie Folgendes aufbewahren", + "confirmationId": "Bestätigungs-ID" + }, + "bcGovAlertBanner": { + "defaultErrMsg": "Fehler: Etwas ist schief gelaufen", + "error": "Fehler" + }, + "permissionUtils": { + "formNotAvailable": "Das Formular ist derzeit nicht verfügbar. Dies kann an einem falschen Link liegen oder das Formular wurde vom Eigentümer gelöscht.", + "missingFormIdAndSubmssId": "Bei den Optionen fehlen sowohl die Form-ID als auch die Einreichungs-ID", + "loadingFormErrMsg": "Beim Laden dieses Formulars ist ein Fehler aufgetreten.", + "loadingForm": "Fehler beim Laden von {options}: {error}", + "idpHintMsg": "Dieses Formular erfordert eine {idpHint}-Authentifizierung. Bitte melden Sie sich erneut an und versuchen Sie es erneut.", + "formIdpMissMatch": "Formular-IDP-Konflikt. Das Formular erfordert {idpHint}, aber der Benutzer hat {userIdp}." + }, + "download": { + "chefsDataExport": "CHEFS-Datenexport", + "preparingForDownloading": "Download wird vorbereitet...", + "downloadInfoA": "Wenn Ihre Datei nicht automatisch heruntergeladen wird", + "downloadInfoB": "Klicken Sie hier, um es erneut zu versuchen" + }, + "history": { + "submissnHistory": "Ihr Einreichungsverlauf (TBD)" + }, + "error": { + "logout": "Ausloggen", + "somethingWentWrong": "Fehler: Etwas ist schiefgelaufen... :(" + }, + "login": { + "authenticateWith": "Authentifizieren mit:", + "alreadyLoggedIn": "Bereits angemeldet", + "home": "Heim", + "about": "Um" + }, + "notFound": { + "about": "Um", + "pageNotFound": "404 Seite nicht gefunden. :(" + }, + "store": { + "admin": { + "addFormOwnerRole": "Die Besitzerrolle für dieses Formular wurde zu {fullName} hinzugefügt.", + "addRowError": "Beim Hinzufügen der Rolle ist ein Fehler aufgetreten.", + "addRowConsoleErr": "Fehler beim Hinzufügen des Benutzers {userId} zum Formular {formId}: {error}", + "apiKeyDelMsg": "Der API-Schlüssel für dieses Formular wurde gelöscht.", + "errDeletingApiKey": "Beim Versuch, den API-Schlüssel zu löschen, ist ein Fehler aufgetreten.", + "consErrDeletingApiKey": "Fehler beim Löschen des API-Schlüssels für das Formular {formId}: {error}", + "fecthingFormsErrMsg": "Beim Abrufen der Formulare ist ein Fehler aufgetreten.", + "fecthingFormsConsErrMsg": "Fehler beim Abrufen der Admin-Formulardaten: {error}", + "fecthingFormErrMsg": "Beim Abrufen dieses Formulars ist ein Fehler aufgetreten.", + "fecthingFormConsErrMsg": "Fehler beim Abrufen der Daten des Admin-Formulars {formId}: {error}", + "fecthFormUserRolesErrMsg": "Beim Abrufen der Formularbenutzerrollen ist ein Fehler aufgetreten.", + "fecthFormUserRolesConsErrMsg": "Fehler beim Abrufen der Administratorrollendaten: {error}", + "fecthApiDetailsErrMsg": "Beim Abrufen der API-Details dieses Formulars ist ein Fehler aufgetreten.", + "fecthApiDetailsConsErrMsg": "Fehler beim Abrufen der Admin-API-Details aus Formular-{formId}-Daten: {error}", + "restoreFormErrMsg": "Beim Wiederherstellen dieses Formulars ist ein Fehler aufgetreten.", + "restoreFormConsErrMsg": "Fehler beim Wiederherstellen der Formular-{formId}-Daten: {error}", + "getUsersErrMsg": "Beim Abrufen von Benutzern ist ein Fehler aufgetreten.", + "getUsersConsErrMsg": "Fehler beim Abrufen der Administratorbenutzerdaten: {error}", + "getUserErrMsg": "Beim Abrufen dieses Benutzers ist ein Fehler aufgetreten.", + "getUserConsErrMsg": "Fehler beim Abrufen der Daten des Administratorbenutzers {userId}: {error}", + "storingFCHelpInfoErrMsg": "Beim Speichern der Hilfeinformationen zur Formularkomponente ist ein Fehler aufgetreten", + "storingFCHelpInfoConsErrMsg": "Fehler beim Speichern der Hilfeinformationen zur Formularkomponente: {error}", + "gettingFCImgUrlErrMsg": "Beim Abrufen der Bild-URL ist ein Fehler aufgetreten", + "gettingFCImgUrlConsErrMsg": "Fehler beim Abrufen der Bild-URL: {error}", + "updatingFCStatusErrMsg": "Beim Aktualisieren des Veröffentlichungsstatus ist ein Fehler aufgetreten", + "updatingFCStatusConsErrMsg": "Fehler beim Aktualisieren des Veröffentlichungsstatus: {error}", + "fecthingFormBuilderCompsErrMsg": "Beim Abrufen der Form Builder-Komponenten ist ein Fehler aufgetreten", + "fecthingFormBuilderCompsConsErrMsg": "Fehler beim Abrufen der Formular-Builder-Komponenten: {error}" + }, + "form": { + "fetchEmailTemplatesConsErrMsg": "Fehler beim Laden der E-Mail-Vorlagen für {formId}: {error}", + "fetchEmailTemplatesErrMsg": "Beim Abrufen der E-Mail-Vorlagen für dieses Formular ist ein Fehler aufgetreten", + "getCurrUserFormsErrMsg": "Beim Abrufen Ihrer Formulare ist ein Fehler aufgetreten.", + "getCurrUserFormsConsErrMsg": "Fehler beim Abrufen der Benutzerdaten: {error}", + "getUserFormPermErrMsg": "Beim Abrufen Ihrer Benutzerdaten für dieses Formular ist ein Fehler aufgetreten.", + "getUserFormPermConsErrMsg": "Fehler beim Abrufen von Benutzerdaten mithilfe der formID {formId}: {error}", + "getUserFormRolesErrmsg": "Beim Abrufen Ihrer Benutzerdaten für dieses Formular ist ein Fehler aufgetreten.", + "getUserFormRolesConsErrmsg": "Fehler beim Abrufen von Benutzerdaten mithilfe der formID {formId}: {error}", + "updCurrUserFormPrefErrMsg": "Beim Speichern Ihrer Einstellungen für dieses Formular ist ein Fehler aufgetreten.", + "updCurrUserFormPrefConsErrMsg": "Fehler beim Aktualisieren der Benutzerformulareinstellungen mithilfe der Formular-ID {formId} und der Einstellungen {preferences}: {error}", + "getCurrUserFormPrefErrMsg": "Beim Abrufen Ihrer Einstellungen für dieses Formular ist ein Fehler aufgetreten.", + "getCurrUserFormPrefConsErrMsg": "Fehler beim Abrufen der Benutzerformulareinstellungen mithilfe der Formular-ID {formId}: {error}", + "delCurrformNotiMsg": "Formular {name} wurde erfolgreich gelöscht.", + "delCurrFormConsErMsg": "Fehler beim Löschen des Formulars {id}: {error}", + "delDraftErrMsg": "Beim Löschen dieses Entwurfs ist ein Fehler aufgetreten.", + "delDraftConsErrMsg": "Fehler beim Löschen von {draftId}: {error}", + "fecthDraftErrMsg": "Beim Suchen nach Entwürfen für dieses Formular ist ein Fehler aufgetreten.", + "fecthDraftConsErrMsg": "Fehler beim Abrufen der Entwürfe für das Formular {formId}: {error}", + "fecthFormErrMsg": "Beim Abrufen dieses Formulars ist ein Fehler aufgetreten.", + "fecthFormConsErrMsg": "Fehler beim Abrufen des Formulars {formId}: {error}", + "fetchFormFieldsErrMsg": "Beim Abrufen der Feldliste für dieses Formular ist ein Fehler aufgetreten.", + "fetchFormFieldsConsErrMsg": "Fehler beim Abrufen des Formulars {formId}: {error}", + "publishDraftErrMsg": "Beim Veröffentlichen ist ein Fehler aufgetreten.", + "publishDraftConsErrMsg": "Fehler beim Veröffentlichen von {draftId}: {error}", + "toggleVersnPublConsErrMsg": "Fehler in toggleVersionPublish {versionId} {publish}: {error}", + "updateEmailTemplateConsErrMsg": "Fehler beim Aktualisieren der E-Mail-Vorlagen für das Formular {formId}: {error}", + "updateEmailTemplateErrMsg": "Beim Aktualisieren der E-Mail-Vorlagen für dieses Formular ist ein Fehler aufgetreten.", + "updateFormErrMsg": "Beim Aktualisieren der Einstellungen für dieses Formular ist ein Fehler aufgetreten.", + "updateFormConsErrMsg": "Fehler beim Aktualisieren des Formulars {id}: {error}", + "deleteSubmissionNotifyMsg": "Einreichung erfolgreich gelöscht.", + "deleteSubmissionErrMsg": "Beim Löschen dieser Übermittlung ist ein Fehler aufgetreten.", + "deleteSubmissionConsErrMsg": "Fehler beim Löschen der Einreichung {submissionId}: {error}", + "deleteSubmissionsNotifyMsg": "Einsendungen erfolgreich gelöscht.", + "deleteSubmissionsErrMsg": "Beim Löschen der ausgewählten Einreichungen ist ein Fehler aufgetreten.", + "deleteSubmissionsConsErrMsg": "Fehler beim Löschen der Einreichungen: {error}", + "restoreSubmissionsNotiMsg": "Übermittlungen erfolgreich wiederhergestellt.", + "restoreSubmissionsErrMsg": "Beim Wiederherstellen dieser Übermittlung ist ein Fehler aufgetreten.", + "restoreSubmissionsConsErrMsg": "Fehler beim Wiederherstellen der Übermittlungen: {error}", + "restoreSubmissionNotiMsg": "Übermittlung erfolgreich wiederhergestellt.", + "restoreSubmissionErrMsg": "Beim Wiederherstellen dieser Übermittlung ist ein Fehler aufgetreten.", + "restoreSubmissionConsErrMsg": "Fehler beim Wiederherstellen der Übermittlung {submissionId}: {error}", + "fecthSubmissnUsersErrMsg": "Beim Abrufen der Empfänger-E-Mail für diese Übermittlung ist ein Fehler aufgetreten.", + "fecthSubmissnUsersConsErrMsg": "Fehler beim Abrufen der Empfänger-E-Mail für die Übermittlung {formSubmissionId}: {error}", + "fetchSubmissnErrMsg": "Beim Abrufen dieser Übermittlung ist ein Fehler aufgetreten.", + "fetchSubmissnConsErrMsg": "Fehler beim Abrufen der Einreichung {submissionId}: {error}", + "fetchFormCSVExptFieldsErrMsg": "Beim Abrufen der Feldliste für dieses Formular ist ein Fehler aufgetreten.", + "fetchFormCSVExptFieldsConsErrMsg": "Fehler beim Abrufen des Formulars {formId}: {error}", + "fetchSubmissnsErrMsg": "Beim Abrufen der Übermittlungen für dieses Formular ist ein Fehler aufgetreten.", + "fetchSubmissnsConsErrMsg": "Fehler beim Abrufen der Übermittlungen für {formId}: {error}", + "fetchVersionErrMsg": "Beim Abrufen dieses Formulars ist ein Fehler aufgetreten.", + "fetchVersionConsErrMsg": "Fehler beim Abrufen der Version {versionId} für das Formular {formId}: {error}", + "deleteApiKeyNotifyMsg": "Der API-Schlüssel für dieses Formular wurde gelöscht.", + "deleteApiKeyErrMsg": "Beim Versuch, den API-Schlüssel zu löschen, ist ein Fehler aufgetreten.", + "deleteApiKeyConsErrMsg": "Fehler beim Löschen des API-Schlüssels für das Formular {formId}: {error}", + "generateApiKeyNotifyMsg": "Für dieses Formular wurde ein API-Schlüssel erstellt.", + "generateApiKeyErrMsg": "Beim Versuch, einen API-Schlüssel zu generieren, ist ein Fehler aufgetreten.", + "generateApiKeyConsErrMsg": "Fehler beim Generieren des API-Schlüssels für das Formular {formId}: {error}", + "readApiKeyErrMsg": "Beim Versuch, den API-Schlüssel abzurufen, ist ein Fehler aufgetreten.", + "readApiKeyConsErrMsg": "Fehler beim Abrufen des API-Schlüssels für das Formular {formId}: {error}.", + "getFCPHImageUrlErrMsg": "Beim Abrufen der Bild-URL ist ein Fehler aufgetreten", + "getFCPHImageUrlConsErrMsg": "Fehler beim Abrufen der Bild-URL: {error}", + "listFCPHErrMsg": "Beim Abrufen der Form Builder-Komponenten ist ein Fehler aufgetreten", + "listFCPHConsErrMsg": "Fehler beim Abrufen der Formular-Builder-Komponenten: {error}", + "downloadFileErrMsg": "Beim Herunterladen der Datei ist ein Fehler aufgetreten", + "downloadFileConsErrMsg": "Fehler beim Herunterladen der Datei: Fehler", + "readSubscriptionSettingsErrMsg": "Beim Versuch, die Abonnementeinstellungen abzurufen, ist ein Fehler aufgetreten.", + "readSubscriptionSettingsConsErrMsg": "Fehler beim Abrufen der Abonnementeinstellungen für das Formular {formId}: {error}.", + "saveSubscriptionSettingsNotifyMsg": "Die Abonnementeinstellungen für dieses Formular wurden gespeichert.", + "saveSubscriptionSettingsErrMsg": "Beim Versuch, die Abonnementeinstellungen zu speichern, ist ein Fehler aufgetreten.", + "saveSubscriptionSettingsConsErrMsg": "Fehler beim Speichern der Abonnementeinstellungen für das Formular {formId}: {error}" + } + }, + "admin": { + "root": { + "admin": "Administrator" + }, + "form": { + "administerForm": "Formular verwalten" + }, + "user": { + "administerUser": "Benutzer verwalten" + } + }, + "user": { + "root": { + "myForms": "MEINE FORMEN", + "history": "GESCHICHTE", + "user": "Benutzer" + } + } +} diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/de/index.js b/frontend/app/frontend/src/internationalization/trans/chefs/de/index.js new file mode 100644 index 0000000..d73f3fb --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/de/index.js @@ -0,0 +1,4 @@ +import de from '~/internationalization/trans/chefs/de/de.json'; +export default { + trans: de, +}; diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/en/en.json b/frontend/app/frontend/src/internationalization/trans/chefs/en/en.json new file mode 100644 index 0000000..073e783 --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/en/en.json @@ -0,0 +1,1001 @@ +{ + "date": { + "date": "yyyy-mm-dd" + }, + "emailManagement": { + "emailManagement": "Email Management", + "manageForm": "Manage Form", + "submissionConfirmation": "Submission Confirmation" + }, + "emailTemplate": { + "body": "Body", + "save": "Save", + "saveEmailTemplateConsoleErrMsg": "Error updating email template for form {formId}: {error}", + "saveEmailTemplateErrMsg": "An error occurred while attempting to update the email template.", + "subject": "Subject", + "title": "Title", + "validBodyRequired": "Please enter a Body for the email", + "validSubjectRequired": "Please enter a Subject line for the email", + "validTitleRequired": "Please enter a Title for the email" + }, + "formsTable": { + "myForms": "My Forms", + "createNewForm": "Create a New Form", + "search": "Search", + "manage": "Manage", + "submissions": "Submissions", + "formTitle": "Form Title", + "viewForm": "View Form", + "description": "description", + "Description": "Description:", + "action": "Actions", + "loadingText": "Loading... Please wait" + }, + "manageLayout": { + "manageForm": "Manage Form" + }, + "shareForm": { + "shareForm": "Share Form", + "shareLink": "Share Link", + "copyQRCode": "Copy the link below or download the QR code.", + "warningMessage": "There is no published version of the form at this time. The link below will not be reachable until a version is published.", + "openThisForm": "Open this form", + "downloadQRCode": "Download QR Code", + "close": "Close", + "copyURLToClipboard": "Copy URL to clipboard" + }, + "manageFormActions": { + "emailManagement": "Email Management", + "viewSubmissions": "View Submissions", + "teamManagement": "Team Management", + "deleteForm": "Delete Form", + "confirmDeletion": "Confirm Deletion", + "deleteMessageA": "Are you sure you wish to delete", + "deleteMessageB": "This form will no longer be accessible.", + "delete": "Delete" + }, + "manageForm": { + "formSettings": "Form Settings", + "apiKey": "Api Key", + "updated": "Updated", + "created": "Created", + "formDesignHistory": "Form Design History", + "totalVersions": "Total Versions", + "status": "Status", + "update": "Update", + "cancel": "Cancel", + "eventSubscription": "Event Subscription" + }, + "formSettings": { + "pressToAddMultiEmail": "Press enter or , or space to add multiple email addresses", + "allowMultiDraft": "Allow multiple draft upload", + "formTitle": "Form Title", + "formDescription": "Form Description", + "formAccess": "Form Access", + "info": "If you will be using this form to gather information from the general public on topics that are of general interest to the public, you are required to contact the GCPE so that your engagement can be listed on", + "important": "IMPORTANT", + "idimNotifyA": "You must notify the Identity Information Management (IDIM) team by email", + "idimNotifyB": "your intent to leverage BCeID to verify the identities of your form submitters.", + "referenceGuideA": "Please reference our", + "referenceGuideB": "user guide", + "referenceGuideC": "for more details", + "specificTeamMembers": "Specific Team Members", + "formFunctionality": "Form Functionality", + "formSubmissinScheduleMsg": "The Form Submissions Schedule will be available in the Form Settings after the form is published.", + "formSubmissionsSchedule": "Form Submissions Schedule", + "experimental": "Experimental", + "learnMore": "Learn more", + "afterSubmission": "After Submission", + "submissionConfirmation": "Show the submission confirmation details", + "theConfirmationID": "the Confirmation ID", + "infoB": "the option for the user to email themselves a submission confirmation", + "loginRequired": "Log-in Required", + "canSaveAndEditDraftLabel": "Submitters can Save and Edit Drafts", + "canUpdateStatusAsReviewer": "Reviewers can Update the Status of this form (i.e. Submitted, Assigned, Completed)", + "submitterCanCopyExistingSubmissn": "Submitters can Copy an existing submission", + "submissionConfirmationToolTip": "Selecting this option controls what the submitting user of this form will see on successful submission.
If checked, it will display", + "emailNotificatnToTeam": "Send my team a notification email", + "emailNotificatnToTeamToolTip": "Send a notification to your specified email address when any user submits this form", + "notificationEmailAddrs": "Notification Email Addresses", + "addMoreValidEmailAddrs": "Add one or more valid email addresses", + "formScheduleSettings": "Form Schedule Settings", + "opensubmissions": "Open submissions", + "submissionsDeadline": "How long do you want to receive submissions?", + "keepSubmissnOpenTilUnplished": "Keep open until manually unpublished", + "submissionsClosingDate": "Schedule a closing date", + "submissionPeriod": "Set up submission period", + "closeSubmissions": "Close submissions", + "keepOpenFor": "Keep open for", + "period": "Period", + "allowLateSubmissions": "Allow late submissions", + "allowLateSubmissionsInfoTip": "If checked, submitters will be able to submit data after the closing date.", + "afterCloseDateFor": "After close date for", + "repeatPeriod": "Repeat period", + "every": "Every", + "repeatUntil": "Repeat until", + "summary": "Summary", + "submissionsOpenDateRange": "This form will be open for submissions from", + "to": "to", + "scheduleRepetition": "The schedule will repeat every", + "allowLateSubmissnInterval": "allowing late submissions for", + "until": "until", + "datesOfSubmissnInfo": "As per the settings these are the available dates of submissions:", + "formOpenInterval": "This form will be open for submissions from", + "allowDateSubmissionDate": "with allowing late submission until", + "customClosingMessage": "Set custom closing message", + "customClosingMessageToolTip": "Allow you to add a customized message for your users when they visit a closed form.", + "closingMessage": "Closing Message", + "sendReminderEmail": "SEND Reminder email", + "autoReminderNotificatn": "Enable automatic reminder notification", + "autoReminderNotificatnToolTip": "Send reminder email/s with the form link during the submission period.", + "selectLoginType": "Please select 1 log-in type", + "formDescriptnMaxChars": "Form Description must be 255 characters or less", + "formTitlemaxChars": "Form Title must be 255 characters or less", + "formTitleReq": "Form Title is required", + "atLeastOneEmailReq": "Please enter at least 1 email address", + "validEmailRequired": "Please enter all valid email addresses", + "fieldRequired": "This field is required.", + "correctDateFormat": "Date must be in correct format. ie. yyyy-mm-dd", + "dateDiffMsg": "Close Submission date should be greater than open submission date.", + "valueMustBeNumber": "Value must be a number. ie. 1,2,3,5,99", + "selectAnOptions": "Please select at least 1 option", + "validInterval": "This should be a valid interval.", + "fieldRequiredAndInterval": "This field is required & should be an interval.", + "dateGrtOpenSubmissnDate": "Repeat untill date should be greater then open submission date", + "public": "Public (anonymous)", + "allowEventSubscription": "Allow event subscription", + "eventSubscription": "Event Subscription", + "validEndpointRequired": "Please enter a valid endpoint starting with https://", + "validBearerTokenRequired": "Enter a valid bearer token example: 89abddfb-2cff-4fda-83e6-13221f0c3d4f" + }, + "subscribeEvent": { + "eventType": "Event Type", + "endpointUrl": "Endpoint URL", + "eventSubmission": "Submission", + "eventAssignment": "Assignment", + "eventStatusChange": "Status Change", + "endpointToken": "Endpoint Token", + "urlPlaceholder": "https://endpoint.gov.bc.ca/api/v1/", + "save": "Save", + "text": "text", + "password": "password", + "hideSecret": "Hide Secret", + "showSecret": "Show Secret", + "key": "Key", + "saveSettingsErrMsg": "An error occurred while attempting to update the settings for this form.", + "updateSettingsConsoleErrMsg": "Error updating settings for form {formId}: {error}" + }, + "apiKey": { + "disclaimer": "Disclaimer", + "infoA": "Ensure that your API key secret is stored in a secure location (i.e. key vault).", + "infoB": "Your API key grants unrestricted access to your form. Do not give out your API key to anyone.", + "infoC": "The API key should ONLY be used for automated system interactions. Do not use your API key for user based access", + "deleteKey": "Delete Key", + "apiKey": "api key", + "hideSecret": "Hide Secret", + "showSecret": "Show Secret", + "sCTC": "Secret copied to clipboard", + "cSTC": "Copy secret to clipboard", + "key": "Key", + "confirmDeletion": "Confirm Deletion", + "deleteMsg": "Are you sure you wish to delete your API Key?", + "delete": "Delete", + "confirmKeyGen": "Confirm Key Generation", + "createAPIKey": "Create an API Key for this form?
Ensure you follow the Disclaimer on this page.", + "regenerateAPIKey": "Regenerate the API Key?
Continuing will delete your current API Key access.", + "formOwnerKeyAcess": "You must be the Form Owner to manage API Keys.", + "regenerate": "Regenerate", + "generate": "Generate", + "secret": "Secret" + }, + "manageVersions": { + "important": "IMPORTANT!", + "infoA": "If there are no published versions, users are unable to access this form until there is a published version assigned. Once a version is published, that version is no longer editable. You must create a new version based on one of the previous form versions to continue editing.", + "infoB": "Note: Only one version can be published.", + "version": "Version", + "draft": "Draft", + "clickToPreview": "Click to preview", + "editVersion": "Edit Version", + "exportDesign": "Export Design", + "infoC": "Please publish or delete your latest draft version before starting a new version.", + "deleteVersion": "Delete Version", + "draftAlreadyExists": "Draft already exists", + "infoD": "Please edit, publish or delete the existing draft before starting a new draft.", + "publishVersion": "Publish Version", + "unpublishVersion": "Unpublish Version", + "infoE": "Unpublishing this form will take the form out of circulation until a version is published again.", + "confirmDeletion": "Confirm Deletion", + "infoF": "Are you sure you wish to delete this Version?", + "delete": "Delete", + "status": "Status", + "dateCreated": "Date Created", + "createdBy": "Created By", + "actions": "Actions", + "published": "Published", + "unpublished": "Unpublished", + "useVersionInfo": "Use version {version} as the base for a new version", + "publishingVersionInfo": "This will make Version {version} of your form live." + }, + "addOwner": { + "infoA": "This should only be done in the event that the current form owner is no longer active or is out of contact in a priority event. Otherwise have the current Owner or a Team Administrator for the form do this themselves.", + "hint": "To find the User ID needed you can go to the 'USERS' tab in the Admin portal and search for them.", + "addowner": "Add owner", + "label": "User ID (guid)" + }, + "adminFormsTable": { + "showDeletedForms": "Show deleted forms", + "search": "Search", + "loadingText": "loading-text", + "noDataText": "There are no forms in your system", + "admin": "Admin", + "launch": "Launch", + "formTitle": "Form Title", + "created": "Created", + "deleted": "Deleted", + "actions": "Actions", + "delete": "Delete" + }, + "administerForm": { + "deleted": "DELETED", + "restoreForm": "Restore this form", + "formDetails": "Form Details", + "apiKeyDetails": "API Key Details", + "deleteApiKey": "Delete API Key", + "formUsers": "Form Users", + "formVersions": "Form Versions", + "assignANewOwner": "Assign A New Owner", + "restoring": "Restoring", + "restore": "Restore", + "toActiveState": "to active state", + "confirmDeletion": "Confirm Deletion", + "confirmDeletionMsg": "Are you sure you want to delete this API Key?", + "delete": "Delete", + "confirmRestore": "Confirm Restore" + }, + "administerUser": { + "userDetails": "User Details", + "openSSOConsole": "Open SSO console" + }, + "adminPage": { + "forms": "Forms", + "users": "Users", + "developer": "Developer", + "infoLinks": "Info Links", + "metrics": "Metrics" + }, + "adminUsersTable": { + "search": "Search", + "loadingText": "Loading... Please wait", + "admin": "Admin", + "fullName": "Full Name", + "userID": "User ID", + "created": "Created", + "actions": "Actions" + }, + "adminVersions": { + "exportDesign": "Export Design", + "versions": "Versions", + "status": "Status", + "created": "Created", + "lastUpdated": "Last Updated", + "actions": "Actions", + "published": "Published", + "unpublished": "Unpublished", + "version": "Version {versionNo}", + "notificationMsg": "An error occurred while loading the form design." + }, + "developer": { + "user": "User", + "name": "Name", + "userName": "UserName", + "JWTContents": "JWT Contents", + "JWTContentsSBTxt": "JWT Contents copied to clipboard", + "JWTContentsTTTxt": "Copy JWT Contents to clipboard", + "JWTToken": "JWT Token", + "JWTTokenSBTxt": "JWT Token copied to clipboard", + "JWTTokenTTTxt": "Copy JWT Token to clipboard", + "chefsAPI": "CHEFS API", + "RBACSBTxt": "RBAC Response copied to clipboard", + "RBACTTTxt": "Copy RBAC Response to clipboard", + "notificationMsg": "Failed to get user from RBAC, see console", + "notificationConsErr": "Error getting User from RBAC" + }, + "baseAuthButton": { + "logout": "Logout", + "login": "Login" + }, + "baseDialog": { + "defaultText": "default text", + "ok": "OK", + "continue": "Continue", + "cancel": "Cancel", + "custom": "Custom" + }, + "baseSecure": { + "about": "About", + "loginInfo": "You must be logged in to use this feature.", + "login": "Login", + "401NotAuthorized": "401: not authorized. :(", + "401ErrorMsg": "Your account is not set up correctly.
Please contact", + "403Forbidden": "403: Forbidden. :(", + "403ErrorMsg": "This page requires {idp} authentication.", + "401UnAuthorized": "401: Unauthorized. :(", + "401UnAuthorizedErrMsg": "You do not have permission to access this page." + }, + "formDesigner": { + "formDesign": "Form Design", + "exportDesign": "Export Design", + "importDesign": "Import Design", + "important": "IMPORTANT", + "formDesignInfoA": "Use the SAVE DESIGN button when you are done building this form.", + "formDesignInfoB": "The SUBMIT button is provided for your user to submit this form and will be activated after it is saved.", + "formLoadErrMsg": "An error occurred while loading the form design.", + "formLoadConsoleErrMsg": "Error loading form {formId} schema (version: {versionId} draft: {draftId}): {error}", + "formSchemaImportErrMsg": "An error occurred while importing the form schema.", + "formSchemaImportConsoleErrMsg": "Error importing form schema : {error}", + "formDesignSaveErrMsg": "An error occurred while attempting to save this form design. If you need to refresh or leave to try again later, you can Export the existing design on the page to save for later.", + "formDesignSaveConsoleErrMsg": "Error updating or creating form (FormID: {formId}, versionId: {versionId}, draftId: {draftId}) Error: {error}", + "collapse": "Collapse", + "actions": "Actions", + "version": "Version", + "save": "Save", + "saving": "Saving", + "notSaved": "Not Saved", + "fieldnameError": "You CAN NOT use 'form' keyword as {label} fieldname" + }, + "formViewerMultiUpload": { + "important": "IMPORTANT", + "uploadSucessMsg": "To ensure successful uploading of multiple drafts, please download and utilize the provided template.", + "confirmDownload": "Do you want to download it?", + "jsonFileUpload": "Select JSON file to upload", + "dragNDrop": "or drag and drop it here", + "chooseAFile": "Choose a file", + "downloadDraftSubmns": "Please download the draft submission report and ensure that the data is entered correctly.", + "downloadReport": "Download report", + "doYouWantToDownload": "Do you want to download it?", + "uploadNewFile": "Upload new file", + "uploadMultipleFileErr": "Sorry, you can upload only one file", + "dragMultipleFileErr": "Sorry, you can drag only one file", + "fileFormatErr": "Sorry, we only accept json files", + "fileSizeErr": "Max file size allowed is 5MB", + "parseJsonErr": "We can not parse json data from the file", + "jsonObjNotArray": "Wrong json file format", + "jsonObjNotArrayConsErr": "An unexpected error occurred.", + "jsonArrayEmpty": "This json file is empty.", + "errorWhileValidate": "There is something wrong with this file", + "errWhileCheckValidity": "There is something wrong with this file", + "errAfterValidate": "Some errors found, see below for more information.", + "fileIsEmpty": "this file is empty.", + "download": "Download" + }, + "formDisclaimer": { + "disclaimerAndStatement": "Disclaimer and statement of responsibility for Form Designers:", + "privacyLaw": "It is your responsibility to comply with Privacy laws governing the collection, use and disclosure of personally identifiable information.", + "disclosure": "Access to this form designer tool does not inherently grant permission to collect, use or disclose any personally identifiable information.", + "consent": "It is your responsibility to obtain consent to collect information as required by law.", + "formIntention": "Before publishing or distributing your form you are required to discuss the intention of the form with your", + "privacyOfficer": "Ministry Privacy Officer", + "assement": "and to complete assessments as required." + }, + "requestReceipt": { + "emailPriority": "Email Priority", + "emailReceipt": "Email a receipt of this submission", + "high": "High", + "low": "Low", + "normal": "Normal", + "send": "SEND", + "sendToEmailAddress": "Send to Email Address", + "emailSent": "An email has been sent to {to}.", + "sendingEmailErrMsg": "An error occurred while attempting to send your email.", + "sendingEmailConsErrMsg": "Email confirmation to {to} failed: {error}", + "emailRequired": "Email is required" + }, + "submissionsTable": { + "noMatchingRecordText": "No matching records found", + "submissions": "Submissions", + "submissionsTable": "SubmissionsTable", + "selectColumns": "Select Columns", + "manageForm": "Manage Form", + "submissionsToFiles": "Export Submissions to Files", + "showDeletedSubmissions": "Show deleted submissions", + "showMySubmissions": "Show my submissions", + "search": "Search", + "loadingText": "Loading... Please wait", + "noDataText": "There are no submissions for this form", + "delSelectedSubmissions": "Delete selected submissions", + "resSelectedSubmissions": "Restore selected submissions", + "yes": "YES", + "no": "NO", + "viewSubmission": "View Submission", + "deleteSubmission": "Delete Submission", + "restore": "Restore", + "confirmDeletion": "Confirm Deletion", + "delete": "Delete", + "confirmRestoration": "Confirm Restoration", + "searchSubmissionFields": "Search submission fields", + "save": "Save", + "searchTitle": "Search and select columns to show under your dashboard", + "status": "Status", + "submitter": "Submitter", + "submissionDate": "Submission Date", + "event": "event", + "view": "View", + "lateSubmission": "Late Submission", + "confirmationID": "Confirmation ID", + "multiDelWarning": "Are you sure you wish to delete selected submissions?", + "singleDelWarning": "Are you sure you wish to delete this submission?", + "multiRestoreWarning": "Are you sure you wish to restore these submissions?", + "singleRestoreWarning": "Are you sure you wish to restore this submission?" + }, + "auditHistory": { + "viewEditHistory": "View Edit History", + "editHistory": "Edit History", + "auditLogMsg": "This is an audit log of who has made changes to this submission after the original submission.", + "loadingText": "Loading... Please wait", + "close": "Close", + "userName": "User Name", + "date": "Date", + "errorMsg": "An error occurred while trying to fetch history.", + "consoleErrMsg": "Error getting audit history for" + }, + "deleteSubmission": { + "deleteThis": "Delete This", + "draft": "Draft", + "submission": "Submission", + "confirmDeletion": "Confirm Deletion", + "deleteWarning": "Are you sure you wish to delete this", + "drafts": "draft", + "formSubmission": "form submission", + "delete": "Delete" + }, + "manageSubmissionUsers": { + "manageTeamMembers": "Manage Team Members", + "add": "Add", + "draftFormInvite": "You can only invite and manage team members while this form is a draft", + "submissionTeamMembers": "Team members for this submission", + "actions": "Actions", + "close": "Close", + "remove": "Remove", + "userNotFoundErrMsg": "Can't find someone? They may not have logged into CHEFS.
Kindly send them a link to CHEFS and ask them to log in.", + "name": "Name", + "username": "Username", + "email": "Email", + "removeUserWarningMsg1": "Are you sure you wish to remove", + "removeUserWarningMsg2": "They will no longer have permissions for this submission.", + "userExistInListMsg": "User {username} is already in the list of team members.", + "getSubmissionUsersErr": "An error occurred while trying to fetch users for this submission.", + "getSubmissionUsersConsoleErr": "Error getting users for {submissionId} : {error}", + "sentInviteEmailTo": "Sent invite email to", + "sentUninvitedEmailTo": "Sent uninvited email to", + "updateUserErrMsg": "An error occurred while trying to update users for this submission.", + "updateUserConsoleErrMsg": "Error setting user permissions. Sub: {submissionId} User: {userId} Error: {error}", + "searchInputLength": "Search input for BCeID username/email must be greater than 6 characters.", + "exactBCEIDSearch": "Email searches for BCeID must be exact.", + "getUsersErrMsg": "Error getting users: {error}", + "exactEmailOrUsername": "Enter an exact email or username.", + "requiredFiled": "Enter a name, email, or username" + }, + "mySubmissionsActions": { + "viewThisSubmission": "View This Submission", + "copyThisSubmission": "Copy This Submission", + "editThisDraft": "Edit This Draft" + }, + "mySubmissionsTable": { + "noMatchingRecordText": "No matching records found", + "previousSubmissions": "Previous Submissions", + "selectColumns": "Select Columns", + "createNewSubmission": "Create a New Submission", + "search": "Search", + "loadingText": "Loading... Please wait", + "noDataText": "You have no submissions", + "searchSubmissionFields": "Search submission fields", + "save": "Save", + "filterTitle": "Search and select columns to show under your dashboard", + "confirmationId": "Confirmation Id", + "actions": "actions", + "createdBy": "Created By", + "statusUpdatedBy": "Status Updated By", + "status": "Status", + "submissionDate": "Submission Date", + "draftUpdatedBy": "Draft Updated By", + "draftLastEdited": "Draft Last Edited", + "createLateSubmissn": "Create late submission", + "formLoading": "Please wait while the form is loading !!!", + "pleaseConfirm": "Please Confirm", + "wantToSaveDraft": "Do you want to save the draft?", + "yes": "Yes", + "no": "No", + "multiDraftUploadSuccess": "Your multiple draft upload has been successful!", + "failedResSubmissn": "Failed response from submission endpoint. Response code: {status}", + "errSubmittingForm": "An error occurred submitting this form", + "errorSavingFile": "Error saving files. Filename: {fileName}. Error: {error}", + "submittingDraftErrMsg": "An error occurred while saving a draft", + "submittingDraftConsErrMsg": "Error saving draft. SubmissionId: {submissionId}. Error: {error}" + }, + "notesPanel": { + "addNewNote": "Add New Note", + "cancel": "Cancel", + "addNote": "ADD NOTE", + "noResponseErr": "No response data from API while submitting form", + "errorMesg": "An error occurred while trying to add the note.", + "consoleErrMsg": "Error adding note:", + "fetchErrMsg": "An error occurred while trying to fetch notes for this submission.", + "fetchConsoleErrMsg": "Error adding note:", + "notes": "Notes", + "note": "Note", + "maxChars": "Max 4000 characters" + }, + "statusPanel": { + "currentStatus": "Current Status:", + "assignedTo": "Assigned To:", + "assignOrUpdateStatus": "Assign or Update Status", + "display": "display", + "statusIsRequired": "Status is required", + "assignTo": "Assign To", + "noDataText": "No Form Reviewers found with search. Add Form Reviewers on the Manage page.", + "assigneeIsRequired": "Assignee is required", + "assignToMe": "ASSIGN TO ME", + "recipientEmail": "Recipient Email", + "attachCommentToEmail": "Attach Comment to Email", + "emailComment": "Email Comment", + "maxChars": "Max 4000 characters", + "viewHistory": "VIEW HISTORY", + "statusHistory": "Status History", + "close": "CLOSE", + "addNoteNoReponserErr": "No response data from API while submitting note for status update", + "addNoteConsoleErrMsg": "Error updating status: {error}", + "addNoteErrMsg": "An error occurred while trying to update the status", + "updtSubmissionsStatusErr": "No response data from API while submitting status update form", + "noStatus": "No Status", + "noStatusesFound": "No statuses found", + "statusCodesErr": "error finding status codes", + "notifyErrorCode": "Error occurred fetching status for this submission.", + "notifyConsoleErrorCode": "Error getting statuses:", + "fetchSubmissionUsersErr": "An error occurred while trying to fetch recipient emails for this submission.", + "fetchSubmissionUsersConsErr": "Error getting recipient emails for", + "assignSubmissnToFormReviewer": "Submissions can be assigned to Form Reviewers.
To add more team members as Form Reviewers, go to the Manage page for this form.", + "update": "UPDATE", + "revise": "REVISE", + "complete": "COMPLETE", + "assign": "ASSIGN" + }, + "statusTable": { + "loadingText": "Loading... Please wait", + "status": "Status", + "dateStatusChanged": "Date Status Changed", + "assignee": "Assignee", + "updatedBy": "Updated By", + "getSubmissionStatusErr": "An error occurred while trying to fetch statuses.", + "getSubmissionStatusConsErr": "Error adding note:" + }, + "exportSubmissions": { + "exportSubmissionsToFile": "Export Submissions to File", + "viewSubmissions": "View Submissions", + "fileType": "File Type", + "json": "JSON", + "csv": "CSV", + "formVersion": "Form Version", + "versionIsRequired": "Version is required.", + "dataFields": "Data Fields", + "searchFields": "Search Fields", + "selectedForExports": "selected for exports", + "submissionDate": "Submission Date", + "all": "All", + "selectDateRange": "Select Date range", + "SelectdateRange": "Select date range", + "from": "From", + "to": "To", + "CSVFormat": "CSV Format", + "multiRowPerSubmissionA": "1 - Multiple rows per submission with indentation spaces", + "multiRowPerSubmissionB": "2 - Multiple rows per submission", + "singleRowPerSubmission": "3 - Single row per submission", + "unformatted": "4 - Unformatted", + "fileNameAndType": "File Name and Type", + "export": "Export", + "noResponseDataErr": "No data in response from exportSubmissions call", + "apiCallErrorMsg": "An error occurred while attempting to export submissions for this form.", + "apiCallConsErrorMsg": "Error export submissions for", + "selectAllFields": "Select all fields", + "emailSentMsg": "An email will be sent to {email} containing a link to download your data when it is ready", + "exportInProgress": "Export in progress", + "of": "of" + }, + "printOptions": { + "submitButtonTxt": "Submit to CDOGS and Download", + "templatePrint": "Template Print", + "uploadTemplateFile": "Upload template file", + "downloadOptions": "Download Options", + "print": "Print", + "browserPrint": "Browser Print", + "pageFromBrowser": "the page from your browser", + "uploadA": "Upload a", + "uploadB": "to have a structured version", + "docGrnSucess": "Document generated successfully", + "failedDocGenErrMsg": "Failed to generate Document", + "failedDocGenConsErrMsg": "Error submitting template: {error}", + "cDogsTemplate": "CDOGS template" + }, + "proactiveHelpDialog": { + "componentInfoLink": "Component Information Link", + "learnMoreLinkTxt": "Learn More Link field cannot be empty.", + "largeImgTxt": "Large image. Image size cannot be large than .5mb", + "componentName": "Component Name:", + "learnMoreLink": "Learn More Link:", + "clickToEnableLink": "Click to enable link", + "clickToDisableLink": "Click to disable link", + "imageUpload": "Image Upload:", + "cancel": "Cancel", + "save": "Save", + "description": "Description" + }, + "user": { + "root": { + "myForms": "MY FORMS", + "history": "HISTORY", + "user": "User" + } + }, + "proactiveHelpPreviewDialog": { + "learnMore": "Learn more" + }, + "preview": { + "preview": "Preview", + "previewToolTip": "This shows a preview of the form version design and behaviour as your submitters will see it. You cannot submit the form from this page." + }, + "generalLayout": { + "loadingText": "Loading... Please wait", + "preview": "PREVIEW", + "published": "PUBLISHED", + "unpublished": "UNPUBLISHED", + "edit": "EDIT", + "formTitle": "Form Title", + "actions": "Actions" + }, + "formSubmission": { + "editThisSubmission": "Edit This Submission", + "submission": "Submission", + "alertInfo": "After editing, re-submit the form to save your changes.", + "viewAllSubmissions": "View All Submissions", + "submitted": "Submitted:", + "confirmationID": "Confirmation ID:", + "submittedBy": "Submitted By:", + "cancel": "CANCEL", + "status": "Status", + "updatedAt": "Modified", + "updatedBy": "Modified By" + }, + "teamManagement": { + "noMatchingRecordText": "No matching records found", + "teamManagement": "Team Management", + "selectColumns": "Select Columns", + "manageForm": "Manage Form", + "search": "Search", + "loadingText": "Loading... Please wait", + "noDataText": "Failed to load team role data", + "removeSelectedUsers": "Remove selected users", + "removeThisUser": "Remove this user", + "confirmRemoval": "Confirm Removal", + "remove": "Remove", + "searchTeamManagementFields": "Search team management fields", + "save": "Save", + "teamMebersTitle": "Search and select columns to show under your dashboard", + "fullName": "Full Name", + "username": "Username", + "identityProvider": "Identity Provider", + "delSelectedMembersWarning": "Are you sure you want to remove the selected members?", + "delSelectedMemberWarning": "Are you sure you want to remove the selected member?", + "idpMessage": "is already in the team.", + "formOwnerErrMsg": "There must always be at least one form owner", + "formOwnerConsoleErrMsg": "Cannot remove {userId} as they are the only remaining owner of this form.", + "insufficientPermissnMsg": "Insufficient permissions to manage team", + "getUserErrMsg": "Error getting form users: ", + "getRolesErrMsg": "Error getting list of roles: ", + "formOwnerRemovalWarning": "Cannot remove as they are the only remaining owner of this form.", + "removeUsersErrMsg": "An error occurred while attempting to delete the selected users", + "removeUserConsoleErrMsg": "Error deleting users from form {formId}: {error}", + "updUserRolesErrMsg": "An error occurred while attempting to update all user roles", + "updUserRolesConsoleErrMsg": "Error setting all user roles for form {formId}: {error}", + "setUserFormsErrMsg": "An error occurred while attempting to update roles for a user", + "setUserFormsConsoleErrMsg": "Error setting user roles for form {formId}: {error}" + }, + "floatButton": { + "publish": "Publish", + "manage": "Manage", + "redo": "Redo", + "undo": "Undo", + "preview": "Preview", + "bottom": "Bottom", + "top": "Top", + "actions": "Actions", + "collapse": "Collapse", + "saved": "Saved", + "save": "Save", + "saving": "Saving", + "notSaved": "Not Saved" + }, + "formViewer": { + "lateFormSubmissions": "The form submission period has expired! You can still create a late submission by clicking the button below.", + "createLateSubmission": "Create late submission", + "draftSaved": "Draft Saved", + "saving": "Saving", + "pleaseConfirm": "Please Confirm", + "submitFormWarningMsg": "Are you sure you wish to submit your form?", + "submit": "Submit", + "wantToSaveDraft": "Do you want to save the draft?", + "version": "Version: {version}", + "formScheduleExpireMessage": "Form submission is not available as the scheduled submission period has expired.", + "getUsersSubmissionsErrMsg": "An error occurred fetching the submission for this form", + "getUsersSubmissionsConsoleErrMsg": "Error loading form submission data {submissionId}: {error}", + "multiDraftUploadSuccess": "Your multiple draft upload has been successful!", + "readVersionErrMsg": "No schema in response. VersionId: {versionId}", + "readDraftErrMsg": "No schema in response. draftId: {draftId}", + "alertRouteMsg": "The form owner has not published the form, and it is not available for submissions.", + "fecthingFormErrMsg": "An error occurred fetching this form", + "fecthingFormConsoleErrMsg": "Error loading form schema {versionId}: {error}", + "savingDraftErrMsg": "An error occurred while saving a draft", + "savingDraftConsoleErrMsg": "Error saving draft. SubmissionId: {submissionId}. Error: {error}", + "submissionsPreviewAlert": "Submission disabled during form preview", + "submissionsSubmitErrMsg": "Error submitting the form: {errors}", + "sendSubmissionErrMsg": "Failed response from submission endpoint. Response code: {status}", + "errMsg": "An error occurred submitting this form", + "customEventAlert": "Custom button events not supported yet. Event Type: {event}", + "formLoading": "Please wait while the form is loading !!!", + "yes": "Yes", + "no": "No", + "failedResSubmissn": "Failed response from submission endpoint. Response code: {status}", + "errSubmittingForm": "An error occurred submitting this form", + "errorSavingFile": "Error saving files. Filename: {fileName}. Error: {error}", + "submittingDraftErrMsg": "An error occurred while saving a draft", + "submittingDraftConsErrMsg": "Error saving draft. SubmissionId: {submissionId}. Error: {error}", + "formDraftAccessErrMsg": "Requested submission is already submitted, redirecting to View page" + }, + "bCGovFooter": { + "home": "Home", + "about": "About gov.bc.ca", + "disclaimer": "Disclaimer", + "privacy": "Privacy", + "accessibility": "Accessibility", + "copyRight": "Copyright", + "contactUs": "Contact Us" + }, + "bCGovNavBar": { + "about": "About", + "myForms": "My Forms", + "createNewForm": "Create a New Form", + "help": "Help", + "feedback": "Feedback", + "admin": "Admin" + }, + "homePage": { + "title": "Create, publish forms, and receive submissions with the Common Hosted Forms Service.", + "subTitle": "All B.C. Government employees or contractors with an IDIR account can use our hosted version of Common Hosted Forms Service (CHEFS) to create forms.", + "takeATourOfChefs": "Take a tour of CHEFS to see it in action.", + "logInToGetStarted": "Log in to get started", + "loginToStart": "Log in with IDIR to get started", + "login": "Login", + "createFormLabel": "Create a Form", + "manageAccessTitle": "Manage access to your form", + "manageAccessSub1": "CHEFS allows you to create public forms, or you can manage access through IDIR or BCeID authentication.", + "manageAccessSub2": "You can also assign roles to your team to manage all of your submissions.", + "createCustomFormTitle": "Create custom forms with the CHEFS form builder", + "createCustomFormSub1": "With CHEFS, you can create secure forms with an intuitive drag-and-drop interface. You can add form components, re-arrange them, and drop them into different layouts configurations.", + "chefsHowToTitle": "CHEFS How-to Videos", + "chefsHowToSub": "Our Quickstart Guide will introduce you to some of the basic functions of CHEFS.", + "getStartedToChefs": "Get started using CHEFS", + "createOnlineTitle": "Create online forms to collect information from your clients and improve your workflows.", + "getStarted": "Get started" + }, + "baseStepper": { + "designForm": "Design Form", + "setUpForm": "Set up Form", + "manageForm": "Manage Form" + }, + "create": { + "formSettings": "Form Settings", + "disclaimer": "Disclaimer", + "disclaimerStmt": "I agree to the disclaimer and statement of responsibility for Form Designers", + "continue": "Continue", + "back": "Back", + "confirmPageNav": "Do you really want to leave this page? Changes you made will not be saved.", + "agreementErrMsg": "You must agree to the privacy disclaimer shown above." + }, + "addTeamMember": { + "cantFindChefsUsers": "Can't find someone? They may not have logged into CHEFS.
Kindly send them a link to CHEFS and ask them to log in.", + "cancel": "Cancel", + "add": "Add", + "mustSelectAUser": "You must select at least one role to add this user.", + "addNewMember": "Add a New Member", + "enterUsername": "Enter a name, email, or username", + "enterExactUsername": "Enter an exact email or username", + "BCeIDInputSearchMaxLen": "Search input for BCeID username/email must be greater than 6 characters.", + "BCeIDMustBeExact": "Email searches for BCeID must be exact.", + "errorGettingUsers": "Error getting users {error}" + }, + "baseFilter": { + "cancel": "Cancel", + "columnName": "Column Name", + "exampleText": "Example Text", + "exampleText2": "Example Text 2", + "filterPlaceholderTxt": "Filter Placeholder Text", + "filter": "Filter", + "value": "value", + "resetColumns": "Reset Columns" + }, + "formViewerActions": { + "viewMyDraftOrSubmissions": "View My Drafts/Submissions", + "saveAsADraft": "Save as a Draft", + "editThisDraft": "Edit this Draft", + "switchSingleSubmssn": "Switch to single submission", + "switchMultiSubmssn": "Switch to multiple submissions" + }, + "baseCopyToClipboard": { + "linkToClipboard": "Link copied to clipboard", + "copyToClipboard": "Copy to Clipboard", + "errCopyToClipboard": "Error attempting to copy to clipboard." + }, + "sucess": { + "sucessFormSubmissn": "Your form has been submitted successfully", + "keepRecord": "If you wish to keep a record of this submission, you can keep the following", + "confirmationId": "Confirmation ID" + }, + "bcGovAlertBanner": { + "defaultErrMsg": "Error: Something went wrong", + "error": "error" + }, + "store": { + "admin": { + "addFormOwnerRole": "Added the Owner role for this form to {fullName}", + "addRowError": "An error occurred while adding the role.", + "addRowConsoleErr": "Error adding user {userId} to form {formId}: {error}", + "apiKeyDelMsg": "The API Key for this form has been deleted.", + "errDeletingApiKey": "An error occurred while trying to delete the API Key.", + "consErrDeletingApiKey": "Error deleting API Key for form {formId}: {error}", + "fecthingFormsErrMsg": "An error occurred while fetching forms.", + "fecthingFormsConsErrMsg": "Error getting admin form data: {error}", + "fecthingFormErrMsg": "An error occurred while fetching this form.", + "fecthingFormConsErrMsg": "Error getting admin form {formId} data: {error}", + "fecthFormUserRolesErrMsg": "An error occurred while fetching form user roles.", + "fecthFormUserRolesConsErrMsg": "Error getting admin roles data: {error}", + "fecthApiDetailsErrMsg": "An error occurred while fetching this form's API details.", + "fecthApiDetailsConsErrMsg": "Error getting admin API details from form {formId} data: {error}", + "restoreFormErrMsg": "An error occurred while restoring this form.", + "restoreFormConsErrMsg": "Error restoring form {formId} data: {error}", + "getUsersErrMsg": "An error occurred while fetching users.", + "getUsersConsErrMsg": "Error getting admin users data: {error}", + "getUserErrMsg": "An error occurred while fetching this user.", + "getUserConsErrMsg": "Error getting admin user {userId} data: {error}", + "storingFCHelpInfoErrMsg": "An error occurred while storing form component help information", + "storingFCHelpInfoConsErrMsg": "Error getting storing form component help information: {error}", + "gettingFCImgUrlErrMsg": "An error occurred while getting image url", + "gettingFCImgUrlConsErrMsg": "Error getting image url: {error}", + "updatingFCStatusErrMsg": "An error occurred while updating publish status", + "updatingFCStatusConsErrMsg": "Error updating publish status: {error}", + "fecthingFormBuilderCompsErrMsg": "An error occurred while fetching form builder components", + "fecthingFormBuilderCompsConsErrMsg": "Error getting form builder components: {error}" + }, + "form": { + "fetchEmailTemplatesConsErrMsg": "Error loading email templates for {formId}: {error}", + "fetchEmailTemplatesErrMsg": "An error occurred fetching the email templates for this form", + "getCurrUserFormsErrMsg": "An error occurred while fetching your forms.", + "getCurrUserFormsConsErrMsg": "Error getting user data: {error}", + "getUserFormPermErrMsg": "An error occurred while fetching your user data for this form.", + "getUserFormPermConsErrMsg": "Error getting user data using formID {formId}: {error}", + "getUserFormRolesErrmsg": "An error occurred while fetching your user data for this form.", + "getUserFormRolesConsErrmsg": "Error getting user data using formID {formId}: {error}", + "updCurrUserFormPrefErrMsg": "An error occurred while saving your preferences for this form.", + "updCurrUserFormPrefConsErrMsg": "Error updating user form prefs using formID {formId}, and prefs {preferences}: {error}", + "getCurrUserFormPrefErrMsg": "An error occurred while fetching your preferences for this form.", + "getCurrUserFormPrefConsErrMsg": "Error getting user form prefs using formID {formId}: {error}", + "delCurrformNotiMsg": "Form {name} has been deleted successfully.", + "delCurrFormConsErMsg": "Error deleting form {id}: {error}", + "delDraftErrMsg": "An error occurred while deleting this draft.", + "delDraftConsErrMsg": "Error deleting {draftId}: {error}", + "fecthDraftErrMsg": "An error occurred while scanning for drafts for this form.", + "fecthDraftConsErrMsg": "Error getting drafts for form {formId}: {error}", + "fecthFormErrMsg": "An error occurred while fetching this form.", + "fecthFormConsErrMsg": "Error getting form {formId}: {error}", + "fetchFormFieldsErrMsg": "An error occurred while fetching the list of fields for this form.", + "fetchFormFieldsConsErrMsg": "Error getting form {formId}: {error}", + "publishDraftErrMsg": "An error occurred while publishing.", + "publishDraftConsErrMsg": "Error publishing {draftId}: {error}", + "toggleVersnPublConsErrMsg": "Error in toggleVersionPublish {versionId} {publish}: {error}", + "updateEmailTemplateConsErrMsg": "Error updating email templates for form {formId}: {error}", + "updateEmailTemplateErrMsg": "An error occurred while updating the email templates for this form.", + "updateFormErrMsg": "An error occurred while updating the settings for this form.", + "updateFormConsErrMsg": "Error updating form {id}: {error}", + "deleteSubmissionNotifyMsg": "Submission deleted successfully.", + "deleteSubmissionErrMsg": "An error occurred while deleting this submission.", + "deleteSubmissionConsErrMsg": "Error deleting submission {submissionId}: {error}", + "deleteSubmissionsNotifyMsg": "Submissions deleted successfully.", + "deleteSubmissionsErrMsg": "An error occurred while deleting the selected submissions.", + "deleteSubmissionsConsErrMsg": "Error deleting submissions: {error}", + "restoreSubmissionsNotiMsg": "Submissions restored successfully.", + "restoreSubmissionsErrMsg": "An error occurred while restoring this submission.", + "restoreSubmissionsConsErrMsg": "Error restoring submissions: {error}", + "restoreSubmissionNotiMsg": "Submission restored successfully.", + "restoreSubmissionErrMsg": "An error occurred while restoring this submission.", + "restoreSubmissionConsErrMsg": "Error restoring submission {submissionId}: {error}", + "fecthSubmissnUsersErrMsg": "An error occurred while fetching the recipient email for this submission.", + "fecthSubmissnUsersConsErrMsg": "Error getting recipient email for submission {formSubmissionId}: {error}", + "fetchSubmissnErrMsg": "An error occurred while fetching this submission.", + "fetchSubmissnConsErrMsg": "Error getting submission {submissionId}: {error}", + "fetchFormCSVExptFieldsErrMsg": "An error occurred while fetching the list of fields for this form.", + "fetchFormCSVExptFieldsConsErrMsg": "Error getting form {formId}: {error}", + "fetchSubmissnsErrMsg": "An error occurred while fetching submissions for this form.", + "fetchSubmissnsConsErrMsg": "Error getting submissions for {formId}: {error}", + "fetchVersionErrMsg": "An error occurred while fetching this form.", + "fetchVersionConsErrMsg": "Error getting version {versionId} for form {formId}: {error}", + "deleteApiKeyNotifyMsg": "The API Key for this form has been deleted.", + "deleteApiKeyErrMsg": "An error occurred while trying to delete the API Key.", + "deleteApiKeyConsErrMsg": "Error deleting API Key for form {formId}: {error}", + "generateApiKeyNotifyMsg": "An API Key for this form has been created.", + "generateApiKeyErrMsg": "An error occurred while trying to generate an API Key.", + "generateApiKeyConsErrMsg": "Error generating API Key for form {formId}: {error}", + "readApiKeyErrMsg": "An error occurred while trying to fetch the API Key.", + "readApiKeyConsErrMsg": "Error getting API Key for form {formId}: {error}.", + "getFCPHImageUrlErrMsg": "An error occurred while getting image url", + "getFCPHImageUrlConsErrMsg": "Error getting image url: {error}", + "listFCPHErrMsg": "An error occurred while fetching form builder components", + "listFCPHConsErrMsg": "Error getting form builder components: {error}", + "downloadFileErrMsg": "An error occurred while downloading file", + "downloadFileConsErrMsg": "Error downloading file: error", + "readSubscriptionSettingsErrMsg": "An error occurred while trying to fetch the subscription settings.", + "readSubscriptionSettingsConsErrMsg": "Error getting subscription settings for form {formId}: {error}.", + "saveSubscriptionSettingsNotifyMsg": "Subscription settings for this form has been saved.", + "saveSubscriptionSettingsErrMsg": "An error occurred while trying to save subscription settings.", + "saveSubscriptionSettingsConsErrMsg": "Error saving subscription settings for form {formId}: {error}" + } + }, + "permissionUtils": { + "formNotAvailable": "The form is currently unavailable. This may be due to an incorrect link, or the form may have been deleted by its owner.", + "missingFormIdAndSubmssId": "Options missing both formId and submissionId", + "loadingFormErrMsg": "An error occurred while loading this form.", + "loadingForm": "Error while loading {options}: {error}", + "idpHintMsg": "This form requires {idpHint} authentication. Please re-login and try again.", + "formIdpMissMatch": "Form IDP mismatch. Form requires {idpHint} but user has {userIdp}." + }, + "download": { + "chefsDataExport": "CHEFS Data Export", + "preparingForDownloading": "Preparing for download...", + "downloadInfoA": "If your file does not automatically download", + "downloadInfoB": "click here to try again" + }, + "history": { + "submissnHistory": "Your Submission History (TBD)" + }, + "error": { + "logout": "Logout", + "somethingWentWrong": "Error: Something went wrong... :(" + }, + "login": { + "authenticateWith": "Authenticate with:", + "alreadyLoggedIn": "Already logged in", + "home": "Home", + "about": "About" + }, + "notFound": { + "about": "About", + "pageNotFound": "404: Page not found. :(" + }, + "admin": { + "root": { + "admin": "Admin" + }, + "form": { + "administerForm": "Administer Form" + }, + "user": { + "administerUser": "Administer User" + } + }, + "user": { + "root": { + "myForms": "MY FORMS", + "history": "HISTORY", + "user": "User" + } + }, + "test": { + "customError": "This is a custom error message for testing." + } +} diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/en/index.js b/frontend/app/frontend/src/internationalization/trans/chefs/en/index.js new file mode 100644 index 0000000..030e22d --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/en/index.js @@ -0,0 +1,4 @@ +import en from '~/internationalization/trans/chefs/en/en.json'; +export default { + trans: en, +}; diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/es/es.json b/frontend/app/frontend/src/internationalization/trans/chefs/es/es.json new file mode 100644 index 0000000..2503d9f --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/es/es.json @@ -0,0 +1,995 @@ +{ + "date": { + "date": "aaaa-mm-dd" + }, + "emailManagement": { + "emailManagement": "Gestión de correo electrónico", + "manageForm": "Administrar formulario", + "submissionConfirmation": "Confirmación de Envío" + }, + "emailTemplate": { + "body": "Cuerpo", + "save": "Ahorrar", + "saveEmailTemplateConsoleErrMsg": "Error al actualizar la plantilla de correo electrónico para el formulario {formId}: {error}", + "saveEmailTemplateErrMsg": "Se produjo un error al intentar actualizar la plantilla de correo electrónico.", + "subject": "Sujeto", + "title": "Título", + "validBodyRequired": "Por favor ingrese un cuerpo para el correo electrónico", + "validSubjectRequired": "Por favor ingrese una línea de Asunto para el correo electrónico", + "validTitleRequired": "Por favor ingrese un Título para el correo electrónico" + }, + "formsTable": { + "myForms": "Mis formularios", + "createNewForm": "Crear un nuevo formulario", + "search": "Buscar", + "manage": "Administrar", + "submissions": "Presentaciones", + "formTitle": "Título del formulario", + "viewForm": "Ver formulario", + "description": "descripción", + "Description": "Descripción:", + "action": "Comportamiento", + "loadingText": "Cargando por favor espere" + }, + "manageLayout": { + "manageForm": "Administrar formulario" + }, + "preview": { + "preview": "Avance", + "previewToolTip": "Esto muestra una vista previa del diseño y el comportamiento de la versión del formulario tal como lo verán los remitentes. No puede enviar el formulario desde esta página." + }, + "shareForm": { + "shareForm": "Compartir formulario", + "shareLink": "Compartir enlace", + "copyQRCode": "Copie el enlace a continuación o descargue el código QR.", + "warningMessage": "No hay una versión publicada del formulario en este momento. No se podrá acceder al siguiente enlace hasta que se publique una versión.", + "openThisForm": "Abre este formulario", + "downloadQRCode": "Descargar Código QR", + "close": "Cerca", + "copyURLToClipboard": "Copiar URL al portapapeles" + }, + "manageFormActions": { + "emailManagement": "Gestión de correo electrónico", + "viewSubmissions": "Ver envíos", + "teamManagement": "Gestión de equipos", + "deleteForm": "Eliminar formulario", + "confirmDeletion": "Confirmar la eliminación", + "deleteMessageA": "¿Está seguro de que desea eliminar", + "deleteMessageB": "Este formulario ya no será accesible.", + "delete": "Borrar" + }, + "manageForm": { + "formSettings": "Configuración de formulario", + "apiKey": "Clave API", + "updated": "Actualizado", + "created": "Creado", + "formDesignHistory": "Historial de diseño de formularios", + "totalVersions": "Versiones totales", + "status": "Estado", + "update": "Actualizar", + "cancel": "Cancelar", + "eventSubscription": "Suscripción a eventos" + }, + "formSettings": { + "pressToAddMultiEmail": "Presiona enter o , o espacio para agregar varias direcciones de correo electrónico", + "allowMultiDraft": "Permitir la carga de varios borradores", + "formTitle": "Título del formulario", + "formDescription": "Descripción del formulario", + "formAccess": "Acceso al formulario", + "info": "Si utilizará este formulario para recopilar información del público en general sobre temas que son de interés general para el público, debe comunicarse con la GCPE para que su participación pueda incluirse en", + "important": "IMPORTANTE", + "idimNotifyA": "Debe notificar al equipo de Gestión de Información de Identidad (IDIM) por correo electrónico", + "idimNotifyB": "su intención de aprovechar BCeID para verificar las identidades de los remitentes de su formulario.", + "referenceGuideA": "Por favor, consulte nuestro", + "referenceGuideB": "guía del usuario", + "referenceGuideC": "para más detalles", + "specificTeamMembers": "Miembros del equipo específicos", + "formFunctionality": "Funcionalidad de formulario", + "formSubmissinScheduleMsg": "El programa de envío de formularios estará disponible en la configuración del formulario después de que se publique el formulario.", + "formSubmissionsSchedule": "Calendario de envío de formularios", + "experimental": "Experimental", + "learnMore": "Aprende más", + "afterSubmission": "Después del envío", + "submissionConfirmation": "Mostrar los detalles de confirmación del envío", + "theConfirmationID": "la identificación de confirmación", + "infoB": "la opción para que el usuario se envíe por correo electrónico una confirmación de envío", + "loginRequired": "Necesario iniciar sesión", + "canSaveAndEditDraftLabel": "Los remitentes pueden guardar y editar borradores", + "canUpdateStatusAsReviewer": "Los revisores pueden actualizar el estado de este formulario (es decir, enviado, asignado, completado)", + "submitterCanCopyExistingSubmissn": "Los remitentes pueden copiar un envío existente", + "submissionConfirmationToolTip": "Al seleccionar esta opción, se controla lo que verá el usuario que envía este formulario cuando se envíe correctamente.
Si está marcada, se mostrará", + "emailNotificatnToTeam": "Enviar a mi equipo un correo electrónico de notificación", + "emailNotificatnToTeamToolTip": "Envíe una notificación a su dirección de correo electrónico especificada cuando cualquier usuario envíe este formulario", + "notificationEmailAddrs": "Direcciones de correo electrónico de notificación", + "addMoreValidEmailAddrs": "Agregue una o más direcciones de correo electrónico válidas", + "formScheduleSettings": "Configuración de programación de formularios", + "opensubmissions": "Envíos abiertos", + "submissionsDeadline": "¿Cuánto tiempo desea recibir las presentaciones?", + "keepSubmissnOpenTilUnplished": "Mantener abierto hasta que no se publique manualmente", + "submissionsClosingDate": "Programar una fecha de cierre", + "submissionPeriod": "Configurar el período de presentación", + "closeSubmissions": "Cerrar envíos", + "keepOpenFor": "Mantener abierto para", + "period": "Período", + "allowLateSubmissions": "Permitir envíos tardíos", + "allowLateSubmissionsInfoTip": "Si está marcado, los remitentes podrán enviar datos después de la fecha de cierre.", + "afterCloseDateFor": "Después de la fecha de cierre de", + "repeatPeriod": "Período de repetición", + "every": "Cada", + "repeatUntil": "Repetir hasta", + "summary": "Resumen", + "submissionsOpenDateRange": "Este formulario estará abierto para envíos de", + "to": "a", + "scheduleRepetition": "El horario se repetirá cada", + "allowLateSubmissnInterval": "permitir envíos tardíos para", + "until": "hasta", + "datesOfSubmissnInfo": "Según la configuración, estas son las fechas disponibles de envío:", + "formOpenInterval": "Este formulario estará abierto para envíos de", + "allowDateSubmissionDate": "con permitir la presentación tardía hasta", + "customClosingMessage": "Establecer mensaje de cierre personalizado", + "customClosingMessageToolTip": "Le permite agregar un mensaje personalizado para sus usuarios cuando visitan un formulario cerrado.", + "closingMessage": "Mensaje de cierre", + "sendReminderEmail": "ENVIAR correo electrónico de recordatorio", + "autoReminderNotificatn": "Habilitar notificación de recordatorio automático", + "autoReminderNotificatnToolTip": "Envíe correos electrónicos de recordatorio con el enlace del formulario durante el período de envío.", + "selectLoginType": "Seleccione 1 tipo de inicio de sesión", + "formDescriptnMaxChars": "La descripción del formulario debe tener 255 caracteres o menos", + "formTitlemaxChars": "El título del formulario debe tener 255 caracteres o menos", + "formTitleReq": "Se requiere el título del formulario", + "atLeastOneEmailReq": "Por favor, introduzca al menos 1 dirección de correo electrónico", + "validEmailRequired": "Por favor, introduzca todas las direcciones de correo electrónico válidas", + "fieldRequired": "Este campo es obligatorio.", + "correctDateFormat": "La fecha debe estar en el formato correcto. es decir. aaaa-mm-dd", + "dateDiffMsg": "La fecha de cierre de la presentación debe ser posterior a la fecha de apertura de la presentación.", + "valueMustBeNumber": "El valor debe ser un número. es decir. 1,2,3,5,99", + "selectAnOptions": "Seleccione al menos 1 opción", + "validInterval": "Este debería ser un intervalo válido.", + "fieldRequiredAndInterval": "Este campo es obligatorio y debe ser un intervalo.", + "dateGrtOpenSubmissnDate": "Repetir hasta la fecha debe ser mayor que la fecha de presentación abierta", + "public": "Público (anónimo)", + "allowEventSubscription": "Permitir suscripción a eventos", + "eventSubscription": "Suscripción a eventos", + "validEndpointRequired": "Ingrese un punto final válido que comience con https://", + "validBearerTokenRequired": "Introduzca un ejemplo de token de portador válido: 89abddfb-2cff-4fda-83e6-13221f0c3d4f" + }, + "subscribeEvent": { + "eventType": "Tipo de evento", + "endpointUrl": "URL de punto final", + "eventSubmission": "Envío", + "eventAssignment": "Asignación", + "eventStatusChange": "Cambio de estado", + "endpointToken": "Token de punto final", + "urlPlaceholder": "https://endpoint.gov.bc.ca/api/v1/", + "save": "Ahorrar", + "text": "texto", + "password": "contraseña", + "hideSecret": "Ocultar secreto", + "showSecret": "Mostrar secreto", + "key": "Llave", + "saveSettingsErrMsg": "Se produjo un error al intentar actualizar la configuración de este formulario.", + "updateSettingsConsoleErrMsg": "Error al actualizar la configuración del formulario {formId}: {error}" + }, + "apiKey": { + "disclaimer": "Descargo de responsabilidad", + "infoA": "Asegúrese de que el secreto de su clave de API esté almacenado en una ubicación segura (es decir, un almacén de claves).", + "infoB": "Su clave API otorga acceso sin restricciones a su formulario. No proporcione su clave API a nadie.", + "infoC": "La clave API SÓLO debe usarse para interacciones automatizadas del sistema. No utilice su clave API para el acceso basado en usuarios", + "deleteKey": "Eliminar clave", + "apiKey": "Clave API", + "hideSecret": "Ocultar secreto", + "showSecret": "Mostrar secreto", + "sCTC": "Secreto copiado al portapapeles", + "cSTC": "Copiar secreto al portapapeles", + "key": "Llave", + "confirmDeletion": "Confirmar la eliminación", + "deleteMsg": "¿Está seguro de que desea eliminar su clave API?", + "delete": "Borrar", + "confirmKeyGen": "Confirmar generación de claves", + "createAPIKey": "¿Crear una clave API para este formulario?
Asegúrese de seguir el Descargo de responsabilidad en esta página.", + "regenerateAPIKey": "¿Regenerar la clave API?
Si continúa, se eliminará su acceso a la clave de API actual .", + "formOwnerKeyAcess": "Debe ser el propietario del formulario para administrar las claves API.", + "regenerate": "Regenerado", + "generate": "Generar", + "secret": "Secreto" + }, + "manageVersions": { + "important": "¡IMPORTANTE!", + "infoA": "Si no hay versiones publicadas, los usuarios no pueden acceder a este formulario hasta que haya una versión publicada asignada. Una vez que se publica una versión, esa versión ya no se puede editar. Debe crear una nueva versión basada en una de las versiones anteriores del formulario para continuar con la edición.", + "infoB": "Nota: Solo se puede publicar una versión.", + "version": "Versión", + "draft": "Borrador", + "clickToPreview": "Haga clic para obtener una vista previa", + "editVersion": "Editar versión", + "exportDesign": "Diseño de exportación", + "infoC": "Publique o elimine su última versión preliminar antes de comenzar una nueva versión.", + "deleteVersion": "Eliminar versión", + "draftAlreadyExists": "El borrador ya existe", + "infoD": "Edite, publique o elimine el borrador existente antes de comenzar un nuevo borrador.", + "publishVersion": "Publicar versión", + "unpublishVersion": "Anular publicación de la versión", + "infoE": "Si cancela la publicación de este formulario, quedará fuera de circulación hasta que se publique una versión nuevamente.", + "confirmDeletion": "Confirmar la eliminación", + "infoF": "¿Está seguro de que desea eliminar esta versión?", + "delete": "Borrar", + "status": "Estado", + "dateCreated": "fecha de creacion", + "createdBy": "Creado por", + "actions": "Comportamiento", + "published": "Publicado", + "unpublished": "Inédito", + "useVersionInfo": "Utilice la versión {version} como base para una nueva versión", + "publishingVersionInfo": "Esto hará que la versión {version} de su formulario esté activa." + }, + "addOwner": { + "infoA": "Esto solo debe hacerse en caso de que el propietario actual del formulario ya no esté activo o no esté en contacto en un evento prioritario. De lo contrario, haga que el propietario actual o un administrador de equipo para el formulario lo haga por sí mismo.", + "hint": "Para encontrar el ID de usuario necesario, puede ir a la pestaña 'USUARIOS' en el portal de administración y buscarlos.", + "addowner": "Agregar propietario", + "label": "ID de usuario (guid)" + }, + "adminFormsTable": { + "showDeletedForms": "Mostrar formularios eliminados", + "search": "Buscar", + "loadingText": "cargando texto", + "noDataText": "No hay formularios en su sistema", + "admin": "Administración", + "launch": "Lanzamiento", + "formTitle": "Título del formulario", + "created": "Creado", + "deleted": "Eliminado", + "actions": "Comportamiento", + "delete": "Borrar" + }, + "administerForm": { + "deleted": "BORRADO", + "restoreForm": "Restaurar este formulario", + "formDetails": "Detalles del formulario", + "apiKeyDetails": "Detalles de la clave API", + "deleteApiKey": "Eliminar clave API", + "formUsers": "Usuarios de formulario", + "formVersions": "Versiones de formulario", + "assignANewOwner": "Asignar un nuevo propietario", + "restoring": "restaurando", + "restore": "Restaurar", + "toActiveState": "al estado activo", + "confirmDeletion": "Confirmar la eliminación", + "confirmDeletionMsg": "¿Está seguro de que desea eliminar esta clave de API?", + "delete": "Borrar", + "confirmRestore": "Confirmar restauración" + }, + "administerUser": { + "userDetails": "Detalles de usuario", + "openSSOConsole": "Abrir consola SSO" + }, + "adminPage": { + "forms": "Formularios", + "users": "Usuarios", + "developer": "Desarrollador", + "infoLinks": "Enlaces de información", + "metrics": "Métrica" + }, + "adminUsersTable": { + "search": "Buscar", + "loadingText": "Cargando por favor espere", + "admin": "Administración", + "fullName": "Nombre completo", + "userID": "Identificación de usuario", + "created": "Creado", + "actions": "Comportamiento" + }, + "adminVersions": { + "exportDesign": "Diseño de exportación", + "versions": "Versiones", + "status": "Estado", + "created": "Creado", + "lastUpdated": "Última actualización", + "actions": "Comportamiento", + "published": "Publicado", + "unpublished": "Inédito", + "version": "Versión {versionNo}", + "notificationMsg": "Ocurrió un error al cargar el diseño del formulario." + }, + "developer": { + "user": "Usuario", + "name": "Nombre", + "userName": "Nombre de usuario", + "JWTContents": "Contenido JWT", + "JWTContentsSBTxt": "JWT Contenido copiado al portapapeles", + "JWTContentsTTTxt": "Copie el contenido de JWT al portapapeles", + "JWTToken": "Ficha JWT", + "JWTTokenSBTxt": "Token JWT copiado al portapapeles", + "JWTTokenTTTxt": "Copie el token JWT al portapapeles", + "chefsAPI": "API DE CHEFS", + "RBACSBTxt": "Respuesta RBAC copiada al portapapeles", + "RBACTTTxt": "Copie la respuesta de RBAC al portapapeles", + "notificationMsg": "No se pudo obtener el usuario de RBAC, consulte la consola", + "notificationConsErr": "Error al obtener el usuario de RBAC" + }, + "baseAuthButton": { + "logout": "Cerrar sesión", + "login": "Acceso" + }, + "baseDialog": { + "defaultText": "texto predeterminado", + "ok": "DE ACUERDO", + "continue": "Continuar", + "cancel": "Cancelar", + "custom": "Costumbre" + }, + "baseSecure": { + "about": "Acerca de", + "loginInfo": "Debe iniciar sesión para utilizar esta función.", + "login": "Acceso", + "401NotAuthorized": "401: no autorizado. :", + "401ErrorMsg": "Su cuenta no está configurada correctamente.
Por favor contactar", + "403Forbidden": "403: Prohibido. :", + "403ErrorMsg": "Esta página requiere autenticación {idp}.", + "401UnAuthorized": "401: No autorizado. :", + "401UnAuthorizedErrMsg": "Usted no tiene permiso para acceder a esta página." + }, + "formDesigner": { + "formDesign": "Diseño de formularios", + "exportDesign": "Diseño de exportación", + "importDesign": "Diseño de importación", + "important": "IMPORTANTE", + "formDesignInfoA": "Utilice el botón GUARDAR DISEÑO cuando haya terminado de crear este formulario.", + "formDesignInfoB": "El botón ENVIAR se proporciona para que su usuario envíe este formulario y se activará después de guardarlo.", + "formLoadErrMsg": "Ocurrió un error al cargar el diseño del formulario.", + "formLoadConsoleErrMsg": "Error al cargar el formulario {formId} esquema (versión: {versionId} borrador: {draftId}): {error}", + "formSchemaImportErrMsg": "Ocurrió un error al importar el esquema del formulario.", + "formSchemaImportConsoleErrMsg": "Error al importar el esquema del formulario: {error}", + "formDesignSaveErrMsg": "Se produjo un error al intentar guardar este diseño de formulario. Si necesita actualizar o salir para volver a intentarlo más tarde, puede exportar el diseño existente en la página para guardarlo más tarde.", + "formDesignSaveConsoleErrMsg": "Error al actualizar o crear el formulario (FormID: {formId}, versionId: {versionId}, draftId: {draftId}) Error: {error}", + "collapse": "Colapsar", + "actions": "Comportamiento", + "version": "Versión", + "save": "Ahorrar", + "saving": "Ahorro", + "notSaved": "No guardado", + "fieldnameError": "NO PUEDES usar la palabra clave `form` como nombre de campo {label}" + }, + "formViewerMultiUpload": { + "important": "IMPORTANTE", + "uploadSucessMsg": "Para garantizar la carga exitosa de varios borradores, descargue y utilice la plantilla provista.", + "confirmDownload": "¿Quieres descargarlo?", + "jsonFileUpload": "Seleccione el archivo JSON para cargar", + "dragNDrop": "o arrástralo y suéltalo aquí", + "chooseAFile": "Escoge un archivo", + "downloadDraftSubmns": "Descargue el borrador del informe de presentación y asegúrese de que los datos se hayan ingresado correctamente.", + "downloadReport": "Descargar informe", + "doYouWantToDownload": "¿Quieres descargarlo?", + "uploadNewFile": "Subir archivo nuevo", + "uploadMultipleFileErr": "Lo sentimos, solo puedes subir un archivo.", + "dragMultipleFileErr": "Lo sentimos, solo puedes arrastrar un archivo", + "fileFormatErr": "Lo sentimos, solo aceptamos archivos json", + "fileSizeErr": "El tamaño máximo de archivo permitido es de 5 MB", + "parseJsonErr": "No podemos analizar los datos json del archivo.", + "jsonObjNotArray": "Formato de archivo json incorrecto", + "jsonObjNotArrayConsErr": "Ocurrió un error inesperado.", + "jsonArrayEmpty": "Este archivo json está vacío.", + "errorWhileValidate": "Hay algo mal con este archivo", + "errWhileCheckValidity": "Hay algo mal con este archivo", + "errAfterValidate": "Se encontraron algunos errores, consulte a continuación para obtener más información.", + "fileIsEmpty": "este archivo está vacío.", + "download": "Descargar" + }, + "formDisclaimer": { + "disclaimerAndStatement": "Descargo de responsabilidad y declaración de responsabilidad para los diseñadores de formularios:", + "privacyLaw": "Es su responsabilidad cumplir con las leyes de privacidad que rigen la recopilación, el uso y la divulgación de información de identificación personal.", + "disclosure": "El acceso a esta herramienta de diseño de formularios no otorga inherentemente permiso para recopilar, usar o divulgar ninguna información de identificación personal.", + "consent": "Es su responsabilidad obtener el consentimiento para recopilar información según lo exige la ley.", + "formIntention": "Antes de publicar o distribuir su formulario, debe discutir la intención del formulario con su", + "privacyOfficer": "Oficial de Privacidad del Ministerio", + "assement": "y para completar las evaluaciones según sea necesario." + }, + "requestReceipt": { + "emailPriority": "Prioridad de correo electrónico", + "emailReceipt": "Enviar por correo electrónico un recibo de este envío", + "high": "Alta", + "low": "Baja", + "normal": "Normal", + "send": "ENVIAR", + "sendToEmailAddress": "Enviar a dirección de correo electrónico", + "emailSent": "Se ha enviado un correo electrónico a {to}.", + "sendingEmailErrMsg": "Ocurrió un error al intentar enviar su correo electrónico.", + "sendingEmailConsErrMsg": "Error de confirmación por correo electrónico a {to}: {error}", + "emailRequired": "Correo electrónico es requerido" + }, + "submissionsTable": { + "noMatchingRecordText": "No se encontraron registros coincidentes", + "submissions": "Presentaciones", + "submissionsTable": "Tabla de envíos", + "selectColumns": "Seleccionar columnas", + "manageForm": "Administrar formulario", + "submissionsToFiles": "Exportar envíos a archivos", + "showDeletedSubmissions": "Mostrar envíos eliminados", + "showMySubmissions": "mostrar mis envíos", + "search": "Buscar", + "loadingText": "Cargando por favor espere", + "noDataText": "No hay envíos para este formulario", + "delSelectedSubmissions": "Eliminar envíos seleccionados", + "resSelectedSubmissions": "Restaurar envíos seleccionados", + "yes": "SÍ", + "no": "NO", + "viewSubmission": "Ver envío", + "deleteSubmission": "Eliminar envío", + "restore": "Restaurar", + "confirmDeletion": "Confirmar la eliminación", + "delete": "Borrar", + "confirmRestoration": "Confirmar restauración", + "searchSubmissionFields": "Buscar campos de envío", + "save": "Ahorrar", + "searchTitle": "Busque y seleccione columnas para mostrar debajo de su tablero", + "status": "Estado", + "submitter": "Remitente", + "submissionDate": "Día de entrega", + "event": "evento", + "view": "Vista", + "lateSubmission": "Envío tardío", + "confirmationID": "Identificación de confirmación", + "multiDelWarning": "¿Está seguro de que desea eliminar los envíos seleccionados?", + "singleDelWarning": "¿Está seguro de que desea eliminar este envío?", + "multiRestoreWarning": "¿Está seguro de que desea restaurar estos envíos?", + "singleRestoreWarning": "¿Está seguro de que desea restaurar este envío?" + }, + "auditHistory": { + "viewEditHistory": "Ver historial de edición", + "editHistory": "Editar historial", + "auditLogMsg": "Este es un registro de auditoría de quién ha realizado cambios en este envío después del envío original.", + "loadingText": "Cargando por favor espere", + "close": "Cerca", + "userName": "Nombre de usuario", + "date": "Fecha", + "errorMsg": "Se produjo un error al intentar recuperar el historial.", + "consoleErrMsg": "Error al obtener el historial de auditoría de" + }, + "deleteSubmission": { + "deleteThis": "Borrar esto", + "draft": "Borrador", + "submission": "Envío", + "confirmDeletion": "Confirmar la eliminación", + "deleteWarning": "¿Estás seguro de que deseas eliminar esto?", + "drafts": "borrador", + "formSubmission": "envío de formulario", + "delete": "Borrar" + }, + "manageSubmissionUsers": { + "manageTeamMembers": "Administrar miembros del equipo", + "add": "Agregar", + "draftFormInvite": "Solo puede invitar y administrar miembros del equipo mientras este formulario es un borrador", + "submissionTeamMembers": "Miembros del equipo para este envío", + "actions": "Comportamiento", + "close": "Cerca", + "remove": "Eliminar", + "userNotFoundErrMsg": "¿No puedes encontrar a alguien? Es posible que no hayan iniciado sesión en CHEFS.
Envíeles un enlace a CHEFS y pídales que inicien sesión.", + "name": "Nombre", + "username": "Nombre de usuario", + "email": "Correo electrónico", + "removeUserWarningMsg1": "¿Está seguro de que desea eliminar", + "removeUserWarningMsg2": "Ya no tendrán permisos para este envío.", + "userExistInListMsg": "El usuario {username} ya está en la lista de miembros del equipo.", + "getSubmissionUsersErr": "Se produjo un error al intentar obtener usuarios para este envío.", + "getSubmissionUsersConsoleErr": "Error al obtener usuarios para {submissionId}: {error}", + "sentInviteEmailTo": "Enviado correo electrónico de invitación a", + "sentUninvitedEmailTo": "Enviado correo electrónico no invitado a", + "updateUserErrMsg": "Se produjo un error al intentar actualizar los usuarios para este envío.", + "updateUserConsoleErrMsg": "Error al establecer los permisos de usuario. Sub: {submissionId} Usuario: {userId} Error: {error}", + "searchInputLength": "La entrada de búsqueda para el nombre de usuario/correo electrónico de BCeID debe tener más de 6 caracteres.", + "exactBCEIDSearch": "Las búsquedas de correo electrónico para BCeID deben ser exactas.", + "getUsersErrMsg": "Error al obtener usuarios: {error}", + "exactEmailOrUsername": "Ingrese un correo electrónico o nombre de usuario exacto.", + "requiredFiled": "Ingrese un nombre, correo electrónico o nombre de usuario" + }, + "mySubmissionsActions": { + "viewThisSubmission": "Ver este envío", + "copyThisSubmission": "Copiar este envío", + "editThisDraft": "Editar este borrador" + }, + "mySubmissionsTable": { + "noMatchingRecordText": "No se encontraron registros coincidentes", + "previousSubmissions": "Envíos anteriores", + "selectColumns": "Seleccionar columnas", + "createNewSubmission": "Crear una nueva presentación", + "search": "Buscar", + "loadingText": "Cargando por favor espere", + "noDataText": "No tienes envíos", + "searchSubmissionFields": "Buscar campos de envío", + "save": "Ahorrar", + "filterTitle": "Busque y seleccione columnas para mostrar debajo de su tablero", + "confirmationId": "Identificación de confirmación", + "actions": "comportamiento", + "createdBy": "Creado por", + "statusUpdatedBy": "Estado actualizado por", + "status": "Estado", + "submissionDate": "Día de entrega", + "draftUpdatedBy": "Borrador actualizado por", + "draftLastEdited": "Borrador editado por última vez", + "createLateSubmissn": "Crear envío tardío", + "formLoading": "¡Por favor espere mientras se carga el formulario!", + "pleaseConfirm": "Por favor confirmar", + "wantToSaveDraft": "¿Quieres guardar el borrador?", + "yes": "Sí", + "no": "No", + "multiDraftUploadSuccess": "¡Tu carga de múltiples borradores ha sido exitosa!", + "failedResSubmissn": "Respuesta fallida desde el punto final de envío. Código de respuesta: {status}", + "errSubmittingForm": "Ocurrió un error al enviar este formulario", + "errorSavingFile": "Error al guardar archivos. Nombre de archivo: {fileName}. Error: {error}", + "submittingDraftErrMsg": "Se produjo un error al guardar un borrador", + "submittingDraftConsErrMsg": "Error al guardar el borrador. Id de envío: {submissionId}. Error: {error}" + }, + "notesPanel": { + "addNewNote": "Agregar nueva nota", + "cancel": "Cancelar", + "addNote": "AÑADIR LA NOTA", + "noResponseErr": "No hay datos de respuesta de la API al enviar el formulario", + "errorMesg": "Ocurrió un error al intentar agregar la nota.", + "consoleErrMsg": "Error al agregar nota:", + "fetchErrMsg": "Se produjo un error al intentar obtener notas para este envío.", + "fetchConsoleErrMsg": "Error al agregar nota:", + "notes": "notas", + "note": "Nota", + "maxChars": "4000 caracteres como máximo" + }, + "statusPanel": { + "currentStatus": "Estado actual:", + "assignedTo": "Asignado a:", + "assignOrUpdateStatus": "Asignar o actualizar estado", + "display": "mostrar", + "statusIsRequired": "Se requiere estado", + "assignTo": "Asignar a", + "noDataText": "No se encontraron revisores de formularios con la búsqueda. Agregue revisores de formularios en la página Administrar.", + "assigneeIsRequired": "Se requiere cesionario", + "assignToMe": "ASIGNARME", + "recipientEmail": "Receptor de E-mail", + "attachCommentToEmail": "Adjuntar comentario al correo electrónico", + "emailComment": "Comentario de correo electrónico", + "maxChars": "4000 caracteres como máximo", + "viewHistory": "VER HISTORIAL", + "statusHistory": "Historial de estado", + "close": "CERCA", + "addNoteNoReponserErr": "No hay datos de respuesta de la API al enviar la nota para la actualización de estado", + "addNoteConsoleErrMsg": "Error al actualizar el estado: {error}", + "addNoteErrMsg": "Ocurrió un error al intentar actualizar el estado", + "updtSubmissionsStatusErr": "No hay datos de respuesta de la API al enviar el formulario de actualización de estado", + "noStatus": "Sin Estado", + "noStatusesFound": "No se encontraron estados", + "statusCodesErr": "error al encontrar códigos de estado", + "notifyErrorCode": "Se produjo un error al obtener el estado de este envío.", + "notifyConsoleErrorCode": "Error al obtener estados:", + "fetchSubmissionUsersErr": "Se produjo un error al intentar obtener los correos electrónicos de los destinatarios para este envío.", + "fetchSubmissionUsersConsErr": "Error al obtener los correos electrónicos de los destinatarios para", + "assignSubmissnToFormReviewer": "Los envíos se pueden asignar a revisores de formularios.
Para agregar más miembros del equipo como revisores de formularios, vaya a la página Administrar de este formulario.", + "update": "ACTUALIZAR", + "revise": "REVISAR", + "complete": "COMPLETO", + "assign": "ASIGNAR" + }, + "statusTable": { + "loadingText": "Cargando por favor espere", + "status": "Estado", + "dateStatusChanged": "Fecha de cambio de estado", + "assignee": "Cesionario", + "updatedBy": "Actualizado por", + "getSubmissionStatusErr": "Se produjo un error al intentar obtener estados.", + "getSubmissionStatusConsErr": "Error al agregar nota:" + }, + "exportSubmissions": { + "exportSubmissionsToFile": "Exportar envíos a archivo", + "viewSubmissions": "Ver envíos", + "fileType": "Tipo de archivo", + "json": "JSON", + "csv": "CSV", + "formVersion": "Versión de formulario", + "versionIsRequired": "Se requiere versión.", + "dataFields": "Campos de información", + "searchFields": "Campos de búsqueda", + "selectedForExports": "seleccionado para exportar", + "submissionDate": "Día de entrega", + "all": "Todo", + "selectDateRange": "Seleccionar rango de fechas", + "SelectdateRange": "Seleccionar rango de fechas", + "from": "De", + "to": "A", + "CSVFormat": "Formato CSV", + "multiRowPerSubmissionA": "1 - Múltiples filas por envío con espacios de sangría", + "multiRowPerSubmissionB": "2 - Múltiples filas por envío", + "singleRowPerSubmission": "3 - Fila única por presentación", + "unformatted": "4 - Sin formato", + "fileNameAndType": "Nombre y tipo de archivo", + "export": "Exportar", + "noResponseDataErr": "No hay datos en respuesta a la llamada de exportSubmissions", + "apiCallErrorMsg": "Se produjo un error al intentar exportar envíos para este formulario.", + "apiCallConsErrorMsg": "Envíos de exportación de errores para", + "selectAllFields": "Seleccionar todos los campos", + "emailSentMsg": "Se enviará un correo electrónico a {email} con un enlace para descargar sus datos cuando esté listo", + "exportInProgress": "Exportación en curso", + "of": "de" + }, + "printOptions": { + "submitButtonTxt": "Enviar a CDOGS y descargar", + "templatePrint": "Impresión de plantilla", + "uploadTemplateFile": "Subir archivo de plantilla", + "downloadOptions": "Opciones de descarga", + "print": "Imprimir", + "browserPrint": "Impresión del navegador", + "pageFromBrowser": "la página desde tu navegador", + "uploadA": "Sube un", + "uploadB": "tener una versión estructurada", + "docGrnSucess": "Documento generado con éxito", + "failedDocGenErrMsg": "No se pudo generar el documento", + "failedDocGenConsErrMsg": "Error al enviar la plantilla: {error}", + "cDogsTemplate": "Plantilla CDDOGS" + }, + "proactiveHelpDialog": { + "componentInfoLink": "Enlace de información del componente", + "learnMoreLinkTxt": "Más información El campo de enlace no puede estar vacío.", + "largeImgTxt": "imagen grande El tamaño de la imagen no puede ser mayor a .5mb", + "componentName": "Nombre del componente:", + "learnMoreLink": "Más información Enlace:", + "clickToEnableLink": "Haga clic para habilitar el enlace", + "clickToDisableLink": "Haga clic para deshabilitar el enlace", + "imageUpload": "Carga de imagen:", + "cancel": "Cancelar", + "save": "Ahorrar", + "description": "Descripción" + }, + "proactiveHelpPreviewDialog": { + "learnMore": "Aprende más" + }, + "preview": { + "preview": "Avance", + "previewToolTip": "Esto muestra una vista previa del diseño y el comportamiento de la versión del formulario tal como lo verán los remitentes. No puede enviar el formulario desde esta página." + }, + "generalLayout": { + "loadingText": "Cargando por favor espere", + "preview": "AVANCE", + "published": "PUBLICADO", + "unpublished": "INÉDITO", + "edit": "EDITAR", + "formTitle": "Título del formulario", + "actions": "Comportamiento" + }, + "formSubmission": { + "editThisSubmission": "Editar este envío", + "submission": "Envío", + "alertInfo": "Después de editar, vuelva a enviar el formulario para guardar los cambios.", + "viewAllSubmissions": "Ver todas las presentaciones", + "submitted": "Enviado:", + "confirmationID": "Identificación de confirmación:", + "submittedBy": "Presentado por:", + "cancel": "CANCELAR", + "status": "Estado", + "updatedAt": "Modificado", + "updatedBy": "Modificado por" + }, + "teamManagement": { + "noMatchingRecordText": "No se encontraron registros coincidentes", + "teamManagement": "Gestión de equipos", + "selectColumns": "Seleccionar columnas", + "manageForm": "Administrar formulario", + "search": "Buscar", + "loadingText": "Cargando por favor espere", + "noDataText": "No se pudieron cargar los datos del rol del equipo", + "removeSelectedUsers": "Eliminar usuarios seleccionados", + "removeThisUser": "Eliminar este usuario", + "confirmRemoval": "Confirmar eliminación", + "remove": "Eliminar", + "searchTeamManagementFields": "Campos de gestión de equipos de búsqueda", + "save": "Ahorrar", + "teamMebersTitle": "Busque y seleccione columnas para mostrar debajo de su tablero", + "fullName": "Nombre completo", + "username": "Nombre de usuario", + "identityProvider": "Proveedor de identidad", + "delSelectedMembersWarning": "¿Está seguro de que desea eliminar los miembros seleccionados?", + "delSelectedMemberWarning": "¿Está seguro de que desea eliminar al miembro seleccionado?", + "idpMessage": "ya está en el equipo.", + "formOwnerErrMsg": "Siempre debe haber al menos un propietario de formulario", + "formOwnerConsoleErrMsg": "No se puede eliminar {userId} porque es el único propietario restante de este formulario.", + "insufficientPermissnMsg": "Permisos insuficientes para administrar el equipo", + "getUserErrMsg": "Error al obtener los usuarios del formulario:", + "getRolesErrMsg": "Error al obtener la lista de roles:", + "formOwnerRemovalWarning": "No se puede eliminar porque es el único propietario restante de este formulario.", + "removeUsersErrMsg": "Ocurrió un error al intentar eliminar los usuarios seleccionados", + "removeUserConsoleErrMsg": "Error al eliminar usuarios del formulario {formId}: {error}", + "updUserRolesErrMsg": "Se produjo un error al intentar actualizar todos los roles de usuario", + "updUserRolesConsoleErrMsg": "Error al establecer todos los roles de usuario para el formulario {formId}: {error}", + "setUserFormsErrMsg": "Se produjo un error al intentar actualizar los roles de un usuario", + "setUserFormsConsoleErrMsg": "Error al establecer roles de usuario para el formulario {formId}: {error}" + }, + "floatButton": { + "publish": "Publicar", + "manage": "Administrar", + "redo": "Rehacer", + "undo": "Deshacer", + "preview": "Avance", + "bottom": "Abajo", + "top": "Arriba", + "actions": "Comportamiento", + "collapse": "Colapsar", + "saved": "Salvado", + "save": "Ahorrar", + "saving": "Ahorro", + "notSaved": "No guardado" + }, + "formViewer": { + "lateFormSubmissions": "¡El período de envío del formulario ha expirado! Todavía puede crear un envío tardío haciendo clic en el botón a continuación.", + "createLateSubmission": "Crear envío tardío", + "draftSaved": "Borrador guardado", + "saving": "Ahorro", + "pleaseConfirm": "Por favor confirmar", + "submitFormWarningMsg": "¿Está seguro de que desea enviar su formulario?", + "submit": "Entregar", + "wantToSaveDraft": "¿Quieres guardar el borrador?", + "version": "Versión: {version}", + "formScheduleExpireMessage": "El envío de formularios no está disponible porque el período de envío programado ha expirado.", + "getUsersSubmissionsErrMsg": "Se produjo un error al obtener el envío de este formulario", + "getUsersSubmissionsConsoleErrMsg": "Error al cargar los datos de envío del formulario {submissionId}: {error}", + "multiDraftUploadSuccess": "¡Tu carga de múltiples borradores ha sido exitosa!", + "readVersionErrMsg": "Sin esquema en respuesta. Id de versión: {versionId}", + "readDraftErrMsg": "Sin esquema en respuesta. ID de borrador: {draftId}", + "alertRouteMsg": "El propietario del formulario no ha publicado el formulario y no está disponible para envíos.", + "fecthingFormErrMsg": "Se produjo un error al obtener este formulario", + "fecthingFormConsoleErrMsg": "Error al cargar el esquema del formulario {versionId}: {error}", + "savingDraftErrMsg": "Se produjo un error al guardar un borrador", + "savingDraftConsoleErrMsg": "Error al guardar el borrador. Id de envío: {submissionId}. Error: {error}", + "submissionsPreviewAlert": "Envío deshabilitado durante la vista previa del formulario", + "submissionsSubmitErrMsg": "Error al enviar el formulario: {errors}", + "sendSubmissionErrMsg": "Respuesta fallida desde el punto final de envío. Código de respuesta: {status}", + "errMsg": "Ocurrió un error al enviar este formulario", + "customEventAlert": "Los eventos de botones personalizados aún no son compatibles. Tipo de evento: {event}", + "formLoading": "¡Por favor espere mientras se carga el formulario!", + "yes": "Sí", + "no": "No", + "failedResSubmissn": "Respuesta fallida desde el punto final de envío. Código de respuesta: {status}", + "errSubmittingForm": "Ocurrió un error al enviar este formulario", + "errorSavingFile": "Error al guardar archivos. Nombre de archivo: {fileName}. Error: {error}", + "submittingDraftErrMsg": "Se produjo un error al guardar un borrador", + "submittingDraftConsErrMsg": "Error al guardar el borrador. Id de envío: {submissionId}. Error: {error}", + "formDraftAccessErrMsg": "El envío solicitado ya se envió, redirigiendo a la página Ver" + }, + "bCGovFooter": { + "home": "Hogar", + "about": "Acerca de gov.bc.ca", + "disclaimer": "Descargo de responsabilidad", + "privacy": "Privacidad", + "accessibility": "Accesibilidad", + "copyRight": "Derechos de autor", + "contactUs": "Contáctenos" + }, + "bCGovNavBar": { + "about": "Acerca de", + "myForms": "Mis formularios", + "createNewForm": "Crear un nuevo formulario", + "help": "Ayuda", + "feedback": "Comentario", + "admin": "Administración" + }, + "homePage": { + "title": "Cree, publique formularios y reciba envíos con Common Hosted Forms Service.", + "subTitle": "Todo BC Los empleados del gobierno o los contratistas con una cuenta IDIR pueden usar nuestra versión alojada de Common Hosted Forms Service (CHEFS) para crear formularios.", + "takeATourOfChefs": "Haga un recorrido por CHEFS para verlo en acción.", + "logInToGetStarted": "Inicia sesión para empezar", + "loginToStart": "Inicie sesión con IDIR para comenzar", + "login": "Acceso", + "createFormLabel": "Crear un formulario", + "manageAccessTitle": "Administra el acceso a tu formulario", + "manageAccessSub1": "CHEFS le permite crear formularios públicos, o puede administrar el acceso a través de la autenticación IDIR o BCeID.", + "manageAccessSub2": "También puede asignar roles a su equipo para administrar todos sus envíos.", + "createCustomFormTitle": "Cree formularios personalizados con el generador de formularios CHEFS", + "createCustomFormSub1": "Con CHEFS, puede crear formularios seguros con una interfaz intuitiva de arrastrar y soltar. Puede agregar componentes de formulario, reorganizarlos y colocarlos en diferentes configuraciones de diseños.", + "chefsHowToTitle": "Videos instructivos de CHEFS", + "chefsHowToSub": "Nuestra Guía de inicio rápido le presentará algunas de las funciones básicas de CHEFS.", + "getStartedToChefs": "Comience a usar CHEFS", + "createOnlineTitle": "Cree formularios en línea para recopilar información de sus clientes y mejorar sus flujos de trabajo.", + "getStarted": "Empezar" + }, + "baseStepper": { + "setUpForm": "Configurar formulario", + "designForm": "Formulario de diseño", + "manageForm": "Administrar formulario" + }, + "create": { + "formSettings": "Configuración de formulario", + "disclaimer": "Descargo de responsabilidad", + "disclaimerStmt": "Acepto el descargo de responsabilidad y la declaración de responsabilidad de Form Designers", + "continue": "Continuar", + "back": "Atrás", + "confirmPageNav": "¿De verdad quieres salir de esta página? Los cambios que haya realizado no se guardarán.", + "agreementErrMsg": "Debe aceptar el descargo de responsabilidad de privacidad que se muestra arriba." + }, + "addTeamMember": { + "cantFindChefsUsers": "¿No puedes encontrar a alguien? Es posible que no hayan iniciado sesión en CHEFS.
Envíeles un enlace a CHEFS y pídales que inicien sesión.", + "cancel": "Cancelar", + "add": "Agregar", + "mustSelectAUser": "Debe seleccionar al menos un rol para agregar este usuario.", + "addNewMember": "Agregar un nuevo miembro", + "enterUsername": "Ingrese un nombre, correo electrónico o nombre de usuario", + "enterExactUsername": "Ingrese un correo electrónico o nombre de usuario exacto", + "BCeIDInputSearchMaxLen": "La entrada de búsqueda para el nombre de usuario/correo electrónico de BCeID debe tener más de 6 caracteres.", + "BCeIDMustBeExact": "Las búsquedas de correo electrónico para BCeID deben ser exactas.", + "errorGettingUsers": "Error al obtener usuarios {error}" + }, + "baseFilter": { + "cancel": "Cancelar", + "columnName": "Nombre de columna", + "exampleText": "Texto de ejemplo", + "exampleText2": "Texto de ejemplo 2", + "filterPlaceholderTxt": "Filtrar texto de marcador de posición", + "filter": "Filtrar", + "value": "valor", + "resetColumns": "Restablecer columnas" + }, + "formViewerActions": { + "viewMyDraftOrSubmissions": "Ver mis borradores/presentaciones", + "saveAsADraft": "Guardar como borrador", + "editThisDraft": "Editar este borrador", + "switchSingleSubmssn": "Cambiar a envío único", + "switchMultiSubmssn": "Cambiar a envíos múltiples" + }, + "baseCopyToClipboard": { + "linkToClipboard": "Enlace copiado al portapapeles", + "copyToClipboard": "Copiar al portapapeles", + "errCopyToClipboard": "Error al intentar copiar al portapapeles." + }, + "sucess": { + "sucessFormSubmissn": "Su formulario ha sido enviado exitosamente", + "keepRecord": "Si desea mantener un registro de este envío, puede conservar lo siguiente", + "confirmationId": "Identificación de confirmación" + }, + "bcGovAlertBanner": { + "defaultErrMsg": "Error: Algo salió mal", + "error": "error" + }, + "permissionUtils": { + "formNotAvailable": "El formulario no está disponible actualmente. Esto puede deberse a un enlace incorrecto, o puede que el propietario haya eliminado el formulario.", + "missingFormIdAndSubmssId": "Opciones que faltan tanto formId como submitId", + "loadingFormErrMsg": "Ocurrió un error al cargar este formulario.", + "loadingForm": "Error al cargar {options}: {error}", + "idpHintMsg": "Este formulario requiere autenticación {idpHint}. Vuelva a iniciar sesión y vuelva a intentarlo.", + "formIdpMissMatch": "Discrepancia de formulario IDP. El formulario requiere {idpHint} pero el usuario tiene {userIdp}." + }, + "download": { + "chefsDataExport": "Exportación de datos CHEFS", + "preparingForDownloading": "Preparando para descargar...", + "downloadInfoA": "Si su archivo no se descarga automáticamente", + "downloadInfoB": "haga clic aquí para intentarlo de nuevo" + }, + "history": { + "submissnHistory": "Su historial de envíos (TBD)" + }, + "error": { + "logout": "Cerrar sesión", + "somethingWentWrong": "Error: Algo salió mal... :(" + }, + "login": { + "authenticateWith": "Autenticar con:", + "alreadyLoggedIn": "Ya iniciado sesión", + "home": "Hogar", + "about": "Acerca de" + }, + "notFound": { + "about": "Acerca de", + "pageNotFound": "404 Pagina no encontrada. :(" + }, + "store": { + "admin": { + "addFormOwnerRole": "Se agregó el rol de Propietario para este formulario a {fullName}", + "addRowError": "Ocurrió un error al agregar el rol.", + "addRowConsoleErr": "Error al agregar el usuario {userId} al formulario {formId}: {error}", + "apiKeyDelMsg": "Se eliminó la clave API para este formulario.", + "errDeletingApiKey": "Se produjo un error al intentar eliminar la clave API.", + "consErrDeletingApiKey": "Error al eliminar la clave API para el formulario {formId}: {error}", + "fecthingFormsErrMsg": "Se produjo un error al obtener formularios.", + "fecthingFormsConsErrMsg": "Error al obtener los datos del formulario de administración: {error}", + "fecthingFormErrMsg": "Se produjo un error al obtener este formulario.", + "fecthingFormConsErrMsg": "Error al obtener los datos del formulario de administración {formId}: {error}", + "fecthFormUserRolesErrMsg": "Se produjo un error al obtener los roles de usuario del formulario.", + "fecthFormUserRolesConsErrMsg": "Error al obtener los datos de los roles de administrador: {error}", + "fecthApiDetailsErrMsg": "Se produjo un error al obtener los detalles de la API de este formulario.", + "fecthApiDetailsConsErrMsg": "Error al obtener los detalles de la API de administración de los datos del formulario {formId}: {error}", + "restoreFormErrMsg": "Ocurrió un error al restaurar este formulario.", + "restoreFormConsErrMsg": "Error al restaurar los datos del formulario {formId}: {error}", + "getUsersErrMsg": "Ocurrió un error al obtener usuarios.", + "getUsersConsErrMsg": "Error al obtener los datos de los usuarios administradores: {error}", + "getUserErrMsg": "Se produjo un error al obtener este usuario.", + "getUserConsErrMsg": "Error al obtener los datos del usuario administrador {userId}: {error}", + "storingFCHelpInfoErrMsg": "Se produjo un error al almacenar la información de ayuda del componente de formulario", + "storingFCHelpInfoConsErrMsg": "Error al obtener información de ayuda del componente de formulario de almacenamiento: {error}", + "gettingFCImgUrlErrMsg": "Ocurrió un error al obtener la URL de la imagen", + "gettingFCImgUrlConsErrMsg": "Error al obtener la URL de la imagen: {error}", + "updatingFCStatusErrMsg": "Ocurrió un error al actualizar el estado de publicación", + "updatingFCStatusConsErrMsg": "Error al actualizar el estado de publicación: {error}", + "fecthingFormBuilderCompsErrMsg": "Se produjo un error al obtener los componentes del generador de formularios", + "fecthingFormBuilderCompsConsErrMsg": "Error al obtener los componentes del generador de formularios: {error}" + }, + "form": { + "fetchEmailTemplatesConsErrMsg": "Error al cargar plantillas de correo electrónico para {formId}: {error}", + "fetchEmailTemplatesErrMsg": "Se produjo un error al obtener las plantillas de correo electrónico para este formulario.", + "getCurrUserFormsErrMsg": "Se produjo un error al obtener sus formularios.", + "getCurrUserFormsConsErrMsg": "Error al obtener los datos del usuario: {error}", + "getUserFormPermErrMsg": "Se produjo un error al obtener sus datos de usuario para este formulario.", + "getUserFormPermConsErrMsg": "Error al obtener datos de usuario usando formID {formId}: {error}", + "getUserFormRolesErrmsg": "Se produjo un error al obtener sus datos de usuario para este formulario.", + "getUserFormRolesConsErrmsg": "Error al obtener datos de usuario usando formID {formId}: {error}", + "updCurrUserFormPrefErrMsg": "Ocurrió un error al guardar sus preferencias para este formulario.", + "updCurrUserFormPrefConsErrMsg": "Error al actualizar las preferencias del formulario de usuario usando formID {formId} y preferencias {preferences}: {error}", + "getCurrUserFormPrefErrMsg": "Se produjo un error al obtener sus preferencias para este formulario.", + "getCurrUserFormPrefConsErrMsg": "Error al obtener las preferencias de formulario del usuario usando formID {formId}: {error}", + "delCurrformNotiMsg": "El formulario {name} se ha eliminado correctamente.", + "delCurrFormConsErMsg": "Error al eliminar el formulario {id}: {error}", + "delDraftErrMsg": "Se produjo un error al eliminar este borrador.", + "delDraftConsErrMsg": "Error al eliminar {draftId}: {error}", + "fecthDraftErrMsg": "Se produjo un error al buscar borradores para este formulario.", + "fecthDraftConsErrMsg": "Error al obtener borradores para el formulario {formId}: {error}", + "fecthFormErrMsg": "Se produjo un error al obtener este formulario.", + "fecthFormConsErrMsg": "Error al obtener el formulario {formId}: {error}", + "fetchFormFieldsErrMsg": "Se produjo un error al obtener la lista de campos para este formulario.", + "fetchFormFieldsConsErrMsg": "Error al obtener el formulario {formId}: {error}", + "publishDraftErrMsg": "Ocurrió un error durante la publicación.", + "publishDraftConsErrMsg": "Error al publicar {draftId}: {error}", + "toggleVersnPublConsErrMsg": "Error en toggleVersionPublish {versionId} {publish}: {error}", + "updateEmailTemplateConsErrMsg": "Error al actualizar las plantillas de correo electrónico para el formulario {formId}: {error}", + "updateEmailTemplateErrMsg": "Se produjo un error al actualizar las plantillas de correo electrónico para este formulario.", + "updateFormErrMsg": "Se produjo un error al actualizar la configuración de este formulario.", + "updateFormConsErrMsg": "Error al actualizar el formulario {id}: {error}", + "deleteSubmissionNotifyMsg": "Envío eliminado con éxito.", + "deleteSubmissionErrMsg": "Ocurrió un error al eliminar este envío.", + "deleteSubmissionConsErrMsg": "Error al eliminar el envío {submissionId}: {error}", + "deleteSubmissionsNotifyMsg": "Envíos eliminados con éxito.", + "deleteSubmissionsErrMsg": "Ocurrió un error al eliminar los envíos seleccionados.", + "deleteSubmissionsConsErrMsg": "Error al eliminar envíos: {error}", + "restoreSubmissionsNotiMsg": "Envíos restaurados con éxito.", + "restoreSubmissionsErrMsg": "Se produjo un error al restaurar este envío.", + "restoreSubmissionsConsErrMsg": "Error al restaurar envíos: {error}", + "restoreSubmissionNotiMsg": "Envío restaurado con éxito.", + "restoreSubmissionErrMsg": "Se produjo un error al restaurar este envío.", + "restoreSubmissionConsErrMsg": "Error al restaurar el envío {submissionId}: {error}", + "fecthSubmissnUsersErrMsg": "Se produjo un error al obtener el correo electrónico del destinatario para este envío.", + "fecthSubmissnUsersConsErrMsg": "Error al obtener el correo electrónico del destinatario para el envío {formSubmissionId}: {error}", + "fetchSubmissnErrMsg": "Se produjo un error al obtener este envío.", + "fetchSubmissnConsErrMsg": "Error al obtener el envío {submissionId}: {error}", + "fetchFormCSVExptFieldsErrMsg": "Se produjo un error al obtener la lista de campos para este formulario.", + "fetchFormCSVExptFieldsConsErrMsg": "Error al obtener el formulario {formId}: {error}", + "fetchSubmissnsErrMsg": "Se produjo un error al obtener envíos para este formulario.", + "fetchSubmissnsConsErrMsg": "Error al obtener envíos para {formId}: {error}", + "fetchVersionErrMsg": "Se produjo un error al obtener este formulario.", + "fetchVersionConsErrMsg": "Error al obtener la versión {versionId} para el formulario {formId}: {error}", + "deleteApiKeyNotifyMsg": "Se eliminó la clave API para este formulario.", + "deleteApiKeyErrMsg": "Se produjo un error al intentar eliminar la clave API.", + "deleteApiKeyConsErrMsg": "Error al eliminar la clave API para el formulario {formId}: {error}", + "generateApiKeyNotifyMsg": "Se ha creado una clave API para este formulario.", + "generateApiKeyErrMsg": "Se produjo un error al intentar generar una clave de API.", + "generateApiKeyConsErrMsg": "Error al generar la clave API para el formulario {formId}: {error}", + "readApiKeyErrMsg": "Se produjo un error al intentar obtener la clave API.", + "readApiKeyConsErrMsg": "Error al obtener la clave API para el formulario {formId}: {error}.", + "getFCPHImageUrlErrMsg": "Ocurrió un error al obtener la URL de la imagen", + "getFCPHImageUrlConsErrMsg": "Error al obtener la URL de la imagen: {error}", + "listFCPHErrMsg": "Se produjo un error al obtener los componentes del generador de formularios", + "listFCPHConsErrMsg": "Error al obtener los componentes del generador de formularios: {error}", + "downloadFileErrMsg": "Ocurrió un error al descargar el archivo", + "downloadFileConsErrMsg": "Error al descargar el archivo: error", + "readSubscriptionSettingsErrMsg": "Se produjo un error al intentar obtener la configuración de la suscripción.", + "readSubscriptionSettingsConsErrMsg": "Error al obtener la configuración de suscripción para el formulario {formId}: {error}.", + "saveSubscriptionSettingsNotifyMsg": "Se ha guardado la configuración de suscripción para este formulario.", + "saveSubscriptionSettingsErrMsg": "Se produjo un error al intentar guardar la configuración de la suscripción.", + "saveSubscriptionSettingsConsErrMsg": "Error al guardar la configuración de suscripción para el formulario {formId}: {error}" + } + }, + "admin": { + "root": { + "admin": "Administración" + }, + "form": { + "administerForm": "Administrar formulario" + }, + "user": { + "administerUser": "Administrar usuario" + } + }, + "user": { + "root": { + "myForms": "MIS FORMULARIOS", + "history": "HISTORIA", + "user": "Usuario" + } + } +} diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/es/index.js b/frontend/app/frontend/src/internationalization/trans/chefs/es/index.js new file mode 100644 index 0000000..fb316d1 --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/es/index.js @@ -0,0 +1,4 @@ +import es from '~/internationalization/trans/chefs/es/es.json'; +export default { + trans: es, +}; diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/fa/fa.json b/frontend/app/frontend/src/internationalization/trans/chefs/fa/fa.json new file mode 100644 index 0000000..e98b6a4 --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/fa/fa.json @@ -0,0 +1,995 @@ +{ + "date": { + "date": "yyyy-mm-dd" + }, + "emailManagement": { + "emailManagement": "مدیریت ایمیل", + "manageForm": "مدیریت فرم", + "submissionConfirmation": "تایید ارسال" + }, + "emailTemplate": { + "body": "بدن", + "save": "صرفه جویی", + "saveEmailTemplateConsoleErrMsg": "خطا در به‌روزرسانی الگوی ایمیل برای فرم {formId}: {error}", + "saveEmailTemplateErrMsg": "هنگام تلاش برای به‌روزرسانی الگوی ایمیل، خطایی روی داد.", + "subject": "موضوع", + "title": "عنوان", + "validBodyRequired": "لطفاً یک متن برای ایمیل وارد کنید", + "validSubjectRequired": "لطفاً یک خط موضوع برای ایمیل وارد کنید", + "validTitleRequired": "لطفا یک عنوان برای ایمیل وارد کنید" + }, + "formsTable": { + "myForms": "فرم های من", + "createNewForm": "یک فرم جدید ایجاد کنید", + "search": "جستجو کردن", + "manage": "مدیریت کنید", + "submissions": "موارد ارسالی", + "formTitle": "عنوان فرم", + "viewForm": "مشاهده فرم", + "description": "شرح", + "Description": "شرح:", + "action": "اقدامات", + "loadingText": "در حال بارگذاری لطفا صبر کنید" + }, + "manageLayout": { + "manageForm": "مدیریت فرم" + }, + "preview": { + "preview": "پیش نمایش", + "previewToolTip": "این یک پیش نمایش از طراحی و رفتار نسخه فرم را نشان می دهد که ارسال کنندگان شما آن را مشاهده می کنند. شما نمی توانید فرم را از این صفحه ارسال کنید." + }, + "shareForm": { + "shareForm": "اشتراک گذاری فرم", + "shareLink": "لینک را به اشتراک بگذارید", + "copyQRCode": "لینک زیر را کپی کنید یا کد QR را دانلود کنید.", + "warningMessage": "در حال حاضر نسخه منتشر شده ای از فرم وجود ندارد. لینک زیر تا زمانی که نسخه منتشر نشود قابل دسترسی نخواهد بود.", + "openThisForm": "این فرم را باز کنید", + "downloadQRCode": "کد QR را دانلود کنید", + "close": "بستن", + "copyURLToClipboard": "URL را در کلیپ بورد کپی کنید" + }, + "manageFormActions": { + "emailManagement": "مدیریت ایمیل", + "viewSubmissions": "مشاهده موارد ارسالی", + "teamManagement": "مدیریت تیم", + "deleteForm": "حذف فرم", + "confirmDeletion": "حذف را تایید کنید", + "deleteMessageA": "آیا مطمئن هستید که می خواهید حذف کنید؟", + "deleteMessageB": "این فرم دیگر در دسترس نخواهد بود.", + "delete": "حذف" + }, + "manageForm": { + "formSettings": "تنظیمات فرم", + "apiKey": "کلید ای پی ای", + "updated": "به روز شد", + "created": "ایجاد شده", + "formDesignHistory": "تاریخچه طراحی فرم", + "totalVersions": "مجموع نسخه ها", + "status": "وضعیت", + "update": "به روز رسانی", + "cancel": "لغو کنید", + "eventSubscription": "اشتراک رویداد" + }, + "formSettings": { + "pressToAddMultiEmail": "برای افزودن چندین آدرس ایمیل، اینتر یا ، یا فاصله را فشار دهید", + "allowMultiDraft": "بارگذاری چند پیش نویس مجاز است", + "formTitle": "عنوان فرم", + "formDescription": "توضیحات فرم", + "formAccess": "دسترسی به فرم", + "info": "اگر از این فرم برای جمع‌آوری اطلاعات از عموم مردم در مورد موضوعاتی استفاده می‌کنید که مورد علاقه عمومی هستند، باید با GCPE تماس بگیرید تا تعامل شما در فهرست قرار گیرد.", + "important": "مهم", + "idimNotifyA": "شما باید از طریق ایمیل به تیم مدیریت اطلاعات هویت (IDIM) اطلاع دهید", + "idimNotifyB": "قصد شما برای استفاده از BCeID برای تأیید هویت ارسال کنندگان فرم شما.", + "referenceGuideA": "لطفا به ما مراجعه کنید", + "referenceGuideB": "راهنمای کاربر", + "referenceGuideC": "برای جزئیات بیشتر", + "specificTeamMembers": "اعضای تیم خاص", + "formFunctionality": "عملکرد فرم", + "formSubmissinScheduleMsg": "پس از انتشار فرم، برنامه ارسال فرم در تنظیمات فرم در دسترس خواهد بود.", + "formSubmissionsSchedule": "جدول ارسال فرم ها", + "experimental": "تجربی", + "learnMore": "بیشتر بدانید", + "afterSubmission": "پس از ارسال", + "submissionConfirmation": "جزئیات تایید ارسال را نشان دهید", + "theConfirmationID": "شناسه تایید", + "infoB": "گزینه ای برای کاربر برای اینکه یک تایید ارسال را برای خود ایمیل کند", + "loginRequired": "ورود به سیستم الزامی است", + "canSaveAndEditDraftLabel": "ارسال کنندگان می توانند پیش نویس ها را ذخیره و ویرایش کنند", + "canUpdateStatusAsReviewer": "بازبینان می توانند وضعیت این فرم را به روز کنند (یعنی ارسال شده، اختصاص داده شده، تکمیل شده)", + "submitterCanCopyExistingSubmissn": "ارسال کنندگان می توانند یک ارسال موجود را کپی کنند", + "submissionConfirmationToolTip": "انتخاب این گزینه کنترل می کند که کاربر ارسال کننده این فرم در ارسال موفقیت آمیز چه چیزی را ببیند.
اگر علامت زده شود نمایش داده می شود", + "emailNotificatnToTeam": "برای تیم من یک ایمیل اعلان ارسال کنید", + "emailNotificatnToTeamToolTip": "هنگامی که هر کاربری این فرم را ارسال کرد، یک اعلان به آدرس ایمیل مشخص شده خود ارسال کنید", + "notificationEmailAddrs": "آدرس های ایمیل اطلاع رسانی", + "addMoreValidEmailAddrs": "یک یا چند آدرس ایمیل معتبر اضافه کنید", + "formScheduleSettings": "تنظیمات زمانبندی فرم", + "opensubmissions": "موارد ارسالی را باز کنید", + "submissionsDeadline": "چه مدت می خواهید مطالب ارسالی را دریافت کنید؟", + "keepSubmissnOpenTilUnplished": "تا زمانی که به صورت دستی لغو انتشار نشود، باز بماند", + "submissionsClosingDate": "یک تاریخ پایانی را برنامه ریزی کنید", + "submissionPeriod": "تنظیم دوره ارسال", + "closeSubmissions": "بسته های ارسالی", + "keepOpenFor": "باز نگه دارید برای", + "period": "دوره زمانی", + "allowLateSubmissions": "اجازه ارسال دیرهنگام", + "allowLateSubmissionsInfoTip": "در صورت علامت زدن، ارسال‌کنندگان می‌توانند پس از تاریخ بسته شدن، داده‌ها را ارسال کنند.", + "afterCloseDateFor": "پس از تاریخ بسته برای", + "repeatPeriod": "دوره تکرار", + "every": "هر", + "repeatUntil": "تکرار کنید تا", + "summary": "خلاصه", + "submissionsOpenDateRange": "این فرم برای ارسال از", + "to": "به", + "scheduleRepetition": "برنامه هر بار تکرار خواهد شد", + "allowLateSubmissnInterval": "اجازه ارسال دیرهنگام برای", + "until": "تا زمان", + "datesOfSubmissnInfo": "طبق تنظیمات، این تاریخ های موجود برای ارسال است:", + "formOpenInterval": "این فرم برای ارسال از", + "allowDateSubmissionDate": "با اجازه ارسال دیرهنگام تا", + "customClosingMessage": "پیام بسته شدن سفارشی را تنظیم کنید", + "customClosingMessageToolTip": "به شما امکان می دهد هنگام بازدید از یک فرم بسته، یک پیام سفارشی برای کاربران خود اضافه کنید.", + "closingMessage": "بسته شدن پیام", + "sendReminderEmail": "ارسال ایمیل یادآوری", + "autoReminderNotificatn": "اعلان یادآوری خودکار را فعال کنید", + "autoReminderNotificatnToolTip": "ایمیل/های یادآوری را با پیوند فرم در طول دوره ارسال ارسال کنید.", + "selectLoginType": "لطفا 1 نوع ورود به سیستم را انتخاب کنید", + "formDescriptnMaxChars": "توضیحات فرم باید 255 کاراکتر یا کمتر باشد", + "formTitlemaxChars": "عنوان فرم باید 255 نویسه یا کمتر باشد", + "formTitleReq": "عنوان فرم الزامی است", + "atLeastOneEmailReq": "لطفا حداقل 1 آدرس ایمیل وارد کنید", + "validEmailRequired": "لطفا تمام آدرس های ایمیل معتبر را وارد کنید", + "fieldRequired": "این فیلد الزامی است.", + "correctDateFormat": "تاریخ باید در قالب صحیح باشد. یعنی yyyy-mm-dd", + "dateDiffMsg": "بستن تاریخ ارسال باید بیشتر از تاریخ ارسال باز باشد.", + "valueMustBeNumber": "مقدار باید یک عدد باشد. یعنی 1،2،3،5،99", + "selectAnOptions": "لطفا حداقل 1 گزینه را انتخاب کنید", + "validInterval": "این باید یک فاصله زمانی معتبر باشد.", + "fieldRequiredAndInterval": "این فیلد الزامی است و باید یک بازه باشد.", + "dateGrtOpenSubmissnDate": "تکرار تا تاریخ باید بیشتر از تاریخ ارسال باز باشد", + "public": "عمومی (ناشناس)", + "allowEventSubscription": "اجازه اشتراک رویداد", + "eventSubscription": "اشتراک رویداد", + "validEndpointRequired": "لطفاً یک نقطه پایان معتبر که با شروع آن شروع می شود وارد کنید https://", + "validBearerTokenRequired": "89abddfb-2cff-4fda-83e6-13221f0c3d4f یک نمونه توکن حامل معتبر وارد کنید" + }, + "subscribeEvent": { + "eventType": "نوع رویدادe", + "endpointUrl": "نشانی وب نقطه پایانی", + "eventSubmission": "ارسال", + "eventAssignment": "وظیفه", + "eventStatusChange": "تغییر وضعیت", + "endpointToken": "نشانه نقطه پایانی", + "urlPlaceholder": "https://endpoint.gov.bc.ca/api/v1/", + "save": "صرفه جویی", + "text": "متن", + "password": "کلمه عبور", + "hideSecret": "پنهان کردن راز", + "showSecret": "نمایش راز", + "key": "کلید", + "saveSettingsErrMsg": "هنگام تلاش برای به‌روزرسانی تنظیمات این فرم خطایی روی داد.", + "updateSettingsConsoleErrMsg": "خطا در به‌روزرسانی تنظیمات فرم {formId}: {error}" + }, + "apiKey": { + "disclaimer": "سلب مسئولیت", + "infoA": "اطمینان حاصل کنید که رمز کلید API شما در یک مکان امن (به عنوان مثال صندوق کلید) ذخیره شده است.", + "infoB": "کلید API شما به فرم شما دسترسی نامحدود می دهد. کلید API خود را به کسی ندهید.", + "infoC": "کلید API فقط باید برای تعاملات سیستم خودکار استفاده شود. از کلید API خود برای دسترسی مبتنی بر کاربر استفاده نکنید", + "deleteKey": "حذف کلید", + "apiKey": "کلید ای پی ای", + "hideSecret": "پنهان کردن راز", + "showSecret": "نمایش راز", + "sCTC": "راز در کلیپ بورد کپی شد", + "cSTC": "راز را در کلیپ بورد کپی کنید", + "key": "کلید", + "confirmDeletion": "حذف را تایید کنید", + "deleteMsg": "آیا مطمئن هستید که می خواهید کلید API خود را حذف کنید؟", + "delete": "حذف", + "confirmKeyGen": "تأیید تولید کلید", + "createAPIKey": "یک کلید API برای این فرم ایجاد شود؟
اطمینان حاصل کنید که سلب مسئولیت در این صفحه را دنبال می کنید.", + "regenerateAPIKey": "کلید API را دوباره تولید کنید؟
ادامه دسترسی کلید API فعلی شما را حذف می کند .", + "formOwnerKeyAcess": "برای مدیریت کلیدهای API باید مالک فرم باشید.", + "regenerate": "بازسازی کنید", + "generate": "تولید می کنند", + "secret": "راز" + }, + "manageVersions": { + "important": "مهم!", + "infoA": "اگر هیچ نسخه منتشر شده ای وجود نداشته باشد، کاربران نمی توانند به این فرم دسترسی داشته باشند تا زمانی که نسخه منتشر شده اختصاص داده شود. پس از انتشار نسخه، آن نسخه دیگر قابل ویرایش نیست. برای ادامه ویرایش، باید یک نسخه جدید بر اساس یکی از نسخه های فرم قبلی ایجاد کنید.", + "infoB": "توجه: فقط یک نسخه قابل انتشار است.", + "version": "نسخه", + "draft": "پیش نویس", + "clickToPreview": "برای پیش نمایش کلیک کنید", + "editVersion": "ویرایش نسخه", + "exportDesign": "طراحی صادرات", + "infoC": "لطفاً قبل از شروع نسخه جدید آخرین نسخه پیش نویس خود را منتشر یا حذف کنید.", + "deleteVersion": "حذف نسخه", + "draftAlreadyExists": "پیش نویس از قبل وجود دارد", + "infoD": "لطفاً قبل از شروع پیش‌نویس جدید، پیش‌نویس موجود را ویرایش، منتشر یا حذف کنید.", + "publishVersion": "نسخه انتشار", + "unpublishVersion": "لغو انتشار نسخه", + "infoE": "لغو انتشار این فرم، فرم را تا انتشار مجدد نسخه از گردش خارج می کند.", + "confirmDeletion": "حذف را تایید کنید", + "infoF": "آیا مطمئن هستید که می خواهید این نسخه را حذف کنید؟", + "delete": "حذف", + "status": "وضعیت", + "dateCreated": "تاریخ ایجاد", + "createdBy": "خلق شده توسط", + "actions": "اقدامات", + "published": "منتشر شده", + "unpublished": "منتشر نشده", + "useVersionInfo": "از نسخه {version} به عنوان پایه نسخه جدید استفاده کنید", + "publishingVersionInfo": "با این کار نسخه {version} فرم شما فعال می شود." + }, + "addOwner": { + "infoA": "این کار فقط در صورتی انجام می‌شود که مالک فعلی فرم دیگر فعال نباشد یا در یک رویداد اولویت‌دار با شما تماس نداشته باشد. در غیر این صورت از مالک فعلی یا مدیر تیم بخواهید که این کار را خودشان انجام دهند.", + "hint": "برای یافتن شناسه کاربری مورد نیاز، می‌توانید به تب 'USERS' در پورتال مدیریت بروید و آنها را جستجو کنید.", + "addowner": "مالک را اضافه کنید", + "label": "شناسه کاربری (راهنما)" + }, + "adminFormsTable": { + "showDeletedForms": "نمایش فرم های حذف شده", + "search": "جستجو کردن", + "loadingText": "بارگذاری متن", + "noDataText": "هیچ فرمی در سیستم شما وجود ندارد", + "admin": "مدیر", + "launch": "راه اندازی", + "formTitle": "عنوان فرم", + "created": "ایجاد شده", + "deleted": "حذف شده", + "actions": "اقدامات", + "delete": "حذف" + }, + "administerForm": { + "deleted": "حذف شده", + "restoreForm": "این فرم را بازیابی کنید", + "formDetails": "جزئیات فرم", + "apiKeyDetails": "جزئیات کلید API", + "deleteApiKey": "کلید API را حذف کنید", + "formUsers": "کاربران فرم", + "formVersions": "نسخه های فرم", + "assignANewOwner": "یک مالک جدید اختصاص دهید", + "restoring": "در حال بازیابی", + "restore": "بازگرداندن", + "toActiveState": "به حالت فعال", + "confirmDeletion": "حذف را تایید کنید", + "confirmDeletionMsg": "آیا مطمئن هستید که می خواهید این کلید API را حذف کنید؟", + "delete": "حذف", + "confirmRestore": "Restore را تایید کنید" + }, + "administerUser": { + "userDetails": "مشخصات کاربر", + "openSSOConsole": "کنسول SSO را باز کنید" + }, + "adminPage": { + "forms": "تشکیل می دهد", + "users": "کاربران", + "developer": "توسعه دهنده", + "infoLinks": "لینک های اطلاعات", + "metrics": "معیارهای" + }, + "adminUsersTable": { + "search": "جستجو کردن", + "loadingText": "در حال بارگذاری لطفا صبر کنید", + "admin": "مدیر", + "fullName": "نام و نام خانوادگی", + "userID": "شناسه کاربر", + "created": "ایجاد شده", + "actions": "اقدامات" + }, + "adminVersions": { + "exportDesign": "طراحی صادرات", + "versions": "نسخه ها", + "status": "وضعیت", + "created": "ایجاد شده", + "lastUpdated": "اخرین به روز رسانی", + "actions": "اقدامات", + "published": "منتشر شده", + "unpublished": "منتشر نشده", + "version": "نسخه {versionNo}", + "notificationMsg": "هنگام بارگیری طرح فرم خطایی روی داد." + }, + "developer": { + "user": "کاربر", + "name": "نام", + "userName": "نام کاربری", + "JWTContents": "محتویات JWT", + "JWTContentsSBTxt": "محتوای JWT در کلیپ بورد کپی شد", + "JWTContentsTTTxt": "مطالب JWT را در کلیپ بورد کپی کنید", + "JWTToken": "توکن JWT", + "JWTTokenSBTxt": "توکن JWT در کلیپ بورد کپی شد", + "JWTTokenTTTxt": "توکن JWT را در کلیپ بورد کپی کنید", + "chefsAPI": "CHEFS API", + "RBACSBTxt": "پاسخ RBAC در کلیپ بورد کپی شد", + "RBACTTTxt": "پاسخ RBAC را در کلیپ بورد کپی کنید", + "notificationMsg": "دریافت کاربر از RBAC انجام نشد، به کنسول مراجعه کنید", + "notificationConsErr": "خطا در دریافت کاربر از RBAC" + }, + "baseAuthButton": { + "logout": "خروج", + "login": "وارد شدن" + }, + "baseDialog": { + "defaultText": "متن پیش فرض", + "ok": "خوب", + "continue": "ادامه هید", + "cancel": "لغو کنید", + "custom": "سفارشی" + }, + "baseSecure": { + "about": "در باره", + "loginInfo": "برای استفاده از این ویژگی باید وارد شوید.", + "login": "وارد شدن", + "401NotAuthorized": "401: مجاز نیست. :", + "401ErrorMsg": "حساب شما به درستی تنظیم نشده است.
لطفا تماس بگیرید", + "403Forbidden": "403: ممنوع. :", + "403ErrorMsg": "این صفحه به احراز هویت {idp} نیاز دارد.", + "401UnAuthorized": "401: غیر مجاز. :", + "401UnAuthorizedErrMsg": "شما اجازه دسترسی به این صفحه را ندارید." + }, + "formDesigner": { + "formDesign": "طراحی فرم", + "exportDesign": "طراحی صادرات", + "importDesign": "طراحی واردات", + "important": "مهم", + "formDesignInfoA": "پس از اتمام ساخت این فرم، از دکمه SAVE DESIGN استفاده کنید.", + "formDesignInfoB": "دکمه SUBMIT برای ارسال این فرم توسط کاربر شما در نظر گرفته شده است و پس از ذخیره فعال خواهد شد.", + "formLoadErrMsg": "هنگام بارگیری طرح فرم خطایی روی داد.", + "formLoadConsoleErrMsg": "خطا در بارگیری طرحواره فرم {formId} (نسخه: {versionId} پیش‌نویس: {draftId}): {error}", + "formSchemaImportErrMsg": "هنگام وارد کردن طرحواره فرم خطایی روی داد.", + "formSchemaImportConsoleErrMsg": "خطا در وارد کردن طرحواره فرم : {error}", + "formDesignSaveErrMsg": "هنگام تلاش برای ذخیره این طرح فرم خطایی روی داد. اگر نیاز به بازخوانی یا خروج دارید تا بعداً دوباره امتحان کنید، می‌توانید طرح موجود در صفحه را صادر کنید تا برای بعد ذخیره شود.", + "formDesignSaveConsoleErrMsg": "خطا در به‌روزرسانی یا ایجاد فرم (FormID: {formId}، versionId: {versionId}، draftId: {draftId}) خطا: {error}", + "collapse": "سقوط - فروپاشی", + "actions": "اقدامات", + "version": "نسخه", + "save": "صرفه جویی", + "saving": "صرفه جویی در", + "notSaved": "ذخیره نشد", + "fieldnameError": "شما نمی توانید از کلمه کلیدی «form» به عنوان نام فیلد {label} استفاده کنید" + }, + "formViewerMultiUpload": { + "important": "مهم", + "uploadSucessMsg": "برای اطمینان از بارگذاری موفق چندین پیش نویس، لطفاً الگوی ارائه شده را دانلود و استفاده کنید.", + "confirmDownload": "آیا می خواهید آن را دانلود کنید؟", + "jsonFileUpload": "فایل JSON را برای آپلود انتخاب کنید", + "dragNDrop": "یا آن را به اینجا بکشید و رها کنید", + "chooseAFile": "یک فایل را انتخاب کنید", + "downloadDraftSubmns": "لطفاً پیش نویس گزارش ارسال را دانلود کنید و مطمئن شوید که داده ها به درستی وارد شده اند.", + "downloadReport": "دانلود گزارش", + "doYouWantToDownload": "آیا می خواهید آن را دانلود کنید؟", + "uploadNewFile": "آپلود فایل جدید", + "uploadMultipleFileErr": "با عرض پوزش، شما فقط می توانید یک فایل آپلود کنید", + "dragMultipleFileErr": "با عرض پوزش، شما می توانید فقط یک فایل را بکشید", + "fileFormatErr": "با عرض پوزش، ما فقط فایل های json را می پذیریم", + "fileSizeErr": "حداکثر اندازه مجاز فایل 5 مگابایت است", + "parseJsonErr": "ما نمی توانیم داده های json را از فایل تجزیه کنیم", + "jsonObjNotArray": "فرمت فایل json اشتباه است", + "jsonObjNotArrayConsErr": "یک خطای غیرمنتظره رخ داد.", + "jsonArrayEmpty": "این فایل json خالی است.", + "errorWhileValidate": "مشکلی در این فایل وجود دارد", + "errWhileCheckValidity": "مشکلی در این فایل وجود دارد", + "errAfterValidate": "برخی از خطاهای یافت شده، برای اطلاعات بیشتر به زیر مراجعه کنید.", + "fileIsEmpty": "این فایل خالی است", + "download": "دانلود" + }, + "formDisclaimer": { + "disclaimerAndStatement": "سلب مسئولیت و بیانیه مسئولیت برای طراحان فرم:", + "privacyLaw": "مسئولیت رعایت قوانین حفظ حریم خصوصی حاکم بر جمع آوری، استفاده و افشای اطلاعات قابل شناسایی شخصی بر عهده شماست.", + "disclosure": "دسترسی به این ابزار طراح فرم ذاتاً اجازه جمع آوری، استفاده یا افشای اطلاعات قابل شناسایی شخصی را نمی دهد.", + "consent": "کسب رضایت برای جمع آوری اطلاعات طبق قانون، مسئولیت شماست.", + "formIntention": "قبل از انتشار یا توزیع فرم خود باید در مورد قصد فرم با خود صحبت کنید", + "privacyOfficer": "افسر حریم خصوصی وزارت", + "assement": "و ارزیابی ها را در صورت لزوم تکمیل کنید." + }, + "requestReceipt": { + "emailPriority": "اولویت ایمیل", + "emailReceipt": "رسید این ارسال را ایمیل کنید", + "high": "بالا", + "low": "کم", + "normal": "طبیعی", + "send": "ارسال", + "sendToEmailAddress": "ارسال به آدرس ایمیل", + "emailSent": "یک ایمیل به {to} ارسال شده است.", + "sendingEmailErrMsg": "هنگام تلاش برای ارسال ایمیل شما خطایی روی داد.", + "sendingEmailConsErrMsg": "تأیید ایمیل به {to} انجام نشد: {error}", + "emailRequired": "ایمیل الزامی است" + }, + "submissionsTable": { + "noMatchingRecordText": "هیچ رکورد منطبقی یافت نشد", + "submissions": "موارد ارسالی", + "submissionsTable": "جدول ارسالی", + "selectColumns": "ستون ها را انتخاب کنید", + "manageForm": "مدیریت فرم", + "submissionsToFiles": "صادرات ارسالی به فایل ها", + "showDeletedSubmissions": "نمایش موارد ارسالی حذف شده", + "showMySubmissions": "موارد ارسالی من را نشان دهید", + "search": "جستجو کردن", + "loadingText": "در حال بارگذاری لطفا صبر کنید", + "noDataText": "هیچ ارسالی برای این فرم وجود ندارد", + "delSelectedSubmissions": "موارد ارسالی انتخاب شده را حذف کنید", + "resSelectedSubmissions": "بازیابی موارد ارسالی انتخاب شده", + "yes": "آره", + "no": "نه", + "viewSubmission": "مشاهده ارسال", + "deleteSubmission": "حذف ارسال", + "restore": "بازگرداندن", + "confirmDeletion": "حذف را تایید کنید", + "delete": "حذف", + "confirmRestoration": "تایید بازیابی", + "searchSubmissionFields": "فیلدهای ارسال را جستجو کنید", + "save": "صرفه جویی", + "searchTitle": "ستون‌ها را برای نمایش در زیر داشبورد خود جستجو و انتخاب کنید", + "status": "وضعیت", + "submitter": "ارسال کننده", + "submissionDate": "تاریخ ارسال", + "event": "رویداد", + "view": "چشم انداز", + "lateSubmission": "ارسال دیرهنگام", + "confirmationID": "شناسه تایید", + "multiDelWarning": "آیا مطمئن هستید که می خواهید موارد ارسالی انتخاب شده را حذف کنید؟", + "singleDelWarning": "آیا مطمئن هستید که می خواهید این ارسال را حذف کنید؟", + "multiRestoreWarning": "آیا مطمئن هستید که می خواهید این موارد ارسالی را بازیابی کنید؟", + "singleRestoreWarning": "آیا مطمئن هستید که می خواهید این ارسال را بازیابی کنید؟" + }, + "auditHistory": { + "viewEditHistory": "مشاهده تاریخچه ویرایش", + "editHistory": "ویرایش تاریخچه", + "auditLogMsg": "این گزارش حسابرسی از افرادی است که پس از ارسال اولیه تغییراتی در این ارسال ایجاد کرده‌اند.", + "loadingText": "در حال بارگذاری لطفا صبر کنید", + "close": "بستن", + "userName": "نام کاربری", + "date": "تاریخ", + "errorMsg": "هنگام تلاش برای واکشی تاریخچه خطایی روی داد.", + "consoleErrMsg": "خطا در دریافت سابقه حسابرسی برای" + }, + "deleteSubmission": { + "deleteThis": "این را پاک کنید", + "draft": "پیش نویس", + "submission": "ارسال", + "confirmDeletion": "حذف را تایید کنید", + "deleteWarning": "آیا مطمئن هستید که می خواهید این را حذف کنید؟", + "drafts": "پیش نویس", + "formSubmission": "ارسال فرم", + "delete": "حذف" + }, + "manageSubmissionUsers": { + "manageTeamMembers": "مدیریت اعضای تیم", + "add": "اضافه کردن", + "draftFormInvite": "شما فقط می‌توانید اعضای تیم را دعوت و مدیریت کنید که این فرم پیش‌نویس باشد", + "submissionTeamMembers": "اعضای تیم برای این ارسال", + "actions": "اقدامات", + "close": "بستن", + "remove": "برداشتن", + "userNotFoundErrMsg": "نمی توانید کسی را پیدا کنید؟ آنها ممکن است وارد CHEFS نشده باشند.
لطفاً یک پیوند به CHEFS برای آنها ارسال کنید و از آنها بخواهید که وارد شوند.", + "name": "نام", + "username": "نام کاربری", + "email": "پست الکترونیک", + "removeUserWarningMsg1": "آیا مطمئن هستید که می خواهید حذف کنید؟", + "removeUserWarningMsg2": "آنها دیگر مجوزی برای این ارسال نخواهند داشت.", + "userExistInListMsg": "کاربر {username} در حال حاضر در لیست اعضای تیم است.", + "getSubmissionUsersErr": "هنگام تلاش برای واکشی کاربران برای این ارسال، خطایی روی داد.", + "getSubmissionUsersConsoleErr": "خطا در دریافت کاربران برای {submissionId} : {error}", + "sentInviteEmailTo": "ایمیل دعوت به", + "sentUninvitedEmailTo": "ایمیل ناخوانده به", + "updateUserErrMsg": "هنگام تلاش برای به‌روزرسانی کاربران برای این ارسال، خطایی روی داد.", + "updateUserConsoleErrMsg": "خطا در تنظیم مجوزهای کاربر. فرعی: {submissionId} کاربر: {userId} خطا: {error}", + "searchInputLength": "ورودی جستجو برای نام کاربری/ایمیل BCeID باید بیشتر از 6 کاراکتر باشد.", + "exactBCEIDSearch": "جستجوی ایمیل برای BCeID باید دقیق باشد.", + "getUsersErrMsg": "خطا در دریافت کاربران: {error}", + "exactEmailOrUsername": "یک ایمیل یا نام کاربری دقیق وارد کنید.", + "requiredFiled": "یک نام، ایمیل یا نام کاربری وارد کنید" + }, + "mySubmissionsActions": { + "viewThisSubmission": "مشاهده این ارسال", + "copyThisSubmission": "این ارسال را کپی کنید", + "editThisDraft": "این پیش نویس را ویرایش کنید" + }, + "mySubmissionsTable": { + "noMatchingRecordText": "هیچ رکورد منطبقی یافت نشد", + "previousSubmissions": "ارسالی های قبلی", + "selectColumns": "ستون ها را انتخاب کنید", + "createNewSubmission": "یک ارسال جدید ایجاد کنید", + "search": "جستجو کردن", + "loadingText": "در حال بارگذاری لطفا صبر کنید", + "noDataText": "شما هیچ ارسالی ندارید", + "searchSubmissionFields": "فیلدهای ارسال را جستجو کنید", + "save": "صرفه جویی", + "filterTitle": "ستون‌ها را برای نمایش در زیر داشبورد خود جستجو و انتخاب کنید", + "confirmationId": "شناسه تایید", + "actions": "اقدامات", + "createdBy": "خلق شده توسط", + "statusUpdatedBy": "وضعیت به روز شده توسط", + "status": "وضعیت", + "submissionDate": "تاریخ ارسال", + "draftUpdatedBy": "پیش نویس به روز شده توسط", + "draftLastEdited": "پیش نویس آخرین ویرایش", + "createLateSubmissn": "ارسال دیرهنگام ایجاد کنید", + "formLoading": "لطفا صبر کنید تا فرم در حال بارگیری باشد!!!", + "pleaseConfirm": "لطفا تایید کنید", + "wantToSaveDraft": "آیا می خواهید پیش نویس را ذخیره کنید؟", + "yes": "آره", + "no": "خیر", + "multiDraftUploadSuccess": "بارگذاری چند پیش نویس شما با موفقیت انجام شد!", + "failedResSubmissn": "پاسخ ناموفق از نقطه پایان ارسال. کد پاسخ: {status}", + "errSubmittingForm": "هنگام ارسال این فرم خطایی روی داد", + "errorSavingFile": "خطا در ذخیره فایل ها. نام فایل: {fileName}. خطا: {error}", + "submittingDraftErrMsg": "هنگام ذخیره پیش نویس خطایی روی داد", + "submittingDraftConsErrMsg": "خطا در ذخیره پیش نویس. SubmissionId: {submissionId}. خطا: {error}" + }, + "notesPanel": { + "addNewNote": "یادداشت جدید اضافه کنید", + "cancel": "لغو کنید", + "addNote": "اضافه کردن توجه", + "noResponseErr": "هنگام ارسال فرم، هیچ داده پاسخی از API وجود ندارد", + "errorMesg": "هنگام تلاش برای افزودن یادداشت، خطایی روی داد.", + "consoleErrMsg": "خطا در افزودن یادداشت:", + "fetchErrMsg": "هنگام تلاش برای واکشی یادداشت برای این ارسال، خطایی روی داد.", + "fetchConsoleErrMsg": "خطا در افزودن یادداشت:", + "notes": "یادداشت", + "note": "توجه داشته باشید", + "maxChars": "حداکثر 4000 کاراکتر" + }, + "statusPanel": { + "currentStatus": "وضعیت فعلی:", + "assignedTo": "اختصاص یافته به:", + "assignOrUpdateStatus": "تعیین یا به روز رسانی وضعیت", + "display": "نمایش دادن", + "statusIsRequired": "وضعیت مورد نیاز است", + "assignTo": "اختصاص دادن به", + "noDataText": "هیچ بازبینی کننده فرم با جستجو پیدا نشد. بازبینان فرم را در صفحه مدیریت اضافه کنید.", + "assigneeIsRequired": "کارمند مورد نیاز است", + "assignToMe": "به من اختصاص دهید", + "recipientEmail": "ایمیل گیرنده", + "attachCommentToEmail": "نظر را به ایمیل ضمیمه کنید", + "emailComment": "نظر ایمیل", + "maxChars": "حداکثر 4000 کاراکتر", + "viewHistory": "مشاهده تاریخچه", + "statusHistory": "تاریخچه وضعیت", + "close": "بستن", + "addNoteNoReponserErr": "هنگام ارسال یادداشت برای به‌روزرسانی وضعیت، هیچ داده پاسخی از API وجود ندارد", + "addNoteConsoleErrMsg": "خطا در به‌روزرسانی وضعیت: {error}", + "addNoteErrMsg": "هنگام تلاش برای به روز رسانی وضعیت خطایی روی داد", + "updtSubmissionsStatusErr": "هنگام ارسال فرم به‌روزرسانی وضعیت، هیچ داده پاسخی از API وجود ندارد", + "noStatus": "هیچ وضعیت", + "noStatusesFound": "هیچ وضعیتی پیدا نشد", + "statusCodesErr": "خطا در یافتن کدهای وضعیت", + "notifyErrorCode": "هنگام واکشی وضعیت این ارسال خطایی روی داد.", + "notifyConsoleErrorCode": "خطا در گرفتن وضعیت ها:", + "fetchSubmissionUsersErr": "هنگام تلاش برای واکشی ایمیل‌های گیرنده برای این ارسال، خطایی روی داد.", + "fetchSubmissionUsersConsErr": "خطا در دریافت ایمیل های گیرنده برای", + "assignSubmissnToFormReviewer": "موارد ارسالی را می توان به بازبینان فرم اختصاص داد.
برای افزودن اعضای تیم بیشتر به عنوان بازبینان فرم، به صفحه مدیریت این فرم بروید.", + "update": "به روز رسانی", + "revise": "تجدید نظر کنید", + "complete": "کامل", + "assign": "اختصاص دهید" + }, + "statusTable": { + "loadingText": "در حال بارگذاری لطفا صبر کنید", + "status": "وضعیت", + "dateStatusChanged": "وضعیت تاریخ تغییر کرد", + "assignee": "مأمور", + "updatedBy": "به روز شده توسط", + "getSubmissionStatusErr": "هنگام تلاش برای واکشی وضعیت ها خطایی روی داد.", + "getSubmissionStatusConsErr": "خطا در افزودن یادداشت:" + }, + "exportSubmissions": { + "exportSubmissionsToFile": "صادرات ارسالی به فایل", + "viewSubmissions": "مشاهده موارد ارسالی", + "fileType": "نوع فایل", + "json": "JSON", + "csv": "CSV", + "formVersion": "نسخه فرم", + "versionIsRequired": "نسخه مورد نیاز است.", + "dataFields": "فیلدهای داده", + "searchFields": "فیلدهای جستجو", + "selectedForExports": "برای صادرات انتخاب شده است", + "submissionDate": "تاریخ ارسال", + "all": "همه", + "selectDateRange": "محدوده تاریخ را انتخاب کنید", + "SelectdateRange": "محدوده تاریخ را انتخاب کنید", + "from": "از جانب", + "to": "به", + "CSVFormat": "فرمت CSV", + "multiRowPerSubmissionA": "1 - چندین ردیف در هر ارسال با فاصله های تورفتگی", + "multiRowPerSubmissionB": "2 - چندین ردیف در هر ارسال", + "singleRowPerSubmission": "3 - تک ردیف در هر ارسال", + "unformatted": "4 - فرمت نشده", + "fileNameAndType": "نام و نوع فایل", + "export": "صادرات", + "noResponseDataErr": "هیچ داده ای در پاسخ از تماس exportSubmissions وجود ندارد", + "apiCallErrorMsg": "هنگام تلاش برای صادر کردن موارد ارسالی برای این فرم خطایی روی داد.", + "apiCallConsErrorMsg": "خطا در ارسال‌های صادراتی برای", + "selectAllFields": "همه فیلدها را انتخاب کنید", + "emailSentMsg": "ایمیلی به {email} ارسال می‌شود که حاوی پیوندی برای دانلود داده‌های شما در صورت آماده شدن است", + "exportInProgress": "صادرات در حال انجام است", + "of": "از" + }, + "printOptions": { + "submitButtonTxt": "ارسال به CDOGS و دانلود", + "templatePrint": "چاپ الگو", + "uploadTemplateFile": "فایل قالب را آپلود کنید", + "downloadOptions": "گزینه های دانلود", + "print": "چاپ", + "browserPrint": "چاپ مرورگر", + "pageFromBrowser": "صفحه از مرورگر شما", + "uploadA": "آپلود a", + "uploadB": "برای داشتن یک نسخه ساختار یافته", + "docGrnSucess": "سند با موفقیت ایجاد شد", + "failedDocGenErrMsg": "سند ایجاد نشد", + "failedDocGenConsErrMsg": "خطا در ارسال الگو: {error}", + "cDogsTemplate": "قالب CDOGS" + }, + "proactiveHelpDialog": { + "componentInfoLink": "لینک اطلاعات کامپوننت", + "learnMoreLinkTxt": "بیشتر بدانید فیلد پیوند نمی تواند خالی باشد.", + "largeImgTxt": "تصویر بزرگ. اندازه تصویر نمی تواند بزرگتر از 0.5 مگابایت باشد", + "componentName": "نام قطعه:", + "learnMoreLink": "لینک بیشتر بدانید:", + "clickToEnableLink": "برای فعال کردن لینک کلیک کنید", + "clickToDisableLink": "برای غیرفعال کردن لینک کلیک کنید", + "imageUpload": "آپلود تصویر:", + "cancel": "لغو کنید", + "save": "صرفه جویی", + "description": "شرح" + }, + "proactiveHelpPreviewDialog": { + "learnMore": "بیشتر بدانید" + }, + "preview": { + "preview": "پیش نمایش", + "previewToolTip": "این یک پیش نمایش از طراحی و رفتار نسخه فرم را نشان می دهد که ارسال کنندگان شما آن را مشاهده می کنند. شما نمی توانید فرم را از این صفحه ارسال کنید." + }, + "generalLayout": { + "loadingText": "در حال بارگذاری لطفا صبر کنید", + "preview": "پیش نمایش", + "published": "منتشر شده", + "unpublished": "منتشر نشده", + "edit": "ویرایش کنید", + "formTitle": "عنوان فرم", + "actions": "اقدامات" + }, + "formSubmission": { + "editThisSubmission": "این ارسال را ویرایش کنید", + "submission": "ارسال", + "alertInfo": "پس از ویرایش، دوباره فرم را ارسال کنید تا تغییرات شما ذخیره شود.", + "viewAllSubmissions": "مشاهده همه موارد ارسالی", + "submitted": "ارسال شده:", + "confirmationID": "شناسه تایید:", + "submittedBy": "ارسال شده توسط:", + "cancel": "لغو", + "status": "وضعیت", + "updatedAt": "اصلاح شده", + "updatedBy": "تغییر داده شده توسط" + }, + "teamManagement": { + "noMatchingRecordText": "هیچ رکورد منطبقی یافت نشد", + "teamManagement": "مدیریت تیم", + "selectColumns": "ستون ها را انتخاب کنید", + "manageForm": "مدیریت فرم", + "search": "جستجو کردن", + "loadingText": "در حال بارگذاری لطفا صبر کنید", + "noDataText": "اطلاعات نقش تیم بارگیری نشد", + "removeSelectedUsers": "کاربران انتخاب شده را حذف کنید", + "removeThisUser": "این کاربر را حذف کنید", + "confirmRemoval": "حذف را تایید کنید", + "remove": "برداشتن", + "searchTeamManagementFields": "جستجو در زمینه های مدیریت تیم", + "save": "صرفه جویی", + "teamMebersTitle": "ستون‌ها را برای نمایش در زیر داشبورد خود جستجو و انتخاب کنید", + "fullName": "نام و نام خانوادگی", + "username": "نام کاربری", + "identityProvider": "ارائه دهنده هویت", + "delSelectedMembersWarning": "آیا مطمئن هستید که می خواهید اعضای انتخاب شده را حذف کنید؟", + "delSelectedMemberWarning": "آیا مطمئن هستید که می خواهید عضو انتخاب شده را حذف کنید؟", + "idpMessage": "در حال حاضر در تیم است.", + "formOwnerErrMsg": "همیشه باید حداقل یک مالک فرم وجود داشته باشد", + "formOwnerConsoleErrMsg": "نمی توان {userId} را حذف کرد زیرا آنها تنها مالک باقیمانده این فرم هستند.", + "insufficientPermissnMsg": "مجوزهای ناکافی برای مدیریت تیم", + "getUserErrMsg": "خطا در دریافت کاربران فرم:", + "getRolesErrMsg": "خطا در دریافت لیست نقش ها:", + "formOwnerRemovalWarning": "نمی توان حذف کرد زیرا آنها تنها مالک باقی مانده این فرم هستند.", + "removeUsersErrMsg": "هنگام تلاش برای حذف کاربران انتخاب شده خطایی روی داد", + "removeUserConsoleErrMsg": "خطا در حذف کاربران از فرم {formId}: {error}", + "updUserRolesErrMsg": "هنگام تلاش برای به‌روزرسانی همه نقش‌های کاربر خطایی روی داد", + "updUserRolesConsoleErrMsg": "خطا در تنظیم همه نقش‌های کاربر برای فرم {formId}: {error}", + "setUserFormsErrMsg": "هنگام تلاش برای به‌روزرسانی نقش‌ها برای یک کاربر، خطایی روی داد", + "setUserFormsConsoleErrMsg": "خطا در تنظیم نقش‌های کاربر برای فرم {formId}: {error}" + }, + "floatButton": { + "publish": "انتشار", + "manage": "مدیریت کنید", + "redo": "دوباره انجام دهید", + "undo": "واگرد", + "preview": "پیش نمایش", + "bottom": "پایین", + "top": "بالا", + "actions": "اقدامات", + "collapse": "سقوط - فروپاشی", + "saved": "ذخیره", + "save": "صرفه جویی", + "saving": "صرفه جویی در", + "notSaved": "ذخیره نشد" + }, + "formViewer": { + "lateFormSubmissions": "مهلت ارسال فرم به پایان رسیده است! همچنان می توانید با کلیک بر روی دکمه زیر یک ارسال دیرهنگام ایجاد کنید.", + "createLateSubmission": "ارسال دیرهنگام ایجاد کنید", + "draftSaved": "پیش نویس ذخیره شد", + "saving": "صرفه جویی در", + "pleaseConfirm": "لطفا تایید کنید", + "submitFormWarningMsg": "آیا مطمئن هستید که می خواهید فرم خود را ارسال کنید؟", + "submit": "ارسال", + "wantToSaveDraft": "آیا می خواهید پیش نویس را ذخیره کنید؟", + "version": "نسخه: {version}", + "formScheduleExpireMessage": "ارسال فرم در دسترس نیست زیرا دوره برنامه ریزی شده ارسال به پایان رسیده است.", + "getUsersSubmissionsErrMsg": "هنگام واکشی ارسال برای این فرم خطایی روی داد", + "getUsersSubmissionsConsoleErrMsg": "خطا در بارگیری داده‌های ارسال فرم {submissionId}: {error}", + "multiDraftUploadSuccess": "بارگذاری چند پیش نویس شما با موفقیت انجام شد!", + "readVersionErrMsg": "هیچ طرحی در پاسخ وجود ندارد. شناسه نسخه: {versionId}", + "readDraftErrMsg": "هیچ طرحی در پاسخ وجود ندارد. شناسه پیش نویس: {draftId}", + "alertRouteMsg": "صاحب فرم فرم را منتشر نکرده است و برای ارسال در دسترس نیست.", + "fecthingFormErrMsg": "هنگام واکشی این فرم خطایی روی داد", + "fecthingFormConsoleErrMsg": "خطا در بارگیری طرحواره فرم {versionId}: {error}", + "savingDraftErrMsg": "هنگام ذخیره پیش نویس خطایی روی داد", + "savingDraftConsoleErrMsg": "خطا در ذخیره پیش نویس. SubmissionId: {submissionId}. خطا: {error}", + "submissionsPreviewAlert": "ارسال در حین پیش نمایش فرم غیرفعال شد", + "submissionsSubmitErrMsg": "خطا در ارسال فرم: {errors}", + "sendSubmissionErrMsg": "پاسخ ناموفق از نقطه پایان ارسال. کد پاسخ: {status}", + "errMsg": "هنگام ارسال این فرم خطایی روی داد", + "customEventAlert": "رویدادهای دکمه سفارشی هنوز پشتیبانی نمی شوند. نوع رویداد: {event}", + "formLoading": "لطفا صبر کنید تا فرم در حال بارگیری باشد!!!", + "yes": "آره", + "no": "خیر", + "failedResSubmissn": "پاسخ ناموفق از نقطه پایان ارسال. کد پاسخ: {status}", + "errSubmittingForm": "هنگام ارسال این فرم خطایی روی داد", + "errorSavingFile": "خطا در ذخیره فایل ها. نام فایل: {fileName}. خطا: {error}", + "submittingDraftErrMsg": "هنگام ذخیره پیش نویس خطایی روی داد", + "submittingDraftConsErrMsg": "خطا در ذخیره پیش نویس. SubmissionId: {submissionId}. خطا: {error}", + "formDraftAccessErrMsg": "ارسال درخواستی قبلا ارسال شده است، به صفحه مشاهده هدایت می شود" + }, + "bCGovFooter": { + "home": "صفحه اصلی", + "about": "درباره gov.bc.ca", + "disclaimer": "سلب مسئولیت", + "privacy": "حریم خصوصی", + "accessibility": "دسترسی", + "copyRight": "کپی رایت", + "contactUs": "با ما تماس بگیرید" + }, + "bCGovNavBar": { + "about": "در باره", + "myForms": "فرم های من", + "createNewForm": "یک فرم جدید ایجاد کنید", + "help": "کمک", + "feedback": "بازخورد", + "admin": "مدیر" + }, + "homePage": { + "title": "با سرویس فرم‌های میزبانی مشترک، فرم‌ها را ایجاد، منتشر کنید و موارد ارسالی را دریافت کنید.", + "subTitle": "تمام B.C. کارمندان دولتی یا پیمانکاران با حساب IDIR می‌توانند از نسخه میزبانی شده خدمات فرم‌های میزبانی مشترک (CHEFS) برای ایجاد فرم‌ها استفاده کنند.", + "takeATourOfChefs": "برای مشاهده عملکرد آن، یک تور از CHEFS داشته باشید.", + "logInToGetStarted": "برای شروع وارد شوید", + "loginToStart": "برای شروع با IDIR وارد شوید", + "login": "وارد شدن", + "createFormLabel": "یک فرم ایجاد کنید", + "manageAccessTitle": "دسترسی به فرم خود را مدیریت کنید", + "manageAccessSub1": "CHEFS به شما امکان می دهد فرم های عمومی ایجاد کنید، یا می توانید دسترسی را از طریق احراز هویت IDIR یا BCeID مدیریت کنید.", + "manageAccessSub2": "همچنین می‌توانید نقش‌هایی را به تیم خود اختصاص دهید تا همه موارد ارسالی خود را مدیریت کند.", + "createCustomFormTitle": "با فرم ساز CHEFS فرم های سفارشی ایجاد کنید", + "createCustomFormSub1": "با CHEFS، می‌توانید فرم‌های ایمن را با رابط بصری کشیدن و رها کردن ایجاد کنید. می‌توانید اجزای فرم را اضافه کنید، آنها را دوباره مرتب کنید و در پیکربندی‌های طرح‌بندی مختلف رها کنید.", + "chefsHowToTitle": "فیلم‌های راهنمای سرآشپز", + "chefsHowToSub": "راهنمای شروع سریع ما شما را با برخی از عملکردهای اساسی CHEFS آشنا می کند.", + "getStartedToChefs": "شروع به استفاده از CHEFS کنید", + "createOnlineTitle": "فرم های آنلاین برای جمع آوری اطلاعات از مشتریان خود و بهبود گردش کار خود ایجاد کنید.", + "getStarted": "شروع کنید" + }, + "baseStepper": { + "setUpForm": "فرم را تنظیم کنید", + "designForm": "فرم طراحی", + "manageForm": "مدیریت فرم" + }, + "create": { + "formSettings": "تنظیمات فرم", + "disclaimer": "سلب مسئولیت", + "disclaimerStmt": "من با سلب مسئولیت و بیانیه مسئولیت طراحان فرم موافقم", + "continue": "ادامه هید", + "back": "بازگشت", + "confirmPageNav": "آیا واقعاً می خواهید این صفحه را ترک کنید؟ تغییراتی که ایجاد کرده اید ذخیره نمی شوند.", + "agreementErrMsg": "شما باید با سلب مسئولیت حریم خصوصی نشان داده شده در بالا موافقت کنید." + }, + "addTeamMember": { + "cantFindChefsUsers": "نمی توانید کسی را پیدا کنید؟ آنها ممکن است وارد CHEFS نشده باشند.
لطفاً یک پیوند به CHEFS برای آنها ارسال کنید و از آنها بخواهید که وارد شوند.", + "cancel": "لغو کنید", + "add": "اضافه کردن", + "mustSelectAUser": "برای افزودن این کاربر باید حداقل یک نقش را انتخاب کنید.", + "addNewMember": "یک عضو جدید اضافه کنید", + "enterUsername": "یک نام، ایمیل یا نام کاربری وارد کنید", + "enterExactUsername": "یک ایمیل یا نام کاربری دقیق وارد کنید", + "BCeIDInputSearchMaxLen": "ورودی جستجو برای نام کاربری/ایمیل BCeID باید بیشتر از 6 کاراکتر باشد.", + "BCeIDMustBeExact": "جستجوی ایمیل برای BCeID باید دقیق باشد.", + "errorGettingUsers": "خطا در دریافت کاربران {error}" + }, + "baseFilter": { + "cancel": "لغو کنید", + "columnName": "نام ستون", + "exampleText": "متن نمونه", + "exampleText2": "متن مثال 2", + "filterPlaceholderTxt": "متن جای جای فیلتر کنید", + "filter": "فیلتر کنید", + "value": "ارزش", + "resetColumns": "بازنشانی ستون ها" + }, + "formViewerActions": { + "viewMyDraftOrSubmissions": "مشاهده پیش نویس/موارد ارسالی من", + "saveAsADraft": "ذخیره به عنوان پیش نویس", + "editThisDraft": "این پیش نویس را ویرایش کنید", + "switchSingleSubmssn": "به ارسال تکی بروید", + "switchMultiSubmssn": "تغییر به ارسال های متعدد" + }, + "baseCopyToClipboard": { + "linkToClipboard": "پیوند در کلیپ بورد کپی شد", + "copyToClipboard": "کپی به کلیپ بورد", + "errCopyToClipboard": "خطا در تلاش برای کپی کردن در کلیپ بورد." + }, + "sucess": { + "sucessFormSubmissn": "فرم شما با موفقیت ارسال شد", + "keepRecord": "اگر مایل به حفظ سابقه این ارسال هستید، می توانید موارد زیر را حفظ کنید", + "confirmationId": "شناسه تایید" + }, + "bcGovAlertBanner": { + "defaultErrMsg": "خطا: مشکلی پیش آمد", + "error": "خطا" + }, + "permissionUtils": { + "formNotAvailable": "فرم در حال حاضر در دسترس نیست. این ممکن است به دلیل پیوند نادرست باشد، یا ممکن است فرم توسط مالک آن حذف شده باشد.", + "missingFormIdAndSubmssId": "گزینه‌هایی که هم formId و هم submissionId را ندارند", + "loadingFormErrMsg": "هنگام بارگیری این فرم خطایی روی داد.", + "loadingForm": "خطا هنگام بارگیری {options}: {error}", + "idpHintMsg": "این فرم به احراز هویت {idpHint} نیاز دارد. لطفا دوباره وارد شوید و دوباره امتحان کنید.", + "formIdpMissMatch": "عدم تطابق فرم IDP. فرم به {idpHint} نیاز دارد اما کاربر دارای {userIdp} است." + }, + "download": { + "chefsDataExport": "CHEFS Data Export", + "preparingForDownloading": "آماده شدن برای دانلود...", + "downloadInfoA": "اگر فایل شما به صورت خودکار دانلود نمی شود", + "downloadInfoB": "جهت تلاش دوباره اینجا کلیک کنید" + }, + "history": { + "submissnHistory": "سابقه ارسال شما (TBD)" + }, + "error": { + "logout": "خروج", + "somethingWentWrong": "خطا: مشکلی پیش آمد... :(" + }, + "login": { + "authenticateWith": "احراز هویت با:", + "alreadyLoggedIn": "قبلا وارد شده اید", + "home": "صفحه اصلی", + "about": "در باره" + }, + "notFound": { + "about": "در باره", + "pageNotFound": "404: صفحه یافت نشد. :(" + }, + "store": { + "admin": { + "addFormOwnerRole": "نقش مالک را برای این فرم به {fullName} اضافه کرد", + "addRowError": "هنگام افزودن نقش خطایی روی داد.", + "addRowConsoleErr": "خطا در افزودن کاربر {userId} به فرم {formId}: {error}", + "apiKeyDelMsg": "کلید API برای این فرم حذف شده است.", + "errDeletingApiKey": "هنگام تلاش برای حذف کلید API خطایی روی داد.", + "consErrDeletingApiKey": "خطا در حذف کلید API برای فرم {formId}: {error}", + "fecthingFormsErrMsg": "هنگام واکشی فرم ها خطایی روی داد.", + "fecthingFormsConsErrMsg": "خطا در دریافت داده‌های فرم سرپرست: {error}", + "fecthingFormErrMsg": "هنگام واکشی این فرم خطایی روی داد.", + "fecthingFormConsErrMsg": "خطا در دریافت اطلاعات فرم سرپرست {formId}: {error}", + "fecthFormUserRolesErrMsg": "هنگام واکشی نقش های کاربر فرم خطایی روی داد.", + "fecthFormUserRolesConsErrMsg": "خطا در دریافت داده‌های نقش سرپرست: {error}", + "fecthApiDetailsErrMsg": "هنگام واکشی جزئیات API این فرم خطایی روی داد.", + "fecthApiDetailsConsErrMsg": "خطا در دریافت جزئیات API admin از داده‌های فرم {formId}: {error}", + "restoreFormErrMsg": "هنگام بازیابی این فرم خطایی روی داد.", + "restoreFormConsErrMsg": "خطا در بازیابی اطلاعات فرم {formId}: {error}", + "getUsersErrMsg": "هنگام واکشی کاربران خطایی روی داد.", + "getUsersConsErrMsg": "خطا در دریافت اطلاعات کاربران سرپرست: {error}", + "getUserErrMsg": "هنگام واکشی این کاربر خطایی روی داد.", + "getUserConsErrMsg": "خطا در دریافت داده‌های کاربر سرپرست {userId}: {error}", + "storingFCHelpInfoErrMsg": "هنگام ذخیره اطلاعات راهنمای مؤلفه فرم خطایی روی داد", + "storingFCHelpInfoConsErrMsg": "خطا در ذخیره اطلاعات راهنمای مؤلفه فرم: {error}", + "gettingFCImgUrlErrMsg": "هنگام دریافت url تصویر خطایی روی داد", + "gettingFCImgUrlConsErrMsg": "خطا در دریافت نشانی اینترنتی تصویر: {error}", + "updatingFCStatusErrMsg": "هنگام به‌روزرسانی وضعیت انتشار خطایی روی داد", + "updatingFCStatusConsErrMsg": "خطا در به‌روزرسانی وضعیت انتشار: {error}", + "fecthingFormBuilderCompsErrMsg": "هنگام واکشی اجزای سازنده فرم خطایی روی داد", + "fecthingFormBuilderCompsConsErrMsg": "خطا در دریافت اجزای فرم ساز: {error}" + }, + "form": { + "fetchEmailTemplatesConsErrMsg": "خطا در بارگیری الگوهای ایمیل برای {formId}: {error}", + "fetchEmailTemplatesErrMsg": "هنگام واکشی الگوهای ایمیل برای این فرم خطایی روی داد", + "getCurrUserFormsErrMsg": "هنگام واکشی فرم های شما خطایی روی داد.", + "getCurrUserFormsConsErrMsg": "خطا در دریافت اطلاعات کاربر: {error}", + "getUserFormPermErrMsg": "هنگام واکشی اطلاعات کاربر شما برای این فرم خطایی روی داد.", + "getUserFormPermConsErrMsg": "خطا در دریافت اطلاعات کاربر با استفاده از formID {formId}: {error}", + "getUserFormRolesErrmsg": "هنگام واکشی اطلاعات کاربر شما برای این فرم خطایی روی داد.", + "getUserFormRolesConsErrmsg": "خطا در دریافت اطلاعات کاربر با استفاده از formID {formId}: {error}", + "updCurrUserFormPrefErrMsg": "هنگام ذخیره تنظیمات برگزیده شما برای این فرم خطایی روی داد.", + "updCurrUserFormPrefConsErrMsg": "خطا در به‌روزرسانی پیشفرض‌های فرم کاربر با استفاده از formID {formId}، و prefs {preferences}: {error}", + "getCurrUserFormPrefErrMsg": "هنگام واکشی تنظیمات برگزیده شما برای این فرم خطایی روی داد.", + "getCurrUserFormPrefConsErrMsg": "خطا در دریافت پیشفرض های فرم کاربر با استفاده از formID {formId}: {error}", + "delCurrformNotiMsg": "فرم {name} با موفقیت حذف شد.", + "delCurrFormConsErMsg": "خطا در حذف فرم {id}: {error}", + "delDraftErrMsg": "هنگام حذف این پیش‌نویس خطایی روی داد.", + "delDraftConsErrMsg": "خطا در حذف {draftId}: {error}", + "fecthDraftErrMsg": "هنگام اسکن برای پیش‌نویس‌های این فرم خطایی روی داد.", + "fecthDraftConsErrMsg": "خطا در دریافت پیش‌نویس‌های فرم {formId}: {error}", + "fecthFormErrMsg": "هنگام واکشی این فرم خطایی روی داد.", + "fecthFormConsErrMsg": "خطا در دریافت فرم {formId}: {error}", + "fetchFormFieldsErrMsg": "هنگام واکشی لیست فیلدهای این فرم خطایی روی داد.", + "fetchFormFieldsConsErrMsg": "خطا در دریافت فرم {formId}: {error}", + "publishDraftErrMsg": "هنگام انتشار خطایی روی داد.", + "publishDraftConsErrMsg": "خطا در انتشار {draftId}: {error}", + "toggleVersnPublConsErrMsg": "خطا در toggleVersionPublish {versionId} {publish}: {error}", + "updateEmailTemplateConsErrMsg": "خطا در به‌روزرسانی الگوهای ایمیل برای فرم {formId}: {error}", + "updateEmailTemplateErrMsg": "هنگام به‌روزرسانی الگوهای ایمیل برای این فرم خطایی روی داد.", + "updateFormErrMsg": "هنگام به روز رسانی تنظیمات این فرم خطایی روی داد.", + "updateFormConsErrMsg": "خطا در به‌روزرسانی فرم {id}: {error}", + "deleteSubmissionNotifyMsg": "ارسال با موفقیت حذف شد.", + "deleteSubmissionErrMsg": "هنگام حذف این ارسال خطایی روی داد.", + "deleteSubmissionConsErrMsg": "خطا در حذف ارسال {submissionId}: {error}", + "deleteSubmissionsNotifyMsg": "موارد ارسالی با موفقیت حذف شدند.", + "deleteSubmissionsErrMsg": "هنگام حذف موارد ارسالی انتخاب شده خطایی روی داد.", + "deleteSubmissionsConsErrMsg": "خطا در حذف موارد ارسالی: {error}", + "restoreSubmissionsNotiMsg": "موارد ارسالی با موفقیت بازیابی شدند.", + "restoreSubmissionsErrMsg": "هنگام بازیابی این ارسال، خطایی روی داد.", + "restoreSubmissionsConsErrMsg": "خطا در بازیابی موارد ارسالی: {error}", + "restoreSubmissionNotiMsg": "ارسال با موفقیت بازیابی شد.", + "restoreSubmissionErrMsg": "هنگام بازیابی این ارسال، خطایی روی داد.", + "restoreSubmissionConsErrMsg": "خطا در بازیابی ارسال {submissionId}: {error}", + "fecthSubmissnUsersErrMsg": "هنگام واکشی ایمیل گیرنده برای این ارسال، خطایی روی داد.", + "fecthSubmissnUsersConsErrMsg": "خطا در دریافت ایمیل گیرنده برای ارسال {formSubmissionId}: {error}", + "fetchSubmissnErrMsg": "هنگام واکشی این ارسال خطایی روی داد.", + "fetchSubmissnConsErrMsg": "خطا در دریافت ارسال {submissionId}: {error}", + "fetchFormCSVExptFieldsErrMsg": "هنگام واکشی لیست فیلدهای این فرم خطایی روی داد.", + "fetchFormCSVExptFieldsConsErrMsg": "خطا در دریافت فرم {formId}: {error}", + "fetchSubmissnsErrMsg": "هنگام واکشی موارد ارسالی برای این فرم خطایی روی داد.", + "fetchSubmissnsConsErrMsg": "خطا در دریافت موارد ارسالی برای {formId}: {error}", + "fetchVersionErrMsg": "هنگام واکشی این فرم خطایی روی داد.", + "fetchVersionConsErrMsg": "خطا در دریافت نسخه {versionId} برای فرم {formId}: {error}", + "deleteApiKeyNotifyMsg": "کلید API برای این فرم حذف شده است.", + "deleteApiKeyErrMsg": "هنگام تلاش برای حذف کلید API خطایی روی داد.", + "deleteApiKeyConsErrMsg": "خطا در حذف کلید API برای فرم {formId}: {error}", + "generateApiKeyNotifyMsg": "یک کلید API برای این فرم ایجاد شده است.", + "generateApiKeyErrMsg": "هنگام تلاش برای ایجاد یک کلید API خطایی روی داد.", + "generateApiKeyConsErrMsg": "خطا در ایجاد کلید API برای فرم {formId}: {error}", + "readApiKeyErrMsg": "هنگام تلاش برای واکشی کلید API خطایی روی داد.", + "readApiKeyConsErrMsg": "خطا در دریافت کلید API برای فرم {formId}: {error}.", + "getFCPHImageUrlErrMsg": "هنگام دریافت url تصویر خطایی روی داد", + "getFCPHImageUrlConsErrMsg": "خطا در دریافت url تصویر: {error}", + "listFCPHErrMsg": "هنگام واکشی اجزای سازنده فرم خطایی روی داد", + "listFCPHConsErrMsg": "خطا در دریافت اجزای فرم ساز: {error}", + "downloadFileErrMsg": "هنگام دانلود فایل خطایی روی داد", + "downloadFileConsErrMsg": "خطا در دانلود فایل: خطا", + "readSubscriptionSettingsErrMsg": "هنگام تلاش برای واکشی تنظیمات اشتراک خطایی روی داد.", + "readSubscriptionSettingsConsErrMsg": "خطا در تنظیمات اشتراک برای فرم {formId}: {error}.", + "saveSubscriptionSettingsNotifyMsg": "تنظیمات اشتراک برای این فرم ذخیره شده است.", + "saveSubscriptionSettingsErrMsg": "هنگام تلاش برای ذخیره تنظیمات اشتراک خطایی روی داد.", + "saveSubscriptionSettingsConsErrMsg": "خطا در ذخیره تنظیمات اشتراک برای فرم {formId}: {error}" + } + }, + "admin": { + "root": { + "admin": "مدیر" + }, + "form": { + "administerForm": "اداره فرم" + }, + "user": { + "administerUser": "مدیریت کاربر" + } + }, + "user": { + "root": { + "myForms": "فرم های من", + "history": "تاریخ", + "user": "کاربر" + } + } +} diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/fa/index.js b/frontend/app/frontend/src/internationalization/trans/chefs/fa/index.js new file mode 100644 index 0000000..92d5337 --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/fa/index.js @@ -0,0 +1,4 @@ +import fa from '~/internationalization/trans/chefs/fa/fa.json'; +export default { + trans: fa, +}; diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/fr/fr.json b/frontend/app/frontend/src/internationalization/trans/chefs/fr/fr.json new file mode 100644 index 0000000..afbd720 --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/fr/fr.json @@ -0,0 +1,995 @@ +{ + "date": { + "date": "aaaa-mm-jj" + }, + "emailManagement": { + "emailManagement": "Gestion des e-mails", + "manageForm": "Gérer le formulaire", + "submissionConfirmation": "Confirmation de soumission" + }, + "emailTemplate": { + "body": "Corps", + "save": "Sauvegarder", + "saveEmailTemplateConsoleErrMsg": "Erreur lors de la mise à jour du modèle d'e-mail pour le formulaire {formId} : {error}", + "saveEmailTemplateErrMsg": "Une erreur s'est produite lors de la tentative de mise à jour du modèle d'e-mail.", + "subject": "Sujet", + "title": "Titre", + "validBodyRequired": "Veuillez saisir un corps pour l'e-mail", + "validSubjectRequired": "Veuillez saisir une ligne d'objet pour l'e-mail", + "validTitleRequired": "Veuillez entrer un titre pour l'e-mail" + }, + "formsTable": { + "myForms": "Mes formulaires", + "createNewForm": "Créer un nouveau formulaire", + "search": "Recherche", + "manage": "Gérer", + "submissions": "Soumissions", + "formTitle": "Titre du formulaire", + "viewForm": "Afficher le formulaire", + "description": "description", + "Description": "Description:", + "action": "Actions", + "loadingText": "Chargement, veuillez patienter" + }, + "manageLayout": { + "manageForm": "Gérer le formulaire" + }, + "preview": { + "preview": "Aperçu", + "previewToolTip": "Cela montre un aperçu de la conception et du comportement de la version du formulaire tels que vos expéditeurs le verront. Vous ne pouvez pas soumettre le formulaire à partir de cette page." + }, + "shareForm": { + "shareForm": "Formulaire de partage", + "shareLink": "Lien de partage", + "copyQRCode": "Copiez le lien ci-dessous ou téléchargez le code QR.", + "warningMessage": "Il n'y a pas de version publiée du formulaire pour le moment. Le lien ci-dessous ne sera pas accessible tant qu'une version n'aura pas été publiée.", + "openThisForm": "Ouvrir ce formulaire", + "downloadQRCode": "Télécharger le code QR", + "close": "Fermer", + "copyURLToClipboard": "Copier l'URL dans le presse-papiers" + }, + "manageFormActions": { + "emailManagement": "Gestion des e-mails", + "viewSubmissions": "Voir les soumissions", + "teamManagement": "Gestion d'équipe", + "deleteForm": "Supprimer le formulaire", + "confirmDeletion": "Confirmer la suppression", + "deleteMessageA": "Êtes-vous sûr de vouloir supprimer", + "deleteMessageB": "Ce formulaire ne sera plus accessible.", + "delete": "Supprimer" + }, + "manageForm": { + "formSettings": "Paramètres du formulaire", + "apiKey": "Clé API", + "updated": "Mis à jour", + "created": "Créé", + "formDesignHistory": "Historique de la conception du formulaire", + "totalVersions": "Versions totales", + "status": "Statut", + "update": "Mise à jour", + "cancel": "Annuler", + "eventSubscription": "Abonnement à l'événement" + }, + "formSettings": { + "pressToAddMultiEmail": "Appuyez sur entrée ou , ou espace pour ajouter plusieurs adresses e-mail", + "allowMultiDraft": "Autoriser le téléchargement de plusieurs brouillons", + "formTitle": "Titre du formulaire", + "formDescription": "Description du formulaire", + "formAccess": "Accès au formulaire", + "info": "Si vous utilisez ce formulaire pour recueillir des informations auprès du grand public sur des sujets d'intérêt général pour le public, vous devez contacter le GCPE afin que votre engagement soit répertorié sur", + "important": "IMPORTANT", + "idimNotifyA": "Vous devez informer l'équipe de gestion des informations d'identité (IDIM) par e-mail", + "idimNotifyB": "votre intention d'utiliser BCeID pour vérifier l'identité de vos expéditeurs de formulaires.", + "referenceGuideA": "Veuillez vous référer à notre", + "referenceGuideB": "mode d'emploi", + "referenceGuideC": "pour plus de détails", + "specificTeamMembers": "Membres spécifiques de l'équipe", + "formFunctionality": "Fonctionnalité du formulaire", + "formSubmissinScheduleMsg": "Le calendrier de soumission des formulaires sera disponible dans les paramètres du formulaire après la publication du formulaire.", + "formSubmissionsSchedule": "Calendrier de soumission des formulaires", + "experimental": "Expérimental", + "learnMore": "Apprendre encore plus", + "afterSubmission": "Après la soumission", + "submissionConfirmation": "Afficher les détails de la confirmation de soumission", + "theConfirmationID": "l'identifiant de confirmation", + "infoB": "la possibilité pour l'utilisateur de s'envoyer par e-mail une confirmation de soumission", + "loginRequired": "Connexion requise", + "canSaveAndEditDraftLabel": "Les expéditeurs peuvent enregistrer et modifier des brouillons", + "canUpdateStatusAsReviewer": "Les réviseurs peuvent mettre à jour le statut de ce formulaire (c.-à-d. Soumis, Attribué, Terminé)", + "submitterCanCopyExistingSubmissn": "Les soumissionnaires peuvent copier une soumission existante", + "submissionConfirmationToolTip": "La sélection de cette option contrôle ce que l'utilisateur soumettant ce formulaire verra en cas de soumission réussie.
Si coché, il affichera", + "emailNotificatnToTeam": "Envoyer à mon équipe un e-mail de notification", + "emailNotificatnToTeamToolTip": "Envoyer une notification à votre adresse e-mail spécifiée lorsqu'un utilisateur soumet ce formulaire", + "notificationEmailAddrs": "Adresses e-mail de notification", + "addMoreValidEmailAddrs": "Ajoutez une ou plusieurs adresses e-mail valides", + "formScheduleSettings": "Paramètres de planification de formulaire", + "opensubmissions": "Soumissions ouvertes", + "submissionsDeadline": "Combien de temps souhaitez-vous recevoir les soumissions ?", + "keepSubmissnOpenTilUnplished": "Rester ouvert jusqu'à dépublication manuelle", + "submissionsClosingDate": "Planifier une date de clôture", + "submissionPeriod": "Configurer la période de soumission", + "closeSubmissions": "Fermer les soumissions", + "keepOpenFor": "Rester ouvert pendant", + "period": "Période", + "allowLateSubmissions": "Autoriser les soumissions tardives", + "allowLateSubmissionsInfoTip": "Si cette case est cochée, les soumissionnaires pourront soumettre des données après la date de clôture.", + "afterCloseDateFor": "Après la date de clôture de", + "repeatPeriod": "Période de répétition", + "every": "Chaque", + "repeatUntil": "Répète jusqu'à", + "summary": "Résumé", + "submissionsOpenDateRange": "Ce formulaire sera ouvert aux soumissions de", + "to": "pour", + "scheduleRepetition": "Le programme se répétera tous les", + "allowLateSubmissnInterval": "autoriser les soumissions tardives pour", + "until": "jusqu'à", + "datesOfSubmissnInfo": "Selon les paramètres, voici les dates de soumission disponibles :", + "formOpenInterval": "Ce formulaire sera ouvert aux soumissions de", + "allowDateSubmissionDate": "en autorisant la soumission tardive jusqu'à", + "customClosingMessage": "Définir un message de clôture personnalisé", + "customClosingMessageToolTip": "Vous permettent d'ajouter un message personnalisé pour vos utilisateurs lorsqu'ils visitent un formulaire fermé.", + "closingMessage": "Message de clôture", + "sendReminderEmail": "ENVOYER un e-mail de rappel", + "autoReminderNotificatn": "Activer la notification de rappel automatique", + "autoReminderNotificatnToolTip": "Envoyez des e-mails de rappel avec le lien du formulaire pendant la période de soumission.", + "selectLoginType": "Veuillez sélectionner 1 type de connexion", + "formDescriptnMaxChars": "La description du formulaire ne doit pas dépasser 255 caractères", + "formTitlemaxChars": "Le titre du formulaire doit comporter 255 caractères maximum", + "formTitleReq": "Le titre du formulaire est requis", + "atLeastOneEmailReq": "Veuillez saisir au moins 1 adresse e-mail", + "validEmailRequired": "Veuillez saisir toutes les adresses e-mail valides", + "fieldRequired": "Ce champ est obligatoire.", + "correctDateFormat": "La date doit être au format correct. c'est à dire. aaaa-mm-jj", + "dateDiffMsg": "La date de clôture de la soumission doit être supérieure à la date d'ouverture de la soumission.", + "valueMustBeNumber": "La valeur doit être un nombre. c'est à dire. 1,2,3,5,99", + "selectAnOptions": "Veuillez sélectionner au moins 1 option", + "validInterval": "Il doit s'agir d'un intervalle valide.", + "fieldRequiredAndInterval": "Ce champ est obligatoire et doit être un intervalle.", + "dateGrtOpenSubmissnDate": "La date de répétition jusqu'au doit être supérieure à la date de soumission ouverte", + "public": "Publique (anonyme)", + "allowEventSubscription": "Autoriser l'abonnement aux événements", + "eventSubscription": "Abonnement à l'événement", + "validEndpointRequired": "Veuillez saisir un point de terminaison valide commençant par https://", + "validBearerTokenRequired": "Saisissez un exemple de jeton de support valide : 89abddfb-2cff-4fda-83e6-13221f0c3d4f" + }, + "subscribeEvent": { + "eventType": "Type d'événement", + "endpointUrl": "URL du point de terminaison", + "eventSubmission": "Soumission", + "eventAssignment": "Mission", + "eventStatusChange": "Changement de statut", + "endpointToken": "Jeton de point de terminaison", + "urlPlaceholder": "https://endpoint.gov.bc.ca/api/v1/", + "save": "Sauvegarder", + "text": "texte", + "password": "mot de passe", + "hideSecret": "Cacher le secret", + "showSecret": "Afficher le secret", + "key": "Clé", + "saveSettingsErrMsg": "Une erreur s'est produite lors de la tentative de mise à jour des paramètres de ce formulaire.", + "updateSettingsConsoleErrMsg": "Erreur lors de la mise à jour des paramètres du formulaire {formId} : {error}" + }, + "apiKey": { + "disclaimer": "Clause de non-responsabilité", + "infoA": "Assurez-vous que la clé secrète de votre API est stockée dans un emplacement sécurisé (c'est-à-dire un coffre de clés).", + "infoB": "Votre clé API accorde un accès illimité à votre formulaire. Ne donnez votre clé API à personne.", + "infoC": "La clé API doit UNIQUEMENT être utilisée pour les interactions système automatisées. N'utilisez pas votre clé API pour un accès basé sur l'utilisateur", + "deleteKey": "Supprimer la clé", + "apiKey": "clé API", + "hideSecret": "Cacher le secret", + "showSecret": "Afficher le secret", + "sCTC": "Secret copié dans le presse-papiers", + "cSTC": "Copier le secret dans le presse-papiers", + "key": "Clé", + "confirmDeletion": "Confirmer la suppression", + "deleteMsg": "Êtes-vous sûr de vouloir supprimer votre clé API ?", + "delete": "Supprimer", + "confirmKeyGen": "Confirmer la génération de clé", + "createAPIKey": "Créer une clé API pour ce formulaire ?
Assurez-vous de suivre la clause de non-responsabilité sur cette page.", + "regenerateAPIKey": "Régénérer la clé API ?
Si vous continuez, votre accès actuel à la clé API sera supprimé .", + "formOwnerKeyAcess": "Vous devez être le propriétaire du formulaire pour gérer les clés API.", + "regenerate": "Régénérer", + "generate": "Générer", + "secret": "Secret" + }, + "manageVersions": { + "important": "IMPORTANT!", + "infoA": "S'il n'y a pas de versions publiées, les utilisateurs ne peuvent pas accéder à ce formulaire tant qu'une version publiée n'est pas attribuée. Une fois qu'une version est publiée, cette version n'est plus modifiable. Vous devez créer une nouvelle version basée sur l'une des versions précédentes du formulaire pour continuer la modification.", + "infoB": "Remarque : Une seule version peut être publiée.", + "version": "Version", + "draft": "Brouillon", + "clickToPreview": "Cliquez pour prévisualiser", + "editVersion": "Modifier la version", + "exportDesign": "Conception d'exportation", + "infoC": "Veuillez publier ou supprimer votre dernière version brouillon avant de commencer une nouvelle version.", + "deleteVersion": "Supprimer la version", + "draftAlreadyExists": "Le brouillon existe déjà", + "infoD": "Veuillez modifier, publier ou supprimer le brouillon existant avant de commencer un nouveau brouillon.", + "publishVersion": "Publier la version", + "unpublishVersion": "Dépublier la version", + "infoE": "La dépublication de ce formulaire le retirera de la circulation jusqu'à ce qu'une version soit à nouveau publiée.", + "confirmDeletion": "Confirmer la suppression", + "infoF": "Voulez-vous vraiment supprimer cette version ?", + "delete": "Supprimer", + "status": "Statut", + "dateCreated": "date créée", + "createdBy": "Créé par", + "actions": "Actions", + "published": "Publié", + "unpublished": "Inédit", + "useVersionInfo": "Utiliser la version {version} comme base pour une nouvelle version", + "publishingVersionInfo": "Cela rendra la version {version} de votre formulaire active." + }, + "addOwner": { + "infoA": "Cela ne devrait être fait que dans le cas où le propriétaire actuel du formulaire n'est plus actif ou est hors de contact dans un événement prioritaire. Sinon, demandez au propriétaire actuel ou à un administrateur d'équipe du formulaire de le faire lui-même.", + "hint": "Pour trouver l'ID utilisateur nécessaire, vous pouvez accéder à l'onglet \"UTILISATEURS\" du portail administrateur et les rechercher.", + "addowner": "Ajouter un propriétaire", + "label": "ID utilisateur (guid)" + }, + "adminFormsTable": { + "showDeletedForms": "Afficher les formulaires supprimés", + "search": "Recherche", + "loadingText": "chargement-texte", + "noDataText": "Il n'y a pas de formulaires dans votre système", + "admin": "Administrateur", + "launch": "Lancement", + "formTitle": "Titre du formulaire", + "created": "Créé", + "deleted": "Supprimé", + "actions": "Actions", + "delete": "Supprimer" + }, + "administerForm": { + "deleted": "SUPPRIMÉ", + "restoreForm": "Restaurer ce formulaire", + "formDetails": "Détails du formulaire", + "apiKeyDetails": "Détails de la clé API", + "deleteApiKey": "Supprimer la clé API", + "formUsers": "Utilisateurs du formulaire", + "formVersions": "Versions de formulaire", + "assignANewOwner": "Attribuer un nouveau propriétaire", + "restoring": "Restaurer", + "restore": "Restaurer", + "toActiveState": "à l'état actif", + "confirmDeletion": "Confirmer la suppression", + "confirmDeletionMsg": "Voulez-vous vraiment supprimer cette clé API ?", + "delete": "Supprimer", + "confirmRestore": "Confirmer la restauration" + }, + "administerUser": { + "userDetails": "Détails de l'utilisateur", + "openSSOConsole": "Ouvrir la console SSO" + }, + "adminPage": { + "forms": "Formes", + "users": "Utilisateurs", + "developer": "Développeur", + "infoLinks": "Liens d'information", + "metrics": "Métrique" + }, + "adminUsersTable": { + "search": "Recherche", + "loadingText": "Chargement, veuillez patienter", + "admin": "Administrateur", + "fullName": "Nom et prénom", + "userID": "ID de l'utilisateur", + "created": "Créé", + "actions": "Actions" + }, + "adminVersions": { + "exportDesign": "Conception d'exportation", + "versions": "Versions", + "status": "Statut", + "created": "Créé", + "lastUpdated": "Dernière mise à jour", + "actions": "Actions", + "published": "Publié", + "unpublished": "Inédit", + "version": "Version {versionNo}", + "notificationMsg": "Une erreur s'est produite lors du chargement de la conception de formulaire." + }, + "developer": { + "user": "Utilisateur", + "name": "Nom", + "userName": "Nom d'utilisateur", + "JWTContents": "Contenu JWT", + "JWTContentsSBTxt": "Contenu JWT copié dans le presse-papiers", + "JWTContentsTTTxt": "Copier le contenu JWT dans le presse-papiers", + "JWTToken": "Jeton JWT", + "JWTTokenSBTxt": "Jeton JWT copié dans le presse-papiers", + "JWTTokenTTTxt": "Copier le jeton JWT dans le presse-papiers", + "chefsAPI": "API CHEFS", + "RBACSBTxt": "Réponse RBAC copiée dans le presse-papiers", + "RBACTTTxt": "Copier la réponse RBAC dans le presse-papiers", + "notificationMsg": "Impossible d'obtenir l'utilisateur à partir du RBAC, voir la console", + "notificationConsErr": "Erreur lors de l'obtention de l'utilisateur à partir du RBAC" + }, + "baseAuthButton": { + "logout": "Se déconnecter", + "login": "Connexion" + }, + "baseDialog": { + "defaultText": "texte par défaut", + "ok": "D'ACCORD", + "continue": "Continuer", + "cancel": "Annuler", + "custom": "Coutume" + }, + "baseSecure": { + "about": "À propos", + "loginInfo": "Vous devez être connecté pour utiliser cette fonctionnalité.", + "login": "Connexion", + "401NotAuthorized": "401 : non autorisé. :", + "401ErrorMsg": "Votre compte n'est pas configuré correctement.
S'il vous plaît contactez", + "403Forbidden": "403 : Interdit. :", + "403ErrorMsg": "Cette page nécessite une authentification {idp}.", + "401UnAuthorized": "401 : non autorisé. :", + "401UnAuthorizedErrMsg": "Vous n'avez pas la permission d'accéder à cette page." + }, + "formDesigner": { + "formDesign": "Conception de formulaire", + "exportDesign": "Conception d'exportation", + "importDesign": "Importer la conception", + "important": "IMPORTANT", + "formDesignInfoA": "Utilisez le bouton ENREGISTRER LA CONCEPTION lorsque vous avez terminé de créer ce formulaire.", + "formDesignInfoB": "Le bouton SOUMETTRE est fourni à votre utilisateur pour soumettre ce formulaire et sera activé après son enregistrement.", + "formLoadErrMsg": "Une erreur s'est produite lors du chargement de la conception de formulaire.", + "formLoadConsoleErrMsg": "Erreur lors du chargement du schéma {formId} du formulaire (version : {versionId} brouillon : {draftId}) : {error}", + "formSchemaImportErrMsg": "Une erreur s'est produite lors de l'importation du schéma du formulaire.", + "formSchemaImportConsoleErrMsg": "Erreur lors de l'importation du schéma du formulaire : {error}", + "formDesignSaveErrMsg": "Une erreur s'est produite lors de la tentative d'enregistrement de cette conception de formulaire. Si vous devez actualiser ou quitter pour réessayer plus tard, vous pouvez exporter le design existant sur la page pour l'enregistrer pour plus tard.", + "formDesignSaveConsoleErrMsg": "Erreur lors de la mise à jour ou de la création du formulaire (FormID : {formId}, versionId : {versionId}, draftId : {draftId}) Erreur : {error}", + "collapse": "Effondrement", + "actions": "Actions", + "version": "Version", + "save": "Sauvegarder", + "saving": "Économie", + "notSaved": "Non enregistré", + "fieldnameError": "Vous NE POUVEZ PAS utiliser le mot-clé `form` comme nom de champ {label}" + }, + "formViewerMultiUpload": { + "important": "IMPORTANT", + "uploadSucessMsg": "Pour assurer le téléchargement réussi de plusieurs brouillons, veuillez télécharger et utiliser le modèle fourni.", + "confirmDownload": "Voulez-vous le télécharger ?", + "jsonFileUpload": "Sélectionnez le fichier JSON à télécharger", + "dragNDrop": "ou glissez-déposez-le ici", + "chooseAFile": "Choisissez un fichier", + "downloadDraftSubmns": "Veuillez télécharger le projet de rapport de soumission et assurez-vous que les données sont saisies correctement.", + "downloadReport": "Télécharger le rapport", + "doYouWantToDownload": "Voulez-vous le télécharger ?", + "uploadNewFile": "Télécharger un nouveau fichier", + "uploadMultipleFileErr": "Désolé, vous ne pouvez télécharger qu'un seul fichier", + "dragMultipleFileErr": "Désolé, vous ne pouvez faire glisser qu'un seul fichier", + "fileFormatErr": "Désolé, nous n'acceptons que les fichiers json", + "fileSizeErr": "La taille de fichier maximale autorisée est de 5 Mo", + "parseJsonErr": "Nous ne pouvons pas analyser les données json du fichier", + "jsonObjNotArray": "Mauvais format de fichier json", + "jsonObjNotArrayConsErr": "Une erreur inattendue est apparue.", + "jsonArrayEmpty": "Ce fichier json est vide.", + "errorWhileValidate": "Il y a quelque chose qui ne va pas avec ce fichier", + "errWhileCheckValidity": "Il y a quelque chose qui ne va pas avec ce fichier", + "errAfterValidate": "Quelques erreurs trouvées, voir ci-dessous pour plus d'informations.", + "fileIsEmpty": "ce fichier est vide.", + "download": "Télécharger" + }, + "formDisclaimer": { + "disclaimerAndStatement": "Clause de non-responsabilité et déclaration de responsabilité pour les concepteurs de formulaire :", + "privacyLaw": "Il est de votre responsabilité de vous conformer aux lois sur la confidentialité régissant la collecte, l'utilisation et la divulgation d'informations personnellement identifiables.", + "disclosure": "L'accès à cet outil de conception de formulaire n'autorise pas intrinsèquement la collecte, l'utilisation ou la divulgation d'informations personnellement identifiables.", + "consent": "Il est de votre responsabilité d'obtenir le consentement pour collecter des informations conformément à la loi.", + "formIntention": "Avant de publier ou de distribuer votre formulaire, vous devez discuter de l'intention du formulaire avec votre", + "privacyOfficer": "Agent de la protection de la vie privée du ministère", + "assement": "et effectuer les évaluations nécessaires." + }, + "requestReceipt": { + "emailPriority": "Priorité aux e-mails", + "emailReceipt": "Envoyer un reçu de cette soumission par e-mail", + "high": "Haut", + "low": "Faible", + "normal": "Normale", + "send": "ENVOYER", + "sendToEmailAddress": "Envoyer à l'adresse e-mail", + "emailSent": "Un e-mail a été envoyé à {to}.", + "sendingEmailErrMsg": "Une erreur s'est produite lors de la tentative d'envoi de votre e-mail.", + "sendingEmailConsErrMsg": "La confirmation par e-mail à {to} a échoué : {error}", + "emailRequired": "L'e-mail est requis" + }, + "submissionsTable": { + "noMatchingRecordText": "Aucun enregistrements correspondants trouvés", + "submissions": "Soumissions", + "submissionsTable": "Tableau des soumissions", + "selectColumns": "Sélectionnez les colonnes", + "manageForm": "Gérer le formulaire", + "submissionsToFiles": "Exporter les soumissions vers des fichiers", + "showDeletedSubmissions": "Afficher les soumissions supprimées", + "showMySubmissions": "Afficher mes soumissions", + "search": "Recherche", + "loadingText": "Chargement, veuillez patienter", + "noDataText": "Il n'y a pas de soumissions pour ce formulaire", + "delSelectedSubmissions": "Supprimer les soumissions sélectionnées", + "resSelectedSubmissions": "Restaurer les soumissions sélectionnées", + "yes": "OUI", + "no": "NON", + "viewSubmission": "Voir la soumission", + "deleteSubmission": "Supprimer la soumission", + "restore": "Restaurer", + "confirmDeletion": "Confirmer la suppression", + "delete": "Supprimer", + "confirmRestoration": "Confirmer la restauration", + "searchSubmissionFields": "Champs de soumission de recherche", + "save": "Sauvegarder", + "searchTitle": "Recherchez et sélectionnez les colonnes à afficher sous votre tableau de bord", + "status": "Statut", + "submitter": "Auteur", + "submissionDate": "Date de soumission", + "event": "événement", + "view": "Voir", + "lateSubmission": "Un dépôt tardif", + "confirmationID": "Identifiant de confirmation", + "multiDelWarning": "Êtes-vous sûr de vouloir supprimer les soumissions sélectionnées ?", + "singleDelWarning": "Êtes-vous sûr de vouloir supprimer cette soumission ?", + "multiRestoreWarning": "Voulez-vous vraiment restaurer ces soumissions ?", + "singleRestoreWarning": "Voulez-vous vraiment restaurer cette soumission ?" + }, + "auditHistory": { + "viewEditHistory": "Afficher l'historique des modifications", + "editHistory": "Modifier l'historique", + "auditLogMsg": "Il s'agit d'un journal d'audit indiquant qui a apporté des modifications à cette soumission après la soumission d'origine.", + "loadingText": "Chargement, veuillez patienter", + "close": "Fermer", + "userName": "Nom d'utilisateur", + "date": "Date", + "errorMsg": "Une erreur s'est produite lors de la tentative de récupération de l'historique.", + "consoleErrMsg": "Erreur lors de l'obtention de l'historique d'audit pour" + }, + "deleteSubmission": { + "deleteThis": "Supprime ça", + "draft": "Brouillon", + "submission": "Soumission", + "confirmDeletion": "Confirmer la suppression", + "deleteWarning": "Êtes-vous sûr de vouloir supprimer ce", + "drafts": "brouillon", + "formSubmission": "soumission de formulaire", + "delete": "Supprimer" + }, + "manageSubmissionUsers": { + "manageTeamMembers": "Gérer les membres de l'équipe", + "add": "Ajouter", + "draftFormInvite": "Vous ne pouvez inviter et gérer les membres de l'équipe que lorsque ce formulaire est un brouillon", + "submissionTeamMembers": "Membres de l'équipe pour cette soumission", + "actions": "Actions", + "close": "Fermer", + "remove": "Retirer", + "userNotFoundErrMsg": "Vous ne trouvez pas quelqu'un ? Ils ne se sont peut-être pas connectés à CHEFS.
Veuillez leur envoyer un lien vers CHEFS et leur demander de se connecter.", + "name": "Nom", + "username": "Nom d'utilisateur", + "email": "E-mail", + "removeUserWarningMsg1": "Êtes-vous sûr de vouloir supprimer", + "removeUserWarningMsg2": "Ils n'auront plus les permissions pour cette soumission.", + "userExistInListMsg": "L'utilisateur {username} figure déjà dans la liste des membres de l'équipe.", + "getSubmissionUsersErr": "Une erreur s'est produite lors de la tentative de récupération des utilisateurs pour cette soumission.", + "getSubmissionUsersConsoleErr": "Erreur lors de l'obtention des utilisateurs pour {submissionId} : {error}", + "sentInviteEmailTo": "E-mail d'invitation envoyé à", + "sentUninvitedEmailTo": "Envoyé un e-mail non invité à", + "updateUserErrMsg": "Une erreur s'est produite lors de la tentative de mise à jour des utilisateurs pour cette soumission.", + "updateUserConsoleErrMsg": "Erreur lors de la définition des autorisations utilisateur. Sous : {submissionId} Utilisateur : {userId} Erreur : {error}", + "searchInputLength": "L'entrée de recherche pour le nom d'utilisateur/e-mail BCeID doit comporter plus de 6 caractères.", + "exactBCEIDSearch": "Les recherches par e-mail pour BCeID doivent être exactes.", + "getUsersErrMsg": "Erreur lors de l'obtention des utilisateurs : {error}", + "exactEmailOrUsername": "Entrez un e-mail ou un nom d'utilisateur exact.", + "requiredFiled": "Saisissez un nom, une adresse e-mail ou un nom d'utilisateur" + }, + "mySubmissionsActions": { + "viewThisSubmission": "Voir cette soumission", + "copyThisSubmission": "Copier cette soumission", + "editThisDraft": "Modifier ce brouillon" + }, + "mySubmissionsTable": { + "noMatchingRecordText": "Aucun enregistrements correspondants trouvés", + "previousSubmissions": "Soumissions précédentes", + "selectColumns": "Sélectionnez les colonnes", + "createNewSubmission": "Créer une nouvelle soumission", + "search": "Recherche", + "loadingText": "Chargement, veuillez patienter", + "noDataText": "Vous n'avez aucune soumission", + "searchSubmissionFields": "Champs de soumission de recherche", + "save": "Sauvegarder", + "filterTitle": "Recherchez et sélectionnez les colonnes à afficher sous votre tableau de bord", + "confirmationId": "Identifiant de confirmation", + "actions": "Actions", + "createdBy": "Créé par", + "statusUpdatedBy": "Statut mis à jour par", + "status": "Statut", + "submissionDate": "Date de soumission", + "draftUpdatedBy": "Brouillon mis à jour par", + "draftLastEdited": "Brouillon modifié en dernier", + "createLateSubmissn": "Créer une soumission tardive", + "formLoading": "Veuillez patienter pendant le chargement du formulaire !!!", + "pleaseConfirm": "Veuillez confirmer", + "wantToSaveDraft": "Voulez-vous enregistrer le brouillon ?", + "yes": "Oui", + "no": "Non", + "multiDraftUploadSuccess": "Votre téléchargement de brouillons multiples a réussi !", + "failedResSubmissn": "Échec de la réponse du point de terminaison de soumission. Code de réponse : {status}", + "errSubmittingForm": "Une erreur s'est produite lors de la soumission de ce formulaire", + "errorSavingFile": "Erreur lors de l'enregistrement des fichiers. Nom de fichier : {fileName}. Erreur : {error}", + "submittingDraftErrMsg": "Une erreur s'est produite lors de l'enregistrement d'un brouillon", + "submittingDraftConsErrMsg": "Erreur lors de l'enregistrement du brouillon. ID de soumission : {submissionId}. Erreur : {error}" + }, + "notesPanel": { + "addNewNote": "Ajouter une nouvelle note", + "cancel": "Annuler", + "addNote": "AJOUTER UNE NOTE", + "noResponseErr": "Aucune donnée de réponse de l'API lors de la soumission du formulaire", + "errorMesg": "Une erreur s'est produite lors de la tentative d'ajout de la note.", + "consoleErrMsg": "Erreur lors de l'ajout de la note :", + "fetchErrMsg": "Une erreur s'est produite lors de la tentative de récupération des notes pour cette soumission.", + "fetchConsoleErrMsg": "Erreur lors de l'ajout de la note :", + "notes": "Remarques", + "note": "Note", + "maxChars": "4000 caractères maximum" + }, + "statusPanel": { + "currentStatus": "Statut actuel:", + "assignedTo": "Assigné à:", + "assignOrUpdateStatus": "Attribuer ou mettre à jour le statut", + "display": "afficher", + "statusIsRequired": "Le statut est requis", + "assignTo": "Affecter à", + "noDataText": "Aucun examinateur de formulaire n'a été trouvé avec la recherche. Ajoutez des réviseurs de formulaires sur la page Gérer.", + "assigneeIsRequired": "Le cessionnaire est requis", + "assignToMe": "M'ASSIGNER", + "recipientEmail": "Destinataire E-mail", + "attachCommentToEmail": "Joindre un commentaire à un e-mail", + "emailComment": "Commentaire par e-mail", + "maxChars": "4000 caractères maximum", + "viewHistory": "VOIR L'HISTORIQUE", + "statusHistory": "Historique des statuts", + "close": "FERMER", + "addNoteNoReponserErr": "Aucune donnée de réponse de l'API lors de la soumission d'une note pour la mise à jour du statut", + "addNoteConsoleErrMsg": "Erreur lors de la mise à jour de l'état : {error}", + "addNoteErrMsg": "Une erreur s'est produite lors de la tentative de mise à jour de l'état", + "updtSubmissionsStatusErr": "Aucune donnée de réponse de l'API lors de la soumission du formulaire de mise à jour du statut", + "noStatus": "Pas de statut", + "noStatusesFound": "Aucun statut trouvé", + "statusCodesErr": "erreur lors de la recherche des codes d'état", + "notifyErrorCode": "Une erreur s'est produite lors de la récupération de l'état de cette soumission.", + "notifyConsoleErrorCode": "Erreur lors de la récupération des états :", + "fetchSubmissionUsersErr": "Une erreur s'est produite lors de la tentative de récupération des e-mails des destinataires pour cette soumission.", + "fetchSubmissionUsersConsErr": "Erreur lors de la récupération des e-mails des destinataires pour", + "assignSubmissnToFormReviewer": "Les soumissions peuvent être attribuées à des réviseurs de formulaires.
Pour ajouter d'autres membres de l'équipe en tant que réviseurs de formulaires, accédez à la page Gérer de ce formulaire.", + "update": "MISE À JOUR", + "revise": "RÉVISER", + "complete": "COMPLET", + "assign": "ATTRIBUER" + }, + "statusTable": { + "loadingText": "Chargement, veuillez patienter", + "status": "Statut", + "dateStatusChanged": "Date de modification du statut", + "assignee": "Cessionnaire", + "updatedBy": "Mis à jour par", + "getSubmissionStatusErr": "Une erreur s'est produite lors de la tentative de récupération des statuts.", + "getSubmissionStatusConsErr": "Erreur lors de l'ajout de la note :" + }, + "exportSubmissions": { + "exportSubmissionsToFile": "Exporter les soumissions vers un fichier", + "viewSubmissions": "Voir les soumissions", + "fileType": "Type de fichier", + "json": "JSON", + "csv": "CSV", + "formVersion": "Version du formulaire", + "versionIsRequired": "La version est requise.", + "dataFields": "Champs de données", + "searchFields": "Champs de recherche", + "selectedForExports": "sélectionnés pour l'exportation", + "submissionDate": "Date de soumission", + "all": "Tous", + "selectDateRange": "Sélectionnez la plage de dates", + "SelectdateRange": "Sélectionnez la plage de dates", + "from": "Depuis", + "to": "Pour", + "CSVFormat": "Format CSV", + "multiRowPerSubmissionA": "1 - Plusieurs lignes par soumission avec des espaces d'indentation", + "multiRowPerSubmissionB": "2 - Plusieurs lignes par soumission", + "singleRowPerSubmission": "3 - Une seule ligne par soumission", + "unformatted": "4 - Non formaté", + "fileNameAndType": "Nom et type de fichier", + "export": "Exporter", + "noResponseDataErr": "Aucune donnée en réponse à l'appel exportSubmissions", + "apiCallErrorMsg": "Une erreur s'est produite lors de la tentative d'exportation des soumissions pour ce formulaire.", + "apiCallConsErrorMsg": "Erreur lors de l'exportation des soumissions pour", + "selectAllFields": "Sélectionner tous les champs", + "emailSentMsg": "Un e-mail sera envoyé à {email} contenant un lien pour télécharger vos données lorsqu'elles seront prêtes", + "exportInProgress": "Exportation en cours", + "of": "de" + }, + "printOptions": { + "submitButtonTxt": "Soumettre à CDOGS et télécharger", + "templatePrint": "Modèle d'impression", + "uploadTemplateFile": "Télécharger le fichier modèle", + "downloadOptions": "Options de téléchargement", + "print": "Imprimer", + "browserPrint": "Impression du navigateur", + "pageFromBrowser": "la page de votre navigateur", + "uploadA": "Télécharger un", + "uploadB": "avoir une version structurée", + "docGrnSucess": "Document généré avec succès", + "failedDocGenErrMsg": "Échec de la génération du document", + "failedDocGenConsErrMsg": "Erreur lors de l'envoi du modèle : {error}", + "cDogsTemplate": "Modèle CDOGS" + }, + "proactiveHelpDialog": { + "componentInfoLink": "Lien d'informations sur les composants", + "learnMoreLinkTxt": "Le champ Lien en savoir plus ne peut pas être vide.", + "largeImgTxt": "Grande image. La taille de l'image ne peut pas être supérieure à 0,5 Mo", + "componentName": "Nom du composant:", + "learnMoreLink": "Lien pour en savoir plus :", + "clickToEnableLink": "Cliquez pour activer le lien", + "clickToDisableLink": "Cliquez pour désactiver le lien", + "imageUpload": "Importation d'images :", + "cancel": "Annuler", + "save": "Sauvegarder", + "description": "Description" + }, + "proactiveHelpPreviewDialog": { + "learnMore": "Apprendre encore plus" + }, + "preview": { + "preview": "Aperçu", + "previewToolTip": "Cela montre un aperçu de la conception et du comportement de la version du formulaire tels que vos expéditeurs le verront. Vous ne pouvez pas soumettre le formulaire à partir de cette page." + }, + "generalLayout": { + "loadingText": "Chargement, veuillez patienter", + "preview": "APERÇU", + "published": "PUBLIÉ", + "unpublished": "INÉDIT", + "edit": "MODIFIER", + "formTitle": "Titre du formulaire", + "actions": "Actions" + }, + "formSubmission": { + "editThisSubmission": "Modifier cette soumission", + "submission": "Soumission", + "alertInfo": "Après modification, soumettez à nouveau le formulaire pour enregistrer vos modifications.", + "viewAllSubmissions": "Voir toutes les soumissions", + "submitted": "Soumis :", + "confirmationID": "Identifiant de validation :", + "submittedBy": "Proposé par:", + "cancel": "ANNULER", + "status": "Statut", + "updatedAt": "Modifié", + "updatedBy": "Modifié par" + }, + "teamManagement": { + "noMatchingRecordText": "Aucun enregistrements correspondants trouvés", + "teamManagement": "Gestion d'équipe", + "selectColumns": "Sélectionnez les colonnes", + "manageForm": "Gérer le formulaire", + "search": "Recherche", + "loadingText": "Chargement, veuillez patienter", + "noDataText": "Échec du chargement des données de rôle d'équipe", + "removeSelectedUsers": "Supprimer les utilisateurs sélectionnés", + "removeThisUser": "Supprimer cet utilisateur", + "confirmRemoval": "Confirmer la suppression", + "remove": "Retirer", + "searchTeamManagementFields": "Champs de gestion d'équipe de recherche", + "save": "Sauvegarder", + "teamMebersTitle": "Recherchez et sélectionnez les colonnes à afficher sous votre tableau de bord", + "fullName": "Nom et prénom", + "username": "Nom d'utilisateur", + "identityProvider": "Fournisseur d'identité", + "delSelectedMembersWarning": "Voulez-vous vraiment supprimer les membres sélectionnés ?", + "delSelectedMemberWarning": "Voulez-vous vraiment supprimer le membre sélectionné ?", + "idpMessage": "est déjà dans l'équipe.", + "formOwnerErrMsg": "Il doit toujours y avoir au moins un propriétaire de formulaire", + "formOwnerConsoleErrMsg": "Impossible de supprimer {userId} car il est le seul propriétaire restant de ce formulaire.", + "insufficientPermissnMsg": "Autorisations insuffisantes pour gérer l'équipe", + "getUserErrMsg": "Erreur lors de la récupération des utilisateurs du formulaire :", + "getRolesErrMsg": "Erreur lors de la récupération de la liste des rôles :", + "formOwnerRemovalWarning": "Impossible de supprimer car ils sont le seul propriétaire restant de ce formulaire.", + "removeUsersErrMsg": "Une erreur s'est produite lors de la tentative de suppression des utilisateurs sélectionnés", + "removeUserConsoleErrMsg": "Erreur lors de la suppression des utilisateurs du formulaire {formId} : {error}", + "updUserRolesErrMsg": "Une erreur s'est produite lors de la tentative de mise à jour de tous les rôles d'utilisateur", + "updUserRolesConsoleErrMsg": "Erreur lors de la définition de tous les rôles d'utilisateur pour le formulaire {formId} : {error}", + "setUserFormsErrMsg": "Une erreur s'est produite lors de la tentative de mise à jour des rôles d'un utilisateur", + "setUserFormsConsoleErrMsg": "Erreur lors de la définition des rôles utilisateur pour le formulaire {formId} : {error}" + }, + "floatButton": { + "publish": "Publier", + "manage": "Gérer", + "redo": "Refaire", + "undo": "annuler", + "preview": "Aperçu", + "bottom": "Bas", + "top": "Haut", + "actions": "Actions", + "collapse": "Effondrement", + "saved": "Enregistré", + "save": "Sauvegarder", + "saving": "Économie", + "notSaved": "Non enregistré" + }, + "formViewer": { + "lateFormSubmissions": "La période de soumission du formulaire est expirée ! Vous pouvez toujours créer une soumission tardive en cliquant sur le bouton ci-dessous.", + "createLateSubmission": "Créer une soumission tardive", + "draftSaved": "Brouillon enregistré", + "saving": "Économie", + "pleaseConfirm": "Veuillez confirmer", + "submitFormWarningMsg": "Êtes-vous sûr de vouloir soumettre votre formulaire ?", + "submit": "Soumettre", + "wantToSaveDraft": "Voulez-vous enregistrer le brouillon ?", + "version": "Version : {version}", + "formScheduleExpireMessage": "La soumission du formulaire n'est pas disponible car la période de soumission prévue a expiré.", + "getUsersSubmissionsErrMsg": "Une erreur s'est produite lors de la récupération de la soumission pour ce formulaire", + "getUsersSubmissionsConsoleErrMsg": "Erreur lors du chargement des données d'envoi du formulaire {submissionId} : {error}", + "multiDraftUploadSuccess": "Votre téléchargement de brouillons multiples a réussi !", + "readVersionErrMsg": "Pas de schéma en réponse. ID de version : {versionId}", + "readDraftErrMsg": "Pas de schéma en réponse. ID brouillon : {draftId}", + "alertRouteMsg": "Le propriétaire du formulaire n'a pas publié le formulaire et il n'est pas disponible pour les soumissions.", + "fecthingFormErrMsg": "Une erreur s'est produite lors de la récupération de ce formulaire", + "fecthingFormConsoleErrMsg": "Erreur lors du chargement du schéma de formulaire {versionId} : {error}", + "savingDraftErrMsg": "Une erreur s'est produite lors de l'enregistrement d'un brouillon", + "savingDraftConsoleErrMsg": "Erreur lors de l'enregistrement du brouillon. ID de soumission : {submissionId}. Erreur : {error}", + "submissionsPreviewAlert": "Soumission désactivée lors de l'aperçu du formulaire", + "submissionsSubmitErrMsg": "Erreur lors de l'envoi du formulaire : {errors}", + "sendSubmissionErrMsg": "Échec de la réponse du point de terminaison de soumission. Code de réponse : {status}", + "errMsg": "Une erreur s'est produite lors de la soumission de ce formulaire", + "customEventAlert": "Les événements de bouton personnalisés ne sont pas encore pris en charge. Type d'événement : {event}", + "formLoading": "Veuillez patienter pendant le chargement du formulaire !!!", + "yes": "Oui", + "no": "Non", + "failedResSubmissn": "Échec de la réponse du point de terminaison de soumission. Code de réponse : {status}", + "errSubmittingForm": "Une erreur s'est produite lors de la soumission de ce formulaire", + "errorSavingFile": "Erreur lors de l'enregistrement des fichiers. Nom de fichier : {fileName}. Erreur : {error}", + "submittingDraftErrMsg": "Une erreur s'est produite lors de l'enregistrement d'un brouillon", + "submittingDraftConsErrMsg": "Erreur lors de l'enregistrement du brouillon. ID de soumission : {submissionId}. Erreur : {error}", + "formDraftAccessErrMsg": "La soumission demandée est déjà soumise, redirigeant vers la page Afficher" + }, + "bCGovFooter": { + "home": "Maison", + "about": "À propos de gov.bc.ca", + "disclaimer": "Clause de non-responsabilité", + "privacy": "Confidentialité", + "accessibility": "Accessibilité", + "copyRight": "droits d'auteur", + "contactUs": "Contactez-nous" + }, + "bCGovNavBar": { + "about": "À propos", + "myForms": "Mes formulaires", + "createNewForm": "Créer un nouveau formulaire", + "help": "Aider", + "feedback": "Retour", + "admin": "Administrateur" + }, + "homePage": { + "title": "Créez, publiez des formulaires et recevez des soumissions avec le service Common Hosted Forms.", + "subTitle": "Tous les B.C. Les employés du gouvernement ou les sous-traitants disposant d'un compte IDIR peuvent utiliser notre version hébergée de Common Hosted Forms Service (CHEFS) pour créer des formulaires.", + "takeATourOfChefs": "Faites le tour de CHEFS pour le voir en action.", + "logInToGetStarted": "Connectez-vous pour commencer", + "loginToStart": "Connectez-vous avec IDIR pour commencer", + "login": "Connexion", + "createFormLabel": "Créer un formulaire", + "manageAccessTitle": "Gérer l'accès à votre formulaire", + "manageAccessSub1": "CHEFS vous permet de créer des formulaires publics, ou vous pouvez gérer l'accès via l'authentification IDIR ou BCeID.", + "manageAccessSub2": "Vous pouvez également attribuer des rôles à votre équipe pour gérer toutes vos soumissions.", + "createCustomFormTitle": "Créez des formulaires personnalisés avec le générateur de formulaires CHEFS", + "createCustomFormSub1": "Avec CHEFS, vous pouvez créer des formulaires sécurisés avec une interface intuitive par glisser-déposer. Vous pouvez ajouter des composants de formulaire, les réorganiser et les déposer dans différentes configurations de mise en page.", + "chefsHowToTitle": "Vidéos explicatives CHEFS", + "chefsHowToSub": "Notre guide de démarrage rapide vous présentera certaines des fonctions de base de CHEFS.", + "getStartedToChefs": "Commencez à utiliser CHEFS", + "createOnlineTitle": "Créez des formulaires en ligne pour collecter des informations auprès de vos clients et améliorer vos flux de travail.", + "getStarted": "Commencer" + }, + "baseStepper": { + "setUpForm": "Configurer le formulaire", + "designForm": "Formulaire de conception", + "manageForm": "Gérer le formulaire" + }, + "create": { + "formSettings": "Paramètres du formulaire", + "disclaimer": "Clause de non-responsabilité", + "disclaimerStmt": "J'accepte la clause de non-responsabilité et la déclaration de responsabilité des concepteurs de formulaires", + "continue": "Continuer", + "back": "Dos", + "confirmPageNav": "Voulez-vous vraiment quitter cette page ? Les modifications que vous avez apportées ne seront pas enregistrées.", + "agreementErrMsg": "Vous devez accepter la clause de non-responsabilité en matière de confidentialité indiquée ci-dessus." + }, + "addTeamMember": { + "cantFindChefsUsers": "Vous ne trouvez pas quelqu'un ? Ils ne se sont peut-être pas connectés à CHEFS.
Veuillez leur envoyer un lien vers CHEFS et leur demander de se connecter.", + "cancel": "Annuler", + "add": "Ajouter", + "mustSelectAUser": "Vous devez sélectionner au moins un rôle pour ajouter cet utilisateur.", + "addNewMember": "Ajouter un nouveau membre", + "enterUsername": "Saisissez un nom, une adresse e-mail ou un nom d'utilisateur", + "enterExactUsername": "Entrez un e-mail ou un nom d'utilisateur exact", + "BCeIDInputSearchMaxLen": "L'entrée de recherche pour le nom d'utilisateur/e-mail BCeID doit comporter plus de 6 caractères.", + "BCeIDMustBeExact": "Les recherches par e-mail pour BCeID doivent être exactes.", + "errorGettingUsers": "Erreur lors de l'obtention des utilisateurs {error}" + }, + "baseFilter": { + "cancel": "Annuler", + "columnName": "Nom de colonne", + "exampleText": "Exemple de texte", + "exampleText2": "Exemple de texte 2", + "filterPlaceholderTxt": "Filtrer le texte de l'espace réservé", + "filter": "Filtre", + "value": "valeur", + "resetColumns": "Réinitialiser les colonnes" + }, + "formViewerActions": { + "viewMyDraftOrSubmissions": "Afficher mes brouillons/soumissions", + "saveAsADraft": "Enregistrer en tant que projet", + "editThisDraft": "Modifier ce brouillon", + "switchSingleSubmssn": "Passer à la soumission unique", + "switchMultiSubmssn": "Passer à plusieurs soumissions" + }, + "baseCopyToClipboard": { + "linkToClipboard": "Lien copié dans le presse-papiers", + "copyToClipboard": "Copier dans le presse-papier", + "errCopyToClipboard": "Erreur lors de la tentative de copie dans le presse-papiers." + }, + "sucess": { + "sucessFormSubmissn": "Votre formulaire a été soumis avec succès", + "keepRecord": "Si vous souhaitez conserver une trace de cette soumission, vous pouvez conserver les éléments suivants", + "confirmationId": "Identifiant de confirmation" + }, + "bcGovAlertBanner": { + "defaultErrMsg": "Erreur : une erreur s'est produite", + "error": "erreur" + }, + "permissionUtils": { + "formNotAvailable": "Le formulaire est actuellement indisponible. Cela peut être dû à un lien incorrect, ou le formulaire a peut-être été supprimé par son propriétaire.", + "missingFormIdAndSubmssId": "Options manquantes à la fois formId et submitId", + "loadingFormErrMsg": "Une erreur s'est produite lors du chargement de ce formulaire.", + "loadingForm": "Erreur lors du chargement de {options} : {error}", + "idpHintMsg": "Ce formulaire nécessite une authentification {idpHint}. Veuillez vous reconnecter et réessayer.", + "formIdpMissMatch": "Non-concordance du formulaire IDP. Le formulaire nécessite {idpHint} mais l'utilisateur a {userIdp}." + }, + "download": { + "chefsDataExport": "Exportation de données CHEFS", + "preparingForDownloading": "Préparation du téléchargement...", + "downloadInfoA": "Si votre fichier ne se télécharge pas automatiquement", + "downloadInfoB": "Cliquez ici pour essayer à nouveau" + }, + "history": { + "submissnHistory": "Votre historique de soumission (à déterminer)" + }, + "error": { + "logout": "Se déconnecter", + "somethingWentWrong": "Erreur : quelque chose s'est mal passé... :(" + }, + "login": { + "authenticateWith": "Authentifiez-vous avec :(", + "alreadyLoggedIn": "Déjà connecté", + "home": "Maison", + "about": "À propos" + }, + "notFound": { + "about": "À propos", + "pageNotFound": "404 Page non trouvée. :(" + }, + "store": { + "admin": { + "addFormOwnerRole": "Ajout du rôle Propriétaire pour ce formulaire à {fullName}", + "addRowError": "Une erreur s'est produite lors de l'ajout du rôle.", + "addRowConsoleErr": "Erreur lors de l'ajout de l'utilisateur {userId} au formulaire {formId} : {error}", + "apiKeyDelMsg": "La clé API de ce formulaire a été supprimée.", + "errDeletingApiKey": "Une erreur s'est produite lors de la tentative de suppression de la clé API.", + "consErrDeletingApiKey": "Erreur lors de la suppression de la clé API pour le formulaire {formId} : {error}", + "fecthingFormsErrMsg": "Une erreur s'est produite lors de la récupération des formulaires.", + "fecthingFormsConsErrMsg": "Erreur lors de la récupération des données du formulaire d'administration : {error}", + "fecthingFormErrMsg": "Une erreur s'est produite lors de la récupération de ce formulaire.", + "fecthingFormConsErrMsg": "Erreur lors de la récupération des données du formulaire d'administration {formId} : {error}", + "fecthFormUserRolesErrMsg": "Une erreur s'est produite lors de la récupération des rôles d'utilisateur du formulaire.", + "fecthFormUserRolesConsErrMsg": "Erreur lors de la récupération des données des rôles d'administrateur : {error}", + "fecthApiDetailsErrMsg": "Une erreur s'est produite lors de la récupération des détails de l'API de ce formulaire.", + "fecthApiDetailsConsErrMsg": "Erreur lors de l'obtention des détails de l'API d'administration à partir des données du formulaire {formId} : {error}", + "restoreFormErrMsg": "Une erreur s'est produite lors de la restauration de ce formulaire.", + "restoreFormConsErrMsg": "Erreur lors de la restauration des données du formulaire {formId} : {error}", + "getUsersErrMsg": "Une erreur s'est produite lors de la récupération des utilisateurs.", + "getUsersConsErrMsg": "Erreur lors de la récupération des données des utilisateurs administrateurs : {error}", + "getUserErrMsg": "Une erreur s'est produite lors de la récupération de cet utilisateur.", + "getUserConsErrMsg": "Erreur lors de la récupération des données de l'utilisateur administrateur {userId} : {error}", + "storingFCHelpInfoErrMsg": "Une erreur s'est produite lors du stockage des informations d'aide du composant de formulaire", + "storingFCHelpInfoConsErrMsg": "Erreur lors de l'enregistrement des informations d'aide sur le composant de formulaire : {error}", + "gettingFCImgUrlErrMsg": "Une erreur s'est produite lors de l'obtention de l'URL de l'image", + "gettingFCImgUrlConsErrMsg": "Erreur lors de l'obtention de l'URL de l'image : {error}", + "updatingFCStatusErrMsg": "Une erreur s'est produite lors de la mise à jour de l'état de publication", + "updatingFCStatusConsErrMsg": "Erreur lors de la mise à jour de l'état de publication : {error}", + "fecthingFormBuilderCompsErrMsg": "Une erreur s'est produite lors de la récupération des composants du générateur de formulaires", + "fecthingFormBuilderCompsConsErrMsg": "Erreur lors de l'obtention des composants du générateur de formulaire : {error}" + }, + "form": { + "fetchEmailTemplatesConsErrMsg": "Erreur lors du chargement des modèles d'e-mail pour {formId} : {error}", + "fetchEmailTemplatesErrMsg": "Une erreur s'est produite lors de la récupération des modèles d'e-mail pour ce formulaire", + "getCurrUserFormsErrMsg": "Une erreur s'est produite lors de la récupération de vos formulaires.", + "getCurrUserFormsConsErrMsg": "Erreur lors de la récupération des données utilisateur : {error}", + "getUserFormPermErrMsg": "Une erreur s'est produite lors de la récupération de vos données utilisateur pour ce formulaire.", + "getUserFormPermConsErrMsg": "Erreur lors de l'obtention des données utilisateur à l'aide du formID {formId} : {error}", + "getUserFormRolesErrmsg": "Une erreur s'est produite lors de la récupération de vos données utilisateur pour ce formulaire.", + "getUserFormRolesConsErrmsg": "Erreur lors de l'obtention des données utilisateur à l'aide du formID {formId} : {error}", + "updCurrUserFormPrefErrMsg": "Une erreur s'est produite lors de l'enregistrement de vos préférences pour ce formulaire.", + "updCurrUserFormPrefConsErrMsg": "Erreur lors de la mise à jour des préférences du formulaire utilisateur à l'aide de formID {formId} et des préférences {preferences} : {error}", + "getCurrUserFormPrefErrMsg": "Une erreur s'est produite lors de la récupération de vos préférences pour ce formulaire.", + "getCurrUserFormPrefConsErrMsg": "Erreur lors de l'obtention des préférences du formulaire utilisateur à l'aide du formID {formId} : {error}", + "delCurrformNotiMsg": "Le formulaire {name} a été supprimé avec succès.", + "delCurrFormConsErMsg": "Erreur lors de la suppression du formulaire {id} : {error}", + "delDraftErrMsg": "Une erreur s'est produite lors de la suppression de ce brouillon.", + "delDraftConsErrMsg": "Erreur lors de la suppression de {draftId} : {error}", + "fecthDraftErrMsg": "Une erreur s'est produite lors de la recherche de brouillons pour ce formulaire.", + "fecthDraftConsErrMsg": "Erreur lors de la récupération des brouillons pour le formulaire {formId} : {error}", + "fecthFormErrMsg": "Une erreur s'est produite lors de la récupération de ce formulaire.", + "fecthFormConsErrMsg": "Erreur lors de la récupération du formulaire {formId} : {error}", + "fetchFormFieldsErrMsg": "Une erreur s'est produite lors de la récupération de la liste des champs de ce formulaire.", + "fetchFormFieldsConsErrMsg": "Erreur lors de la récupération du formulaire {formId} : {error}", + "publishDraftErrMsg": "Une erreur s'est produite lors de la publication.", + "publishDraftConsErrMsg": "Erreur lors de la publication de {draftId} : {error}", + "toggleVersnPublConsErrMsg": "Erreur dans toggleVersionPublish {versionId} {publish} : {error}", + "updateEmailTemplateConsErrMsg": "Erreur lors de la mise à jour des modèles d'e-mail pour le formulaire {formId} : {error}", + "updateEmailTemplateErrMsg": "Une erreur s'est produite lors de la mise à jour des modèles d'e-mails pour ce formulaire.", + "updateFormErrMsg": "Une erreur s'est produite lors de la mise à jour des paramètres de ce formulaire.", + "updateFormConsErrMsg": "Erreur lors de la mise à jour du formulaire {id} : {error}", + "deleteSubmissionNotifyMsg": "Soumission supprimée avec succès.", + "deleteSubmissionErrMsg": "Une erreur s'est produite lors de la suppression de cette soumission.", + "deleteSubmissionConsErrMsg": "Erreur lors de la suppression de la soumission {submissionId} : {error}", + "deleteSubmissionsNotifyMsg": "Soumissions supprimées avec succès.", + "deleteSubmissionsErrMsg": "Une erreur s'est produite lors de la suppression des soumissions sélectionnées.", + "deleteSubmissionsConsErrMsg": "Erreur lors de la suppression des soumissions : {error}", + "restoreSubmissionsNotiMsg": "Soumissions restaurées avec succès.", + "restoreSubmissionsErrMsg": "Une erreur s'est produite lors de la restauration de cette soumission.", + "restoreSubmissionsConsErrMsg": "Erreur lors de la restauration des soumissions : {error}", + "restoreSubmissionNotiMsg": "Soumission restaurée avec succès.", + "restoreSubmissionErrMsg": "Une erreur s'est produite lors de la restauration de cette soumission.", + "restoreSubmissionConsErrMsg": "Erreur lors de la restauration de la soumission {submissionId} : {error}", + "fecthSubmissnUsersErrMsg": "Une erreur s'est produite lors de la récupération de l'e-mail du destinataire pour cette soumission.", + "fecthSubmissnUsersConsErrMsg": "Erreur lors de la réception de l'e-mail du destinataire pour la soumission {formSubmissionId} : {error}", + "fetchSubmissnErrMsg": "Une erreur s'est produite lors de la récupération de cette soumission.", + "fetchSubmissnConsErrMsg": "Erreur lors de l'obtention de la soumission {submissionId} : {error}", + "fetchFormCSVExptFieldsErrMsg": "Une erreur s'est produite lors de la récupération de la liste des champs de ce formulaire.", + "fetchFormCSVExptFieldsConsErrMsg": "Erreur lors de la récupération du formulaire {formId} : {error}", + "fetchSubmissnsErrMsg": "Une erreur s'est produite lors de la récupération des soumissions pour ce formulaire.", + "fetchSubmissnsConsErrMsg": "Erreur lors de l'obtention des soumissions pour {formId} : {error}", + "fetchVersionErrMsg": "Une erreur s'est produite lors de la récupération de ce formulaire.", + "fetchVersionConsErrMsg": "Erreur lors de l'obtention de la version {versionId} pour le formulaire {formId} : {error}", + "deleteApiKeyNotifyMsg": "La clé API de ce formulaire a été supprimée.", + "deleteApiKeyErrMsg": "Une erreur s'est produite lors de la tentative de suppression de la clé API.", + "deleteApiKeyConsErrMsg": "Erreur lors de la suppression de la clé API pour le formulaire {formId} : {error}", + "generateApiKeyNotifyMsg": "Une clé API pour ce formulaire a été créée.", + "generateApiKeyErrMsg": "Une erreur s'est produite lors de la tentative de génération d'une clé API.", + "generateApiKeyConsErrMsg": "Erreur lors de la génération de la clé API pour le formulaire {formId} : {error}", + "readApiKeyErrMsg": "Une erreur s'est produite lors de la tentative de récupération de la clé API.", + "readApiKeyConsErrMsg": "Erreur lors de l'obtention de la clé API pour le formulaire {formId} : {error}.", + "getFCPHImageUrlErrMsg": "Une erreur s'est produite lors de l'obtention de l'URL de l'image", + "getFCPHImageUrlConsErrMsg": "Erreur lors de l'obtention de l'URL de l'image : {error}", + "listFCPHErrMsg": "Une erreur s'est produite lors de la récupération des composants du générateur de formulaires", + "listFCPHConsErrMsg": "Erreur lors de l'obtention des composants du générateur de formulaire : {error}", + "downloadFileErrMsg": "Une erreur s'est produite lors du téléchargement du fichier", + "downloadFileConsErrMsg": "Erreur lors du téléchargement du fichier : erreur", + "readSubscriptionSettingsErrMsg": "Une erreur s'est produite lors de la tentative de récupération des paramètres d'abonnement.", + "readSubscriptionSettingsConsErrMsg": "Erreur lors de l'obtention des paramètres d'abonnement pour le formulaire {formId} : {error}.", + "saveSubscriptionSettingsNotifyMsg": "Les paramètres d'abonnement pour ce formulaire ont été enregistrés.", + "saveSubscriptionSettingsErrMsg": "Une erreur s'est produite lors de la tentative d'enregistrement des paramètres d'abonnement.", + "saveSubscriptionSettingsConsErrMsg": "Erreur lors de l'enregistrement des paramètres d'abonnement pour le formulaire {formId} : {error}" + } + }, + "admin": { + "root": { + "admin": "Administrateur" + }, + "form": { + "administerForm": "Formulaire d'administration" + }, + "user": { + "administerUser": "Administrer l'utilisateur" + } + }, + "user": { + "root": { + "myForms": "MES FORMULAIRES", + "history": "HISTOIRE", + "user": "Utilisateur" + } + } +} diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/fr/index.js b/frontend/app/frontend/src/internationalization/trans/chefs/fr/index.js new file mode 100644 index 0000000..63afd66 --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/fr/index.js @@ -0,0 +1,4 @@ +import fr from '~/internationalization/trans/chefs/fr/fr.json'; +export default { + trans: fr, +}; diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/hi/hi.json b/frontend/app/frontend/src/internationalization/trans/chefs/hi/hi.json new file mode 100644 index 0000000..8dfa769 --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/hi/hi.json @@ -0,0 +1,995 @@ +{ + "date": { + "date": "yyyy-mm-dd" + }, + "emailManagement": { + "emailManagement": "ईमेल प्रबंधन", + "manageForm": "प्रपत्र प्रबंधित करें", + "submissionConfirmation": "प्रस्तुत करने की पुष्टि" + }, + "emailTemplate": { + "body": "शरीर", + "save": "बचाना", + "saveEmailTemplateConsoleErrMsg": "फ़ॉर्म {formId} के लिए ईमेल टेम्पलेट अपडेट करने में त्रुटि: {error}", + "saveEmailTemplateErrMsg": "ईमेल टेम्पलेट को अद्यतन करने का प्रयास करते समय एक त्रुटि उत्पन्न हुई।", + "subject": "विषय", + "title": "शीर्षक", + "validBodyRequired": "कृपया ईमेल के लिए एक मुख्य भाग दर्ज करें", + "validSubjectRequired": "कृपया ईमेल के लिए विषय पंक्ति दर्ज करें", + "validTitleRequired": "कृपया ईमेल के लिए एक शीर्षक दर्ज करें" + }, + "formsTable": { + "myForms": "मेरे प्रपत्र", + "createNewForm": "एक नया फॉर्म बनाएं", + "search": "खोज", + "manage": "प्रबंधित करना", + "submissions": "प्रविष्टियों", + "formTitle": "प्रपत्र शीर्षक", + "viewForm": "प्रपत्र देखें", + "description": "विवरण", + "Description": "विवरण:", + "action": "कार्रवाई", + "loadingText": "लोड हो रहा है कृपया प्रतीक्षा करें" + }, + "manageLayout": { + "manageForm": "प्रपत्र प्रबंधित करें" + }, + "preview": { + "preview": "पूर्व दर्शन", + "previewToolTip": "यह प्रपत्र संस्करण डिज़ाइन और व्यवहार का पूर्वावलोकन दिखाता है जैसा कि आपके सबमिटर्स इसे देखेंगे। आप इस पेज से फ़ॉर्म सबमिट नहीं कर सकते." + }, + "shareForm": { + "shareForm": "प्रपत्र साझा करें", + "shareLink": "लिंक शेयर करें", + "copyQRCode": "नीचे दिए गए लिंक को कॉपी करें या क्यूआर कोड डाउनलोड करें।", + "warningMessage": "इस समय फॉर्म का कोई प्रकाशित संस्करण नहीं है। संस्करण प्रकाशित होने तक नीचे दिया गया लिंक उपलब्ध नहीं होगा।", + "openThisForm": "इस फॉर्म को खोलें", + "downloadQRCode": "क्यूआर कोड डाउनलोड करें", + "close": "बंद करना", + "copyURLToClipboard": "यूआरएल को क्लिपबोर्ड पर कॉपी करें" + }, + "manageFormActions": { + "emailManagement": "ईमेल प्रबंधन", + "viewSubmissions": "सबमिशन देखें", + "teamManagement": "टीम प्रबंधन", + "deleteForm": "फ़ॉर्म हटाएँ", + "confirmDeletion": "मिटाने की पुष्टि", + "deleteMessageA": "क्या आप वाकई हटाना चाहते हैं?", + "deleteMessageB": "यह फॉर्म अब पहुंच योग्य नहीं होगा.", + "delete": "मिटाना" + }, + "manageForm": { + "formSettings": "फॉर्म सेटिंग्स", + "apiKey": "एपीआई कुंजी", + "updated": "अद्यतन", + "created": "बनाया था", + "formDesignHistory": "प्रपत्र डिज़ाइन इतिहास", + "totalVersions": "कुल संस्करण", + "status": "दर्जा", + "update": "अद्यतन", + "cancel": "रद्द करना", + "eventSubscription": "इवेंट सदस्यता" + }, + "formSettings": { + "pressToAddMultiEmail": "एकाधिक ईमेल पते जोड़ने के लिए एंटर या , या स्पेस दबाएँ", + "allowMultiDraft": "एकाधिक ड्राफ्ट अपलोड की अनुमति दें", + "formTitle": "प्रपत्र शीर्षक", + "formDescription": "प्रपत्र विवरण", + "formAccess": "प्रपत्र प्रवेश", + "info": "यदि आप इस फॉर्म का उपयोग उन विषयों पर आम जनता से जानकारी इकट्ठा करने के लिए करेंगे जो जनता के लिए सामान्य रुचि के हैं, तो आपको जीसीपीई से संपर्क करना होगा ताकि आपकी भागीदारी को सूचीबद्ध किया जा सके।", + "important": "महत्वपूर्ण", + "idimNotifyA": "आपको पहचान सूचना प्रबंधन (आईडीआईएम) टीम को ईमेल द्वारा सूचित करना होगा", + "idimNotifyB": "अपने फॉर्म जमा करने वालों की पहचान सत्यापित करने के लिए बीसीईआईडी का लाभ उठाने का आपका इरादा।", + "referenceGuideA": "कृपया हमारा संदर्भ लें", + "referenceGuideB": "उपयोगकर्ता गाइड", + "referenceGuideC": "अधिक जानकारी के लिए", + "specificTeamMembers": "विशिष्ट टीम के सदस्य", + "formFunctionality": "फॉर्म की कार्यक्षमता", + "formSubmissinScheduleMsg": "फॉर्म सबमिशन शेड्यूल फॉर्म प्रकाशित होने के बाद फॉर्म सेटिंग्स में उपलब्ध होगा।", + "formSubmissionsSchedule": "फॉर्म जमा करने की अनुसूची", + "experimental": "प्रयोगात्मक", + "learnMore": "और अधिक जानें", + "afterSubmission": "सबमिशन के बाद", + "submissionConfirmation": "सबमिशन पुष्टिकरण विवरण दिखाएं", + "theConfirmationID": "पुष्टिकरण आईडी", + "infoB": "उपयोगकर्ता के लिए खुद को सबमिशन पुष्टिकरण ईमेल करने का विकल्प", + "loginRequired": "लॉगिन आवश्यक", + "canSaveAndEditDraftLabel": "जमाकर्ता ड्राफ्ट सहेज और संपादित कर सकते हैं", + "canUpdateStatusAsReviewer": "समीक्षक इस फॉर्म की स्थिति को अपडेट कर सकते हैं (अर्थात सबमिट किया गया, सौंपा गया, पूरा किया गया)", + "submitterCanCopyExistingSubmissn": "सबमिटर्स मौजूदा सबमिशन की प्रतिलिपि बना सकते हैं", + "submissionConfirmationToolTip": "इस विकल्प का चयन यह नियंत्रित करता है कि इस फॉर्म को सबमिट करने वाला उपयोगकर्ता सफल सबमिशन पर क्या देखेगा।
यदि जांच की जाए तो यह प्रदर्शित हो जाएगा", + "emailNotificatnToTeam": "मेरी टीम को एक अधिसूचना ईमेल भेजें", + "emailNotificatnToTeamToolTip": "जब कोई उपयोगकर्ता यह फॉर्म सबमिट करे तो अपने निर्दिष्ट ईमेल पते पर एक अधिसूचना भेजें", + "notificationEmailAddrs": "अधिसूचना ईमेल पते", + "addMoreValidEmailAddrs": "एक या अधिक मान्य ईमेल पते जोड़ें", + "formScheduleSettings": "फॉर्म शेड्यूल सेटिंग्स", + "opensubmissions": "सबमिशन खोलें", + "submissionsDeadline": "आप कब तक सबमिशन प्राप्त करना चाहते हैं?", + "keepSubmissnOpenTilUnplished": "मैन्युअल रूप से अप्रकाशित होने तक खुला रखें", + "submissionsClosingDate": "एक समापन तिथि निर्धारित करें", + "submissionPeriod": "सबमिशन अवधि निर्धारित करें", + "closeSubmissions": "सबमिशन बंद करें", + "keepOpenFor": "के लिए खुला रखें", + "period": "अवधि", + "allowLateSubmissions": "देर से सबमिशन की अनुमति दें", + "allowLateSubmissionsInfoTip": "यदि जाँच की जाती है, तो जमाकर्ता अंतिम तिथि के बाद डेटा जमा करने में सक्षम होंगे।", + "afterCloseDateFor": "के लिए अंतिम तिथि के बाद", + "repeatPeriod": "अवधि दोहराएँ", + "every": "प्रत्येक", + "repeatUntil": "दोहराओ जब तक", + "summary": "सारांश", + "submissionsOpenDateRange": "यह फॉर्म सबमिशन के लिए खुला रहेगा", + "to": "को", + "scheduleRepetition": "शेड्यूल हर बार दोहराया जाएगा", + "allowLateSubmissnInterval": "के लिए देर से सबमिशन की अनुमति देना", + "until": "जब तक", + "datesOfSubmissnInfo": "सेटिंग्स के अनुसार ये सबमिशन की उपलब्ध तिथियां हैं:", + "formOpenInterval": "यह फॉर्म सबमिशन के लिए खुला रहेगा", + "allowDateSubmissionDate": "तक देर से जमा करने की अनुमति के साथ", + "customClosingMessage": "कस्टम समापन संदेश सेट करें", + "customClosingMessageToolTip": "जब आपके उपयोगकर्ता किसी बंद फॉर्म पर जाएँ तो आपको उनके लिए एक अनुकूलित संदेश जोड़ने की अनुमति देता है।", + "closingMessage": "समापन संदेश", + "sendReminderEmail": "अनुस्मारक ईमेल भेजें", + "autoReminderNotificatn": "स्वचालित अनुस्मारक अधिसूचना सक्षम करें", + "autoReminderNotificatnToolTip": "जमा करने की अवधि के दौरान फॉर्म लिंक के साथ अनुस्मारक ईमेल भेजें।", + "selectLoginType": "कृपया 1 लॉग-इन प्रकार चुनें", + "formDescriptnMaxChars": "फॉर्म विवरण 255 अक्षर या उससे कम होना चाहिए", + "formTitlemaxChars": "फॉर्म शीर्षक 255 अक्षर या उससे कम होना चाहिए", + "formTitleReq": "प्रपत्र शीर्षक आवश्यक है", + "atLeastOneEmailReq": "कृपया कम से कम 1 ईमेल पता दर्ज करें", + "validEmailRequired": "कृपया सभी वैध ईमेल पते दर्ज करें", + "fieldRequired": "यह फ़ील्ड आवश्यक है.", + "correctDateFormat": "दिनांक सही प्रारूप में होनी चाहिए. अर्थात। yyyy-mm-dd", + "dateDiffMsg": "सबमिशन बंद करने की तारीख, ओपन सबमिशन की तारीख से अधिक होनी चाहिए।", + "valueMustBeNumber": "मान एक संख्या होना चाहिए. अर्थात। 1,2,3,5,99", + "selectAnOptions": "कृपया कम से कम 1 विकल्प चुनें", + "validInterval": "यह एक वैध अंतराल होना चाहिए.", + "fieldRequiredAndInterval": "यह फ़ील्ड आवश्यक है और एक अंतराल होना चाहिए.", + "dateGrtOpenSubmissnDate": "तब तक दोहराएँ जब तक दिनांक ओपन सबमिशन दिनांक से अधिक न हो जाए", + "public": "सार्वजनिक (गुमनाम)", + "allowEventSubscription": "ईवेंट सदस्यता की अनुमति दें", + "eventSubscription": "इवेंट सदस्यता", + "validEndpointRequired": "कृपया प्रारंभ करने वाला एक वैध समापन बिंदु दर्ज करें https://", + "validBearerTokenRequired": "एक वैध वाहक टोकन उदाहरण दर्ज करें: 89abddfb-2cff-4fda-83e6-13221f0c3d4f" + }, + "subscribeEvent": { + "eventType": "घटना प्रकार", + "endpointUrl": "समापन बिंदु यूआरएल", + "eventSubmission": "जमा करना", + "eventAssignment": "कार्यभार", + "eventStatusChange": "स्थिति परिवर्तन", + "endpointToken": "समापन बिंदु टोकन", + "urlPlaceholder": "https://endpoint.gov.bc.ca/api/v1/", + "save": "बचाना", + "text": "मूलपाठ", + "password": "पासवर्ड", + "hideSecret": "गुप्त छुपाएं", + "showSecret": "राज दिखाओ", + "key": "चाबी", + "saveSettingsErrMsg": "इस फॉर्म के लिए सेटिंग्स को अद्यतन करने का प्रयास करते समय एक त्रुटि उत्पन्न हुई।", + "updateSettingsConsoleErrMsg": "फ़ॉर्म {formId} के लिए सेटिंग अपडेट करने में त्रुटि: {error}" + }, + "apiKey": { + "disclaimer": "अस्वीकरण", + "infoA": "सुनिश्चित करें कि आपकी एपीआई कुंजी रहस्य एक सुरक्षित स्थान (यानी कुंजी वॉल्ट) में संग्रहीत है।", + "infoB": "आपकी एपीआई कुंजी आपके फॉर्म तक अप्रतिबंधित पहुंच प्रदान करती है। अपनी एपीआई कुंजी किसी को न दें।", + "infoC": "एपीआई कुंजी का उपयोग केवल स्वचालित सिस्टम इंटरैक्शन के लिए किया जाना चाहिए। उपयोगकर्ता आधारित पहुंच के लिए अपनी एपीआई कुंजी का उपयोग न करें", + "deleteKey": "कुंजी हटाएँ", + "apiKey": "एपीआई कुंजी", + "hideSecret": "गुप्त छिपाएँ", + "showSecret": "रहस्य दिखाओ", + "sCTC": "गुप्त क्लिपबोर्ड पर कॉपी किया गया", + "cSTC": "क्लिपबोर्ड पर रहस्य कॉपी करें", + "key": "चाबी", + "confirmDeletion": "मिटाने की पुष्टि", + "deleteMsg": "क्या आप वाकई अपनी एपीआई कुंजी हटाना चाहते हैं?", + "delete": "मिटाना", + "confirmKeyGen": "कुंजी पीढ़ी की पुष्टि करें", + "createAPIKey": "इस फॉर्म के लिए एक एपीआई कुंजी बनाएं?
सुनिश्चित करें कि आप इस पृष्ठ पर अस्वीकरण का पालन करें।", + "regenerateAPIKey": "एपीआई कुंजी पुन: उत्पन्न करें?
जारी रखने से आपकी वर्तमान एपीआई कुंजी पहुंच नष्ट हो जाएगी ।", + "formOwnerKeyAcess": "एपीआई कुंजी प्रबंधित करने के लिए आपको फॉर्म स्वामी होना चाहिए।", + "regenerate": "पुनः जेनरेट", + "generate": "बनाना", + "secret": "गुप्त" + }, + "manageVersions": { + "important": "महत्वपूर्ण!", + "infoA": "यदि कोई प्रकाशित संस्करण नहीं है, तो उपयोगकर्ता इस फॉर्म तक पहुंचने में असमर्थ हैं जब तक कि कोई प्रकाशित संस्करण आवंटित न हो। एक बार जब कोई संस्करण प्रकाशित हो जाता है, तो वह संस्करण संपादन योग्य नहीं रह जाता है। संपादन जारी रखने के लिए आपको पिछले फॉर्म संस्करणों में से एक के आधार पर एक नया संस्करण बनाना होगा।", + "infoB": "नोट: केवल एक संस्करण ही प्रकाशित किया जा सकता है।", + "version": "संस्करण", + "draft": "प्रारूप", + "clickToPreview": "पूर्वावलोकन करने के लिए क्लिक करें", + "editVersion": "संस्करण संपादित करें", + "exportDesign": "निर्यात डिजाइन", + "infoC": "कृपया नया संस्करण शुरू करने से पहले अपना नवीनतम ड्राफ्ट संस्करण प्रकाशित करें या हटा दें।", + "deleteVersion": "संस्करण हटाएँ", + "draftAlreadyExists": "ड्राफ्ट पहले से मौजूद है", + "infoD": "कृपया नया ड्राफ्ट शुरू करने से पहले मौजूदा ड्राफ्ट को संपादित करें, प्रकाशित करें या हटा दें।", + "publishVersion": "संस्करण प्रकाशित करें", + "unpublishVersion": "संस्करण अप्रकाशित करें", + "infoE": "इस फॉर्म को अप्रकाशित करने से फॉर्म तब तक प्रचलन से बाहर हो जाएगा जब तक कोई संस्करण दोबारा प्रकाशित न हो जाए।", + "confirmDeletion": "मिटाने की पुष्टि", + "infoF": "क्या आप वाकई इस संस्करण को हटाना चाहते हैं?", + "delete": "मिटाना", + "status": "दर्जा", + "dateCreated": "बनाया गया दिनांक", + "createdBy": "के द्वारा बनाई गई", + "actions": "कार्रवाई", + "published": "प्रकाशित", + "unpublished": "अप्रकाशित", + "useVersionInfo": "नए संस्करण के लिए आधार के रूप में संस्करण {version} का उपयोग करें", + "publishingVersionInfo": "इससे आपके फॉर्म का वर्जन {version} लाइव हो जाएगा।" + }, + "addOwner": { + "infoA": "यह केवल उस स्थिति में किया जाना चाहिए जब वर्तमान फॉर्म स्वामी अब सक्रिय नहीं है या किसी प्राथमिकता वाले कार्यक्रम में संपर्क से बाहर है। अन्यथा फॉर्म के वर्तमान मालिक या टीम प्रशासक को यह स्वयं करने दें।", + "hint": "आवश्यक उपयोगकर्ता आईडी ढूंढने के लिए आप एडमिन पोर्टल में 'उपयोगकर्ता' टैब पर जा सकते हैं और उन्हें खोज सकते हैं।", + "addowner": "स्वामी जोड़ें", + "label": "उपयोगकर्ता आईडी (गाइड)" + }, + "adminFormsTable": { + "showDeletedForms": "हटाए गए फॉर्म दिखाएं", + "search": "खोज", + "loadingText": "लोड हो रहा है-पाठ", + "noDataText": "आपके सिस्टम में कोई फॉर्म नहीं हैं", + "admin": "व्यवस्थापक", + "launch": "शुरू करना", + "formTitle": "प्रपत्र शीर्षक", + "created": "बनाया था", + "deleted": "हटाए गए", + "actions": "कार्रवाई", + "delete": "मिटाना" + }, + "administerForm": { + "deleted": "हटाए गए", + "restoreForm": "इस फॉर्म को पुनर्स्थापित करें", + "formDetails": "प्रपत्र विवरण", + "apiKeyDetails": "एपीआई कुंजी विवरण", + "deleteApiKey": "एपीआई कुंजी हटाएं", + "formUsers": "प्रपत्र उपयोगकर्ता", + "formVersions": "प्रपत्र संस्करण", + "assignANewOwner": "एक नया स्वामी नियुक्त करें", + "restoring": "पुनर्स्थापित कर रहा है", + "restore": "पुनर्स्थापित करना", + "toActiveState": "सक्रिय अवस्था में", + "confirmDeletion": "मिटाने की पुष्टि", + "confirmDeletionMsg": "क्या आप वाकई इस एपीआई कुंजी को हटाना चाहते हैं?", + "delete": "मिटाना", + "confirmRestore": "पुनर्स्थापना की पुष्टि करें" + }, + "administerUser": { + "userDetails": "उपयोगकर्ता विवरण", + "openSSOConsole": "एसएसओ कंसोल खोलें" + }, + "adminPage": { + "forms": "फार्म", + "users": "उपयोगकर्ताओं", + "developer": "डेवलपर", + "infoLinks": "जानकारी लिंक", + "metrics": "मेट्रिक्स" + }, + "adminUsersTable": { + "search": "खोज", + "loadingText": "लोड हो रहा है कृपया प्रतीक्षा करें", + "admin": "व्यवस्थापक", + "fullName": "पूरा नाम", + "userID": "उपयोगकर्ता पहचान", + "created": "बनाया था", + "actions": "कार्रवाई" + }, + "adminVersions": { + "exportDesign": "निर्यात डिजाइन", + "versions": "संस्करणों", + "status": "दर्जा", + "created": "बनाया था", + "lastUpdated": "आखरी अपडेट", + "actions": "कार्रवाई", + "published": "प्रकाशित", + "unpublished": "अप्रकाशित", + "version": "संस्करण {versionNo}", + "notificationMsg": "प्रपत्र डिज़ाइन लोड करते समय कोई त्रुटि उत्पन्न हुई." + }, + "developer": { + "user": "उपयोगकर्ता", + "name": "नाम", + "userName": "उपयोगकर्ता नाम", + "JWTContents": "जेडब्ल्यूटी सामग्री", + "JWTContentsSBTxt": "JWT सामग्री को क्लिपबोर्ड पर कॉपी किया गया", + "JWTContentsTTTxt": "JWT सामग्री को क्लिपबोर्ड पर कॉपी करें", + "JWTToken": "जेडब्ल्यूटी टोकन", + "JWTTokenSBTxt": "JWT टोकन को क्लिपबोर्ड पर कॉपी किया गया", + "JWTTokenTTTxt": "JWT टोकन को क्लिपबोर्ड पर कॉपी करें", + "chefsAPI": "शेफ्स एपीआई", + "RBACSBTxt": "आरबीएसी प्रतिक्रिया को क्लिपबोर्ड पर कॉपी किया गया", + "RBACTTTxt": "आरबीएसी प्रतिक्रिया को क्लिपबोर्ड पर कॉपी करें", + "notificationMsg": "आरबीएसी से उपयोगकर्ता प्राप्त करने में विफल, कंसोल देखें", + "notificationConsErr": "आरबीएसी से उपयोगकर्ता प्राप्त करने में त्रुटि" + }, + "baseAuthButton": { + "logout": "लॉग आउट", + "login": "लॉग इन करें" + }, + "baseDialog": { + "defaultText": "डिफ़ॉल्ट पाठ", + "ok": "ठीक", + "continue": "जारी रखना", + "cancel": "रद्द करना", + "custom": "रिवाज़" + }, + "baseSecure": { + "about": "के बारे में", + "loginInfo": "इस फीचर का इस्तेमाल करने के लिए आपको लॉग इन होना होगा।", + "login": "लॉग इन करें", + "401NotAuthorized": "401: अधिकृत नहीं. :", + "401ErrorMsg": "आपका खाता ठीक से सेट नहीं है.
कृपया संपर्क करें", + "403Forbidden": "403 निषिद्ध। :", + "403ErrorMsg": "इस पृष्ठ को {idp} प्रमाणीकरण की आवश्यकता है।", + "401UnAuthorized": "अनधिकृत 401। :", + "401UnAuthorizedErrMsg": "आपको इस पेज को एक्सेस करने की अनुमति नहीं है।" + }, + "formDesigner": { + "formDesign": "फॉर्म डिजाइन", + "exportDesign": "निर्यात डिजाइन", + "importDesign": "डिज़ाइन आयात करें", + "important": "महत्वपूर्ण", + "formDesignInfoA": "जब आप इस फॉर्म का निर्माण पूरा कर लें तो सेव डिज़ाइन बटन का उपयोग करें।", + "formDesignInfoB": "आपके उपयोगकर्ता को यह फॉर्म जमा करने के लिए SUBMIT बटन प्रदान किया गया है और इसे सहेजे जाने के बाद सक्रिय किया जाएगा।", + "formLoadErrMsg": "प्रपत्र डिज़ाइन लोड करते समय कोई त्रुटि उत्पन्न हुई.", + "formLoadConsoleErrMsg": "फॉर्म {formId} स्कीमा लोड करने में त्रुटि (संस्करण: {versionId} ड्राफ्ट: {draftId})", + "formSchemaImportErrMsg": "प्रपत्र स्कीमा आयात करते समय एक त्रुटि उत्पन्न हुई.", + "formSchemaImportConsoleErrMsg": "प्रपत्र स्कीमा आयात करने में त्रुटि: {error}", + "formDesignSaveErrMsg": "इस प्रपत्र डिज़ाइन को सहेजने का प्रयास करते समय एक त्रुटि उत्पन्न हुई। यदि आपको बाद में पुनः प्रयास करने के लिए रीफ़्रेश करने या छोड़ने की आवश्यकता है, तो आप बाद के लिए सहेजने के लिए पृष्ठ पर मौजूदा डिज़ाइन को निर्यात कर सकते हैं।", + "formDesignSaveConsoleErrMsg": "फ़ॉर्म को अपडेट करने या बनाने में त्रुटि (फ़ॉर्मआईडी: {formId}, संस्करणआईडी: {versionId}, ड्राफ्टआईडी: {draftId}) त्रुटि: {error}", + "collapse": "गिर जाना", + "actions": "कार्रवाई", + "version": "संस्करण", + "save": "बचाना", + "saving": "सहेजा जा रहा है", + "notSaved": "सहेजा नहीं गया", + "fieldnameError": "आप `फ़ॉर्म` कीवर्ड का उपयोग {लेबल} फ़ील्डनाम के रूप में नहीं कर सकते" + }, + "formViewerMultiUpload": { + "important": "महत्वपूर्ण", + "uploadSucessMsg": "एकाधिक ड्राफ्ट की सफल अपलोडिंग सुनिश्चित करने के लिए, कृपया दिए गए टेम्पलेट को डाउनलोड करें और उसका उपयोग करें।", + "confirmDownload": "क्या आप इसे डाउनलोड करना चाहते हैं?", + "jsonFileUpload": "अपलोड करने के लिए JSON फ़ाइल चुनें", + "dragNDrop": "या इसे यहां खींचें और छोड़ें", + "chooseAFile": "एक फ़ाइल चुनें", + "downloadDraftSubmns": "कृपया ड्राफ्ट सबमिशन रिपोर्ट डाउनलोड करें और सुनिश्चित करें कि डेटा सही ढंग से दर्ज किया गया है।", + "downloadReport": "रिपोर्ट डाउनलोड करें", + "doYouWantToDownload": "क्या आप इसे डाउनलोड करना चाहते हैं?", + "uploadNewFile": "नई फ़ाइल अपलोड करें", + "uploadMultipleFileErr": "क्षमा करें, आप केवल एक फ़ाइल अपलोड कर सकते हैं", + "dragMultipleFileErr": "क्षमा करें, आप केवल एक फ़ाइल खींच सकते हैं", + "fileFormatErr": "क्षमा करें, हम केवल json फ़ाइलें स्वीकार करते हैं", + "fileSizeErr": "अधिकतम अनुमत फ़ाइल आकार 5एमबी है", + "parseJsonErr": "हम फ़ाइल से json डेटा को पार्स नहीं कर सकते", + "jsonObjNotArray": "ग़लत json फ़ाइल स्वरूप", + "jsonObjNotArrayConsErr": "एक अप्रत्याशित त्रुटि हुई।", + "jsonArrayEmpty": "यह json फ़ाइल खाली है.", + "errorWhileValidate": "इस फ़ाइल में कुछ गड़बड़ है", + "errWhileCheckValidity": "इस फ़ाइल में कुछ गड़बड़ है", + "errAfterValidate": "कुछ त्रुटियाँ मिलीं, अधिक जानकारी के लिए नीचे देखें।", + "fileIsEmpty": "यह फ़ाइल खाली है.", + "download": "डाउनलोड करना" + }, + "formDisclaimer": { + "disclaimerAndStatement": "फॉर्म डिज़ाइनरों के लिए अस्वीकरण और जिम्मेदारी का विवरण:", + "privacyLaw": "व्यक्तिगत रूप से पहचान योग्य जानकारी के संग्रह, उपयोग और प्रकटीकरण को नियंत्रित करने वाले गोपनीयता कानूनों का अनुपालन करना आपकी ज़िम्मेदारी है।", + "disclosure": "इस फॉर्म डिज़ाइनर टूल तक पहुंच स्वाभाविक रूप से किसी भी व्यक्तिगत पहचान योग्य जानकारी को एकत्र करने, उपयोग करने या प्रकट करने की अनुमति नहीं देती है।", + "consent": "कानून के अनुसार जानकारी एकत्र करने के लिए सहमति प्राप्त करना आपकी जिम्मेदारी है।", + "formIntention": "अपना फॉर्म प्रकाशित या वितरित करने से पहले आपको अपने फॉर्म के इरादे पर चर्चा करनी होगी", + "privacyOfficer": "मंत्रालय गोपनीयता अधिकारी", + "assement": "और आवश्यकतानुसार मूल्यांकन पूरा करना।" + }, + "requestReceipt": { + "emailPriority": "ईमेल प्राथमिकता", + "emailReceipt": "इस सबमिशन की रसीद ईमेल करें", + "high": "उच्च", + "low": "कम", + "normal": "सामान्य", + "send": "भेजना", + "sendToEmailAddress": "ई-मेल पते पर भेजें", + "emailSent": "एक ईमेल इन्हें भेजी गई है {to}।", + "sendingEmailErrMsg": "आपका ईमेल भेजने का प्रयास करते समय एक त्रुटि उत्पन्न हुई.", + "sendingEmailConsErrMsg": "{to} को ईमेल पुष्टि विफल: {error}", + "emailRequired": "ईमेल की जरूरत है" + }, + "submissionsTable": { + "noMatchingRecordText": "कोई मिलान रिकॉर्ड पाया", + "submissions": "प्रविष्टियों", + "submissionsTable": "सबमिशनटेबल", + "selectColumns": "कॉलम चुनें", + "manageForm": "प्रपत्र प्रबंधित करें", + "submissionsToFiles": "सबमिशन को फ़ाइलों में निर्यात करें", + "showDeletedSubmissions": "हटाए गए सबमिशन दिखाएं", + "showMySubmissions": "मेरी प्रस्तुतियाँ दिखाएँ", + "search": "खोज", + "loadingText": "लोड हो रहा है कृपया प्रतीक्षा करें", + "noDataText": "इस फॉर्म के लिए कोई सबमिशन नहीं है", + "delSelectedSubmissions": "चयनित सबमिशन हटाएँ", + "resSelectedSubmissions": "चयनित सबमिशन पुनर्स्थापित करें", + "yes": "हाँ", + "no": "नहीं", + "viewSubmission": "सबमिशन देखें", + "deleteSubmission": "सबमिशन हटाएँ", + "restore": "पुनर्स्थापित करना", + "confirmDeletion": "मिटाने की पुष्टि", + "delete": "मिटाना", + "confirmRestoration": "पुनर्स्थापना की पुष्टि करें", + "searchSubmissionFields": "सबमिशन फ़ील्ड खोजें", + "save": "बचाना", + "searchTitle": "अपने डैशबोर्ड के अंतर्गत दिखाने के लिए कॉलम खोजें और चुनें", + "status": "दर्जा", + "submitter": "सबमिट करने", + "submissionDate": "स करने की तारीख", + "event": "आयोजन", + "view": "देखना", + "lateSubmission": "देर प्रस्तुत", + "confirmationID": "पुष्टिकरण आईडी", + "multiDelWarning": "क्या आप वाकई चयनित सबमिशन हटाना चाहते हैं?", + "singleDelWarning": "क्या आप वाकई इस सबमिशन को हटाना चाहते हैं?", + "multiRestoreWarning": "क्या आप वाकई इन सबमिशन को पुनर्स्थापित करना चाहते हैं?", + "singleRestoreWarning": "क्या आप वाकई इस सबमिशन को पुनर्स्थापित करना चाहते हैं?" + }, + "auditHistory": { + "viewEditHistory": "इतिहास संपादित करें देखें", + "editHistory": "इतिहास संपादित करें", + "auditLogMsg": "यह एक ऑडिट लॉग है कि मूल सबमिशन के बाद इस सबमिशन में किसने बदलाव किए हैं।", + "loadingText": "लोड हो रहा है कृपया प्रतीक्षा करें", + "close": "बंद करना", + "userName": "उपयोगकर्ता नाम", + "date": "तारीख", + "errorMsg": "इतिहास लाने का प्रयास करते समय एक त्रुटि उत्पन्न हुई.", + "consoleErrMsg": "ऑडिट इतिहास प्राप्त करने में त्रुटि" + }, + "deleteSubmission": { + "deleteThis": "इसे मिटायें", + "draft": "प्रारूप", + "submission": "जमा करना", + "confirmDeletion": "मिटाने की पुष्टि", + "deleteWarning": "क्या आप वाकई इसे हटाना चाहते हैं?", + "drafts": "प्रारूप", + "formSubmission": "फॉर्म जमा करना", + "delete": "मिटाना" + }, + "manageSubmissionUsers": { + "manageTeamMembers": "टीम के सदस्यों को प्रबंधित करें", + "add": "जोड़ना", + "draftFormInvite": "आप केवल टीम के सदस्यों को आमंत्रित और प्रबंधित कर सकते हैं जबकि यह फॉर्म एक ड्राफ्ट है", + "submissionTeamMembers": "इस प्रस्तुतिकरण के लिए टीम के सदस्य", + "actions": "कार्रवाई", + "close": "बंद करना", + "remove": "निकालना", + "userNotFoundErrMsg": "कोई नहीं मिल रहा? हो सकता है कि उन्होंने CHEFS में लॉग इन न किया हो।
कृपया उन्हें शेफ्स को एक लिंक भेजें और उन्हें लॉग इन करने के लिए कहें।", + "name": "नाम", + "username": "उपयोगकर्ता नाम", + "email": "ईमेल", + "removeUserWarningMsg1": "क्या आप वाकई हटाना चाहते हैं", + "removeUserWarningMsg2": "उनके पास अब इस सबमिशन की अनुमति नहीं होगी.", + "userExistInListMsg": "उपयोगकर्ता {username} पहले से ही टीम के सदस्यों की सूची में है।", + "getSubmissionUsersErr": "इस सबमिशन के लिए उपयोगकर्ताओं को लाने का प्रयास करते समय एक त्रुटि उत्पन्न हुई।", + "getSubmissionUsersConsoleErr": "{submissionId} के लिए उपयोगकर्ता प्राप्त करने में त्रुटि: {error}", + "sentInviteEmailTo": "को आमंत्रण ईमेल भेजा गया", + "sentUninvitedEmailTo": "को बिन बुलाए ईमेल भेजा गया", + "updateUserErrMsg": "इस सबमिशन के लिए उपयोगकर्ताओं को अपडेट करने का प्रयास करते समय एक त्रुटि उत्पन्न हुई।", + "updateUserConsoleErrMsg": "उपयोगकर्ता अनुमतियाँ सेट करने में त्रुटि. विषय: {submissionId} उपयोगकर्ता: {userId} त्रुटि: {error}", + "searchInputLength": "बीसीईआईडी उपयोगकर्ता नाम/ईमेल के लिए खोज इनपुट 6 अक्षरों से अधिक होना चाहिए।", + "exactBCEIDSearch": "बीसीईआईडी के लिए ईमेल खोजें सटीक होनी चाहिए।", + "getUsersErrMsg": "उपयोगकर्ता प्राप्त करने में त्रुटि: {error}", + "exactEmailOrUsername": "सटीक ई-मेल या उपयोगकर्ता नाम दर्ज करें.", + "requiredFiled": "एक नाम, ई-मेल या उपयोगकर्ता नाम दर्ज करें" + }, + "mySubmissionsActions": { + "viewThisSubmission": "यह सबमिशन देखें", + "copyThisSubmission": "इस सबमिशन को कॉपी करें", + "editThisDraft": "इस ड्राफ्ट को संपादित करें" + }, + "mySubmissionsTable": { + "noMatchingRecordText": "कोई मिलान रिकॉर्ड पाया", + "previousSubmissions": "पिछली प्रस्तुतियाँ", + "selectColumns": "कॉलम चुनें", + "createNewSubmission": "एक नया सबमिशन बनाएं", + "search": "खोज", + "loadingText": "लोड हो रहा है कृपया प्रतीक्षा करें", + "noDataText": "आपके पास कोई सबमिशन नहीं है", + "searchSubmissionFields": "सबमिशन फ़ील्ड खोजें", + "save": "बचाना", + "filterTitle": "अपने डैशबोर्ड के अंतर्गत दिखाने के लिए कॉलम खोजें और चुनें", + "confirmationId": "पुष्टिकरण आईडी", + "actions": "कार्रवाई", + "createdBy": "के द्वारा बनाई गई", + "statusUpdatedBy": "स्थिति अद्यतन द्वारा", + "status": "दर्जा", + "submissionDate": "स करने की तारीख", + "draftUpdatedBy": "ड्राफ्ट द्वारा अद्यतन किया गया", + "draftLastEdited": "ड्राफ्ट अंतिम बार संपादित", + "createLateSubmissn": "देर से सबमिशन बनाएं", + "formLoading": "कृपया फॉर्म लोड होने तक प्रतीक्षा करें!!!", + "pleaseConfirm": "कृपया पुष्टि करें", + "wantToSaveDraft": "क्या आप ड्राफ्ट सहेजना चाहते हैं?", + "yes": "हाँ", + "no": "नहीं", + "multiDraftUploadSuccess": "आपका एकाधिक ड्राफ्ट अपलोड सफल रहा है!", + "failedResSubmissn": "सबमिशन समापन बिंदु से विफल प्रतिक्रिया। प्रतिक्रिया कोड: {status}", + "errSubmittingForm": "इस फ़ॉर्म को सबमिट करते समय एक त्रुटि हुई", + "errorSavingFile": "फ़ाइलें सहेजने में त्रुटि. फ़ाइल का नाम: {fileName}. त्रुटि: {error}", + "submittingDraftErrMsg": "ड्राफ्ट सहेजते समय एक त्रुटि उत्पन्न हुई", + "submittingDraftConsErrMsg": "ड्राफ्ट सहेजने में त्रुटि. सबमिशनआईडी: {submissionId}। त्रुटि: {error}" + }, + "notesPanel": { + "addNewNote": "नया नोट जोड़ें", + "cancel": "रद्द करना", + "addNote": "नोट जोड़े", + "noResponseErr": "फॉर्म सबमिट करते समय एपीआई से कोई प्रतिक्रिया डेटा नहीं", + "errorMesg": "नोट जोड़ने का प्रयास करते समय एक त्रुटि उत्पन्न हुई.", + "consoleErrMsg": "नोट जोड़ने में त्रुटि:", + "fetchErrMsg": "इस सबमिशन के लिए नोट्स लाने का प्रयास करते समय एक त्रुटि उत्पन्न हुई।", + "fetchConsoleErrMsg": "नोट जोड़ने में त्रुटि:", + "notes": "टिप्पणियाँ", + "note": "टिप्पणी", + "maxChars": "अधिकतम 4000 अक्षर" + }, + "statusPanel": { + "currentStatus": "वर्तमान स्थिति:", + "assignedTo": "को सौंपना:", + "assignOrUpdateStatus": "स्थिति निर्दिष्ट करें या अद्यतन करें", + "display": "दिखाना", + "statusIsRequired": "स्थिति आवश्यक है", + "assignTo": "के लिए आवंटित", + "noDataText": "खोज से कोई फॉर्म समीक्षक नहीं मिला। प्रबंधन पृष्ठ पर प्रपत्र समीक्षक जोड़ें।", + "assigneeIsRequired": "समनुदेशिती आवश्यक है", + "assignToMe": "मेरे लिए आवंटित", + "recipientEmail": "प्राप्तकर्ता का ई - मेल", + "attachCommentToEmail": "ईमेल पर टिप्पणी संलग्न करें", + "emailComment": "ईमेल टिप्पणी", + "maxChars": "अधिकतम 4000 अक्षर", + "viewHistory": "इतिहास देखें", + "statusHistory": "स्थिति इतिहास", + "close": "बंद करना", + "addNoteNoReponserErr": "स्थिति अद्यतन के लिए नोट सबमिट करते समय एपीआई से कोई प्रतिक्रिया डेटा नहीं", + "addNoteConsoleErrMsg": "स्थिति अपडेट करने में त्रुटि: {error}", + "addNoteErrMsg": "स्थिति अद्यतन करने का प्रयास करते समय एक त्रुटि उत्पन्न हुई", + "updtSubmissionsStatusErr": "स्टेटस अपडेट फॉर्म सबमिट करते समय एपीआई से कोई प्रतिक्रिया डेटा नहीं", + "noStatus": "कोई स्थिति नहीं", + "noStatusesFound": "कोई स्थिति नहीं मिली", + "statusCodesErr": "स्थिति कोड ढूंढने में त्रुटि", + "notifyErrorCode": "इस सबमिशन के लिए स्थिति प्राप्त करने में त्रुटि हुई।", + "notifyConsoleErrorCode": "स्थितियाँ प्राप्त करने में त्रुटि:", + "fetchSubmissionUsersErr": "इस सबमिशन के लिए प्राप्तकर्ता ईमेल लाने का प्रयास करते समय एक त्रुटि उत्पन्न हुई।", + "fetchSubmissionUsersConsErr": "प्राप्तकर्ता के ईमेल प्राप्त करने में त्रुटि", + "assignSubmissnToFormReviewer": "सबमिशन फॉर्म समीक्षकों को सौंपे जा सकते हैं।
फ़ॉर्म समीक्षक के रूप में अधिक टीम सदस्यों को जोड़ने के लिए, इस फ़ॉर्म के प्रबंधन पृष्ठ पर जाएँ।", + "update": "अद्यतन", + "revise": "दोहराना", + "complete": "पूरा", + "assign": "सौंपना" + }, + "statusTable": { + "loadingText": "लोड हो रहा है कृपया प्रतीक्षा करें", + "status": "दर्जा", + "dateStatusChanged": "दिनांक स्थिति परिवर्तित", + "assignee": "संपत्ति-भागी", + "updatedBy": "द्वारा अपडेट", + "getSubmissionStatusErr": "स्थितियाँ लाने का प्रयास करते समय एक त्रुटि उत्पन्न हुई।", + "getSubmissionStatusConsErr": "नोट जोड़ने में त्रुटि:" + }, + "exportSubmissions": { + "exportSubmissionsToFile": "फ़ाइल में सबमिशन निर्यात करें", + "viewSubmissions": "सबमिशन देखें", + "fileType": "फाइल का प्रकार", + "json": "JSON", + "csv": "सीएसवी", + "formVersion": "प्रपत्र संस्करण", + "versionIsRequired": "संस्करण आवश्यक है.", + "dataFields": "डेटा फ़ील्ड", + "searchFields": "फ़ील्ड खोजें", + "selectedForExports": "निर्यात के लिए चयनित", + "submissionDate": "स करने की तारीख", + "all": "सभी", + "selectDateRange": "दिनांक सीमा चुनें", + "SelectdateRange": "दिनांक सीमा चुनें", + "from": "से", + "to": "को", + "CSVFormat": "सीएसवी प्रारूप", + "multiRowPerSubmissionA": "1 - इंडेंटेशन रिक्त स्थान के साथ प्रति सबमिशन एकाधिक पंक्तियाँ", + "multiRowPerSubmissionB": "2 - प्रति सबमिशन एकाधिक पंक्तियाँ", + "singleRowPerSubmission": "3 - प्रति सबमिशन एकल पंक्ति", + "unformatted": "4-अस्वरूपित", + "fileNameAndType": "फ़ाइल का नाम और प्रकार", + "export": "निर्यात", + "noResponseDataErr": "एक्सपोर्टसबमिशन कॉल के जवाब में कोई डेटा नहीं", + "apiCallErrorMsg": "इस फॉर्म के लिए सबमिशन निर्यात करने का प्रयास करते समय एक त्रुटि उत्पन्न हुई।", + "apiCallConsErrorMsg": "त्रुटि निर्यात सबमिशन के लिए", + "selectAllFields": "सभी फ़ील्ड चुनें", + "emailSentMsg": "{email} पर एक ईमेल भेजा जाएगा जिसमें आपका डेटा तैयार होने पर उसे डाउनलोड करने के लिए एक लिंक होगा", + "exportInProgress": "निर्यात प्रगति पर है", + "of": "का" + }, + "printOptions": { + "submitButtonTxt": "सीडीओजीएस पर सबमिट करें और डाउनलोड करें", + "templatePrint": "टेम्पलेट प्रिंट", + "uploadTemplateFile": "टेम्प्लेट फ़ाइल अपलोड करें", + "downloadOptions": "विकल्प डाउनलोड करें", + "print": "छाप", + "browserPrint": "ब्राउज़र प्रिंट", + "pageFromBrowser": "आपके ब्राउज़र से पृष्ठ", + "uploadA": "एक अपलोड करें", + "uploadB": "एक संरचित संस्करण होना", + "docGrnSucess": "दस्तावेज़ सफलतापूर्वक तैयार हुआ", + "failedDocGenErrMsg": "दस्तावेज़ जनरेट करने में विफल", + "failedDocGenConsErrMsg": "टेम्प्लेट सबमिट करने में त्रुटि: {error}", + "cDogsTemplate": "सीडीओजीएस टेम्पलेट" + }, + "proactiveHelpDialog": { + "componentInfoLink": "घटक सूचना लिंक", + "learnMoreLinkTxt": "और जानें लिंक फ़ील्ड खाली नहीं हो सकती.", + "largeImgTxt": "बड़ी छवि. छवि का आकार .5 एमबी से बड़ा नहीं हो सकता", + "componentName": "घटक का नाम:", + "learnMoreLink": "अधिक जानें लिंक:", + "clickToEnableLink": "लिंक सक्षम करने के लिए क्लिक करें", + "clickToDisableLink": "लिंक को अक्षम करने के लिए क्लिक करें", + "imageUpload": "छवि अपलोड करें:", + "cancel": "रद्द करना", + "save": "बचाना", + "description": "विवरण" + }, + "proactiveHelpPreviewDialog": { + "learnMore": "और अधिक जानें" + }, + "preview": { + "preview": "पूर्व दर्शन", + "previewToolTip": "यह प्रपत्र संस्करण डिज़ाइन और व्यवहार का पूर्वावलोकन दिखाता है जैसा कि आपके सबमिटर्स इसे देखेंगे। आप इस पेज से फ़ॉर्म सबमिट नहीं कर सकते." + }, + "generalLayout": { + "loadingText": "लोड हो रहा है कृपया प्रतीक्षा करें", + "preview": "पूर्व दर्शन", + "published": "प्रकाशित", + "unpublished": "अप्रकाशित", + "edit": "संपादन करना", + "formTitle": "प्रपत्र शीर्षक", + "actions": "कार्रवाई" + }, + "formSubmission": { + "editThisSubmission": "इस सबमिशन को संपादित करें", + "submission": "जमा करना", + "alertInfo": "संपादन के बाद, अपने परिवर्तनों को सहेजने के लिए फ़ॉर्म को दोबारा सबमिट करें।", + "viewAllSubmissions": "सभी प्रस्तुतियाँ देखें", + "submitted": "प्रस्तुत:", + "confirmationID": "पुष्टिकरण आईडी:", + "submittedBy": "द्वारा प्रस्तुत:", + "cancel": "रद्द करना", + "status": "दर्जा", + "updatedAt": "संशोधित", + "updatedBy": "द्वारा संशोधित" + }, + "teamManagement": { + "noMatchingRecordText": "कोई मिलान रिकॉर्ड पाया", + "teamManagement": "टीम प्रबंधन", + "selectColumns": "कॉलम चुनें", + "manageForm": "प्रपत्र प्रबंधित करें", + "search": "खोज", + "loadingText": "लोड हो रहा है कृपया प्रतीक्षा करें", + "noDataText": "टीम भूमिका डेटा लोड करने में विफल", + "removeSelectedUsers": "चयनित उपयोगकर्ताओं को हटाएँ", + "removeThisUser": "इस उपयोगकर्ता को हटाएं", + "confirmRemoval": "हटाने की पुष्टि करें", + "remove": "निकालना", + "searchTeamManagementFields": "टीम प्रबंधन फ़ील्ड खोजें", + "save": "बचाना", + "teamMebersTitle": "अपने डैशबोर्ड के अंतर्गत दिखाने के लिए कॉलम खोजें और चुनें", + "fullName": "पूरा नाम", + "username": "उपयोगकर्ता नाम", + "identityProvider": "पहचान प्रदाता", + "delSelectedMembersWarning": "क्या आप वाकई चयनित सदस्यों को हटाना चाहते हैं?", + "delSelectedMemberWarning": "क्या आप वाकई चयनित सदस्य को हटाना चाहते हैं?", + "idpMessage": "पहले से ही टीम में है.", + "formOwnerErrMsg": "हमेशा कम से कम एक फॉर्म स्वामी होना चाहिए", + "formOwnerConsoleErrMsg": "{userId} को नहीं हटाया जा सकता क्योंकि वे इस फॉर्म के एकमात्र शेष स्वामी हैं।", + "insufficientPermissnMsg": "टीम को प्रबंधित करने के लिए अपर्याप्त अनुमतियाँ", + "getUserErrMsg": "प्रपत्र उपयोगकर्ता प्राप्त करने में त्रुटि:", + "getRolesErrMsg": "भूमिकाओं की सूची प्राप्त करने में त्रुटि:", + "formOwnerRemovalWarning": "हटाया नहीं जा सकता क्योंकि वे इस फॉर्म के एकमात्र शेष स्वामी हैं।", + "removeUsersErrMsg": "चयनित उपयोगकर्ताओं को हटाने का प्रयास करते समय एक त्रुटि उत्पन्न हुई", + "removeUserConsoleErrMsg": "फ़ॉर्म {formId} से उपयोगकर्ताओं को हटाने में त्रुटि: {error}", + "updUserRolesErrMsg": "सभी उपयोगकर्ता भूमिकाओं को अद्यतन करने का प्रयास करते समय एक त्रुटि उत्पन्न हुई", + "updUserRolesConsoleErrMsg": "फ़ॉर्म {formId} के लिए सभी उपयोगकर्ता भूमिकाएँ सेट करने में त्रुटि: {error}", + "setUserFormsErrMsg": "किसी उपयोगकर्ता के लिए भूमिकाएँ अद्यतन करने का प्रयास करते समय एक त्रुटि उत्पन्न हुई", + "setUserFormsConsoleErrMsg": "प्रपत्र {formId} के लिए उपयोगकर्ता भूमिकाएँ निर्धारित करने में त्रुटि: {error}" + }, + "floatButton": { + "publish": "प्रकाशित करना", + "manage": "प्रबंधित करना", + "redo": "फिर से करना", + "undo": "पूर्ववत", + "preview": "पूर्व दर्शन", + "bottom": "तल", + "top": "ऊपर", + "actions": "कार्रवाई", + "collapse": "गिर जाना", + "saved": "बचाया", + "save": "बचाना", + "saving": "सहेजा जा रहा है", + "notSaved": "सहेजा नहीं गया" + }, + "formViewer": { + "lateFormSubmissions": "फॉर्म जमा करने की अवधि समाप्त हो गई है! आप अभी भी नीचे दिए गए बटन पर क्लिक करके देर से सबमिशन बना सकते हैं।", + "createLateSubmission": "देर से सबमिशन बनाएं", + "draftSaved": "ड्राफ्ट सहेजा गया", + "saving": "सहेजा जा रहा है", + "pleaseConfirm": "कृपया पुष्टि करें", + "submitFormWarningMsg": "क्या आप वाकई अपना फॉर्म जमा करना चाहते हैं?", + "submit": "जमा करना", + "wantToSaveDraft": "क्या आप ड्राफ्ट सहेजना चाहते हैं?", + "version": "संस्करण: {version}", + "formScheduleExpireMessage": "फॉर्म जमा करना उपलब्ध नहीं है क्योंकि जमा करने की निर्धारित अवधि समाप्त हो गई है।", + "getUsersSubmissionsErrMsg": "इस फ़ॉर्म के लिए सबमिशन लाते समय एक त्रुटि उत्पन्न हुई", + "getUsersSubmissionsConsoleErrMsg": "फ़ॉर्म सबमिशन डेटा लोड करने में त्रुटि {submissionId}: {error}", + "multiDraftUploadSuccess": "आपका एकाधिक ड्राफ्ट अपलोड सफल रहा है!", + "readVersionErrMsg": "प्रत्युत्तर में कोई स्कीमा नहीं. संस्करणआईडी: {versionId}", + "readDraftErrMsg": "प्रत्युत्तर में कोई स्कीमा नहीं. ड्राफ्टआईडी: {draftId}", + "alertRouteMsg": "फॉर्म स्वामी ने फॉर्म प्रकाशित नहीं किया है, और यह सबमिशन के लिए उपलब्ध नहीं है।", + "fecthingFormErrMsg": "यह फ़ॉर्म लाते समय एक त्रुटि हुई", + "fecthingFormConsoleErrMsg": "प्रपत्र स्कीमा लोड करने में त्रुटि {versionId}: {error}", + "savingDraftErrMsg": "ड्राफ्ट सहेजते समय एक त्रुटि उत्पन्न हुई", + "savingDraftConsoleErrMsg": "ड्राफ्ट सहेजने में त्रुटि. सबमिशनआईडी: {submissionId}। त्रुटि: {error}", + "submissionsPreviewAlert": "फॉर्म पूर्वावलोकन के दौरान सबमिशन अक्षम कर दिया गया", + "submissionsSubmitErrMsg": "फ़ॉर्म सबमिट करने में त्रुटि: {errors}", + "sendSubmissionErrMsg": "सबमिशन समापन बिंदु से विफल प्रतिक्रिया। प्रतिक्रिया कोड: {status}", + "errMsg": "इस फ़ॉर्म को सबमिट करते समय एक त्रुटि हुई", + "customEventAlert": "कस्टम बटन ईवेंट अभी समर्थित नहीं हैं. इवेंट प्रकार: {event}", + "formLoading": "कृपया फॉर्म लोड होने तक प्रतीक्षा करें!!!", + "yes": "हाँ", + "no": "नहीं", + "failedResSubmissn": "सबमिशन समापन बिंदु से विफल प्रतिक्रिया। प्रतिक्रिया कोड: {status}", + "errSubmittingForm": "इस फ़ॉर्म को सबमिट करते समय एक त्रुटि हुई", + "errorSavingFile": "फ़ाइलें सहेजने में त्रुटि. फ़ाइल का नाम: {fileName}. त्रुटि: {error}", + "submittingDraftErrMsg": "ड्राफ्ट सहेजते समय एक त्रुटि उत्पन्न हुई", + "submittingDraftConsErrMsg": "ड्राफ्ट सहेजने में त्रुटि. सबमिशनआईडी: {submissionId}। त्रुटि: {error}", + "formDraftAccessErrMsg": "अनुरोधित सबमिशन पहले ही सबमिट किया जा चुका है, व्यू पेज पर रीडायरेक्ट किया जा रहा है" + }, + "bCGovFooter": { + "home": "घर", + "about": "gov.bc.ca के बारे में", + "disclaimer": "अस्वीकरण", + "privacy": "गोपनीयता", + "accessibility": "सरल उपयोग", + "copyRight": "कॉपीराइट", + "contactUs": "संपर्क करें" + }, + "bCGovNavBar": { + "about": "के बारे में", + "myForms": "मेरे प्रपत्र", + "createNewForm": "एक नया फॉर्म बनाएं", + "help": "मदद", + "feedback": "प्रतिक्रिया", + "admin": "व्यवस्थापक" + }, + "homePage": { + "title": "कॉमन होस्टेड फॉर्म सर्विस के साथ फॉर्म बनाएं, प्रकाशित करें और सबमिशन प्राप्त करें।", + "subTitle": "सभी बी.सी. आईडीआईआर खाते वाले सरकारी कर्मचारी या ठेकेदार फॉर्म बनाने के लिए कॉमन होस्टेड फॉर्म सर्विस (सीएचईएफएस) के हमारे होस्टेड संस्करण का उपयोग कर सकते हैं।", + "takeATourOfChefs": "इसे कार्यान्वित होते देखने के लिए शेफ्स का भ्रमण करें।", + "logInToGetStarted": "आरंभ करने के लिए लॉग इन करें", + "loginToStart": "आरंभ करने के लिए आईडीआईआर के साथ लॉग इन करें", + "login": "लॉग इन करें", + "createFormLabel": "एक फॉर्म बनाएं", + "manageAccessTitle": "अपने फ़ॉर्म तक पहुंच प्रबंधित करें", + "manageAccessSub1": "CHEFS आपको सार्वजनिक फॉर्म बनाने की अनुमति देता है, या आप IDIR या BCeID प्रमाणीकरण के माध्यम से पहुंच का प्रबंधन कर सकते हैं।", + "manageAccessSub2": "आप अपने सभी सबमिशन को प्रबंधित करने के लिए अपनी टीम को भूमिकाएँ भी सौंप सकते हैं।", + "createCustomFormTitle": "CHEFS फॉर्म बिल्डर के साथ कस्टम फॉर्म बनाएं", + "createCustomFormSub1": "CHEFS के साथ, आप सहज ज्ञान युक्त ड्रैग-एंड-ड्रॉप इंटरफ़ेस के साथ सुरक्षित फॉर्म बना सकते हैं। आप प्रपत्र घटकों को जोड़ सकते हैं, उन्हें पुनः व्यवस्थित कर सकते हैं, और उन्हें विभिन्न लेआउट कॉन्फ़िगरेशन में छोड़ सकते हैं।", + "chefsHowToTitle": "शेफ कैसे करें वीडियो", + "chefsHowToSub": "हमारी क्विकस्टार्ट गाइड आपको शेफ के कुछ बुनियादी कार्यों से परिचित कराएगी।", + "getStartedToChefs": "शेफ्स का उपयोग शुरू करें", + "createOnlineTitle": "अपने ग्राहकों से जानकारी एकत्र करने और अपने कार्यप्रवाह में सुधार करने के लिए ऑनलाइन फॉर्म बनाएं।", + "getStarted": "शुरू हो जाओ" + }, + "baseStepper": { + "setUpForm": "फॉर्म सेट करें", + "designForm": "डिज़ाइन फॉर्म", + "manageForm": "प्रपत्र प्रबंधित करें" + }, + "create": { + "formSettings": "फॉर्म सेटिंग्स", + "disclaimer": "अस्वीकरण", + "disclaimerStmt": "मैं फॉर्म डिजाइनरों के अस्वीकरण और जिम्मेदारी के बयान से सहमत हूं", + "continue": "जारी रखना", + "back": "पीछे", + "confirmPageNav": "क्या आप सचमुच यह पेज छोड़ना चाहते हैं? आपके द्वारा किए गए परिवर्तन सहेजे नहीं जाएंगे.", + "agreementErrMsg": "आपको ऊपर दिखाए गए गोपनीयता अस्वीकरण से सहमत होना होगा।" + }, + "addTeamMember": { + "cantFindChefsUsers": "कोई नहीं मिल रहा? हो सकता है कि उन्होंने CHEFS में लॉग इन न किया हो।
कृपया उन्हें शेफ्स को एक लिंक भेजें और उन्हें लॉग इन करने के लिए कहें।", + "cancel": "रद्द करना", + "add": "जोड़ना", + "mustSelectAUser": "इस उपयोगकर्ता को जोड़ने के लिए आपको कम से कम एक भूमिका का चयन करना होगा।", + "addNewMember": "एक नया सदस्य जोड़ें", + "enterUsername": "एक नाम, ई-मेल या उपयोगकर्ता नाम दर्ज करें", + "enterExactUsername": "सटीक ई-मेल या उपयोगकर्ता नाम दर्ज करें", + "BCeIDInputSearchMaxLen": "बीसीईआईडी उपयोगकर्ता नाम/ईमेल के लिए खोज इनपुट 6 अक्षरों से अधिक होना चाहिए।", + "BCeIDMustBeExact": "बीसीईआईडी के लिए ईमेल खोजें सटीक होनी चाहिए।", + "errorGettingUsers": "उपयोगकर्ता प्राप्त करने में त्रुटि {error}" + }, + "baseFilter": { + "cancel": "रद्द करना", + "columnName": "आम नाम", + "exampleText": "उदाहरण पाठ", + "exampleText2": "उदाहरण पाठ 2", + "filterPlaceholderTxt": "प्लेसहोल्डर टेक्स्ट फ़िल्टर करें", + "filter": "फ़िल्टर", + "value": "कीमत", + "resetColumns": "कॉलम रीसेट करें" + }, + "formViewerActions": { + "viewMyDraftOrSubmissions": "मेरा ड्राफ्ट/प्रस्तुतियाँ देखें", + "saveAsADraft": "एक मसौदे के रूप में सहेजो", + "editThisDraft": "इस ड्राफ्ट को संपादित करें", + "switchSingleSubmssn": "एकल सबमिशन पर स्विच करें", + "switchMultiSubmssn": "एकाधिक सबमिशन पर स्विच करें" + }, + "baseCopyToClipboard": { + "linkToClipboard": "लिंक को क्लिपबोर्ड पर कॉपी किया गया", + "copyToClipboard": "क्लिपबोर्ड पर कॉपी करें", + "errCopyToClipboard": "क्लिपबोर्ड पर प्रतिलिपि बनाने का प्रयास करने में त्रुटि." + }, + "sucess": { + "sucessFormSubmissn": "आपका फॉर्म सफलतापूर्वक सबमिट हो गया है", + "keepRecord": "यदि आप इस सबमिशन का रिकॉर्ड रखना चाहते हैं, तो आप निम्नलिखित रख सकते हैं", + "confirmationId": "पुष्टिकरण आईडी" + }, + "bcGovAlertBanner": { + "defaultErrMsg": "त्रुटि: कुछ गलत हो गया", + "error": "गलती" + }, + "permissionUtils": { + "formNotAvailable": "फॉर्म फिलहाल अनुपलब्ध है. यह किसी ग़लत लिंक के कारण हो सकता है, या फ़ॉर्म उसके स्वामी द्वारा हटा दिया गया हो सकता है।", + "missingFormIdAndSubmssId": "विकल्पों में फॉर्मआईडी और सबमिशनआईडी दोनों गायब हैं", + "loadingFormErrMsg": "इस फॉर्म को लोड करते समय एक त्रुटि उत्पन्न हुई.", + "loadingForm": "{options} लोड करते समय त्रुटि: {error}", + "idpHintMsg": "इस फॉर्म के लिए {idpHint} प्रमाणीकरण की आवश्यकता है। कृपया पुनः लॉगिन करें और पुनः प्रयास करें।", + "formIdpMissMatch": "फॉर्म आईडीपी बेमेल। फॉर्म के लिए {idpHint} की आवश्यकता है लेकिन उपयोगकर्ता के पास {userIdp} है।" + }, + "download": { + "chefsDataExport": "शेफ डेटा निर्यात", + "preparingForDownloading": "डाउनलोड के लिए तैयारी की जा रही है...", + "downloadInfoA": "यदि आपकी फ़ाइल स्वचालित रूप से डाउनलोड नहीं होती है", + "downloadInfoB": "पुनः प्रयास करने के लिए यहां पर क्लिक करें" + }, + "history": { + "submissnHistory": "आपका सबमिशन इतिहास (टीबीडी)" + }, + "error": { + "logout": "लॉग आउट", + "somethingWentWrong": "त्रुटि: कुछ गलत हो गया... :(" + }, + "login": { + "authenticateWith": "इसके साथ प्रमाणित करें:", + "alreadyLoggedIn": "पहले से लॉग्ड इन", + "home": "घर", + "about": "के बारे में" + }, + "notFound": { + "about": "के बारे में", + "pageNotFound": "404 पृष्ठ नहीं मिला। :(" + }, + "store": { + "admin": { + "addFormOwnerRole": "इस फ़ॉर्म के लिए स्वामी की भूमिका को {fullName} में जोड़ा गया", + "addRowError": "भूमिका जोड़ते समय एक त्रुटि उत्पन्न हुई.", + "addRowConsoleErr": "उपयोगकर्ता {userId} को फॉर्म {formId} में जोड़ने में त्रुटि: {error}", + "apiKeyDelMsg": "इस फॉर्म की एपीआई कुंजी हटा दी गई है।", + "errDeletingApiKey": "एपीआई कुंजी को हटाने का प्रयास करते समय एक त्रुटि उत्पन्न हुई।", + "consErrDeletingApiKey": "फ़ॉर्म {formId} के लिए API कुंजी हटाने में त्रुटि: {error}", + "fecthingFormsErrMsg": "प्रपत्र लाते समय एक त्रुटि उत्पन्न हुई.", + "fecthingFormsConsErrMsg": "व्यवस्थापक प्रपत्र डेटा प्राप्त करने में त्रुटि: {error}", + "fecthingFormErrMsg": "इस फॉर्म को लाते समय एक त्रुटि हुई.", + "fecthingFormConsErrMsg": "व्यवस्थापक प्रपत्र {formId} डेटा प्राप्त करने में त्रुटि: {error}", + "fecthFormUserRolesErrMsg": "प्रपत्र उपयोगकर्ता भूमिकाएँ लाते समय एक त्रुटि उत्पन्न हुई।", + "fecthFormUserRolesConsErrMsg": "व्यवस्थापक भूमिकाएँ डेटा प्राप्त करने में त्रुटि: {error}", + "fecthApiDetailsErrMsg": "इस फॉर्म का एपीआई विवरण लाते समय एक त्रुटि उत्पन्न हुई।", + "fecthApiDetailsConsErrMsg": "प्रपत्र {formId} डेटा से व्यवस्थापक API विवरण प्राप्त करने में त्रुटि: {error}", + "restoreFormErrMsg": "इस फॉर्म को पुनर्स्थापित करते समय एक त्रुटि उत्पन्न हुई.", + "restoreFormConsErrMsg": "फ़ॉर्म {formId} डेटा पुनर्स्थापित करने में त्रुटि: {error}", + "getUsersErrMsg": "उपयोगकर्ताओं को लाते समय एक त्रुटि उत्पन्न हुई.", + "getUsersConsErrMsg": "व्यवस्थापक उपयोगकर्ता डेटा प्राप्त करने में त्रुटि: {error}", + "getUserErrMsg": "इस उपयोगकर्ता को लाते समय एक त्रुटि उत्पन्न हुई.", + "getUserConsErrMsg": "व्यवस्थापक उपयोगकर्ता {userId} डेटा प्राप्त करने में त्रुटि: {error}", + "storingFCHelpInfoErrMsg": "प्रपत्र घटक सहायता जानकारी संग्रहीत करते समय एक त्रुटि उत्पन्न हुई", + "storingFCHelpInfoConsErrMsg": "प्रपत्र घटक सहायता जानकारी संग्रहीत करने में त्रुटि: {error}", + "gettingFCImgUrlErrMsg": "छवि यूआरएल प्राप्त करते समय एक त्रुटि उत्पन्न हुई", + "gettingFCImgUrlConsErrMsg": "छवि यूआरएल प्राप्त करने में त्रुटि: {error}", + "updatingFCStatusErrMsg": "प्रकाशन स्थिति अद्यतन करते समय एक त्रुटि उत्पन्न हुई", + "updatingFCStatusConsErrMsg": "प्रकाशन स्थिति अपडेट करने में त्रुटि: {error}", + "fecthingFormBuilderCompsErrMsg": "फॉर्म बिल्डर घटकों को लाते समय एक त्रुटि उत्पन्न हुई", + "fecthingFormBuilderCompsConsErrMsg": "प्रपत्र बिल्डर घटक प्राप्त करने में त्रुटि: {error}" + }, + "form": { + "fetchEmailTemplatesConsErrMsg": "{formId} के लिए ईमेल टेम्पलेट लोड करने में त्रुटि: {error}", + "fetchEmailTemplatesErrMsg": "इस फ़ॉर्म के लिए ईमेल टेम्प्लेट लाने में त्रुटि हुई", + "getCurrUserFormsErrMsg": "आपके प्रपत्र लाते समय एक त्रुटि उत्पन्न हुई.", + "getCurrUserFormsConsErrMsg": "उपयोगकर्ता डेटा प्राप्त करने में त्रुटि: {error}", + "getUserFormPermErrMsg": "इस फ़ॉर्म के लिए आपका उपयोगकर्ता डेटा लाते समय एक त्रुटि उत्पन्न हुई.", + "getUserFormPermConsErrMsg": "फॉर्मआईडी {formId} का उपयोग करके उपयोगकर्ता डेटा प्राप्त करने में त्रुटि: {error}", + "getUserFormRolesErrmsg": "इस फ़ॉर्म के लिए आपका उपयोगकर्ता डेटा लाते समय एक त्रुटि उत्पन्न हुई.", + "getUserFormRolesConsErrmsg": "फॉर्मआईडी {formId} का उपयोग करके उपयोगकर्ता डेटा प्राप्त करने में त्रुटि: {error}", + "updCurrUserFormPrefErrMsg": "इस फ़ॉर्म के लिए आपकी प्राथमिकताएँ सहेजते समय एक त्रुटि उत्पन्न हुई.", + "updCurrUserFormPrefConsErrMsg": "फॉर्मआईडी {formId} और प्रीफ्स {preferences} का उपयोग करके उपयोगकर्ता फॉर्म प्रीफ़्स को अपडेट करने में त्रुटि: {error}", + "getCurrUserFormPrefErrMsg": "इस फॉर्म के लिए आपकी प्राथमिकताएँ लाते समय एक त्रुटि हुई।", + "getCurrUserFormPrefConsErrMsg": "फॉर्मआईडी {formId} का उपयोग करके उपयोगकर्ता फॉर्म प्रीफ़्स प्राप्त करने में त्रुटि: {error}", + "delCurrformNotiMsg": "फ़ॉर्म {name} सफलतापूर्वक हटा दिया गया है.", + "delCurrFormConsErMsg": "फ़ॉर्म {id} हटाने में त्रुटि: {error}", + "delDraftErrMsg": "इस ड्राफ्ट को हटाते समय एक त्रुटि उत्पन्न हुई.", + "delDraftConsErrMsg": "{draftId} को हटाने में त्रुटि: {error}", + "fecthDraftErrMsg": "इस फॉर्म के लिए ड्राफ्ट स्कैन करते समय एक त्रुटि उत्पन्न हुई।", + "fecthDraftConsErrMsg": "फ़ॉर्म {formId} के लिए ड्राफ्ट प्राप्त करने में त्रुटि: {error}", + "fecthFormErrMsg": "इस फॉर्म को लाते समय एक त्रुटि हुई.", + "fecthFormConsErrMsg": "फ़ॉर्म {formId} प्राप्त करने में त्रुटि: {error}", + "fetchFormFieldsErrMsg": "इस फ़ॉर्म के लिए फ़ील्ड की सूची लाते समय एक त्रुटि उत्पन्न हुई.", + "fetchFormFieldsConsErrMsg": "फ़ॉर्म {formId} प्राप्त करने में त्रुटि: {error}", + "publishDraftErrMsg": "प्रकाशन करते समय एक त्रुटि उत्पन्न हुई.", + "publishDraftConsErrMsg": "{draftId} प्रकाशित करने में त्रुटि: {error}", + "toggleVersnPublConsErrMsg": "toggleVersionPublish {versionId} {publish} में त्रुटि: {error}", + "updateEmailTemplateConsErrMsg": "फ़ॉर्म {formId} के लिए ईमेल टेम्पलेट अपडेट करने में त्रुटि: {error}", + "updateEmailTemplateErrMsg": "इस फ़ॉर्म के लिए ईमेल टेम्प्लेट अपडेट करते समय एक त्रुटि उत्पन्न हुई.", + "updateFormErrMsg": "इस फ़ॉर्म की सेटिंग अपडेट करते समय एक त्रुटि उत्पन्न हुई.", + "updateFormConsErrMsg": "फॉर्म {id} अपडेट करने में त्रुटि: {error}", + "deleteSubmissionNotifyMsg": "सबमिशन सफलतापूर्वक हटा दिया गया.", + "deleteSubmissionErrMsg": "इस सबमिशन को हटाते समय एक त्रुटि उत्पन्न हुई.", + "deleteSubmissionConsErrMsg": "सबमिशन हटाने में त्रुटि {submissionId}: {error}", + "deleteSubmissionsNotifyMsg": "सबमिशन सफलतापूर्वक हटा दिए गए.", + "deleteSubmissionsErrMsg": "चयनित सबमिशन हटाते समय एक त्रुटि उत्पन्न हुई।", + "deleteSubmissionsConsErrMsg": "सबमिशन हटाने में त्रुटि: {error}", + "restoreSubmissionsNotiMsg": "सबमिशन सफलतापूर्वक बहाल हो गए.", + "restoreSubmissionsErrMsg": "इस सबमिशन को पुनर्स्थापित करते समय एक त्रुटि उत्पन्न हुई.", + "restoreSubmissionsConsErrMsg": "सबमिशन पुनर्स्थापित करने में त्रुटि: {error}", + "restoreSubmissionNotiMsg": "सबमिशन सफलतापूर्वक बहाल हो गया.", + "restoreSubmissionErrMsg": "इस सबमिशन को पुनर्स्थापित करते समय एक त्रुटि उत्पन्न हुई.", + "restoreSubmissionConsErrMsg": "सबमिशन बहाल करने में त्रुटि {submissionId}: {error}", + "fecthSubmissnUsersErrMsg": "इस सबमिशन के लिए प्राप्तकर्ता ईमेल लाते समय एक त्रुटि उत्पन्न हुई।", + "fecthSubmissnUsersConsErrMsg": "जमा करने के लिए प्राप्तकर्ता ईमेल प्राप्त करने में त्रुटि {formSubmissionId}: {error}", + "fetchSubmissnErrMsg": "इस सबमिशन को लाते समय एक त्रुटि उत्पन्न हुई.", + "fetchSubmissnConsErrMsg": "सबमिशन प्राप्त करने में त्रुटि {submissionId}: {error}", + "fetchFormCSVExptFieldsErrMsg": "इस फ़ॉर्म के लिए फ़ील्ड की सूची लाते समय एक त्रुटि उत्पन्न हुई.", + "fetchFormCSVExptFieldsConsErrMsg": "फ़ॉर्म {formId} प्राप्त करने में त्रुटि: {error}", + "fetchSubmissnsErrMsg": "इस फ़ॉर्म के लिए सबमिशन लाते समय एक त्रुटि उत्पन्न हुई.", + "fetchSubmissnsConsErrMsg": "{formId} के लिए सबमिशन प्राप्त करने में त्रुटि: {error}", + "fetchVersionErrMsg": "इस फॉर्म को लाते समय एक त्रुटि हुई.", + "fetchVersionConsErrMsg": "फ़ॉर्म {formId} के लिए संस्करण {versionId} प्राप्त करने में त्रुटि: {error}", + "deleteApiKeyNotifyMsg": "इस फॉर्म की एपीआई कुंजी हटा दी गई है।", + "deleteApiKeyErrMsg": "एपीआई कुंजी को हटाने का प्रयास करते समय एक त्रुटि उत्पन्न हुई।", + "deleteApiKeyConsErrMsg": "फ़ॉर्म {formId} के लिए API कुंजी हटाने में त्रुटि: {error}", + "generateApiKeyNotifyMsg": "इस फॉर्म के लिए एक एपीआई कुंजी बनाई गई है।", + "generateApiKeyErrMsg": "एपीआई कुंजी उत्पन्न करने का प्रयास करते समय एक त्रुटि उत्पन्न हुई।", + "generateApiKeyConsErrMsg": "प्रपत्र {formId} के लिए API कुंजी उत्पन्न करने में त्रुटि: {error}", + "readApiKeyErrMsg": "एपीआई कुंजी लाने का प्रयास करते समय एक त्रुटि उत्पन्न हुई।", + "readApiKeyConsErrMsg": "फ़ॉर्म {formId} के लिए API कुंजी प्राप्त करने में त्रुटि: {error}।", + "getFCPHImageUrlErrMsg": "छवि यूआरएल प्राप्त करते समय एक त्रुटि उत्पन्न हुई", + "getFCPHImageUrlConsErrMsg": "छवि यूआरएल प्राप्त करने में त्रुटि: {error}", + "listFCPHErrMsg": "फॉर्म बिल्डर घटकों को लाते समय एक त्रुटि उत्पन्न हुई", + "listFCPHConsErrMsg": "प्रपत्र बिल्डर घटक प्राप्त करने में त्रुटि: {error}", + "downloadFileErrMsg": "फ़ाइल डाउनलोड करते समय एक त्रुटि उत्पन्न हुई", + "downloadFileConsErrMsg": "फ़ाइल डाउनलोड करने में त्रुटि: त्रुटि", + "readSubscriptionSettingsErrMsg": "सदस्यता सेटिंग लाने का प्रयास करते समय एक त्रुटि उत्पन्न हुई.", + "readSubscriptionSettingsConsErrMsg": "फ़ॉर्म {formId} के लिए सदस्यता सेटिंग प्राप्त करने में त्रुटि: {त्रुटि}।", + "saveSubscriptionSettingsNotifyMsg": "इस फॉर्म के लिए सदस्यता सेटिंग्स सहेज ली गई हैं।", + "saveSubscriptionSettingsErrMsg": "सदस्यता सेटिंग सहेजने का प्रयास करते समय एक त्रुटि उत्पन्न हुई.", + "saveSubscriptionSettingsConsErrMsg": "फ़ॉर्म {formId} के लिए सदस्यता सेटिंग सहेजने में त्रुटि: {त्रुटि}" + } + }, + "admin": { + "root": { + "admin": "व्यवस्थापक" + }, + "form": { + "administerForm": "प्रशासन प्रपत्र" + }, + "user": { + "administerUser": "उपयोगकर्ता को प्रशासित करें" + } + }, + "user": { + "root": { + "myForms": "मेरे फॉर्म", + "history": "इतिहास", + "user": "उपयोगकर्ता" + } + } +} diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/hi/index.js b/frontend/app/frontend/src/internationalization/trans/chefs/hi/index.js new file mode 100644 index 0000000..4bfbdac --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/hi/index.js @@ -0,0 +1,4 @@ +import hi from '~/internationalization/trans/chefs/hi/hi.json'; +export default { + trans: hi, +}; diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/index.js b/frontend/app/frontend/src/internationalization/trans/chefs/index.js new file mode 100644 index 0000000..a8a1cd5 --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/index.js @@ -0,0 +1,38 @@ +import ar from '~/internationalization/trans/chefs/ar'; +import de from '~/internationalization/trans/chefs/de'; +import en from '~/internationalization/trans/chefs/en'; +import es from '~/internationalization/trans/chefs/es'; +import fa from '~/internationalization/trans/chefs/fa'; +import fr from '~/internationalization/trans/chefs/fr'; +import hi from '~/internationalization/trans/chefs/hi'; +import it from '~/internationalization/trans/chefs/it'; +import ja from '~/internationalization/trans/chefs/ja'; +import ko from '~/internationalization/trans/chefs/ko'; +import pa from '~/internationalization/trans/chefs/pa'; +import pt from '~/internationalization/trans/chefs/pt'; +import ru from '~/internationalization/trans/chefs/ru'; +import tl from '~/internationalization/trans/chefs/tl'; +import uk from '~/internationalization/trans/chefs/uk'; +import vi from '~/internationalization/trans/chefs/vi'; +import zh from '~/internationalization/trans/chefs/zh'; +import zhTW from '~/internationalization/trans/chefs/zhTW'; +export { + ar, + en, + de, + es, + fa, + fr, + hi, + it, + ja, + ko, + pa, + pt, + ru, + tl, + uk, + vi, + zhTW, + zh, +}; diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/it/index.js b/frontend/app/frontend/src/internationalization/trans/chefs/it/index.js new file mode 100644 index 0000000..9335c0b --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/it/index.js @@ -0,0 +1,4 @@ +import it from '~/internationalization/trans/chefs/it/it.json'; +export default { + trans: it, +}; diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/it/it.json b/frontend/app/frontend/src/internationalization/trans/chefs/it/it.json new file mode 100644 index 0000000..a99e3dd --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/it/it.json @@ -0,0 +1,995 @@ +{ + "date": { + "date": "aaaa-mm-gg" + }, + "emailManagement": { + "emailManagement": "Gestione della posta elettronica", + "manageForm": "Gestisci modulo", + "submissionConfirmation": "Conferma di invio" + }, + "emailTemplate": { + "body": "Corpo", + "save": "Salva", + "saveEmailTemplateConsoleErrMsg": "Errore durante l'aggiornamento del modello di email per il modulo {formId}: {error}", + "saveEmailTemplateErrMsg": "Si è verificato un errore durante il tentativo di aggiornare il modello di email.", + "subject": "Soggetto", + "title": "Titolo", + "validBodyRequired": "Inserisci un corpo per l'e-mail", + "validSubjectRequired": "Inserisci una riga dell'oggetto per l'e-mail", + "validTitleRequired": "Inserisci un titolo per l'e-mail" + }, + "formsTable": { + "myForms": "Le mie Forme", + "createNewForm": "Crea un nuovo modulo", + "search": "Ricerca", + "manage": "Maneggio", + "submissions": "Contributi", + "formTitle": "Titolo del modulo", + "viewForm": "Visualizza modulo", + "description": "descrizione", + "Description": "Descrizione:", + "action": "Azioni", + "loadingText": "Attendere il caricamento prego" + }, + "manageLayout": { + "manageForm": "Gestisci modulo" + }, + "preview": { + "preview": "Anteprima", + "previewToolTip": "Questo mostra un'anteprima del design e del comportamento della versione del modulo come lo vedranno i tuoi mittenti. Non puoi inviare il modulo da questa pagina." + }, + "shareForm": { + "shareForm": "Modulo di condivisione", + "shareLink": "Condividi il link", + "copyQRCode": "Copia il link qui sotto o scarica il codice QR.", + "warningMessage": "Al momento non esiste una versione pubblicata del modulo. Il collegamento sottostante non sarà raggiungibile fino a quando non verrà pubblicata una versione.", + "openThisForm": "Apri questo modulo", + "downloadQRCode": "Scarica codice QR", + "close": "Vicino", + "copyURLToClipboard": "Copia l'URL negli appunti" + }, + "manageFormActions": { + "emailManagement": "Gestione della posta elettronica", + "viewSubmissions": "Visualizza invii", + "teamManagement": "Gestione della squadra", + "deleteForm": "Elimina modulo", + "confirmDeletion": "Confermare la cancellazione", + "deleteMessageA": "Sei sicuro di voler eliminare", + "deleteMessageB": "Questo modulo non sarà più accessibile.", + "delete": "Eliminare" + }, + "manageForm": { + "formSettings": "Impostazioni modulo", + "apiKey": "Chiave API", + "updated": "Aggiornato", + "created": "Creato", + "formDesignHistory": "Storia del design dei moduli", + "totalVersions": "Versioni totali", + "status": "Stato", + "update": "Aggiornamento", + "cancel": "Annulla", + "eventSubscription": "Abbonamento all'evento" + }, + "formSettings": { + "pressToAddMultiEmail": "Premi invio o , o spazio per aggiungere più indirizzi email", + "allowMultiDraft": "Consenti il caricamento di più bozze", + "formTitle": "Titolo del modulo", + "formDescription": "Descrizione del modulo", + "formAccess": "Accesso al modulo", + "info": "Se utilizzerai questo modulo per raccogliere informazioni dal pubblico in generale su argomenti di interesse generale per il pubblico, sei tenuto a contattare il GCPE in modo che il tuo impegno possa essere elencato su", + "important": "IMPORTANTE", + "idimNotifyA": "È necessario informare il team IDIM (Identity Information Management) tramite e-mail", + "idimNotifyB": "la tua intenzione di sfruttare BCeID per verificare le identità dei tuoi mittenti di moduli.", + "referenceGuideA": "Si prega di fare riferimento al nostro", + "referenceGuideB": "guida utente", + "referenceGuideC": "per ulteriori dettagli", + "specificTeamMembers": "Membri specifici del team", + "formFunctionality": "Funzionalità della forma", + "formSubmissinScheduleMsg": "Il programma di invio del modulo sarà disponibile nelle Impostazioni del modulo dopo la pubblicazione del modulo.", + "formSubmissionsSchedule": "Programma di invio dei moduli", + "experimental": "Sperimentale", + "learnMore": "Saperne di più", + "afterSubmission": "Dopo l'invio", + "submissionConfirmation": "Mostra i dettagli di conferma dell'invio", + "theConfirmationID": "l'ID di conferma", + "infoB": "l'opzione per l'utente di inviare a se stesso tramite e-mail una conferma di invio", + "loginRequired": "Accesso richiesto", + "canSaveAndEditDraftLabel": "I sottoscrittori possono salvare e modificare le bozze", + "canUpdateStatusAsReviewer": "I revisori possono aggiornare lo stato di questo modulo (ovvero inviato, assegnato, completato)", + "submitterCanCopyExistingSubmissn": "I sottomittenti possono copiare un invio esistente", + "submissionConfirmationToolTip": "La selezione di questa opzione controlla ciò che l'utente che invia questo modulo vedrà in caso di invio riuscito.
Se selezionato, verrà visualizzato", + "emailNotificatnToTeam": "Invia al mio team un'e-mail di notifica", + "emailNotificatnToTeamToolTip": "Invia una notifica al tuo indirizzo email specificato quando un utente invia questo modulo", + "notificationEmailAddrs": "Indirizzi e-mail di notifica", + "addMoreValidEmailAddrs": "Aggiungi uno o più indirizzi email validi", + "formScheduleSettings": "Impostazioni pianificazione modulo", + "opensubmissions": "Presentazioni aperte", + "submissionsDeadline": "Per quanto tempo vuoi ricevere i contributi?", + "keepSubmissnOpenTilUnplished": "Tieni aperto fino a quando non viene annullata manualmente la pubblicazione", + "submissionsClosingDate": "Pianifica una data di chiusura", + "submissionPeriod": "Impostare il periodo di invio", + "closeSubmissions": "Chiudi invii", + "keepOpenFor": "Tieni aperto per", + "period": "Periodo", + "allowLateSubmissions": "Consenti invii tardivi", + "allowLateSubmissionsInfoTip": "Se selezionata, i richiedenti potranno inviare i dati dopo la data di chiusura.", + "afterCloseDateFor": "Dopo la data di chiusura per", + "repeatPeriod": "Ripeti periodo", + "every": "Ogni", + "repeatUntil": "Ripetere fino a", + "summary": "Riepilogo", + "submissionsOpenDateRange": "Questo modulo sarà aperto per l'invio da parte di", + "to": "A", + "scheduleRepetition": "Il programma si ripeterà ogni", + "allowLateSubmissnInterval": "consentire invii tardivi per", + "until": "Fino a", + "datesOfSubmissnInfo": "In base alle impostazioni, queste sono le date disponibili per l'invio:", + "formOpenInterval": "Questo modulo sarà aperto per l'invio da parte di", + "allowDateSubmissionDate": "con consentire l'invio tardivo fino a", + "customClosingMessage": "Imposta messaggio di chiusura personalizzato", + "customClosingMessageToolTip": "Ti consente di aggiungere un messaggio personalizzato per i tuoi utenti quando visitano un modulo chiuso.", + "closingMessage": "Messaggio di chiusura", + "sendReminderEmail": "INVIA E-mail di sollecito", + "autoReminderNotificatn": "Abilita la notifica automatica del promemoria", + "autoReminderNotificatnToolTip": "Invia e-mail di promemoria con il collegamento al modulo durante il periodo di invio.", + "selectLoginType": "Seleziona 1 tipo di accesso", + "formDescriptnMaxChars": "La descrizione del modulo deve contenere al massimo 255 caratteri", + "formTitlemaxChars": "Il titolo del modulo non deve superare i 255 caratteri", + "formTitleReq": "Il titolo del modulo è obbligatorio", + "atLeastOneEmailReq": "Inserisci almeno 1 indirizzo email", + "validEmailRequired": "Inserisci tutti gli indirizzi email validi", + "fieldRequired": "Questo campo è obbligatorio.", + "correctDateFormat": "La data deve essere nel formato corretto. cioè. aaaa-mm-gg", + "dateDiffMsg": "La data di chiusura dell'invio deve essere successiva alla data di apertura dell'invio.", + "valueMustBeNumber": "Il valore deve essere un numero. cioè. 1,2,3,5,99", + "selectAnOptions": "Seleziona almeno 1 opzione", + "validInterval": "Questo dovrebbe essere un intervallo valido.", + "fieldRequiredAndInterval": "Questo campo è obbligatorio e dovrebbe essere un intervallo.", + "dateGrtOpenSubmissnDate": "La data di ripetizione deve essere maggiore della data di invio aperta", + "public": "Pubblico (anonimo)", + "allowEventSubscription": "Consenti l'iscrizione agli eventi", + "eventSubscription": "Abbonamento all'evento", + "validEndpointRequired": "Inserisci un endpoint valido che inizi con https://", + "validBearerTokenRequired": "Inserisci un esempio di token al portatore valido: 89abddfb-2cff-4fda-83e6-13221f0c3d4f" + }, + "subscribeEvent": { + "eventType": "Tipo di evento", + "endpointUrl": "URL dell'endpoint", + "eventSubmission": "Sottomissione", + "eventAssignment": "Incarico", + "eventStatusChange": "Cambio di stato", + "endpointToken": "Token dell'endpoint", + "urlPlaceholder": "https://endpoint.gov.bc.ca/api/v1/", + "save": "Salva", + "text": "testo", + "password": "parola d'ordine", + "hideSecret": "Nascondi segreto", + "showSecret": "Mostra Segreto", + "key": "Chiave", + "saveSettingsErrMsg": "Si è verificato un errore durante il tentativo di aggiornare le impostazioni per questo modulo.", + "updateSettingsConsoleErrMsg": "Errore durante l'aggiornamento delle impostazioni per il modulo {formId}: {error}" + }, + "apiKey": { + "disclaimer": "Disclaimer", + "infoA": "Assicurati che il segreto della tua chiave API sia archiviato in un luogo sicuro (ad es. Key Vault).", + "infoB": "La tua chiave API garantisce l'accesso illimitato al tuo modulo. Non dare la tua chiave API a nessuno.", + "infoC": "La chiave API deve essere utilizzata SOLO per le interazioni di sistema automatizzate. Non utilizzare la chiave API per l'accesso basato sull'utente", + "deleteKey": "Elimina chiave", + "apiKey": "chiave API", + "hideSecret": "Nascondi segreto", + "showSecret": "Mostra Segreto", + "sCTC": "Segreto copiato negli appunti", + "cSTC": "Copia segreto negli appunti", + "key": "Chiave", + "confirmDeletion": "Confermare la cancellazione", + "deleteMsg": "Sei sicuro di voler eliminare la tua chiave API?", + "delete": "Eliminare", + "confirmKeyGen": "Conferma la generazione della chiave", + "createAPIKey": "Creare una chiave API per questo modulo?
Assicurati di seguire il Disclaimer in questa pagina.", + "regenerateAPIKey": "Rigenerare la chiave API?
Continuando eliminerai il tuo attuale accesso alla chiave API .", + "formOwnerKeyAcess": "Devi essere il proprietario del modulo per gestire le chiavi API.", + "regenerate": "Rigenerare", + "generate": "creare", + "secret": "Segreto" + }, + "manageVersions": { + "important": "IMPORTANTE!", + "infoA": "Se non sono presenti versioni pubblicate, gli utenti non possono accedere a questo modulo fino a quando non viene assegnata una versione pubblicata. Una volta pubblicata una versione, quella versione non è più modificabile. È necessario creare una nuova versione basata su una delle versioni precedenti del modulo per continuare a modificare.", + "infoB": "Nota: è possibile pubblicare solo una versione.", + "version": "Versione", + "draft": "Bozza", + "clickToPreview": "Fare clic per visualizzare l'anteprima", + "editVersion": "Modifica versione", + "exportDesign": "Esporta disegno", + "infoC": "Si prega di pubblicare o eliminare la bozza dell'ultima versione prima di iniziare una nuova versione.", + "deleteVersion": "Elimina versione", + "draftAlreadyExists": "La bozza esiste già", + "infoD": "Modifica, pubblica o elimina la bozza esistente prima di iniziare una nuova bozza.", + "publishVersion": "Pubblica versione", + "unpublishVersion": "Annulla pubblicazione versione", + "infoE": "L'annullamento della pubblicazione di questo modulo eliminerà la circolazione del modulo fino a quando non verrà pubblicata nuovamente una versione.", + "confirmDeletion": "Confermare la cancellazione", + "infoF": "Sei sicuro di voler eliminare questa versione?", + "delete": "Eliminare", + "status": "Stato", + "dateCreated": "data di creazione", + "createdBy": "Creato da", + "actions": "Azioni", + "published": "Pubblicato", + "unpublished": "Inedito", + "useVersionInfo": "Utilizza la versione {version} come base per una nuova versione", + "publishingVersionInfo": "Questo renderà attiva la versione {version} del tuo modulo." + }, + "addOwner": { + "infoA": "Questo dovrebbe essere fatto solo nel caso in cui l'attuale proprietario del modulo non sia più attivo o sia fuori contatto in un evento prioritario. In caso contrario, chiedi all'attuale proprietario o a un amministratore del team per il modulo di farlo da solo.", + "hint": "Per trovare l'ID utente necessario, puoi andare alla scheda \"UTENTI\" nel portale di amministrazione e cercarli.", + "addowner": "Aggiungi proprietario", + "label": "ID utente (guida)" + }, + "adminFormsTable": { + "showDeletedForms": "Mostra i moduli eliminati", + "search": "Ricerca", + "loadingText": "caricamento del testo", + "noDataText": "Non ci sono moduli nel tuo sistema", + "admin": "Amministratore", + "launch": "Lancio", + "formTitle": "Titolo del modulo", + "created": "Creato", + "deleted": "Eliminato", + "actions": "Azioni", + "delete": "Eliminare" + }, + "administerForm": { + "deleted": "CANCELLATO", + "restoreForm": "Ripristina questo modulo", + "formDetails": "Dettagli del modulo", + "apiKeyDetails": "Dettagli della chiave API", + "deleteApiKey": "Elimina chiave API", + "formUsers": "Utenti del modulo", + "formVersions": "Versioni del modulo", + "assignANewOwner": "Assegna un nuovo proprietario", + "restoring": "Ripristino", + "restore": "Ristabilire", + "toActiveState": "allo stato attivo", + "confirmDeletion": "Confermare la cancellazione", + "confirmDeletionMsg": "Sei sicuro di voler eliminare questa chiave API?", + "delete": "Eliminare", + "confirmRestore": "Conferma ripristino" + }, + "administerUser": { + "userDetails": "Dettagli utente", + "openSSOConsole": "Apri la console SSO" + }, + "adminPage": { + "forms": "Forme", + "users": "Utenti", + "developer": "Sviluppatore", + "infoLinks": "Collegamenti informativi", + "metrics": "Metrica" + }, + "adminUsersTable": { + "search": "Ricerca", + "loadingText": "Attendere il caricamento prego", + "admin": "Amministratore", + "fullName": "Nome e cognome", + "userID": "ID utente", + "created": "Creato", + "actions": "Azioni" + }, + "adminVersions": { + "exportDesign": "Esporta disegno", + "versions": "Versioni", + "status": "Stato", + "created": "Creato", + "lastUpdated": "Ultimo aggiornamento", + "actions": "Azioni", + "published": "Pubblicato", + "unpublished": "Inedito", + "version": "Versione {versionNo}", + "notificationMsg": "Si è verificato un errore durante il caricamento del progetto del modulo." + }, + "developer": { + "user": "Utente", + "name": "Nome", + "userName": "Nome utente", + "JWTContents": "Contenuto JWT", + "JWTContentsSBTxt": "JWT Contenuti copiati negli appunti", + "JWTContentsTTTxt": "Copia i contenuti JWT negli appunti", + "JWTToken": "Gettone JWT", + "JWTTokenSBTxt": "Token JWT copiato negli appunti", + "JWTTokenTTTxt": "Copia il token JWT negli appunti", + "chefsAPI": "API CHEF", + "RBACSBTxt": "Risposta RBAC copiata negli appunti", + "RBACTTTxt": "Copia la risposta RBAC negli appunti", + "notificationMsg": "Impossibile ottenere l'utente da RBAC, vedere la console", + "notificationConsErr": "Errore durante il recupero dell'utente da RBAC" + }, + "baseAuthButton": { + "logout": "Disconnettersi", + "login": "Login" + }, + "baseDialog": { + "defaultText": "testo predefinito", + "ok": "OK", + "continue": "Continua", + "cancel": "Annulla", + "custom": "Costume" + }, + "baseSecure": { + "about": "Di", + "loginInfo": "Devi essere loggato per usare questa funzione.", + "login": "Login", + "401NotAuthorized": "401: non autorizzato. :", + "401ErrorMsg": "Il tuo account non è impostato correttamente.
Si prega di contattare", + "403Forbidden": "403: Proibito. :", + "403ErrorMsg": "Questa pagina richiede l'autenticazione {idp}.", + "401UnAuthorized": "401: non autorizzato. :", + "401UnAuthorizedErrMsg": "Non sei autorizzato ad accedere a questa pagina." + }, + "formDesigner": { + "formDesign": "Progettazione della forma", + "exportDesign": "Esporta disegno", + "importDesign": "Importa disegno", + "important": "IMPORTANTE", + "formDesignInfoA": "Usa il pulsante SALVA PROGETTO quando hai finito di costruire questo modulo.", + "formDesignInfoB": "Il pulsante INVIA viene fornito all'utente per inviare questo modulo e verrà attivato dopo che è stato salvato.", + "formLoadErrMsg": "Si è verificato un errore durante il caricamento del progetto del modulo.", + "formLoadConsoleErrMsg": "Errore durante il caricamento dello schema del modulo {formId} (versione: {versionId} bozza: {draftId}): {error}", + "formSchemaImportErrMsg": "Si è verificato un errore durante l'importazione dello schema del modulo.", + "formSchemaImportConsoleErrMsg": "Errore durante l'importazione dello schema del modulo: {error}", + "formDesignSaveErrMsg": "Si è verificato un errore durante il tentativo di salvare questo modello di modulo. Se devi aggiornare o partire per riprovare più tardi, puoi esportare il design esistente sulla pagina per salvarlo per dopo.", + "formDesignSaveConsoleErrMsg": "Errore durante l'aggiornamento o la creazione del modulo (FormID: {formId}, versionId: {versionId}, draftId: {draftId}) Errore: {error}", + "collapse": "Crollo", + "actions": "Azioni", + "version": "Versione", + "save": "Salva", + "saving": "Salvataggio", + "notSaved": "Non salvato", + "fieldnameError": "NON PUOI utilizzare la parola chiave 'form' come nome campo {label}" + }, + "formViewerMultiUpload": { + "important": "IMPORTANTE", + "uploadSucessMsg": "Per garantire il corretto caricamento di più bozze, scaricare e utilizzare il modello fornito.", + "confirmDownload": "Vuoi scaricarlo?", + "jsonFileUpload": "Seleziona il file JSON da caricare", + "dragNDrop": "o trascinalo qui", + "chooseAFile": "Scegli un file", + "downloadDraftSubmns": "Si prega di scaricare la bozza del rapporto di presentazione e assicurarsi che i dati siano inseriti correttamente.", + "downloadReport": "Scarica rapporto", + "doYouWantToDownload": "Vuoi scaricarlo?", + "uploadNewFile": "Carica nuovo file", + "uploadMultipleFileErr": "Spiacenti, puoi caricare un solo file", + "dragMultipleFileErr": "Spiacenti, puoi trascinare solo un file", + "fileFormatErr": "Siamo spiacenti, accettiamo solo file json", + "fileSizeErr": "La dimensione massima del file consentita è di 5 MB", + "parseJsonErr": "Non possiamo analizzare i dati json dal file", + "jsonObjNotArray": "Formato file json errato", + "jsonObjNotArrayConsErr": "Si è verificato un errore imprevisto.", + "jsonArrayEmpty": "Questo file json è vuoto.", + "errorWhileValidate": "C'è qualcosa che non va in questo file", + "errWhileCheckValidity": "C'è qualcosa che non va in questo file", + "errAfterValidate": "Sono stati rilevati alcuni errori, vedere di seguito per ulteriori informazioni.", + "fileIsEmpty": "questo file è vuoto.", + "download": "Scaricamento" + }, + "formDisclaimer": { + "disclaimerAndStatement": "Dichiarazione di non responsabilità e dichiarazione di responsabilità per i progettisti di moduli:", + "privacyLaw": "È tua responsabilità rispettare le leggi sulla privacy che regolano la raccolta, l'uso e la divulgazione di informazioni di identificazione personale.", + "disclosure": "L'accesso a questo strumento di progettazione di moduli non concede intrinsecamente il permesso di raccogliere, utilizzare o divulgare alcuna informazione di identificazione personale.", + "consent": "È tua responsabilità ottenere il consenso per raccogliere informazioni come richiesto dalla legge.", + "formIntention": "Prima di pubblicare o distribuire il tuo modulo, devi discutere l'intenzione del modulo con il tuo", + "privacyOfficer": "Responsabile della Privacy del Ministero", + "assement": "e per completare le valutazioni come richiesto." + }, + "requestReceipt": { + "emailPriority": "Priorità e-mail", + "emailReceipt": "Invia una ricevuta di questo invio tramite e-mail", + "high": "Alto", + "low": "Basso", + "normal": "Normale", + "send": "INVIARE", + "sendToEmailAddress": "Invia a indirizzo e-mail", + "emailSent": "È stata inviata un'e-mail a {to}.", + "sendingEmailErrMsg": "Si è verificato un errore durante il tentativo di inviare la tua e-mail.", + "sendingEmailConsErrMsg": "Email di conferma a {to} non riuscita: {error}", + "emailRequired": "L'e-mail è obbligatoria" + }, + "submissionsTable": { + "noMatchingRecordText": "Nessuna corrispondenza trovata", + "submissions": "Contributi", + "submissionsTable": "Tabella degli invii", + "selectColumns": "Seleziona Colonne", + "manageForm": "Gestisci modulo", + "submissionsToFiles": "Esporta invii su file", + "showDeletedSubmissions": "Mostra invii eliminati", + "showMySubmissions": "Mostra i miei invii", + "search": "Ricerca", + "loadingText": "Attendere il caricamento prego", + "noDataText": "Non ci sono invii per questo modulo", + "delSelectedSubmissions": "Elimina gli invii selezionati", + "resSelectedSubmissions": "Ripristina gli invii selezionati", + "yes": "SÌ", + "no": "NO", + "viewSubmission": "Visualizza invio", + "deleteSubmission": "Elimina invio", + "restore": "Ristabilire", + "confirmDeletion": "Confermare la cancellazione", + "delete": "Eliminare", + "confirmRestoration": "Conferma ripristino", + "searchSubmissionFields": "Cerca nei campi di invio", + "save": "Salva", + "searchTitle": "Cerca e seleziona le colonne da mostrare sotto la dashboard", + "status": "Stato", + "submitter": "Inviato", + "submissionDate": "Data di presentazione", + "event": "evento", + "view": "Visualizzazione", + "lateSubmission": "Invio in ritardo", + "confirmationID": "ID di conferma", + "multiDelWarning": "Sei sicuro di voler eliminare gli invii selezionati?", + "singleDelWarning": "Sei sicuro di voler eliminare questo invio?", + "multiRestoreWarning": "Sei sicuro di voler ripristinare questi invii?", + "singleRestoreWarning": "Sei sicuro di voler ripristinare questo invio?" + }, + "auditHistory": { + "viewEditHistory": "Visualizza la cronologia delle modifiche", + "editHistory": "Modifica cronologia", + "auditLogMsg": "Questo è un registro di controllo di chi ha apportato modifiche a questo invio dopo l'invio originale.", + "loadingText": "Attendere il caricamento prego", + "close": "Vicino", + "userName": "Nome utente", + "date": "Data", + "errorMsg": "Si è verificato un errore durante il tentativo di recuperare la cronologia.", + "consoleErrMsg": "Errore durante il recupero della cronologia di controllo per" + }, + "deleteSubmission": { + "deleteThis": "Cancella questo", + "draft": "Bozza", + "submission": "Sottomissione", + "confirmDeletion": "Confermare la cancellazione", + "deleteWarning": "Sei sicuro di voler eliminare questo", + "drafts": "bozza", + "formSubmission": "invio del modulo", + "delete": "Eliminare" + }, + "manageSubmissionUsers": { + "manageTeamMembers": "Gestisci i membri del team", + "add": "Aggiungere", + "draftFormInvite": "Puoi solo invitare e gestire i membri del team mentre questo modulo è una bozza", + "submissionTeamMembers": "Membri del team per questa sottomissione", + "actions": "Azioni", + "close": "Vicino", + "remove": "Rimuovere", + "userNotFoundErrMsg": "Non riesci a trovare qualcuno? Potrebbero non aver effettuato l'accesso a CHEFS.
Si prega di inviare loro un collegamento a CHEFS e chiedere loro di accedere.", + "name": "Nome", + "username": "Nome utente", + "email": "E-mail", + "removeUserWarningMsg1": "Sei sicuro di voler rimuovere", + "removeUserWarningMsg2": "Non avranno più le autorizzazioni per questo invio.", + "userExistInListMsg": "L'utente {username} è già nell'elenco dei membri del team.", + "getSubmissionUsersErr": "Si è verificato un errore durante il tentativo di recuperare gli utenti per questo invio.", + "getSubmissionUsersConsoleErr": "Errore durante il recupero degli utenti per {submissionId} : {error}", + "sentInviteEmailTo": "Email di invito inviata a", + "sentUninvitedEmailTo": "Email non invitata inviata a", + "updateUserErrMsg": "Si è verificato un errore durante il tentativo di aggiornare gli utenti per questo invio.", + "updateUserConsoleErrMsg": "Errore durante l'impostazione delle autorizzazioni utente. Sub: {submissionId} Utente: {userId} Errore: {error}", + "searchInputLength": "L'input di ricerca per nome utente/e-mail BCeID deve contenere più di 6 caratteri.", + "exactBCEIDSearch": "Le ricerche e-mail per BCeID devono essere esatte.", + "getUsersErrMsg": "Errore durante il recupero degli utenti: {error}", + "exactEmailOrUsername": "Inserisci un'e-mail o un nome utente esatti.", + "requiredFiled": "Inserisci un nome, un'e-mail o un nome utente" + }, + "mySubmissionsActions": { + "viewThisSubmission": "Visualizza questa presentazione", + "copyThisSubmission": "Copia questa presentazione", + "editThisDraft": "Modifica questa bozza" + }, + "mySubmissionsTable": { + "noMatchingRecordText": "Nessuna corrispondenza trovata", + "previousSubmissions": "Invii precedenti", + "selectColumns": "Seleziona Colonne", + "createNewSubmission": "Crea un nuovo invio", + "search": "Ricerca", + "loadingText": "Attendere il caricamento prego", + "noDataText": "Non hai invii", + "searchSubmissionFields": "Cerca nei campi di invio", + "save": "Salva", + "filterTitle": "Cerca e seleziona le colonne da mostrare sotto la dashboard", + "confirmationId": "Identificativo di conferma", + "actions": "Azioni", + "createdBy": "Creato da", + "statusUpdatedBy": "Stato aggiornato da", + "status": "Stato", + "submissionDate": "Data di presentazione", + "draftUpdatedBy": "Bozza aggiornata da", + "draftLastEdited": "Bozza Ultima modifica", + "createLateSubmissn": "Crea invio tardivo", + "formLoading": "Attendere il caricamento del modulo !!!", + "pleaseConfirm": "Si prega di confermare", + "wantToSaveDraft": "Vuoi salvare la bozza?", + "yes": "SÌ", + "no": "NO", + "multiDraftUploadSuccess": "Il caricamento di più bozze è andato a buon fine!", + "failedResSubmissn": "Risposta non riuscita dall'endpoint di invio. Codice di risposta: {status}", + "errSubmittingForm": "Si è verificato un errore durante l'invio di questo modulo", + "errorSavingFile": "Errore durante il salvataggio dei file. nome file: {fileName}. Errore: {error}", + "submittingDraftErrMsg": "Si è verificato un errore durante il salvataggio di una bozza", + "submittingDraftConsErrMsg": "Errore durante il salvataggio della bozza. SubmissionId: {submissionId}. Errore: {error}" + }, + "notesPanel": { + "addNewNote": "Aggiungi nuova nota", + "cancel": "Annulla", + "addNote": "AGGIUNGI NOTA", + "noResponseErr": "Nessun dato di risposta dall'API durante l'invio del modulo", + "errorMesg": "Si è verificato un errore durante il tentativo di aggiungere la nota.", + "consoleErrMsg": "Errore durante l'aggiunta della nota:", + "fetchErrMsg": "Si è verificato un errore durante il tentativo di recuperare le note per questo invio.", + "fetchConsoleErrMsg": "Errore durante l'aggiunta della nota:", + "notes": "Appunti", + "note": "Nota", + "maxChars": "Massimo 4000 caratteri" + }, + "statusPanel": { + "currentStatus": "Stato attuale:", + "assignedTo": "Assegnato a:", + "assignOrUpdateStatus": "Assegna o aggiorna lo stato", + "display": "Schermo", + "statusIsRequired": "Lo stato è obbligatorio", + "assignTo": "Assegnato a", + "noDataText": "Nessun revisore di moduli trovato con la ricerca. Aggiungi i revisori del modulo nella pagina Gestisci.", + "assigneeIsRequired": "L'assegnatario è obbligatorio", + "assignToMe": "ASSEGNAMI", + "recipientEmail": "Destinatario dell'email", + "attachCommentToEmail": "Allega commento all'e-mail", + "emailComment": "E-mail Commento", + "maxChars": "Massimo 4000 caratteri", + "viewHistory": "GUARDA LA STORIA", + "statusHistory": "Cronologia dello stato", + "close": "VICINO", + "addNoteNoReponserErr": "Nessun dato di risposta dall'API durante l'invio della nota per l'aggiornamento dello stato", + "addNoteConsoleErrMsg": "Errore durante l'aggiornamento dello stato: {error}", + "addNoteErrMsg": "Si è verificato un errore durante il tentativo di aggiornare lo stato", + "updtSubmissionsStatusErr": "Nessun dato di risposta dall'API durante l'invio del modulo di aggiornamento dello stato", + "noStatus": "Nessuno Stato", + "noStatusesFound": "Nessuno stato trovato", + "statusCodesErr": "errore nella ricerca dei codici di stato", + "notifyErrorCode": "Si è verificato un errore durante il recupero dello stato per questo invio.", + "notifyConsoleErrorCode": "Errore durante l'acquisizione degli stati:", + "fetchSubmissionUsersErr": "Si è verificato un errore durante il tentativo di recuperare le email dei destinatari per questo invio.", + "fetchSubmissionUsersConsErr": "Errore durante il recupero delle email del destinatario per", + "assignSubmissnToFormReviewer": "Gli invii possono essere assegnati ai revisori dei moduli.
Per aggiungere altri membri del team come revisori del modulo, vai alla pagina Gestisci per questo modulo.", + "update": "AGGIORNAMENTO", + "revise": "RIVEDERE", + "complete": "COMPLETARE", + "assign": "ASSEGNARE" + }, + "statusTable": { + "loadingText": "Attendere il caricamento prego", + "status": "Stato", + "dateStatusChanged": "Data Stato Modificato", + "assignee": "Assegnatario", + "updatedBy": "Aggiornato da", + "getSubmissionStatusErr": "Si è verificato un errore durante il tentativo di recupero degli stati.", + "getSubmissionStatusConsErr": "Errore durante l'aggiunta della nota:" + }, + "exportSubmissions": { + "exportSubmissionsToFile": "Esporta invii su file", + "viewSubmissions": "Visualizza invii", + "fileType": "Tipo di file", + "json": "JSON", + "csv": "CSV", + "formVersion": "Versione modulo", + "versionIsRequired": "È richiesta la versione.", + "dataFields": "Campi dati", + "searchFields": "Campi di ricerca", + "selectedForExports": "selezionati per l'esportazione", + "submissionDate": "Data di presentazione", + "all": "Tutto", + "selectDateRange": "Seleziona Intervallo di date", + "SelectdateRange": "Seleziona l'intervallo di date", + "from": "Da", + "to": "A", + "CSVFormat": "Formato CSV", + "multiRowPerSubmissionA": "1 - Righe multiple per invio con spazi di rientro", + "multiRowPerSubmissionB": "2 - Righe multiple per invio", + "singleRowPerSubmission": "3 - Riga singola per invio", + "unformatted": "4 - Non formattato", + "fileNameAndType": "Nome file e tipo", + "export": "Esportare", + "noResponseDataErr": "Nessun dato in risposta alla chiamata exportSubmissions", + "apiCallErrorMsg": "Si è verificato un errore durante il tentativo di esportare gli invii per questo modulo.", + "apiCallConsErrorMsg": "Errore nell'esportazione degli invii per", + "selectAllFields": "Seleziona tutti i campi", + "emailSentMsg": "Verrà inviata un'e-mail a {email} contenente un collegamento per scaricare i tuoi dati quando saranno pronti", + "exportInProgress": "Esportazione in corso", + "of": "Di" + }, + "printOptions": { + "submitButtonTxt": "Invia a CDOGS e scarica", + "templatePrint": "Stampa del modello", + "uploadTemplateFile": "Carica file modello", + "downloadOptions": "Opzioni di download", + "print": "Stampa", + "browserPrint": "Stampa browser", + "pageFromBrowser": "la pagina dal tuo browser", + "uploadA": "Carica un", + "uploadB": "avere una versione strutturata", + "docGrnSucess": "Documento generato con successo", + "failedDocGenErrMsg": "Impossibile generare il documento", + "failedDocGenConsErrMsg": "Errore durante l'invio del modello: {error}", + "cDogsTemplate": "Modello CDOGS" + }, + "proactiveHelpDialog": { + "componentInfoLink": "Collegamento alle informazioni sui componenti", + "learnMoreLinkTxt": "Ulteriori informazioni Il campo Link non può essere vuoto.", + "largeImgTxt": "Immagine grande. La dimensione dell'immagine non può essere maggiore di 0,5 MB", + "componentName": "Nome del componente:", + "learnMoreLink": "Link per saperne di più:", + "clickToEnableLink": "Fare clic per abilitare il collegamento", + "clickToDisableLink": "Fare clic per disattivare il collegamento", + "imageUpload": "Caricamento immagine:", + "cancel": "Annulla", + "save": "Salva", + "description": "Descrizione" + }, + "proactiveHelpPreviewDialog": { + "learnMore": "Saperne di più" + }, + "preview": { + "preview": "Anteprima", + "previewToolTip": "Questo mostra un'anteprima del design e del comportamento della versione del modulo come lo vedranno i tuoi mittenti. Non puoi inviare il modulo da questa pagina." + }, + "generalLayout": { + "loadingText": "Attendere il caricamento prego", + "preview": "ANTEPRIMA", + "published": "PUBBLICATO", + "unpublished": "INEDITO", + "edit": "MODIFICARE", + "formTitle": "Titolo del modulo", + "actions": "Azioni" + }, + "formSubmission": { + "editThisSubmission": "Modifica questa presentazione", + "submission": "Sottomissione", + "alertInfo": "Dopo la modifica, invia nuovamente il modulo per salvare le modifiche.", + "viewAllSubmissions": "Visualizza tutti gli invii", + "submitted": "Inviato:", + "confirmationID": "ID di conferma:", + "submittedBy": "Inviato da:", + "cancel": "ANNULLA", + "status": "Stato", + "updatedAt": "Modificata", + "updatedBy": "Modificato da" + }, + "teamManagement": { + "noMatchingRecordText": "Nessuna corrispondenza trovata", + "teamManagement": "Gestione della squadra", + "selectColumns": "Seleziona Colonne", + "manageForm": "Gestisci modulo", + "search": "Ricerca", + "loadingText": "Attendere il caricamento prego", + "noDataText": "Impossibile caricare i dati del ruolo del team", + "removeSelectedUsers": "Rimuovi gli utenti selezionati", + "removeThisUser": "Rimuovi questo utente", + "confirmRemoval": "Conferma rimozione", + "remove": "Rimuovere", + "searchTeamManagementFields": "Cerca i campi di gestione del team", + "save": "Salva", + "teamMebersTitle": "Cerca e seleziona le colonne da mostrare sotto la dashboard", + "fullName": "Nome e cognome", + "username": "Nome utente", + "identityProvider": "Fornitore di identità", + "delSelectedMembersWarning": "Sei sicuro di voler rimuovere i membri selezionati?", + "delSelectedMemberWarning": "Sei sicuro di voler rimuovere il membro selezionato?", + "idpMessage": "è già in squadra", + "formOwnerErrMsg": "Deve esserci sempre almeno un proprietario del modulo", + "formOwnerConsoleErrMsg": "Impossibile rimuovere {userId} poiché è l'unico proprietario rimasto di questo modulo.", + "insufficientPermissnMsg": "Autorizzazioni insufficienti per gestire il team", + "getUserErrMsg": "Errore durante il recupero degli utenti del modulo:", + "getRolesErrMsg": "Errore durante l'acquisizione dell'elenco dei ruoli:", + "formOwnerRemovalWarning": "Impossibile rimuovere poiché è l'unico proprietario rimasto di questo modulo.", + "removeUsersErrMsg": "Si è verificato un errore durante il tentativo di eliminare gli utenti selezionati", + "removeUserConsoleErrMsg": "Errore durante l'eliminazione degli utenti dal modulo {formId}: {error}", + "updUserRolesErrMsg": "Si è verificato un errore durante il tentativo di aggiornare tutti i ruoli utente", + "updUserRolesConsoleErrMsg": "Errore durante l'impostazione di tutti i ruoli utente per il modulo {formId}: {error}", + "setUserFormsErrMsg": "Si è verificato un errore durante il tentativo di aggiornare i ruoli per un utente", + "setUserFormsConsoleErrMsg": "Errore durante l'impostazione dei ruoli utente per il modulo {formId}: {error}" + }, + "floatButton": { + "publish": "Pubblicare", + "manage": "Maneggio", + "redo": "Rifare", + "undo": "Disfare", + "preview": "Anteprima", + "bottom": "Metter il fondo a", + "top": "Superiore", + "actions": "Azioni", + "collapse": "Crollo", + "saved": "Salvato", + "save": "Salva", + "saving": "Salvataggio", + "notSaved": "Non salvato" + }, + "formViewer": { + "lateFormSubmissions": "Il periodo di invio del modulo è scaduto! Puoi comunque creare un invio tardivo facendo clic sul pulsante in basso.", + "createLateSubmission": "Crea invio tardivo", + "draftSaved": "Bozza salvata", + "saving": "Salvataggio", + "pleaseConfirm": "Si prega di confermare", + "submitFormWarningMsg": "Sei sicuro di voler inviare il modulo?", + "submit": "Invia", + "wantToSaveDraft": "Vuoi salvare la bozza?", + "version": "Versione: {version}", + "formScheduleExpireMessage": "L'invio del modulo non è disponibile poiché il periodo di invio programmato è scaduto.", + "getUsersSubmissionsErrMsg": "Si è verificato un errore durante il recupero dell'invio per questo modulo", + "getUsersSubmissionsConsoleErrMsg": "Errore durante il caricamento dei dati di invio del modulo {submissionId}: {error}", + "multiDraftUploadSuccess": "Il caricamento di più bozze è andato a buon fine!", + "readVersionErrMsg": "Nessuno schema in risposta. ID versione: {versionId}", + "readDraftErrMsg": "Nessuno schema in risposta. ID bozza: {draftId}", + "alertRouteMsg": "Il proprietario del modulo non ha pubblicato il modulo e non è disponibile per l'invio.", + "fecthingFormErrMsg": "Si è verificato un errore durante il recupero di questo modulo", + "fecthingFormConsoleErrMsg": "Errore durante il caricamento dello schema del modulo {versionId}: {error}", + "savingDraftErrMsg": "Si è verificato un errore durante il salvataggio di una bozza", + "savingDraftConsoleErrMsg": "Errore durante il salvataggio della bozza. SubmissionId: {submissionId}. Errore: {error}", + "submissionsPreviewAlert": "Invio disabilitato durante l'anteprima del modulo", + "submissionsSubmitErrMsg": "Errore durante l'invio del modulo: {errors}", + "sendSubmissionErrMsg": "Risposta non riuscita dall'endpoint di invio. Codice di risposta: {status}", + "errMsg": "Si è verificato un errore durante l'invio di questo modulo", + "customEventAlert": "Eventi pulsante personalizzati non ancora supportati. Tipo di evento: {event}", + "formLoading": "Attendere il caricamento del modulo !!!", + "yes": "SÌ", + "no": "NO", + "failedResSubmissn": "Risposta non riuscita dall'endpoint di invio. Codice di risposta: {status}", + "errSubmittingForm": "Si è verificato un errore durante l'invio di questo modulo", + "errorSavingFile": "Errore durante il salvataggio dei file. nome file: {fileName}. Errore: {error}", + "submittingDraftErrMsg": "Si è verificato un errore durante il salvataggio di una bozza", + "submittingDraftConsErrMsg": "Errore durante il salvataggio della bozza. SubmissionId: {submissionId}. Errore: {error}", + "formDraftAccessErrMsg": "L'invio richiesto è già stato inviato, reindirizzamento alla pagina Visualizza" + }, + "bCGovFooter": { + "home": "Casa", + "about": "Informazioni su gov.bc.ca", + "disclaimer": "Disclaimer", + "privacy": "Riservatezza", + "accessibility": "Accessibilità", + "copyRight": "Diritto d'autore", + "contactUs": "Contattaci" + }, + "bCGovNavBar": { + "about": "Di", + "myForms": "Le mie Forme", + "createNewForm": "Crea un nuovo modulo", + "help": "Aiuto", + "feedback": "Feedback", + "admin": "Amministratore" + }, + "homePage": { + "title": "Crea, pubblica moduli e ricevi invii con Common Hosted Forms Service.", + "subTitle": "Tutto a.C. I dipendenti pubblici o gli appaltatori con un account IDIR possono utilizzare la nostra versione ospitata di Common Hosted Forms Service (CHEFS) per creare moduli.", + "takeATourOfChefs": "Fai un tour di CHEFS per vederlo in azione.", + "logInToGetStarted": "Accedi per iniziare", + "loginToStart": "Accedi con IDIR per iniziare", + "login": "Login", + "createFormLabel": "Crea un modulo", + "manageAccessTitle": "Gestisci l'accesso al tuo modulo", + "manageAccessSub1": "CHEFS ti consente di creare moduli pubblici oppure puoi gestire l'accesso tramite autenticazione IDIR o BCeID.", + "manageAccessSub2": "Puoi anche assegnare ruoli al tuo team per gestire tutti i tuoi invii.", + "createCustomFormTitle": "Crea moduli personalizzati con il generatore di moduli CHEFS", + "createCustomFormSub1": "Con CHEFS, puoi creare moduli sicuri con un'intuitiva interfaccia drag-and-drop. È possibile aggiungere componenti del modulo, riorganizzarli e rilasciarli in diverse configurazioni di layout.", + "chefsHowToTitle": "Video dimostrativi per CHEF", + "chefsHowToSub": "La nostra guida rapida ti introdurrà ad alcune delle funzioni di base di CHEFS.", + "getStartedToChefs": "Inizia a usare CHEFS", + "createOnlineTitle": "Crea moduli online per raccogliere informazioni dai tuoi clienti e migliorare i tuoi flussi di lavoro.", + "getStarted": "Iniziare" + }, + "baseStepper": { + "setUpForm": "Imposta modulo", + "designForm": "Modulo di progettazione", + "manageForm": "Gestisci modulo" + }, + "create": { + "formSettings": "Impostazioni modulo", + "disclaimer": "Disclaimer", + "disclaimerStmt": "Accetto il disclaimer e la dichiarazione di responsabilità per Form Designers", + "continue": "Continua", + "back": "Indietro", + "confirmPageNav": "Vuoi davvero lasciare questa pagina? Le modifiche apportate non verranno salvate.", + "agreementErrMsg": "Devi accettare il disclaimer sulla privacy mostrato sopra." + }, + "addTeamMember": { + "cantFindChefsUsers": "Non riesci a trovare qualcuno? Potrebbero non aver effettuato l'accesso a CHEFS.
Si prega di inviare loro un collegamento a CHEFS e chiedere loro di accedere.", + "cancel": "Annulla", + "add": "Aggiungere", + "mustSelectAUser": "Devi selezionare almeno un ruolo per aggiungere questo utente.", + "addNewMember": "Aggiungi un nuovo membro", + "enterUsername": "Inserisci un nome, un'e-mail o un nome utente", + "enterExactUsername": "Inserisci un'e-mail o un nome utente esatti", + "BCeIDInputSearchMaxLen": "L'input di ricerca per nome utente/e-mail BCeID deve contenere più di 6 caratteri.", + "BCeIDMustBeExact": "Le ricerche e-mail per BCeID devono essere esatte.", + "errorGettingUsers": "Errore durante il recupero degli utenti {error}" + }, + "baseFilter": { + "cancel": "Annulla", + "columnName": "Nome colonna", + "exampleText": "Esempio di testo", + "exampleText2": "Esempio di testo 2", + "filterPlaceholderTxt": "Filtra testo segnaposto", + "filter": "Filtro", + "value": "valore", + "resetColumns": "Reimposta colonne" + }, + "formViewerActions": { + "viewMyDraftOrSubmissions": "Visualizza le mie bozze/presentazioni", + "saveAsADraft": "Salva come bozza", + "editThisDraft": "Modifica questa bozza", + "switchSingleSubmssn": "Passa all'invio singolo", + "switchMultiSubmssn": "Passa a più invii" + }, + "baseCopyToClipboard": { + "linkToClipboard": "Link copiato negli appunti", + "copyToClipboard": "Copia negli appunti", + "errCopyToClipboard": "Errore nel tentativo di copiare negli appunti." + }, + "sucess": { + "sucessFormSubmissn": "Il tuo modulo è stato inviato con successo", + "keepRecord": "Se desideri conservare una registrazione di questa presentazione, puoi conservare quanto segue", + "confirmationId": "ID di conferma" + }, + "bcGovAlertBanner": { + "defaultErrMsg": "Errore: qualcosa è andato storto", + "error": "errore" + }, + "permissionUtils": { + "formNotAvailable": "Il modulo non è al momento disponibile. Ciò potrebbe essere dovuto a un collegamento errato o il modulo potrebbe essere stato eliminato dal suo proprietario.", + "missingFormIdAndSubmssId": "Opzioni mancanti sia di formId che di submissionId", + "loadingFormErrMsg": "Si è verificato un errore durante il caricamento di questo modulo.", + "loadingForm": "Errore durante il caricamento di {options}: {error}", + "idpHintMsg": "Questo modulo richiede l'autenticazione {idpHint}. Effettua nuovamente il login e riprova.", + "formIdpMissMatch": "Form IDP non corrispondente. Il modulo richiede {idpHint} ma l'utente ha {userIdp}." + }, + "download": { + "chefsDataExport": "Esportazione dati CHEFS", + "preparingForDownloading": "Preparazione per il download...", + "downloadInfoA": "Se il tuo file non viene scaricato automaticamente", + "downloadInfoB": "clicca qui per riprovare" + }, + "history": { + "submissnHistory": "La tua cronologia di invio (TBD)" + }, + "error": { + "logout": "Disconnettersi", + "somethingWentWrong": "Errore: Qualcosa è andato storto... :(" + }, + "login": { + "authenticateWith": "Autenticati con:", + "alreadyLoggedIn": "Ha già effettuato il login", + "home": "Casa", + "about": "Di" + }, + "notFound": { + "about": "Di", + "pageNotFound": "404 pagina non trovata. :(" + }, + "store": { + "admin": { + "addFormOwnerRole": "Aggiunto il ruolo Proprietario per questo modulo a {fullName}", + "addRowError": "Si è verificato un errore durante l'aggiunta del ruolo.", + "addRowConsoleErr": "Errore durante l'aggiunta dell'utente {userId} al modulo {formId}: {error}", + "apiKeyDelMsg": "La chiave API per questo modulo è stata eliminata.", + "errDeletingApiKey": "Si è verificato un errore durante il tentativo di eliminare la chiave API.", + "consErrDeletingApiKey": "Errore durante l'eliminazione della chiave API per il modulo {formId}: {error}", + "fecthingFormsErrMsg": "Si è verificato un errore durante il recupero dei moduli.", + "fecthingFormsConsErrMsg": "Errore durante il recupero dei dati del modulo di amministrazione: {error}", + "fecthingFormErrMsg": "Si è verificato un errore durante il recupero di questo modulo.", + "fecthingFormConsErrMsg": "Errore durante il recupero dei dati del modulo di amministrazione {formId}: {error}", + "fecthFormUserRolesErrMsg": "Si è verificato un errore durante il recupero dei ruoli utente del modulo.", + "fecthFormUserRolesConsErrMsg": "Errore durante il recupero dei dati sui ruoli di amministratore: {error}", + "fecthApiDetailsErrMsg": "Si è verificato un errore durante il recupero dei dettagli dell'API di questo modulo.", + "fecthApiDetailsConsErrMsg": "Errore durante l'acquisizione dei dettagli dell'API di amministrazione dai dati del modulo {formId}: {error}", + "restoreFormErrMsg": "Si è verificato un errore durante il ripristino di questo modulo.", + "restoreFormConsErrMsg": "Errore durante il ripristino dei dati del modulo {formId}: {error}", + "getUsersErrMsg": "Si è verificato un errore durante il recupero degli utenti.", + "getUsersConsErrMsg": "Errore durante il recupero dei dati degli utenti amministratori: {error}", + "getUserErrMsg": "Si è verificato un errore durante il recupero di questo utente.", + "getUserConsErrMsg": "Errore durante il recupero dei dati dell'utente amministratore {userId}: {error}", + "storingFCHelpInfoErrMsg": "Si è verificato un errore durante la memorizzazione delle informazioni della guida del componente del modulo", + "storingFCHelpInfoConsErrMsg": "Errore durante la memorizzazione delle informazioni della guida del componente del modulo: {error}", + "gettingFCImgUrlErrMsg": "Si è verificato un errore durante il recupero dell'URL dell'immagine", + "gettingFCImgUrlConsErrMsg": "Errore durante l'acquisizione dell'URL dell'immagine: {error}", + "updatingFCStatusErrMsg": "Si è verificato un errore durante l'aggiornamento dello stato di pubblicazione", + "updatingFCStatusConsErrMsg": "Errore durante l'aggiornamento dello stato di pubblicazione: {error}", + "fecthingFormBuilderCompsErrMsg": "Si è verificato un errore durante il recupero dei componenti del generatore di moduli", + "fecthingFormBuilderCompsConsErrMsg": "Errore durante il recupero dei componenti del generatore di moduli: {error}" + }, + "form": { + "fetchEmailTemplatesConsErrMsg": "Errore durante il caricamento dei modelli di email per {formId}: {error}", + "fetchEmailTemplatesErrMsg": "Si è verificato un errore durante il recupero dei modelli di email per questo modulo", + "getCurrUserFormsErrMsg": "Si è verificato un errore durante il recupero dei moduli.", + "getCurrUserFormsConsErrMsg": "Errore durante il recupero dei dati utente: {error}", + "getUserFormPermErrMsg": "Si è verificato un errore durante il recupero dei dati utente per questo modulo.", + "getUserFormPermConsErrMsg": "Errore durante il recupero dei dati utente utilizzando formID {formId}: {error}", + "getUserFormRolesErrmsg": "Si è verificato un errore durante il recupero dei dati utente per questo modulo.", + "getUserFormRolesConsErrmsg": "Errore durante il recupero dei dati utente utilizzando formID {formId}: {error}", + "updCurrUserFormPrefErrMsg": "Si è verificato un errore durante il salvataggio delle preferenze per questo modulo.", + "updCurrUserFormPrefConsErrMsg": "Errore durante l'aggiornamento delle preferenze del modulo utente utilizzando formID {formId} e preferenze {preferences}: {error}", + "getCurrUserFormPrefErrMsg": "Si è verificato un errore durante il recupero delle tue preferenze per questo modulo.", + "getCurrUserFormPrefConsErrMsg": "Errore nell'ottenere le preferenze del modulo utente utilizzando formID {formId}: {error}", + "delCurrformNotiMsg": "Il modulo {name} è stato eliminato con successo.", + "delCurrFormConsErMsg": "Errore durante l'eliminazione del modulo {id}: {error}", + "delDraftErrMsg": "Si è verificato un errore durante l'eliminazione di questa bozza.", + "delDraftConsErrMsg": "Errore durante l'eliminazione di {draftId}: {error}", + "fecthDraftErrMsg": "Si è verificato un errore durante la scansione delle bozze per questo modulo.", + "fecthDraftConsErrMsg": "Errore durante il recupero delle bozze per il modulo {formId}: {error}", + "fecthFormErrMsg": "Si è verificato un errore durante il recupero di questo modulo.", + "fecthFormConsErrMsg": "Errore durante l'acquisizione del modulo {formId}: {error}", + "fetchFormFieldsErrMsg": "Si è verificato un errore durante il recupero dell'elenco dei campi per questo modulo.", + "fetchFormFieldsConsErrMsg": "Errore durante l'acquisizione del modulo {formId}: {error}", + "publishDraftErrMsg": "Si è verificato un errore durante la pubblicazione.", + "publishDraftConsErrMsg": "Errore durante la pubblicazione di {draftId}: {error}", + "toggleVersnPublConsErrMsg": "Errore in toggleVersionPublish {versionId} {publish}: {error}", + "updateEmailTemplateConsErrMsg": "Errore durante l'aggiornamento dei modelli di email per il modulo {formId}: {error}", + "updateEmailTemplateErrMsg": "Si è verificato un errore durante l'aggiornamento dei modelli di posta elettronica per questo modulo.", + "updateFormErrMsg": "Si è verificato un errore durante l'aggiornamento delle impostazioni per questo modulo.", + "updateFormConsErrMsg": "Errore durante l'aggiornamento del modulo {id}: {error}", + "deleteSubmissionNotifyMsg": "Invio eliminato con successo.", + "deleteSubmissionErrMsg": "Si è verificato un errore durante l'eliminazione di questo invio.", + "deleteSubmissionConsErrMsg": "Errore durante l'eliminazione dell'invio {submissionId}: {error}", + "deleteSubmissionsNotifyMsg": "Invii eliminati con successo.", + "deleteSubmissionsErrMsg": "Si è verificato un errore durante l'eliminazione degli invii selezionati.", + "deleteSubmissionsConsErrMsg": "Errore durante l'eliminazione degli invii: {error}", + "restoreSubmissionsNotiMsg": "Invii ripristinati correttamente.", + "restoreSubmissionsErrMsg": "Si è verificato un errore durante il ripristino di questo invio.", + "restoreSubmissionsConsErrMsg": "Errore durante il ripristino degli invii: {error}", + "restoreSubmissionNotiMsg": "Invio ripristinato correttamente.", + "restoreSubmissionErrMsg": "Si è verificato un errore durante il ripristino di questo invio.", + "restoreSubmissionConsErrMsg": "Errore durante il ripristino dell'invio {submissionId}: {error}", + "fecthSubmissnUsersErrMsg": "Si è verificato un errore durante il recupero dell'e-mail del destinatario per questo invio.", + "fecthSubmissnUsersConsErrMsg": "Errore durante il recupero dell'email del destinatario per l'invio {formSubmissionId}: {error}", + "fetchSubmissnErrMsg": "Si è verificato un errore durante il recupero di questo invio.", + "fetchSubmissnConsErrMsg": "Errore durante l'ottenimento dell'invio {submissionId}: {error}", + "fetchFormCSVExptFieldsErrMsg": "Si è verificato un errore durante il recupero dell'elenco dei campi per questo modulo.", + "fetchFormCSVExptFieldsConsErrMsg": "Errore durante l'acquisizione del modulo {formId}: {error}", + "fetchSubmissnsErrMsg": "Si è verificato un errore durante il recupero degli invii per questo modulo.", + "fetchSubmissnsConsErrMsg": "Errore durante la ricezione di invii per {formId}: {error}", + "fetchVersionErrMsg": "Si è verificato un errore durante il recupero di questo modulo.", + "fetchVersionConsErrMsg": "Errore durante il recupero della versione {versionId} per il modulo {formId}: {error}", + "deleteApiKeyNotifyMsg": "La chiave API per questo modulo è stata eliminata.", + "deleteApiKeyErrMsg": "Si è verificato un errore durante il tentativo di eliminare la chiave API.", + "deleteApiKeyConsErrMsg": "Errore durante l'eliminazione della chiave API per il modulo {formId}: {error}", + "generateApiKeyNotifyMsg": "È stata creata una chiave API per questo modulo.", + "generateApiKeyErrMsg": "Si è verificato un errore durante il tentativo di generare una chiave API.", + "generateApiKeyConsErrMsg": "Errore durante la generazione della chiave API per il modulo {formId}: {error}", + "readApiKeyErrMsg": "Si è verificato un errore durante il tentativo di recuperare la chiave API.", + "readApiKeyConsErrMsg": "Errore durante l'ottenimento della chiave API per il modulo {formId}: {error}.", + "getFCPHImageUrlErrMsg": "Si è verificato un errore durante il recupero dell'URL dell'immagine", + "getFCPHImageUrlConsErrMsg": "Errore durante l'acquisizione dell'URL dell'immagine: {error}", + "listFCPHErrMsg": "Si è verificato un errore durante il recupero dei componenti del generatore di moduli", + "listFCPHConsErrMsg": "Errore durante il recupero dei componenti del generatore di moduli: {errors}", + "downloadFileErrMsg": "Si è verificato un errore durante il download del file", + "downloadFileConsErrMsg": "Errore durante il download del file: errore", + "readSubscriptionSettingsErrMsg": "Si è verificato un errore durante il tentativo di recuperare le impostazioni dell'abbonamento.", + "readSubscriptionSettingsConsErrMsg": "Errore durante il recupero delle impostazioni di sottoscrizione per il modulo {formId}: {errore}.", + "saveSubscriptionSettingsNotifyMsg": "Le impostazioni di iscrizione per questo modulo sono state salvate.", + "saveSubscriptionSettingsErrMsg": "Si è verificato un errore durante il tentativo di salvare le impostazioni dell'abbonamento.", + "saveSubscriptionSettingsConsErrMsg": "Errore durante il salvataggio delle impostazioni di sottoscrizione per il modulo {formId}: {error}" + } + }, + "admin": { + "root": { + "admin": "Amministratore" + }, + "form": { + "administerForm": "Modulo Amministrare" + }, + "user": { + "administerUser": "Amministra utente" + } + }, + "user": { + "root": { + "myForms": "LE MIE FORME", + "history": "STORIA", + "user": "Utente" + } + } +} diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/ja/index.js b/frontend/app/frontend/src/internationalization/trans/chefs/ja/index.js new file mode 100644 index 0000000..acc5b0c --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/ja/index.js @@ -0,0 +1,4 @@ +import ja from '~/internationalization/trans/chefs/ja/ja.json'; +export default { + trans: ja, +}; diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/ja/ja.json b/frontend/app/frontend/src/internationalization/trans/chefs/ja/ja.json new file mode 100644 index 0000000..ce993c4 --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/ja/ja.json @@ -0,0 +1,995 @@ +{ + "date": { + "date": "yyyy-mm-dd" + }, + "emailManagement": { + "emailManagement": "電子メール管理", + "manageForm": "フォームの管理", + "submissionConfirmation": "提出の確認" + }, + "emailTemplate": { + "body": "体", + "save": "保存", + "saveEmailTemplateConsoleErrMsg": "フォーム {formId} の電子メール テンプレートの更新中にエラーが発生しました: {error}", + "saveEmailTemplateErrMsg": "電子メール テンプレートを更新しようとしたときにエラーが発生しました。", + "subject": "主題", + "title": "タイトル", + "validBodyRequired": "メールの本文を入力してください", + "validSubjectRequired": "メールの件名を入力してください", + "validTitleRequired": "メールのタイトルを入力してください" + }, + "formsTable": { + "myForms": "私のフォーム", + "createNewForm": "新しいフォームを作成する", + "search": "検索", + "manage": "管理", + "submissions": "提出物", + "formTitle": "フォームのタイトル", + "viewForm": "フォームを見る", + "description": "説明", + "Description": "説明:", + "action": "行動", + "loadingText": "読み込み中。。。待って下さい" + }, + "manageLayout": { + "manageForm": "フォームの管理" + }, + "preview": { + "preview": "プレビュー", + "previewToolTip": "これは、送信者に表示されるフォーム バージョンのデザインと動作のプレビューを示します。このページからフォームを送信することはできません。" + }, + "shareForm": { + "shareForm": "共有フォーム", + "shareLink": "共有リンク", + "copyQRCode": "下のリンクをコピーするか、QR コードをダウンロードしてください。", + "warningMessage": "現時点では、フォームの公開バージョンはありません。バージョンが公開されるまで、以下のリンクにアクセスできません。", + "openThisForm": "このフォームを開く", + "downloadQRCode": "QRコードをダウンロード", + "close": "近い", + "copyURLToClipboard": "URLをクリップボードにコピー" + }, + "manageFormActions": { + "emailManagement": "電子メール管理", + "viewSubmissions": "提出物を見る", + "teamManagement": "チーム管理", + "deleteForm": "フォームの削除", + "confirmDeletion": "削除の確認", + "deleteMessageA": "削除してもよろしいですか", + "deleteMessageB": "このフォームにはアクセスできなくなります。", + "delete": "消去" + }, + "manageForm": { + "formSettings": "フォーム設定", + "apiKey": "APIキー", + "updated": "更新しました", + "created": "作成した", + "formDesignHistory": "フォーム設計の歴史", + "totalVersions": "合計バージョン数", + "status": "スターテス", + "update": "アップデート", + "cancel": "キャンセル", + "eventSubscription": "イベントのサブスクリプション" + }, + "formSettings": { + "pressToAddMultiEmail": "Enterまたはまたはスペースを押して複数の電子メール アドレスを追加します", + "allowMultiDraft": "複数の下書きのアップロードを許可する", + "formTitle": "フォームのタイトル", + "formDescription": "フォームの説明", + "formAccess": "フォームアクセス", + "info": "このフォームを使用して、一般の関心のあるトピックについて一般の人々から情報を収集する場合は、GCPE に連絡して、あなたの取り組みを掲載できるようにする必要があります。", + "important": "重要", + "idimNotifyA": "IDIM (IDIM) チームに電子メールで通知する必要があります。", + "idimNotifyB": "BCeID を利用してフォーム送信者の身元を確認するという意図。", + "referenceGuideA": "ご参照ください。", + "referenceGuideB": "ユーザーガイド", + "referenceGuideC": "詳細については", + "specificTeamMembers": "特定のチームメンバー", + "formFunctionality": "フォーム機能", + "formSubmissinScheduleMsg": "フォーム送信スケジュールは、フォームが公開された後、フォーム設定で利用できるようになります。", + "formSubmissionsSchedule": "フォーム送信スケジュール", + "experimental": "実験的", + "learnMore": "もっと詳しく知る", + "afterSubmission": "提出後", + "submissionConfirmation": "送信確認の詳細を表示する", + "theConfirmationID": "確認ID", + "infoB": "ユーザーが自分自身に送信確認を電子メールで送信するオプション", + "loginRequired": "ログインが必要です", + "canSaveAndEditDraftLabel": "提出者は下書きを保存および編集できます", + "canUpdateStatusAsReviewer": "レビュー担当者はこのフォームのステータス (つまり、送信済み、割り当て済み、完了) を更新できます。", + "submitterCanCopyExistingSubmissn": "提出者は既存の提出物をコピーできます", + "submissionConfirmationToolTip": "このオプションを選択すると、このフォームを送信したユーザーが送信に成功したときに表示される内容が制御されます。
チェックを入れると表示されます", + "emailNotificatnToTeam": "チームに通知メールを送信する", + "emailNotificatnToTeamToolTip": "ユーザーがこのフォームを送信したときに、指定した電子メール アドレスに通知を送信します", + "notificationEmailAddrs": "通知メールアドレス", + "addMoreValidEmailAddrs": "1 つ以上の有効な電子メール アドレスを追加します", + "formScheduleSettings": "フォームのスケジュール設定", + "opensubmissions": "オープンな提出物", + "submissionsDeadline": "提出物をどれくらいの期間受け取りたいですか?", + "keepSubmissnOpenTilUnplished": "手動で非公開にするまで開いたままにする", + "submissionsClosingDate": "締め日をスケジュールする", + "submissionPeriod": "提出期間を設定する", + "closeSubmissions": "提出を閉じる", + "keepOpenFor": "オープンにしておいてください", + "period": "期間", + "allowLateSubmissions": "遅れての提出を許可する", + "allowLateSubmissionsInfoTip": "チェックすると、提出者は締切日以降にデータを提出できるようになります。", + "afterCloseDateFor": "締切日以降", + "repeatPeriod": "繰り返し期間", + "every": "毎日", + "repeatUntil": "まで繰り返します", + "summary": "まとめ", + "submissionsOpenDateRange": "このフォームは以下からの送信を受け付けます。", + "to": "に", + "scheduleRepetition": "スケジュールは毎回繰り返されます", + "allowLateSubmissnInterval": "遅れての提出を許可する", + "until": "それまで", + "datesOfSubmissnInfo": "設定に従って、提出可能な日付は次のとおりです。", + "formOpenInterval": "このフォームは以下からの送信を受け付けます。", + "allowDateSubmissionDate": "まで提出が遅れても構いません", + "customClosingMessage": "カスタム終了メッセージを設定する", + "customClosingMessageToolTip": "ユーザーが閉じたフォームにアクセスしたときに、カスタマイズされたメッセージを追加できるようにします。", + "closingMessage": "終わりのメッセージ", + "sendReminderEmail": "リマインダーメールを送信する", + "autoReminderNotificatn": "自動リマインダー通知を有効にする", + "autoReminderNotificatnToolTip": "提出期間中にフォームのリンクを含むリマインダーメールを送信します。", + "selectLoginType": "ログインタイプを1つ選択してください", + "formDescriptnMaxChars": "フォームの説明は 255 文字以下にする必要があります", + "formTitlemaxChars": "フォームのタイトルは 255 文字以下である必要があります", + "formTitleReq": "フォームのタイトルは必須です", + "atLeastOneEmailReq": "少なくとも 1 つの電子メール アドレスを入力してください", + "validEmailRequired": "有効な電子メール アドレスをすべて入力してください", + "fieldRequired": "この項目は必須です。", + "correctDateFormat": "日付は正しい形式である必要があります。つまり。 yyyy-mm-dd", + "dateDiffMsg": "閉じる提出日は、オープン提出日よりも後の日付である必要があります。", + "valueMustBeNumber": "値は数値である必要があります。つまり。 1、2、3、5、99", + "selectAnOptions": "少なくとも 1 つのオプションを選択してください", + "validInterval": "これは有効な間隔である必要があります。", + "fieldRequiredAndInterval": "このフィールドは必須であり、間隔である必要があります。", + "dateGrtOpenSubmissnDate": "繰り返しの日付は提出開始日よりも後の日付にする必要があります", + "public": "公開(匿名)", + "allowEventSubscription": "イベントのサブスクリプションを許可する", + "eventSubscription": "イベントのサブスクリプション", + "validEndpointRequired": "で始まる有効なエンドポイントを入力してください https://", + "validBearerTokenRequired": "有効なベアラー トークンの例を入力してください: 89abddfb-2cff-4fda-83e6-13221f0c3d4f" + }, + "subscribeEvent": { + "eventType": "イベントタイプ", + "endpointUrl": "エンドポイント URL", + "eventSubmission": "提出", + "eventAssignment": "課題", + "eventStatusChange": "ステータス変更", + "endpointToken": "エンドポイントトークン", + "urlPlaceholder": "https://endpoint.gov.bc.ca/api/v1/", + "save": "保存", + "text": "文章", + "password": "パスワード", + "hideSecret": "秘密を隠す", + "showSecret": "シークレットを表示", + "key": "鍵", + "saveSettingsErrMsg": "このフォームの設定を更新しようとしたときにエラーが発生しました。", + "updateSettingsConsoleErrMsg": "フォーム {formId} の設定更新中にエラーが発生しました: {error}" + }, + "apiKey": { + "disclaimer": "免責事項", + "infoA": "API キー シークレットが安全な場所 (キー コンテナーなど) に保存されていることを確認してください。", + "infoB": "API キーにより、フォームへの無制限のアクセスが許可されます。 API キーを誰にも渡さないでください。", + "infoC": "API キーは、自動化されたシステム操作にのみ使用してください。ユーザーベースのアクセスには API キーを使用しないでください", + "deleteKey": "キーの削除", + "apiKey": "APIキー", + "hideSecret": "秘密を隠す", + "showSecret": "シークレットを表示", + "sCTC": "シークレットがクリップボードにコピーされました", + "cSTC": "シークレットをクリップボードにコピー", + "key": "鍵", + "confirmDeletion": "削除の確認", + "deleteMsg": "API キーを削除してもよろしいですか?", + "delete": "消去", + "confirmKeyGen": "キー生成の確認", + "createAPIKey": "このフォームの API キーを作成しますか?
このページの免責事項に従ってください。", + "regenerateAPIKey": "APIキーを再生成しますか?
続行すると、現在の API キー アクセスが削除されます。", + "formOwnerKeyAcess": "API キーを管理するには、フォーム所有者である必要があります。", + "regenerate": "再生する", + "generate": "生成", + "secret": "ひみつ" + }, + "manageVersions": { + "important": "重要!", + "infoA": "公開バージョンがない場合、ユーザーは公開バージョンが割り当てられるまでこのフォームにアクセスできません。バージョンが公開されると、そのバージョンは編集できなくなります。編集を続けるには、以前のフォーム バージョンのいずれかに基づいて新しいバージョンを作成する必要があります。", + "infoB": "注: 公開できるバージョンは 1 つだけです。", + "version": "バージョン", + "draft": "下書き", + "clickToPreview": "クリックしてプレビューします", + "editVersion": "バージョンの編集", + "exportDesign": "デザインのエクスポート", + "infoC": "新しいバージョンを開始する前に、最新のドラフト バージョンを公開または削除してください。", + "deleteVersion": "バージョンの削除", + "draftAlreadyExists": "ドラフトはすでに存在します", + "infoD": "新しい下書きを開始する前に、既存の下書きを編集、公開、または削除してください。", + "publishVersion": "バージョンの公開", + "unpublishVersion": "非公開バージョン", + "infoE": "このフォームを非公開にすると、バージョンが再度公開されるまでフォームは配布されなくなります。", + "confirmDeletion": "削除の確認", + "infoF": "このバージョンを削除してもよろしいですか?", + "delete": "消去", + "status": "スターテス", + "dateCreated": "作成日", + "createdBy": "によって作成された", + "actions": "行動", + "published": "発行済み", + "unpublished": "未公開", + "useVersionInfo": "バージョン {version} を新しいバージョンのベースとして使用します", + "publishingVersionInfo": "これにより、フォームのバージョン {version} が有効になります。" + }, + "addOwner": { + "infoA": "これは、現在のフォーム所有者がアクティブでなくなった場合、または優先イベントで連絡が取れなくなった場合にのみ実行してください。それ以外の場合は、フォームの現在の所有者またはチーム管理者に自分でこれを行ってもらいます。", + "hint": "必要なユーザー ID を見つけるには、管理者ポータルの「ユーザー」タブに移動して検索します。", + "addowner": "所有者の追加", + "label": "ユーザーID(ガイド)" + }, + "adminFormsTable": { + "showDeletedForms": "削除されたフォームを表示する", + "search": "検索", + "loadingText": "ローディングテキスト", + "noDataText": "システムにフォームがありません", + "admin": "管理者", + "launch": "発売", + "formTitle": "フォームのタイトル", + "created": "作成した", + "deleted": "削除されました", + "actions": "行動", + "delete": "消去" + }, + "administerForm": { + "deleted": "削除されました", + "restoreForm": "このフォームを復元する", + "formDetails": "フォームの詳細", + "apiKeyDetails": "APIキーの詳細", + "deleteApiKey": "APIキーの削除", + "formUsers": "フォームユーザー", + "formVersions": "フォームのバージョン", + "assignANewOwner": "新しい所有者の割り当て", + "restoring": "復元中", + "restore": "戻す", + "toActiveState": "アクティブ状態へ", + "confirmDeletion": "削除の確認", + "confirmDeletionMsg": "この API キーを削除してもよろしいですか?", + "delete": "消去", + "confirmRestore": "復元の確認" + }, + "administerUser": { + "userDetails": "ユーザーの詳細", + "openSSOConsole": "SSO コンソールを開く" + }, + "adminPage": { + "forms": "フォーム", + "users": "ユーザー", + "developer": "デベロッパー", + "infoLinks": "情報リンク", + "metrics": "メトリクス" + }, + "adminUsersTable": { + "search": "検索", + "loadingText": "読み込み中。。。待って下さい", + "admin": "管理者", + "fullName": "フルネーム", + "userID": "ユーザーID", + "created": "作成した", + "actions": "行動" + }, + "adminVersions": { + "exportDesign": "デザインのエクスポート", + "versions": "バージョン", + "status": "スターテス", + "created": "作成した", + "lastUpdated": "最終更新", + "actions": "行動", + "published": "発行済み", + "unpublished": "未公開", + "version": "バージョン {versionNo}", + "notificationMsg": "フォームデザインの読み込み中にエラーが発生しました。" + }, + "developer": { + "user": "ユーザー", + "name": "名前", + "userName": "ユーザー名", + "JWTContents": "JWTの内容", + "JWTContentsSBTxt": "JWT コンテンツがクリップボードにコピーされました", + "JWTContentsTTTxt": "JWT コンテンツをクリップボードにコピー", + "JWTToken": "JWTトークン", + "JWTTokenSBTxt": "JWT トークンがクリップボードにコピーされました", + "JWTTokenTTTxt": "JWT トークンをクリップボードにコピー", + "chefsAPI": "シェフAPI", + "RBACSBTxt": "RBAC 応答がクリップボードにコピーされました", + "RBACTTTxt": "RBAC 応答をクリップボードにコピー", + "notificationMsg": "RBAC からユーザーを取得できませんでした。コンソールを参照してください", + "notificationConsErr": "RBAC からユーザーを取得中にエラーが発生しました" + }, + "baseAuthButton": { + "logout": "ログアウト", + "login": "ログイン" + }, + "baseDialog": { + "defaultText": "デフォルトのテキスト", + "ok": "OK", + "continue": "続く", + "cancel": "キャンセル", + "custom": "カスタム" + }, + "baseSecure": { + "about": "だいたい", + "loginInfo": "この機能を使用するにはログインする必要があります。", + "login": "ログイン", + "401NotAuthorized": "401: 権限がありません。 :", + "401ErrorMsg": "アカウントが正しく設定されていません。
お問い合わせください", + "403Forbidden": "403禁止します。 :", + "403ErrorMsg": "このページには {idp} 認証が必要です。", + "401UnAuthorized": "401: 不正です。 :", + "401UnAuthorizedErrMsg": "このページにアクセスする権限がありません。" + }, + "formDesigner": { + "formDesign": "フォームデザイン", + "exportDesign": "デザインのエクスポート", + "importDesign": "デザインのインポート", + "important": "重要", + "formDesignInfoA": "このフォームの作成が完了したら、 [デザインを保存]ボタンを使用します。", + "formDesignInfoB": "[送信]ボタンは、ユーザーがこのフォームを送信するために提供されており、保存後にアクティブになります。", + "formLoadErrMsg": "フォームデザインの読み込み中にエラーが発生しました。", + "formLoadConsoleErrMsg": "フォーム {formId} スキーマの読み込みエラー (バージョン: {versionId} ドラフト: {draftId}): {error}", + "formSchemaImportErrMsg": "フォーム スキーマのインポート中にエラーが発生しました。", + "formSchemaImportConsoleErrMsg": "フォーム スキーマのインポート中にエラーが発生しました: {error}", + "formDesignSaveErrMsg": "このフォームデザインを保存しようとしたときにエラーが発生しました。更新するか、後で再試行するために終了する必要がある場合は、ページ上の既存のデザインをエクスポートして、後で使用できるように保存できます。", + "formDesignSaveConsoleErrMsg": "フォームの更新または作成中にエラーが発生しました (FormID: {formId}、versionId: {versionId}、draftId: {draftId}) エラー: {error}", + "collapse": "崩壊", + "actions": "行動", + "version": "バージョン", + "save": "保存", + "saving": "保存", + "notSaved": "保存されていません", + "fieldnameError": "`form` キーワードを {label} フィールド名として使用することはできません" + }, + "formViewerMultiUpload": { + "important": "重要", + "uploadSucessMsg": "複数の下書きを確実にアップロードするには、提供されているテンプレートをダウンロードしてご利用ください。", + "confirmDownload": "ダウンロードしますか?", + "jsonFileUpload": "アップロードするJSONファイルを選択してください", + "dragNDrop": "またはここにドラッグアンドドロップします", + "chooseAFile": "ファイルを選択してください", + "downloadDraftSubmns": "ドラフト提出レポートをダウンロードし、データが正しく入力されていることを確認してください。", + "downloadReport": "レポートのダウンロード", + "doYouWantToDownload": "ダウンロードしますか?", + "uploadNewFile": "新しいファイルをアップロードする", + "uploadMultipleFileErr": "申し訳ありませんが、アップロードできるファイルは 1 つだけです", + "dragMultipleFileErr": "申し訳ありませんが、ドラッグできるファイルは 1 つだけです", + "fileFormatErr": "申し訳ありませんが、JSON ファイルのみ受け付けます", + "fileSizeErr": "許可される最大ファイルサイズは5MBです", + "parseJsonErr": "ファイルからの JSON データを解析できません", + "jsonObjNotArray": "間違ったjsonファイル形式", + "jsonObjNotArrayConsErr": "予期しないエラーが発生しました。", + "jsonArrayEmpty": "この json ファイルは空です。", + "errorWhileValidate": "このファイルには問題があります", + "errWhileCheckValidity": "このファイルには問題があります", + "errAfterValidate": "いくつかのエラーが見つかりました。詳細については、以下を参照してください。", + "fileIsEmpty": "このファイルは空です。", + "download": "ダウンロード" + }, + "formDisclaimer": { + "disclaimerAndStatement": "フォームデザイナーに対する免責事項と責任声明:", + "privacyLaw": "個人を特定できる情報の収集、使用、開示を規定するプライバシー法を遵守するのはあなたの責任です。", + "disclosure": "このフォーム デザイナー ツールへのアクセスは、本質的に個人を特定できる情報を収集、使用、または開示する許可を与えるものではありません。", + "consent": "法律で義務付けられているように情報を収集することに同意を得るのはあなたの責任です。", + "formIntention": "フォームを公開または配布する前に、フォームの意図について担当者と話し合う必要があります。", + "privacyOfficer": "省のプライバシー担当官", + "assement": "必要に応じて評価を完了します。" + }, + "requestReceipt": { + "emailPriority": "電子メールの優先順位", + "emailReceipt": "この提出物の受領書を電子メールで送信する", + "high": "高い", + "low": "低い", + "normal": "普通", + "send": "送信", + "sendToEmailAddress": "電子メールアドレスに送信", + "emailSent": "電子メールが {to} に送信されました。", + "sendingEmailErrMsg": "電子メールを送信しようとしたときにエラーが発生しました。", + "sendingEmailConsErrMsg": "{to} へのメール確認に失敗しました: {error}", + "emailRequired": "電子メールは必須です" + }, + "submissionsTable": { + "noMatchingRecordText": "該当する記録が見つかりません", + "submissions": "提出物", + "submissionsTable": "提出物テーブル", + "selectColumns": "列の選択", + "manageForm": "フォームの管理", + "submissionsToFiles": "提出物をファイルにエクスポート", + "showDeletedSubmissions": "削除された提出物を表示する", + "showMySubmissions": "私の提出物を表示する", + "search": "検索", + "loadingText": "読み込み中。。。待って下さい", + "noDataText": "このフォームには送信がありません", + "delSelectedSubmissions": "選択した提出物を削除します", + "resSelectedSubmissions": "選択した提出物を復元する", + "yes": "はい", + "no": "いいえ", + "viewSubmission": "提出物を見る", + "deleteSubmission": "提出物の削除", + "restore": "戻す", + "confirmDeletion": "削除の確認", + "delete": "消去", + "confirmRestoration": "復元の確認", + "searchSubmissionFields": "提出フィールドの検索", + "save": "保存", + "searchTitle": "ダッシュボードの下に表示する列を検索して選択します", + "status": "スターテス", + "submitter": "提出者", + "submissionDate": "提出日", + "event": "イベント", + "view": "意見", + "lateSubmission": "提出が遅れた場合", + "confirmationID": "確認ID", + "multiDelWarning": "選択した提出物を削除してもよろしいですか?", + "singleDelWarning": "この提出物を削除してもよろしいですか?", + "multiRestoreWarning": "これらの提出物を復元してもよろしいですか?", + "singleRestoreWarning": "この提出物を復元してもよろしいですか?" + }, + "auditHistory": { + "viewEditHistory": "編集履歴の表示", + "editHistory": "編集履歴", + "auditLogMsg": "これは、最初の提出後に誰がこの提出に変更を加えたかの監査ログです。", + "loadingText": "読み込み中。。。待って下さい", + "close": "近い", + "userName": "ユーザー名", + "date": "日にち", + "errorMsg": "履歴を取得しようとしたときにエラーが発生しました。", + "consoleErrMsg": "監査履歴の取得中にエラーが発生しました" + }, + "deleteSubmission": { + "deleteThis": "これを削除", + "draft": "下書き", + "submission": "提出", + "confirmDeletion": "削除の確認", + "deleteWarning": "これを削除してもよろしいですか", + "drafts": "下書き", + "formSubmission": "フォームの送信", + "delete": "消去" + }, + "manageSubmissionUsers": { + "manageTeamMembers": "チームメンバーの管理", + "add": "追加", + "draftFormInvite": "このフォームがドラフトである間は、チーム メンバーのみを招待および管理できます。", + "submissionTeamMembers": "この提出のチームメンバー", + "actions": "行動", + "close": "近い", + "remove": "削除", + "userNotFoundErrMsg": "誰かが見つかりませんか?彼らは CHEFS にログインしていない可能性があります。
CHEFS へのリンクを送信し、ログインするようお願いしてください。", + "name": "名前", + "username": "ユーザー名", + "email": "Eメール", + "removeUserWarningMsg1": "削除してもよろしいですか", + "removeUserWarningMsg2": "彼らはこの送信に対する権限を失います。", + "userExistInListMsg": "ユーザー {username} はすでにチームメンバーのリストに含まれています。", + "getSubmissionUsersErr": "この送信のためにユーザーを取得しようとしたときにエラーが発生しました。", + "getSubmissionUsersConsoleErr": "{submissionId} のユーザー取得エラー: {error}", + "sentInviteEmailTo": "に招待メールを送信しました", + "sentUninvitedEmailTo": "招待されていないメールを次の宛先に送信しました", + "updateUserErrMsg": "この送信のユーザーを更新しようとしたときにエラーが発生しました。", + "updateUserConsoleErrMsg": "ユーザー権限の設定中にエラーが発生しました。サブ: {submissionId} ユーザー: {userId} エラー: {error}", + "searchInputLength": "BCeID ユーザー名/電子メールの検索入力は 6 文字以上である必要があります。", + "exactBCEIDSearch": "BCeID の電子メール検索は正確である必要があります。", + "getUsersErrMsg": "ユーザー取得エラー: {error}", + "exactEmailOrUsername": "正確な電子メールまたはユーザー名を入力します。", + "requiredFiled": "名前、電子メール、またはユーザー名を入力してください" + }, + "mySubmissionsActions": { + "viewThisSubmission": "この提出物を見る", + "copyThisSubmission": "この提出物をコピーする", + "editThisDraft": "この下書きを編集する" + }, + "mySubmissionsTable": { + "noMatchingRecordText": "該当する記録が見つかりません", + "previousSubmissions": "以前の投稿", + "selectColumns": "列の選択", + "createNewSubmission": "新しい提出物を作成する", + "search": "検索", + "loadingText": "読み込み中。。。待って下さい", + "noDataText": "提出物はありません", + "searchSubmissionFields": "提出フィールドの検索", + "save": "保存", + "filterTitle": "ダッシュボードの下に表示する列を検索して選択します", + "confirmationId": "確認ID", + "actions": "行動", + "createdBy": "によって作成された", + "statusUpdatedBy": "ステータスの更新者", + "status": "スターテス", + "submissionDate": "提出日", + "draftUpdatedBy": "ドラフトの更新者", + "draftLastEdited": "ドラフトの最終編集日", + "createLateSubmissn": "遅延提出を作成する", + "formLoading": "フォームを読み込んでいる間お待ちください!!!", + "pleaseConfirm": "ご確認ください", + "wantToSaveDraft": "下書きを保存しますか?", + "yes": "はい", + "no": "いいえ", + "multiDraftUploadSuccess": "複数の下書きのアップロードが成功しました。", + "failedResSubmissn": "送信エンドポイントからの応答が失敗しました。レスポンスコード: {status}", + "errSubmittingForm": "このフォームの送信中にエラーが発生しました", + "errorSavingFile": "ファイルの保存中にエラーが発生しました。ファイル名: {fileName}。エラー: {error}", + "submittingDraftErrMsg": "下書きの保存中にエラーが発生しました", + "submittingDraftConsErrMsg": "下書きの保存中にエラーが発生しました。送信 ID: {submissionId}。エラー: {error}" + }, + "notesPanel": { + "addNewNote": "新しいメモを追加", + "cancel": "キャンセル", + "addNote": "メモを追加", + "noResponseErr": "フォームの送信中に API からの応答データがありません", + "errorMesg": "メモを追加しようとしたときにエラーが発生しました。", + "consoleErrMsg": "注記の追加中にエラーが発生しました:", + "fetchErrMsg": "この送信のメモを取得しようとしたときにエラーが発生しました。", + "fetchConsoleErrMsg": "注記の追加中にエラーが発生しました:", + "notes": "ノート", + "note": "ノート", + "maxChars": "最大4000文字" + }, + "statusPanel": { + "currentStatus": "現在のステータス:", + "assignedTo": "に割り当てられた:", + "assignOrUpdateStatus": "ステータスの割り当てまたは更新", + "display": "画面", + "statusIsRequired": "ステータスは必須です", + "assignTo": "に割り当てます", + "noDataText": "検索してもフォームレビュー担当者が見つかりませんでした。 「管理」ページでフォームレビュー担当者を追加します。", + "assigneeIsRequired": "譲受人は必須です", + "assignToMe": "私に割り当ててください", + "recipientEmail": "受信者のEメール", + "attachCommentToEmail": "メールにコメントを添付", + "emailComment": "メールでのコメント", + "maxChars": "最大4000文字", + "viewHistory": "履歴を見る", + "statusHistory": "ステータス履歴", + "close": "近い", + "addNoteNoReponserErr": "ステータス更新のメモを送信中に API からの応答データがありません", + "addNoteConsoleErrMsg": "ステータスの更新中にエラーが発生しました: {error}", + "addNoteErrMsg": "ステータスを更新しようとしたときにエラーが発生しました", + "updtSubmissionsStatusErr": "ステータス更新フォームの送信中に API からの応答データがありません", + "noStatus": "ステタスはありません", + "noStatusesFound": "ステータスが見つかりません", + "statusCodesErr": "ステータスコードの検索エラー", + "notifyErrorCode": "この送信のステータスを取得中にエラーが発生しました。", + "notifyConsoleErrorCode": "ステータス取得エラー:", + "fetchSubmissionUsersErr": "この送信の受信者の電子メールを取得しようとしたときにエラーが発生しました。", + "fetchSubmissionUsersConsErr": "受信者の電子メールを取得中にエラーが発生しました", + "assignSubmissnToFormReviewer": "提出物はフォームレビュー担当者に割り当てることができます。
さらにチームメンバーをフォームレビュー担当者として追加するには、このフォームの「管理」ページに移動します。", + "update": "アップデート", + "revise": "改訂", + "complete": "完了", + "assign": "割当" + }, + "statusTable": { + "loadingText": "読み込み中。。。待って下さい", + "status": "スターテス", + "dateStatusChanged": "ステータスが変更された日", + "assignee": "譲受人", + "updatedBy": "更新者", + "getSubmissionStatusErr": "ステータスを取得しようとしたときにエラーが発生しました。", + "getSubmissionStatusConsErr": "注記の追加中にエラーが発生しました:" + }, + "exportSubmissions": { + "exportSubmissionsToFile": "提出物をファイルにエクスポート", + "viewSubmissions": "提出物を見る", + "fileType": "ファイルの種類", + "json": "JSON", + "csv": "CSV", + "formVersion": "フォームのバージョン", + "versionIsRequired": "バージョンは必須です。", + "dataFields": "データフィールド", + "searchFields": "検索フィールド", + "selectedForExports": "輸出用に選ばれた", + "submissionDate": "提出日", + "all": "全て", + "selectDateRange": "日付範囲を選択してください", + "SelectdateRange": "日付範囲を選択してください", + "from": "から", + "to": "に", + "CSVFormat": "CSV形式", + "multiRowPerSubmissionA": "1 - インデントスペースを含む送信ごとに複数の行", + "multiRowPerSubmissionB": "2 - 送信ごとに複数の行", + "singleRowPerSubmission": "3 - 送信ごとに 1 行", + "unformatted": "4 - 未フォーマット", + "fileNameAndType": "ファイル名と種類", + "export": "輸出", + "noResponseDataErr": "exportSubmissions 呼び出しからの応答にデータがありません", + "apiCallErrorMsg": "このフォームの送信内容をエクスポートしようとしたときにエラーが発生しました。", + "apiCallConsErrorMsg": "エクスポート送信エラー", + "selectAllFields": "すべてのフィールドを選択します", + "emailSentMsg": "準備ができたら、データをダウンロードするためのリンクを含むメールが {email} に送信されます", + "exportInProgress": "エクスポート中です", + "of": "の" + }, + "printOptions": { + "submitButtonTxt": "CDOGS に送信してダウンロードする", + "templatePrint": "テンプレート印刷", + "uploadTemplateFile": "テンプレートファイルをアップロードする", + "downloadOptions": "ダウンロードオプション", + "print": "印刷する", + "browserPrint": "ブラウザ印刷", + "pageFromBrowser": "ブラウザからのページ", + "uploadA": "アップロードする", + "uploadB": "構造化されたバージョンを作成する", + "docGrnSucess": "ドキュメントが正常に生成されました", + "failedDocGenErrMsg": "ドキュメントの生成に失敗しました", + "failedDocGenConsErrMsg": "テンプレートの送信エラー: {error}", + "cDogsTemplate": "CDOGS テンプレート" + }, + "proactiveHelpDialog": { + "componentInfoLink": "コンポーネント情報リンク", + "learnMoreLinkTxt": "詳細はこちら リンクフィールドを空にすることはできません。", + "largeImgTxt": "大きな画像。画像サイズは 0.5mb を超えることはできません", + "componentName": "コンポーネント名:", + "learnMoreLink": "詳細リンク:", + "clickToEnableLink": "クリックしてリンクを有効にします", + "clickToDisableLink": "クリックしてリンクを無効にする", + "imageUpload": "画像のアップロード:", + "cancel": "キャンセル", + "save": "保存", + "description": "説明" + }, + "proactiveHelpPreviewDialog": { + "learnMore": "もっと詳しく知る" + }, + "preview": { + "preview": "プレビュー", + "previewToolTip": "これは、送信者に表示されるフォーム バージョンのデザインと動作のプレビューを示します。このページからフォームを送信することはできません。" + }, + "generalLayout": { + "loadingText": "読み込み中。。。待って下さい", + "preview": "プレビュー", + "published": "出版されました", + "unpublished": "未公開", + "edit": "編集", + "formTitle": "フォームのタイトル", + "actions": "行動" + }, + "formSubmission": { + "editThisSubmission": "この提出物を編集する", + "submission": "提出", + "alertInfo": "編集後、フォームを再送信して変更を保存します。", + "viewAllSubmissions": "すべての提出物を表示", + "submitted": "提出済み:", + "confirmationID": "確認ID:", + "submittedBy": "から提出された:", + "cancel": "キャンセル", + "status": "スターテス", + "updatedAt": "修正済み", + "updatedBy": "によって変更" + }, + "teamManagement": { + "noMatchingRecordText": "該当する記録が見つかりません", + "teamManagement": "チーム管理", + "selectColumns": "列の選択", + "manageForm": "フォームの管理", + "search": "検索", + "loadingText": "読み込み中。。。待って下さい", + "noDataText": "チーム役割データのロードに失敗しました", + "removeSelectedUsers": "選択したユーザーを削除する", + "removeThisUser": "このユーザーを削除する", + "confirmRemoval": "削除の確認", + "remove": "削除", + "searchTeamManagementFields": "チーム管理フィールドの検索", + "save": "保存", + "teamMebersTitle": "ダッシュボードの下に表示する列を検索して選択します", + "fullName": "フルネーム", + "username": "ユーザー名", + "identityProvider": "アイデンティティプロバイダー", + "delSelectedMembersWarning": "選択したメンバーを削除してもよろしいですか?", + "delSelectedMemberWarning": "選択したメンバーを削除してもよろしいですか?", + "idpMessage": "すでにチームにいます。", + "formOwnerErrMsg": "常に少なくとも 1 人のフォーム所有者が必要です", + "formOwnerConsoleErrMsg": "{userId} はこのフォームの残りの唯一の所有者であるため、削除できません。", + "insufficientPermissnMsg": "チームを管理するための十分な権限がありません", + "getUserErrMsg": "フォームユーザーの取得中にエラーが発生しました:", + "getRolesErrMsg": "役割のリストの取得中にエラーが発生しました:", + "formOwnerRemovalWarning": "このフォームの残りの所有者は彼らだけであるため、削除できません。", + "removeUsersErrMsg": "選択したユーザーを削除しようとしたときにエラーが発生しました", + "removeUserConsoleErrMsg": "フォーム {formId} からユーザーを削除中にエラーが発生しました: {error}", + "updUserRolesErrMsg": "すべてのユーザーの役割を更新しようとしたときにエラーが発生しました", + "updUserRolesConsoleErrMsg": "フォーム {formId} のすべてのユーザー ロールを設定中にエラーが発生しました: {error}", + "setUserFormsErrMsg": "ユーザーのロールを更新しようとしたときにエラーが発生しました", + "setUserFormsConsoleErrMsg": "フォーム {formId} のユーザー役割を設定中にエラーが発生しました: {error}" + }, + "floatButton": { + "publish": "公開", + "manage": "管理", + "redo": "やり直し", + "undo": "元に戻す", + "preview": "プレビュー", + "bottom": "下", + "top": "上", + "actions": "行動", + "collapse": "崩壊", + "saved": "保存されました", + "save": "保存", + "saving": "保存", + "notSaved": "保存されていません" + }, + "formViewer": { + "lateFormSubmissions": "フォーム送信期間は終了しました。下のボタンをクリックすると、遅れて提出することもできます。", + "createLateSubmission": "遅延提出を作成する", + "draftSaved": "下書きが保存されました", + "saving": "保存", + "pleaseConfirm": "ご確認ください", + "submitFormWarningMsg": "フォームを送信してもよろしいですか?", + "submit": "送信", + "wantToSaveDraft": "下書きを保存しますか?", + "version": "バージョン: {version}", + "formScheduleExpireMessage": "予定されていた提出期間が過ぎているため、フォームを提出することはできません。", + "getUsersSubmissionsErrMsg": "このフォームの送信を取得中にエラーが発生しました", + "getUsersSubmissionsConsoleErrMsg": "フォーム送信データ {submissionId} の読み込みエラー: {error}", + "multiDraftUploadSuccess": "複数の下書きのアップロードが成功しました。", + "readVersionErrMsg": "応答するスキーマがありません。バージョン ID: {versionId}", + "readDraftErrMsg": "スキーマが応答しません。ドラフトID: {draftId}", + "alertRouteMsg": "フォーム所有者がフォームを公開していないため、送信できません。", + "fecthingFormErrMsg": "このフォームを取得中にエラーが発生しました", + "fecthingFormConsoleErrMsg": "フォーム スキーマ {versionId} の読み込みエラー: {error}", + "savingDraftErrMsg": "下書きの保存中にエラーが発生しました", + "savingDraftConsoleErrMsg": "下書きの保存中にエラーが発生しました。送信 ID: {submissionId}。エラー: {error}", + "submissionsPreviewAlert": "フォームのプレビュー中は送信が無効になります", + "submissionsSubmitErrMsg": "フォーム送信エラー: {errors}", + "sendSubmissionErrMsg": "送信エンドポイントからの応答が失敗しました。レスポンスコード: {status}", + "errMsg": "このフォームの送信中にエラーが発生しました", + "customEventAlert": "カスタム ボタン イベントはまだサポートされていません。イベントタイプ: {event}", + "formLoading": "フォームを読み込んでいる間お待ちください!!!", + "yes": "はい", + "no": "いいえ", + "failedResSubmissn": "送信エンドポイントからの応答が失敗しました。レスポンスコード: {status}", + "errSubmittingForm": "このフォームの送信中にエラーが発生しました", + "errorSavingFile": "ファイルの保存中にエラーが発生しました。ファイル名: {fileName}。エラー: {error}", + "submittingDraftErrMsg": "下書きの保存中にエラーが発生しました", + "submittingDraftConsErrMsg": "下書きの保存中にエラーが発生しました。送信 ID: {submissionId}。エラー: {error}", + "formDraftAccessErrMsg": "リクエストされた送信はすでに送信されており、[表示] ページにリダイレクトされます。" + }, + "bCGovFooter": { + "home": "家", + "about": "gov.bc.caについて", + "disclaimer": "免責事項", + "privacy": "プライバシー", + "accessibility": "アクセシビリティ", + "copyRight": "著作権", + "contactUs": "お問い合わせ" + }, + "bCGovNavBar": { + "about": "だいたい", + "myForms": "私のフォーム", + "createNewForm": "新しいフォームを作成する", + "help": "ヘルプ", + "feedback": "フィードバック", + "admin": "管理者" + }, + "homePage": { + "title": "Common Hosted Forms Service を使用して、フォームを作成、公開し、送信を受け取ります。", + "subTitle": "すべて紀元前IDIR アカウントを持つ政府職員または請負業者は、Common Hosted Forms Service (CHEFS) のホスト型バージョンを使用してフォームを作成できます。", + "takeATourOfChefs": "CHEFS のツアーに参加して、実際の動作を確認してください。", + "logInToGetStarted": "ログインして始めましょう", + "loginToStart": "IDIR でログインして開始してください", + "login": "ログイン", + "createFormLabel": "フォームを作成する", + "manageAccessTitle": "フォームへのアクセスを管理する", + "manageAccessSub1": "CHEFS を使用すると、パブリック フォームを作成したり、IDIR または BCeID 認証を通じてアクセスを管理したりできます。", + "manageAccessSub2": "すべての提出物を管理するためにチームに役割を割り当てることもできます。", + "createCustomFormTitle": "CHEFS フォーム ビルダーを使用してカスタム フォームを作成する", + "createCustomFormSub1": "CHEFS を使用すると、直感的なドラッグ アンド ドロップ インターフェイスで安全なフォームを作成できます。フォーム コンポーネントを追加したり、再配置したり、さまざまなレイアウト構成にドロップしたりできます。", + "chefsHowToTitle": "シェフのハウツービデオ", + "chefsHowToSub": "クイックスタート ガイドでは、CHEFS の基本機能のいくつかを紹介します。", + "getStartedToChefs": "CHFS の使用を開始する", + "createOnlineTitle": "オンライン フォームを作成してクライアントから情報を収集し、ワークフローを改善します。", + "getStarted": "始めましょう" + }, + "baseStepper": { + "setUpForm": "フォームの設定", + "designForm": "デザインフォーム", + "manageForm": "フォームの管理" + }, + "create": { + "formSettings": "フォーム設定", + "disclaimer": "免責事項", + "disclaimerStmt": "フォームデザイナーの免責事項と責任声明に同意します", + "continue": "続く", + "back": "戻る", + "confirmPageNav": "本当にこのページを離れてもよろしいですか?加えた変更は保存されません。", + "agreementErrMsg": "上記のプライバシー免責事項に同意する必要があります。" + }, + "addTeamMember": { + "cantFindChefsUsers": "誰かが見つかりませんか?彼らは CHEFS にログインしていない可能性があります。
CHEFS へのリンクを送信して、ログインするようお願いしてください。", + "cancel": "キャンセル", + "add": "追加", + "mustSelectAUser": "このユーザーを追加するには、少なくとも 1 つの役割を選択する必要があります。", + "addNewMember": "新しいメンバーを追加する", + "enterUsername": "名前、電子メール、またはユーザー名を入力してください", + "enterExactUsername": "正確な電子メールまたはユーザー名を入力してください", + "BCeIDInputSearchMaxLen": "BCeID ユーザー名/電子メールの検索入力は 6 文字以上である必要があります。", + "BCeIDMustBeExact": "BCeID の電子メール検索は正確である必要があります。", + "errorGettingUsers": "ユーザーの取得中にエラーが発生しました {error}" + }, + "baseFilter": { + "cancel": "キャンセル", + "columnName": "列名", + "exampleText": "テキストの例", + "exampleText2": "テキスト例 2", + "filterPlaceholderTxt": "プレースホルダーテキストのフィルター", + "filter": "フィルター", + "value": "価値", + "resetColumns": "列をリセット" + }, + "formViewerActions": { + "viewMyDraftOrSubmissions": "私のドラフト/提出物を表示する", + "saveAsADraft": "下書きとして保存", + "editThisDraft": "この下書きを編集する", + "switchSingleSubmssn": "単一の提出に切り替える", + "switchMultiSubmssn": "複数の提出に切り替える" + }, + "baseCopyToClipboard": { + "linkToClipboard": "リンクがクリップボードにコピーされました", + "copyToClipboard": "クリップボードにコピー", + "errCopyToClipboard": "クリップボードにコピーしようとしたときにエラーが発生しました。" + }, + "sucess": { + "sucessFormSubmissn": "フォームは正常に送信されました", + "keepRecord": "この提出の記録を保存したい場合は、以下を保存できます。", + "confirmationId": "確認ID" + }, + "bcGovAlertBanner": { + "defaultErrMsg": "エラー: 何か問題が発生しました", + "error": "エラー" + }, + "permissionUtils": { + "formNotAvailable": "現在フォームはご利用いただけません。これは、リンクが間違っているか、フォームが所有者によって削除されたことが原因である可能性があります。", + "missingFormIdAndSubmssId": "オプションに formId と submitId の両方がありません", + "loadingFormErrMsg": "このフォームのロード中にエラーが発生しました。", + "loadingForm": "{options} のロード中にエラーが発生しました: {error}", + "idpHintMsg": "このフォームには {idpHint} 認証が必要です。再ログインしてもう一度お試しください。", + "formIdpMissMatch": "フォーム IDP の不一致。フォームには {idpHint} が必要ですが、ユーザーには {userIdp} が必要です。" + }, + "download": { + "chefsDataExport": "CHFS データのエクスポート", + "preparingForDownloading": "ダウンロードの準備をしています...", + "downloadInfoA": "ファイルが自動的にダウンロードされない場合", + "downloadInfoB": "ここをクリックしてもう一度試してください" + }, + "history": { + "submissnHistory": "あなたの提出履歴 (TBD)" + }, + "error": { + "logout": "ログアウト", + "somethingWentWrong": "エラー: 何か問題が発生しました... :(" + }, + "login": { + "authenticateWith": "以下で認証します:", + "alreadyLoggedIn": "ログイン済み", + "home": "家", + "about": "だいたい" + }, + "notFound": { + "about": "だいたい", + "pageNotFound": "404: ページが見つかりません。 :(" + }, + "store": { + "admin": { + "addFormOwnerRole": "このフォームの所有者の役割を {fullName} に追加しました", + "addRowError": "ロールの追加中にエラーが発生しました。", + "addRowConsoleErr": "ユーザー {userId} をフォーム {formId} に追加中にエラーが発生しました: {error}", + "apiKeyDelMsg": "このフォームの API キーは削除されました。", + "errDeletingApiKey": "API キーを削除しようとしたときにエラーが発生しました。", + "consErrDeletingApiKey": "フォーム {formId} の API キーの削除中にエラーが発生しました: {error}", + "fecthingFormsErrMsg": "フォームの取得中にエラーが発生しました。", + "fecthingFormsConsErrMsg": "管理フォームデータの取得中にエラーが発生しました: {error}", + "fecthingFormErrMsg": "このフォームを取得中にエラーが発生しました。", + "fecthingFormConsErrMsg": "管理フォーム {formId} データの取得中にエラーが発生しました: {error}", + "fecthFormUserRolesErrMsg": "フォームユーザーロールを取得中にエラーが発生しました。", + "fecthFormUserRolesConsErrMsg": "管理者ロール データの取得中にエラーが発生しました: {error}", + "fecthApiDetailsErrMsg": "このフォームの API 詳細を取得中にエラーが発生しました。", + "fecthApiDetailsConsErrMsg": "フォーム {formId} データから管理 API 詳細を取得中にエラーが発生しました: {error}", + "restoreFormErrMsg": "このフォームの復元中にエラーが発生しました。", + "restoreFormConsErrMsg": "フォーム {formId} データの復元中にエラーが発生しました: {error}", + "getUsersErrMsg": "ユーザーの取得中にエラーが発生しました。", + "getUsersConsErrMsg": "管理者ユーザーデータの取得中にエラーが発生しました: {error}", + "getUserErrMsg": "このユーザーを取得中にエラーが発生しました。", + "getUserConsErrMsg": "管理者ユーザー {userId} データの取得エラー: {error}", + "storingFCHelpInfoErrMsg": "フォームコンポーネントのヘルプ情報を保存中にエラーが発生しました", + "storingFCHelpInfoConsErrMsg": "フォーム コンポーネントのヘルプ情報の保存中にエラーが発生しました: {error}", + "gettingFCImgUrlErrMsg": "画像URLの取得中にエラーが発生しました", + "gettingFCImgUrlConsErrMsg": "画像 URL の取得中にエラーが発生しました: {error}", + "updatingFCStatusErrMsg": "公開ステータスの更新中にエラーが発生しました", + "updatingFCStatusConsErrMsg": "公開ステータスの更新中にエラーが発生しました: {error}", + "fecthingFormBuilderCompsErrMsg": "フォームビルダーコンポーネントの取得中にエラーが発生しました", + "fecthingFormBuilderCompsConsErrMsg": "フォームビルダーコンポーネントの取得エラー: {error}" + }, + "form": { + "fetchEmailTemplatesConsErrMsg": "{formId} の電子メール テンプレートの読み込みエラー: {error}", + "fetchEmailTemplatesErrMsg": "このフォームの電子メール テンプレートを取得中にエラーが発生しました", + "getCurrUserFormsErrMsg": "フォームの取得中にエラーが発生しました。", + "getCurrUserFormsConsErrMsg": "ユーザーデータ取得エラー: {error}", + "getUserFormPermErrMsg": "このフォームのユーザー データを取得中にエラーが発生しました。", + "getUserFormPermConsErrMsg": "formID {formId} を使用したユーザー データの取得エラー: {error}", + "getUserFormRolesErrmsg": "このフォームのユーザー データを取得中にエラーが発生しました。", + "getUserFormRolesConsErrmsg": "formID {formId} を使用したユーザー データの取得エラー: {error}", + "updCurrUserFormPrefErrMsg": "このフォームの設定を保存中にエラーが発生しました。", + "updCurrUserFormPrefConsErrMsg": "formID {formId} および prefs {preferences} を使用してユーザー フォームの設定を更新中にエラーが発生しました: {error}", + "getCurrUserFormPrefErrMsg": "このフォームの設定を取得中にエラーが発生しました。", + "getCurrUserFormPrefConsErrMsg": "formID {formId} を使用したユーザー フォーム設定の取得エラー: {error}", + "delCurrformNotiMsg": "フォーム {name} は正常に削除されました。", + "delCurrFormConsErMsg": "フォーム {id} の削除中にエラーが発生しました: {error}", + "delDraftErrMsg": "このドラフトの削除中にエラーが発生しました。", + "delDraftConsErrMsg": "{draftId} の削除エラー: {error}", + "fecthDraftErrMsg": "このフォームの下書きをスキャン中にエラーが発生しました。", + "fecthDraftConsErrMsg": "フォーム {formId} の下書き取得エラー: {error}", + "fecthFormErrMsg": "このフォームを取得中にエラーが発生しました。", + "fecthFormConsErrMsg": "フォーム {formId} の取得中にエラーが発生しました: {error}", + "fetchFormFieldsErrMsg": "このフォームのフィールドのリストを取得中にエラーが発生しました。", + "fetchFormFieldsConsErrMsg": "フォーム {formId} の取得中にエラーが発生しました: {error}", + "publishDraftErrMsg": "公開中にエラーが発生しました。", + "publishDraftConsErrMsg": "{draftId} の公開エラー: {error}", + "toggleVersnPublConsErrMsg": "toggleVersionPublish {versionId} {publish} でのエラー: {error}", + "updateEmailTemplateConsErrMsg": "フォーム {formId} の電子メール テンプレートの更新中にエラーが発生しました: {error}", + "updateEmailTemplateErrMsg": "このフォームの電子メール テンプレートを更新中にエラーが発生しました。", + "updateFormErrMsg": "このフォームの設定を更新中にエラーが発生しました。", + "updateFormConsErrMsg": "フォーム {id} の更新中にエラーが発生しました: {error}", + "deleteSubmissionNotifyMsg": "提出物は正常に削除されました。", + "deleteSubmissionErrMsg": "この提出物を削除中にエラーが発生しました。", + "deleteSubmissionConsErrMsg": "提出物 {submissionId} の削除中にエラーが発生しました: {error}", + "deleteSubmissionsNotifyMsg": "提出物は正常に削除されました。", + "deleteSubmissionsErrMsg": "選択した提出物の削除中にエラーが発生しました。", + "deleteSubmissionsConsErrMsg": "提出物の削除中にエラーが発生しました: {error}", + "restoreSubmissionsNotiMsg": "提出物は正常に復元されました。", + "restoreSubmissionsErrMsg": "この送信を復元中にエラーが発生しました。", + "restoreSubmissionsConsErrMsg": "提出物の復元中にエラーが発生しました: {error}", + "restoreSubmissionNotiMsg": "送信は正常に復元されました。", + "restoreSubmissionErrMsg": "この送信を復元中にエラーが発生しました。", + "restoreSubmissionConsErrMsg": "提出物 {submissionId} の復元中にエラーが発生しました: {error}", + "fecthSubmissnUsersErrMsg": "この送信の受信者の電子メールを取得中にエラーが発生しました。", + "fecthSubmissnUsersConsErrMsg": "送信用の受信者電子メールの取得エラー {formSubmissionId}: {error}", + "fetchSubmissnErrMsg": "この送信を取得中にエラーが発生しました。", + "fetchSubmissnConsErrMsg": "提出物 {submissionId} の取得エラー: {error}", + "fetchFormCSVExptFieldsErrMsg": "このフォームのフィールドのリストを取得中にエラーが発生しました。", + "fetchFormCSVExptFieldsConsErrMsg": "フォーム {formId} の取得中にエラーが発生しました: {error}", + "fetchSubmissnsErrMsg": "このフォームの送信内容を取得中にエラーが発生しました。", + "fetchSubmissnsConsErrMsg": "{formId} の送信の取得中にエラーが発生しました: {error}", + "fetchVersionErrMsg": "このフォームを取得中にエラーが発生しました。", + "fetchVersionConsErrMsg": "フォーム {formId} のバージョン {versionId} を取得中にエラーが発生しました: {error}", + "deleteApiKeyNotifyMsg": "このフォームの API キーは削除されました。", + "deleteApiKeyErrMsg": "API キーを削除しようとしたときにエラーが発生しました。", + "deleteApiKeyConsErrMsg": "フォーム {formId} の API キーの削除中にエラーが発生しました: {error}", + "generateApiKeyNotifyMsg": "このフォームの API キーが作成されました。", + "generateApiKeyErrMsg": "API キーを生成しようとしたときにエラーが発生しました。", + "generateApiKeyConsErrMsg": "フォーム {formId} の API キー生成エラー: {error}", + "readApiKeyErrMsg": "API キーを取得しようとしたときにエラーが発生しました。", + "readApiKeyConsErrMsg": "フォーム {formId} の API キーを取得中にエラーが発生しました: {error}。", + "getFCPHImageUrlErrMsg": "画像URLの取得中にエラーが発生しました", + "getFCPHImageUrlConsErrMsg": "画像 URL の取得中にエラーが発生しました: {error}", + "listFCPHErrMsg": "フォームビルダーコンポーネントの取得中にエラーが発生しました", + "listFCPHConsErrMsg": "フォームビルダーコンポーネントの取得エラー: {error}", + "downloadFileErrMsg": "ファイルのダウンロード中にエラーが発生しました", + "downloadFileConsErrMsg": "ファイルのダウンロード中にエラーが発生しました: エラー", + "readSubscriptionSettingsErrMsg": "サブスクリプション設定を取得しようとしたときにエラーが発生しました。", + "readSubscriptionSettingsConsErrMsg": "フォーム {formId} のサブスクリプション設定の取得中にエラーが発生しました: {error}。", + "saveSubscriptionSettingsNotifyMsg": "このフォームの購読設定が保存されました。", + "saveSubscriptionSettingsErrMsg": "サブスクリプション設定を保存しようとしたときにエラーが発生しました。", + "saveSubscriptionSettingsConsErrMsg": "フォーム {formId} のサブスクリプション設定を保存中にエラーが発生しました: {error}" + } + }, + "admin": { + "root": { + "admin": "管理者" + }, + "form": { + "administerForm": "フォームの管理" + }, + "user": { + "administerUser": "ユーザーの管理" + } + }, + "user": { + "root": { + "myForms": "私のフォーム", + "history": "歴史", + "user": "ユーザー" + } + } +} diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/ko/index.js b/frontend/app/frontend/src/internationalization/trans/chefs/ko/index.js new file mode 100644 index 0000000..ef32765 --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/ko/index.js @@ -0,0 +1,4 @@ +import ko from '~/internationalization/trans/chefs/ko/ko.json'; +export default { + trans: ko, +}; diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/ko/ko.json b/frontend/app/frontend/src/internationalization/trans/chefs/ko/ko.json new file mode 100644 index 0000000..8a6ebfc --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/ko/ko.json @@ -0,0 +1,995 @@ +{ + "date": { + "date": "yyyy-mm-dd" + }, + "emailManagement": { + "emailManagement": "이메일 관리", + "manageForm": "양식 관리", + "submissionConfirmation": "제출 확인" + }, + "emailTemplate": { + "body": "몸", + "save": "구하다", + "saveEmailTemplateConsoleErrMsg": "{formId} 양식의 이메일 템플릿을 업데이트하는 중에 오류가 발생했습니다. {error}", + "saveEmailTemplateErrMsg": "이메일 템플릿을 업데이트하는 동안 오류가 발생했습니다.", + "subject": "주제", + "title": "제목", + "validBodyRequired": "이메일 본문을 입력하세요.", + "validSubjectRequired": "이메일 제목을 입력하세요.", + "validTitleRequired": "이메일 제목을 입력하세요." + }, + "formsTable": { + "myForms": "내 양식", + "createNewForm": "새 양식 만들기", + "search": "찾다", + "manage": "관리하다", + "submissions": "제출물", + "formTitle": "양식 제목", + "viewForm": "양식 보기", + "description": "설명", + "Description": "설명:", + "action": "행위", + "loadingText": "로딩 중 기다려주세요" + }, + "preview": { + "preview": "시사", + "previewToolTip": "이는 제출자가 볼 수 있는 양식 버전 디자인 및 동작의 미리보기를 보여줍니다. 이 페이지에서는 양식을 제출할 수 없습니다." + }, + "manageLayout": { + "manageForm": "양식 관리" + }, + "shareForm": { + "shareForm": "양식 공유", + "shareLink": "링크 공유", + "copyQRCode": "아래 링크를 복사하거나 QR 코드를 다운로드하십시오.", + "warningMessage": "현재 양식의 게시된 버전이 없습니다. 아래 링크는 버전이 게시될 때까지 연결할 수 없습니다.", + "openThisForm": "이 양식 열기", + "downloadQRCode": "QR 코드 다운로드", + "close": "닫다", + "copyURLToClipboard": "클립보드에 URL 복사" + }, + "manageFormActions": { + "emailManagement": "이메일 관리", + "viewSubmissions": "제출물 보기", + "teamManagement": "팀 관리", + "deleteForm": "양식 삭제", + "confirmDeletion": "삭제 확인", + "deleteMessageA": "삭제하시겠습니까?", + "deleteMessageB": "이 양식은 더 이상 액세스할 수 없습니다.", + "delete": "삭제" + }, + "manageForm": { + "formSettings": "양식 설정", + "apiKey": "API 키", + "updated": "업데이트됨", + "created": "만들어진", + "formDesignHistory": "양식 디자인 역사", + "totalVersions": "총 버전", + "status": "상태", + "update": "업데이트", + "cancel": "취소", + "eventSubscription": "イベントのサブスクリプション" + }, + "formSettings": { + "pressToAddMultiEmail": "여러 이메일 주소를 추가하려면 enter 또는 , 또는 space를 누르십시오.", + "allowMultiDraft": "여러 초안 업로드 허용", + "formTitle": "양식 제목", + "formDescription": "양식 설명", + "formAccess": "양식 액세스", + "info": "이 양식을 사용하여 대중이 일반적으로 관심을 갖는 주제에 대한 정보를 일반 대중으로부터 수집하려면 GCPE에 연락하여 참여가 목록에 표시될 수 있도록 해야 합니다.", + "important": "중요한", + "idimNotifyA": "IDIM(ID 정보 관리) 팀에 이메일로 알려야 합니다.", + "idimNotifyB": "양식 제출자의 신원을 확인하기 위해 BCeID를 활용하려는 귀하의 의도.", + "referenceGuideA": "우리를 참조하십시오", + "referenceGuideB": "사용자 설명서", + "referenceGuideC": "상세 사항은", + "specificTeamMembers": "특정 팀원", + "formFunctionality": "양식 기능", + "formSubmissinScheduleMsg": "양식 제출 일정은 양식이 게시된 후 양식 설정에서 사용할 수 있습니다.", + "formSubmissionsSchedule": "양식 제출 일정", + "experimental": "실험적", + "learnMore": "더 알아보기", + "afterSubmission": "제출 후", + "submissionConfirmation": "제출 확인 세부 정보 표시", + "theConfirmationID": "확인 ID", + "infoB": "사용자가 자신에게 제출 확인 이메일을 보낼 수 있는 옵션", + "loginRequired": "로그인 필요", + "canSaveAndEditDraftLabel": "제출자는 초안을 저장하고 편집 할 수 있습니다.", + "canUpdateStatusAsReviewer": "검토자는 이 양식의 상태를 업데이트 할 수 있습니다(예: 제출됨, 지정됨, 완료됨).", + "submitterCanCopyExistingSubmissn": "제출자는 기존 제출을 복사 할 수 있습니다.", + "submissionConfirmationToolTip": "이 옵션을 선택하면 이 양식을 제출하는 사용자가 성공적으로 제출했을 때 보게 될 내용을 제어할 수 있습니다.
체크하면 표시됩니다", + "emailNotificatnToTeam": "내 팀에 알림 이메일 보내기", + "emailNotificatnToTeamToolTip": "사용자가 이 양식을 제출하면 지정된 이메일 주소로 알림을 보냅니다.", + "notificationEmailAddrs": "알림 이메일 주소", + "addMoreValidEmailAddrs": "유효한 이메일 주소를 하나 이상 추가하세요.", + "formScheduleSettings": "양식 일정 설정", + "opensubmissions": "공개 제출", + "submissionsDeadline": "언제까지 제출물을 받기를 원하십니까?", + "keepSubmissnOpenTilUnplished": "수동으로 게시를 취소할 때까지 열어 둡니다.", + "submissionsClosingDate": "마감 날짜 예약", + "submissionPeriod": "제출 기간 설정", + "closeSubmissions": "제출 마감", + "keepOpenFor": "계속 열어두세요", + "period": "기간", + "allowLateSubmissions": "늦은 제출 허용", + "allowLateSubmissionsInfoTip": "체크하면 제출자는 마감일 이후에 데이터를 제출할 수 있습니다.", + "afterCloseDateFor": "마감일 이후", + "repeatPeriod": "반복 기간", + "every": "모든", + "repeatUntil": "까지 반복", + "summary": "요약", + "submissionsOpenDateRange": "이 양식은", + "to": "에게", + "scheduleRepetition": "일정은 매주 반복됩니다.", + "allowLateSubmissnInterval": "늦은 제출 허용", + "until": "~까지", + "datesOfSubmissnInfo": "설정에 따라 제출 가능한 날짜는 다음과 같습니다.", + "formOpenInterval": "이 양식은", + "allowDateSubmissionDate": "까지 늦은 제출 허용", + "customClosingMessage": "맞춤 종료 메시지 설정", + "customClosingMessageToolTip": "사용자가 닫힌 양식을 방문할 때 사용자 정의 메시지를 추가할 수 있습니다.", + "closingMessage": "마무리 메시지", + "sendReminderEmail": "알림 이메일 보내기", + "autoReminderNotificatn": "자동 알림 알림 활성화", + "autoReminderNotificatnToolTip": "제출 기간 동안 양식 링크가 포함된 알림 이메일을 보냅니다.", + "selectLoginType": "로그인 유형을 1개 선택하세요.", + "formDescriptnMaxChars": "양식 설명은 255자 이하여야 합니다.", + "formTitlemaxChars": "양식 제목은 255자 이하여야 합니다.", + "formTitleReq": "양식 제목이 필요합니다", + "atLeastOneEmailReq": "이메일 주소를 1개 이상 입력하세요.", + "validEmailRequired": "유효한 이메일 주소를 모두 입력하세요.", + "fieldRequired": "이 필드는 필수입니다.", + "correctDateFormat": "날짜는 올바른 형식이어야 합니다. 즉. yyyy-mm-dd", + "dateDiffMsg": "마감 제출 날짜는 공개 제출 날짜보다 이후여야 합니다.", + "valueMustBeNumber": "값은 숫자여야 합니다. 즉. 1,2,3,5,99", + "selectAnOptions": "옵션을 1개 이상 선택하세요.", + "validInterval": "유효한 간격이어야 합니다.", + "fieldRequiredAndInterval": "이 필드는 필수이며 간격이어야 합니다.", + "dateGrtOpenSubmissnDate": "날짜가 공개 제출 날짜보다 커질 때까지 반복합니다.", + "public": "공개(익명)", + "allowEventSubscription": "イベントのサブスクリプションを許可する", + "eventSubscription": "イベントのサブスクリプション", + "validEndpointRequired": "で始まる有効なエンドポイントを入力してください https://", + "validBearerTokenRequired": "有効なベアラー トークンの例を入力してください: 89abddfb-2cff-4fda-83e6-13221f0c3d4f" + }, + "subscribeEvent": { + "eventType": "イベントタイプ", + "endpointUrl": "エンドポイント URL", + "eventSubmission": "提出", + "eventAssignment": "割り当て", + "eventStatusChange": "ステータス変更", + "endpointToken": "エンドポイントトークン", + "urlPlaceholder": "https://endpoint.gov.bc.ca/api/v1/", + "save": "구하다", + "text": "텍스트", + "password": "비밀번호", + "hideSecret": "비밀 숨기기", + "showSecret": "비밀 표시", + "key": "열쇠", + "saveSettingsErrMsg": "이 양식에 대한 설정을 업데이트하는 동안 오류가 발생했습니다.", + "updateSettingsConsoleErrMsg": "양식 {formId}에 대한 설정 업데이트 오류: {error}" + }, + "apiKey": { + "disclaimer": "부인 성명", + "infoA": "API 키 비밀이 안전한 위치(예: 키 자격 증명 모음)에 저장되어 있는지 확인합니다.", + "infoB": "API 키는 양식에 대한 무제한 액세스 권한을 부여합니다. 누구에게도 API 키를 제공하지 마십시오.", + "infoC": "API 키는 자동화된 시스템 상호 작용에만 사용해야 합니다. 사용자 기반 액세스에 API 키를 사용하지 마십시오.", + "deleteKey": "키 삭제", + "apiKey": "API 키", + "hideSecret": "비밀 숨기기", + "showSecret": "비밀 표시", + "sCTC": "클립보드에 복사된 비밀", + "cSTC": "클립보드에 암호 복사", + "key": "열쇠", + "confirmDeletion": "삭제 확인", + "deleteMsg": "API 키를 삭제하시겠습니까?", + "delete": "삭제", + "confirmKeyGen": "키 생성 확인", + "createAPIKey": "이 양식에 대한 API 키를 만드시겠습니까?
이 페이지의 고지 사항을 따르십시오.", + "regenerateAPIKey": "API 키를 재생성하시겠습니까?
계속하면 현재 API 키 액세스 권한이 삭제됩니다 .", + "formOwnerKeyAcess": "API 키를 관리하려면 양식 소유자 여야 합니다.", + "regenerate": "재생하다", + "generate": "생성하다", + "secret": "비밀" + }, + "manageVersions": { + "important": "중요한!", + "infoA": "게시된 버전이 없는 경우 사용자는 게시된 버전이 할당될 때까지 이 양식에 액세스할 수 없습니다. 버전이 게시되면 해당 버전은 더 이상 편집할 수 없습니다. 편집을 계속하려면 이전 양식 버전 중 하나를 기반으로 새 버전을 만들어야 합니다.", + "infoB": "참고: 하나의 버전만 게시할 수 있습니다.", + "version": "버전", + "draft": "초안", + "clickToPreview": "미리 보려면 클릭", + "editVersion": "버전 수정", + "exportDesign": "디자인 내보내기", + "infoC": "새 버전을 시작하기 전에 최신 초안 버전을 게시하거나 삭제하십시오.", + "deleteVersion": "버전 삭제", + "draftAlreadyExists": "초안이 이미 존재합니다.", + "infoD": "새 초안을 시작하기 전에 기존 초안을 편집, 게시 또는 삭제하십시오.", + "publishVersion": "버전 게시", + "unpublishVersion": "버전 게시 취소", + "infoE": "이 양식을 게시 취소하면 버전이 다시 게시될 때까지 양식이 순환되지 않습니다.", + "confirmDeletion": "삭제 확인", + "infoF": "이 버전을 삭제하시겠습니까?", + "delete": "삭제", + "status": "상태", + "dateCreated": "생성 일자", + "createdBy": "작성자", + "actions": "행위", + "published": "게시됨", + "unpublished": "널리 알려지지 않은", + "useVersionInfo": "{version} 버전을 새 버전의 기반으로 사용", + "publishingVersionInfo": "이렇게 하면 양식의 {version} 버전이 활성화됩니다." + }, + "addOwner": { + "infoA": "이는 현재 양식 소유자가 더 이상 활성 상태가 아니거나 우선 순위 이벤트에서 연락이 두절된 경우에만 수행해야 합니다. 그렇지 않으면 양식의 현재 소유자 또는 팀 관리자가 직접 이 작업을 수행하도록 합니다.", + "hint": "필요한 사용자 ID를 찾으려면 관리 포털의 '사용자' 탭으로 이동하여 검색할 수 있습니다.", + "addowner": "소유자 추가", + "label": "사용자 ID(가이드)" + }, + "adminFormsTable": { + "showDeletedForms": "삭제된 양식 표시", + "search": "찾다", + "loadingText": "로딩 텍스트", + "noDataText": "시스템에 양식이 없습니다.", + "admin": "관리자", + "launch": "시작하다", + "formTitle": "양식 제목", + "created": "만들어진", + "deleted": "삭제됨", + "actions": "행위", + "delete": "삭제" + }, + "administerForm": { + "deleted": "삭제됨", + "restoreForm": "이 양식 복원", + "formDetails": "양식 세부정보", + "apiKeyDetails": "API 키 세부정보", + "deleteApiKey": "API 키 삭제", + "formUsers": "양식 사용자", + "formVersions": "양식 버전", + "assignANewOwner": "새 소유자 지정", + "restoring": "복원 중", + "restore": "복원하다", + "toActiveState": "활성 상태로", + "confirmDeletion": "삭제 확인", + "confirmDeletionMsg": "이 API 키를 삭제하시겠습니까?", + "delete": "삭제", + "confirmRestore": "복원 확인" + }, + "administerUser": { + "userDetails": "사용자 세부정보", + "openSSOConsole": "SSO 콘솔 열기" + }, + "adminPage": { + "forms": "양식", + "users": "사용자", + "developer": "개발자", + "infoLinks": "정보 링크", + "metrics": "측정항목" + }, + "adminUsersTable": { + "search": "찾다", + "loadingText": "로딩 중 기다려주세요", + "admin": "관리자", + "fullName": "전체 이름", + "userID": "사용자 아이디", + "created": "만들어진", + "actions": "행위" + }, + "adminVersions": { + "exportDesign": "디자인 내보내기", + "versions": "버전", + "status": "상태", + "created": "만들어진", + "lastUpdated": "마지막 업데이트", + "actions": "행위", + "published": "게시됨", + "unpublished": "널리 알려지지 않은", + "version": "버전 {versionNo}", + "notificationMsg": "양식 디자인을 로드하는 동안 오류가 발생했습니다." + }, + "developer": { + "user": "사용자", + "name": "이름", + "userName": "사용자 이름", + "JWTContents": "JWT 콘텐츠", + "JWTContentsSBTxt": "클립보드에 복사된 JWT 콘텐츠", + "JWTContentsTTTxt": "클립보드에 JWT 콘텐츠 복사", + "JWTToken": "JWT 토큰", + "JWTTokenSBTxt": "클립보드에 복사된 JWT 토큰", + "JWTTokenTTTxt": "클립보드에 JWT 토큰 복사", + "chefsAPI": "셰프 API", + "RBACSBTxt": "클립보드에 복사된 RBAC 응답", + "RBACTTTxt": "클립보드에 RBAC 응답 복사", + "notificationMsg": "RBAC에서 사용자를 가져오지 못했습니다. 콘솔을 참조하세요.", + "notificationConsErr": "RBAC에서 사용자를 가져오는 중 오류가 발생했습니다." + }, + "baseAuthButton": { + "logout": "로그 아웃", + "login": "로그인" + }, + "baseDialog": { + "defaultText": "기본 텍스트", + "ok": "좋아요", + "continue": "계속하다", + "cancel": "취소", + "custom": "관습" + }, + "baseSecure": { + "about": "에 대한", + "loginInfo": "이 기능을 사용하려면 로그인해야 합니다.", + "login": "로그인", + "401NotAuthorized": "401: 권한이 없습니다. :", + "401ErrorMsg": "귀하의 계정이 올바르게 설정되지 않았습니다.
연락주세요", + "403Forbidden": "403 금지. :", + "403ErrorMsg": "이 페이지는 {idp} 인증이 필요합니다.", + "401UnAuthorized": "401: 권한이 없습니다. :", + "401UnAuthorizedErrMsg": "이 페이지에 액세스할 수 있는 권한이 없습니다." + }, + "formDesigner": { + "formDesign": "양식 디자인", + "exportDesign": "디자인 내보내기", + "importDesign": "디자인 가져오기", + "important": "중요한", + "formDesignInfoA": "이 양식 작성을 완료하면 SAVE DESIGN 버튼을 사용하십시오.", + "formDesignInfoB": "SUBMIT 버튼은 사용자가 이 양식을 제출할 수 있도록 제공되며 양식이 저장되면 활성화됩니다.", + "formLoadErrMsg": "양식 디자인을 로드하는 동안 오류가 발생했습니다.", + "formLoadConsoleErrMsg": "양식 {formId} 스키마(버전: {versionId} 초안: {draftId}) 로드 오류: {error}", + "formSchemaImportErrMsg": "양식 스키마를 가져오는 동안 오류가 발생했습니다.", + "formSchemaImportConsoleErrMsg": "양식 스키마 가져오기 오류: {error}", + "formDesignSaveErrMsg": "이 양식 디자인을 저장하는 동안 오류가 발생했습니다. 새로고침하거나 나중에 다시 시도하기 위해 나가야 하는 경우 페이지에서 기존 디자인을 내보내 나중에 저장할 수 있습니다.", + "formDesignSaveConsoleErrMsg": "양식 업데이트 또는 생성 오류(FormID: {formId}, versionId: {versionId}, draftId: {draftId}) 오류: {error}", + "collapse": "무너지다", + "actions": "행위", + "version": "버전", + "save": "구하다", + "saving": "절약", + "notSaved": "저장되지 않음", + "fieldnameError": "{label} 필드 이름으로 `form` 키워드를 사용할 수 없습니다." + }, + "formViewerMultiUpload": { + "important": "중요한", + "uploadSucessMsg": "여러 개의 초안을 성공적으로 업로드하려면 제공된 템플릿을 다운로드하여 활용하십시오.", + "confirmDownload": "다운로드하시겠습니까?", + "jsonFileUpload": "업로드할 JSON 파일 선택", + "dragNDrop": "또는 여기로 드래그 앤 드롭", + "chooseAFile": "파일 선택", + "downloadDraftSubmns": "초안 제출 보고서를 다운로드하고 데이터가 올바르게 입력되었는지 확인하십시오.", + "downloadReport": "보고서 다운로드", + "doYouWantToDownload": "다운로드하시겠습니까?", + "uploadNewFile": "새 파일 업로드", + "uploadMultipleFileErr": "죄송합니다. 하나의 파일만 업로드할 수 있습니다.", + "dragMultipleFileErr": "죄송합니다. 하나의 파일만 드래그할 수 있습니다.", + "fileFormatErr": "죄송합니다. json 파일만 허용됩니다.", + "fileSizeErr": "허용되는 최대 파일 크기는 5MB입니다.", + "parseJsonErr": "파일에서 json 데이터를 구문 분석할 수 없습니다.", + "jsonObjNotArray": "잘못된 json 파일 형식", + "jsonObjNotArrayConsErr": "예상치 못한 오류가 발생했습니다.", + "jsonArrayEmpty": "이 json 파일은 비어 있습니다.", + "errorWhileValidate": "이 파일에 문제가 있습니다.", + "errWhileCheckValidity": "이 파일에 문제가 있습니다.", + "errAfterValidate": "일부 오류가 발견되었습니다. 자세한 내용은 아래를 참조하세요.", + "fileIsEmpty": "이 파일은 비어 있습니다.", + "download": "다운로드" + }, + "formDisclaimer": { + "disclaimerAndStatement": "양식 설계자에 대한 면책 및 책임 진술:", + "privacyLaw": "개인 식별 정보의 수집, 사용 및 공개에 적용되는 개인 정보 보호법을 준수하는 것은 귀하의 책임입니다.", + "disclosure": "이 양식 디자이너 도구에 대한 액세스는 본질적으로 개인 식별 정보를 수집, 사용 또는 공개할 수 있는 권한을 부여하지 않습니다.", + "consent": "법률에서 요구하는 정보 수집에 대한 동의를 얻는 것은 귀하의 책임입니다.", + "formIntention": "양식을 게시하거나 배포하기 전에 양식의 의도를 귀하와 논의해야 합니다.", + "privacyOfficer": "사역 개인 정보 보호 책임자", + "assement": "필요에 따라 평가를 완료합니다." + }, + "requestReceipt": { + "emailPriority": "이메일 우선순위", + "emailReceipt": "이 제출 영수증을 이메일로 보내기", + "high": "높은", + "low": "낮은", + "normal": "정상", + "send": "보내다", + "sendToEmailAddress": "이메일 주소로 보내기", + "emailSent": "{to}에게 이메일을 보냈습니다.", + "sendingEmailErrMsg": "이메일을 보내는 동안 오류가 발생했습니다.", + "sendingEmailConsErrMsg": "{to}에 대한 이메일 확인 실패: {error}", + "emailRequired": "이메일이 필요합니다" + }, + "submissionsTable": { + "noMatchingRecordText": "일치하는 기록이 없습니다", + "submissions": "제출물", + "submissionsTable": "제출물표", + "selectColumns": "열 선택", + "manageForm": "양식 관리", + "submissionsToFiles": "제출물을 파일로 내보내기", + "showDeletedSubmissions": "삭제된 제출물 표시", + "showMySubmissions": "내 제출물 표시", + "search": "찾다", + "loadingText": "로딩 중 기다려주세요", + "noDataText": "이 양식에 대한 제출물이 없습니다", + "delSelectedSubmissions": "선택한 제출물 삭제", + "resSelectedSubmissions": "선택한 제출물 복원", + "yes": "예", + "no": "아니요", + "viewSubmission": "제출물 보기", + "deleteSubmission": "제출물 삭제", + "restore": "복원하다", + "confirmDeletion": "삭제 확인", + "delete": "삭제", + "confirmRestoration": "복원 확인", + "searchSubmissionFields": "제출 필드 검색", + "save": "구하다", + "searchTitle": "대시보드 아래에 표시할 열 검색 및 선택", + "status": "상태", + "submitter": "제출자", + "submissionDate": "제출 날짜", + "event": "이벤트", + "view": "보다", + "lateSubmission": "늦은 제출", + "confirmationID": "확인 ID", + "multiDelWarning": "선택한 제출물을 삭제하시겠습니까?", + "singleDelWarning": "이 제출물을 삭제하시겠습니까?", + "multiRestoreWarning": "이 제출물을 복원하시겠습니까?", + "singleRestoreWarning": "이 제출을 복원하시겠습니까?" + }, + "auditHistory": { + "viewEditHistory": "편집 기록 보기", + "editHistory": "기록 편집", + "auditLogMsg": "이것은 원래 제출 후 누가 이 제출을 변경했는지에 대한 감사 로그입니다.", + "loadingText": "로딩 중 기다려주세요", + "close": "닫다", + "userName": "사용자 이름", + "date": "날짜", + "errorMsg": "기록을 가져오는 중에 오류가 발생했습니다.", + "consoleErrMsg": "다음에 대한 감사 기록을 가져오는 중에 오류가 발생했습니다." + }, + "deleteSubmission": { + "deleteThis": "삭제", + "draft": "초안", + "submission": "제출", + "confirmDeletion": "삭제 확인", + "deleteWarning": "삭제하시겠습니까?", + "drafts": "초안", + "formSubmission": "양식 제출", + "delete": "삭제" + }, + "manageSubmissionUsers": { + "manageTeamMembers": "팀원 관리", + "add": "추가하다", + "draftFormInvite": "이 양식이 초안일 때만 팀원을 초대하고 관리할 수 있습니다.", + "submissionTeamMembers": "이 제출물을 위한 팀원", + "actions": "행위", + "close": "닫다", + "remove": "제거하다", + "userNotFoundErrMsg": "사람을 찾을 수 없습니까? CHEFS에 로그인하지 않았을 수 있습니다.
그들에게 CHEFS에 대한 링크를 보내고 로그인하도록 요청하십시오.", + "name": "이름", + "username": "사용자 이름", + "email": "이메일", + "removeUserWarningMsg1": "제거하시겠습니까?", + "removeUserWarningMsg2": "더 이상 이 제출물에 대한 권한이 없습니다.", + "userExistInListMsg": "{username} 사용자는 이미 팀 구성원 목록에 있습니다.", + "getSubmissionUsersErr": "이 제출물에 대해 사용자를 가져오는 중에 오류가 발생했습니다.", + "getSubmissionUsersConsoleErr": "{submissionId}에 대한 사용자를 가져오는 중 오류 발생: {error}", + "sentInviteEmailTo": "초대 이메일을 보낸 사람", + "sentUninvitedEmailTo": "초대받지 않은 이메일을 보낸 사람", + "updateUserErrMsg": "이 제출에 대해 사용자를 업데이트하는 동안 오류가 발생했습니다.", + "updateUserConsoleErrMsg": "사용자 권한을 설정하는 중에 오류가 발생했습니다. 하위: {submissionId} 사용자: {userId} 오류: {error}", + "searchInputLength": "BCeID 사용자 이름/이메일에 대한 검색 입력은 6자보다 커야 합니다.", + "exactBCEIDSearch": "BCeID에 대한 이메일 검색은 정확해야 합니다.", + "getUsersErrMsg": "사용자 가져오기 오류: {error}", + "exactEmailOrUsername": "정확한 이메일 또는 사용자 이름을 입력하세요.", + "requiredFiled": "이름, 이메일 또는 사용자 이름을 입력하세요." + }, + "mySubmissionsActions": { + "viewThisSubmission": "이 제출물 보기", + "copyThisSubmission": "이 제출물 복사", + "editThisDraft": "이 초안 편집" + }, + "mySubmissionsTable": { + "noMatchingRecordText": "일치하는 기록이 없습니다", + "previousSubmissions": "이전 제출물", + "selectColumns": "열 선택", + "createNewSubmission": "새 제출물 만들기", + "search": "찾다", + "loadingText": "로딩 중 기다려주세요", + "noDataText": "제출물이 없습니다.", + "searchSubmissionFields": "제출 필드 검색", + "save": "구하다", + "filterTitle": "대시보드 아래에 표시할 열 검색 및 선택", + "confirmationId": "확인 ID", + "actions": "행위", + "createdBy": "작성자", + "statusUpdatedBy": "상태 업데이트자", + "status": "상태", + "submissionDate": "제출 날짜", + "draftUpdatedBy": "초안 업데이트자", + "draftLastEdited": "최종 수정된 초안", + "createLateSubmissn": "늦은 제출 만들기", + "formLoading": "폼이 로딩되는 동안 기다려주세요!!!", + "pleaseConfirm": "확인 해주세요", + "wantToSaveDraft": "초안을 저장하시겠습니까?", + "yes": "예", + "no": "아니요", + "multiDraftUploadSuccess": "여러 초안 업로드가 성공적으로 완료되었습니다!", + "failedResSubmissn": "제출 끝점에서 실패한 응답입니다. 응답 코드: {status}", + "errSubmittingForm": "이 양식을 제출하는 중에 오류가 발생했습니다.", + "errorSavingFile": "파일을 저장하는 중에 오류가 발생했습니다. 파일 이름: {fileName}. 오류: {error}", + "submittingDraftErrMsg": "초안을 저장하는 중에 오류가 발생했습니다.", + "submittingDraftConsErrMsg": "초안을 저장하는 중에 오류가 발생했습니다. 제출 ID: {submissionId}. 오류: {error}" + }, + "notesPanel": { + "addNewNote": "새 메모 추가", + "cancel": "취소", + "addNote": "메모를 추가", + "noResponseErr": "양식을 제출하는 동안 API의 응답 데이터가 없습니다.", + "errorMesg": "메모를 추가하는 중에 오류가 발생했습니다.", + "consoleErrMsg": "메모 추가 오류:", + "fetchErrMsg": "이 제출물에 대한 메모를 가져오는 동안 오류가 발생했습니다.", + "fetchConsoleErrMsg": "메모 추가 오류:", + "notes": "노트", + "note": "메모", + "maxChars": "최대 4000자" + }, + "statusPanel": { + "currentStatus": "현재 상태:", + "assignedTo": "할당:", + "assignOrUpdateStatus": "상태 할당 또는 업데이트", + "display": "표시하다", + "statusIsRequired": "상태가 필요합니다.", + "assignTo": "할당 대상", + "noDataText": "검색 결과 양식 검토자가 없습니다. 관리 페이지에서 양식 검토자를 추가합니다.", + "assigneeIsRequired": "담당자는 필수 항목입니다.", + "assignToMe": "나에게 할당", + "recipientEmail": "이메일 수령인", + "attachCommentToEmail": "이메일에 댓글 첨부", + "emailComment": "이메일 댓글", + "maxChars": "최대 4000자", + "viewHistory": "기록 보기", + "statusHistory": "상태 기록", + "close": "닫다", + "addNoteNoReponserErr": "상태 업데이트에 대한 메모를 제출하는 동안 API의 응답 데이터가 없습니다.", + "addNoteConsoleErrMsg": "상태 업데이트 오류: {error}", + "addNoteErrMsg": "상태를 업데이트하는 동안 오류가 발생했습니다.", + "updtSubmissionsStatusErr": "상태 업데이트 양식을 제출하는 동안 API의 응답 데이터가 없습니다.", + "noStatus": "상태 없음", + "noStatusesFound": "상태를 찾을 수 없습니다.", + "statusCodesErr": "상태 코드 찾기 오류", + "notifyErrorCode": "이 제출물의 상태를 가져오는 중에 오류가 발생했습니다.", + "notifyConsoleErrorCode": "상태 가져오기 오류:", + "fetchSubmissionUsersErr": "이 제출에 대한 수신자 이메일을 가져오는 동안 오류가 발생했습니다.", + "fetchSubmissionUsersConsErr": "에 대한 수신자 이메일을 가져오는 중 오류가 발생했습니다.", + "assignSubmissnToFormReviewer": "제출물을 양식 검토자에게 할당할 수 있습니다.
더 많은 팀 구성원을 양식 검토자로 추가하려면 이 양식의 관리 페이지로 이동하십시오.", + "update": "업데이트", + "revise": "개정하다", + "complete": "완벽한", + "assign": "양수인" + }, + "statusTable": { + "loadingText": "로딩 중 기다려주세요", + "status": "상태", + "dateStatusChanged": "상태가 변경된 날짜", + "assignee": "양수인", + "updatedBy": "업데이트자", + "getSubmissionStatusErr": "상태를 가져오는 중에 오류가 발생했습니다.", + "getSubmissionStatusConsErr": "메모 추가 오류:" + }, + "exportSubmissions": { + "exportSubmissionsToFile": "제출물을 파일로 내보내기", + "viewSubmissions": "제출물 보기", + "fileType": "파일 유형", + "json": "JSON", + "csv": "CSV", + "formVersion": "양식 버전", + "versionIsRequired": "버전이 필요합니다.", + "dataFields": "데이터 필드", + "searchFields": "검색 필드", + "selectedForExports": "수출용으로 선정", + "submissionDate": "제출 날짜", + "all": "모두", + "selectDateRange": "기간 선택", + "SelectdateRange": "기간 선택", + "from": "에서", + "to": "에게", + "CSVFormat": "CSV 형식", + "multiRowPerSubmissionA": "1 - 들여쓰기 공간이 있는 제출물당 여러 행", + "multiRowPerSubmissionB": "2 - 제출당 여러 행", + "singleRowPerSubmission": "3 - 제출당 단일 행", + "unformatted": "4 - 포맷되지 않음", + "fileNameAndType": "파일 이름 및 유형", + "export": "내보내다", + "noResponseDataErr": "exportSubmissions 호출에 응답한 데이터가 없습니다.", + "apiCallErrorMsg": "이 양식에 대한 제출을 내보내는 동안 오류가 발생했습니다.", + "apiCallConsErrorMsg": "에 대한 내보내기 제출 오류", + "selectAllFields": "모든 필드 선택", + "emailSentMsg": "준비가 되면 데이터를 다운로드할 수 있는 링크가 포함된 이메일이 {email}로 전송됩니다.", + "exportInProgress": "내보내기 진행 중", + "of": "~의" + }, + "printOptions": { + "submitButtonTxt": "CDOGS에 제출 및 다운로드", + "templatePrint": "템플릿 인쇄", + "uploadTemplateFile": "템플릿 파일 업로드", + "downloadOptions": "다운로드 옵션", + "print": "인쇄", + "browserPrint": "브라우저 인쇄", + "pageFromBrowser": "브라우저의 페이지", + "uploadA": "업로드", + "uploadB": "구조화 된 버전을 갖기 위해", + "docGrnSucess": "문서가 성공적으로 생성되었습니다.", + "failedDocGenErrMsg": "문서를 생성하지 못했습니다.", + "failedDocGenConsErrMsg": "템플릿 제출 오류: {error}", + "cDogsTemplate": "CDOGS 템플릿" + }, + "proactiveHelpDialog": { + "componentInfoLink": "구성품 정보 링크", + "learnMoreLinkTxt": "자세히 알아보기 링크 필드는 비워둘 수 없습니다.", + "largeImgTxt": "큰 이미지. 이미지 크기는 .5mb보다 클 수 없습니다.", + "componentName": "구성 요소 이름:", + "learnMoreLink": "더 알아보기 링크:", + "clickToEnableLink": "링크를 활성화하려면 클릭", + "clickToDisableLink": "링크를 비활성화하려면 클릭", + "imageUpload": "이미지 업로드:", + "cancel": "취소", + "save": "구하다", + "description": "설명" + }, + "proactiveHelpPreviewDialog": { + "learnMore": "더 알아보기" + }, + "preview": { + "preview": "시사", + "previewToolTip": "이는 제출자가 볼 수 있는 양식 버전 디자인 및 동작의 미리보기를 보여줍니다. 이 페이지에서는 양식을 제출할 수 없습니다." + }, + "generalLayout": { + "loadingText": "로딩 중 기다려주세요", + "preview": "시사", + "published": "출판됨", + "unpublished": "널리 알려지지 않은", + "edit": "편집하다", + "formTitle": "양식 제목", + "actions": "행위" + }, + "formSubmission": { + "editThisSubmission": "이 제출물 편집", + "submission": "제출", + "alertInfo": "편집 후 양식을 다시 제출하여 변경 사항을 저장하십시오.", + "viewAllSubmissions": "모든 제출물 보기", + "submitted": "제출된:", + "confirmationID": "확인 ID:", + "submittedBy": "에 의해 제출 된:", + "cancel": "취소", + "status": "상태", + "updatedAt": "수정", + "updatedBy": "수정자" + }, + "teamManagement": { + "noMatchingRecordText": "일치하는 기록이 없습니다", + "teamManagement": "팀 관리", + "selectColumns": "열 선택", + "manageForm": "양식 관리", + "search": "찾다", + "loadingText": "로딩 중 기다려주세요", + "noDataText": "팀 역할 데이터를 로드하지 못했습니다.", + "removeSelectedUsers": "선택한 사용자 제거", + "removeThisUser": "이 사용자 제거", + "confirmRemoval": "삭제 확인", + "remove": "제거하다", + "searchTeamManagementFields": "팀 관리 분야 검색", + "save": "구하다", + "teamMebersTitle": "대시보드 아래에 표시할 열 검색 및 선택", + "fullName": "전체 이름", + "username": "사용자 이름", + "identityProvider": "ID 제공자", + "delSelectedMembersWarning": "선택한 구성원을 제거하시겠습니까?", + "delSelectedMemberWarning": "선택한 구성원을 제거하시겠습니까?", + "idpMessage": "이미 팀에 있습니다.", + "formOwnerErrMsg": "항상 양식 소유자가 한 명 이상 있어야 합니다.", + "formOwnerConsoleErrMsg": "{userId}님은 이 양식의 유일한 소유자이므로 제거할 수 없습니다.", + "insufficientPermissnMsg": "팀을 관리할 권한이 부족합니다.", + "getUserErrMsg": "양식 사용자 가져오기 오류:", + "getRolesErrMsg": "역할 목록을 가져오는 중 오류 발생:", + "formOwnerRemovalWarning": "이 양식의 유일한 소유자이므로 삭제할 수 없습니다.", + "removeUsersErrMsg": "선택한 사용자를 삭제하는 동안 오류가 발생했습니다.", + "removeUserConsoleErrMsg": "양식 {formId}에서 사용자 삭제 오류: {error}", + "updUserRolesErrMsg": "모든 사용자 역할을 업데이트하는 동안 오류가 발생했습니다.", + "updUserRolesConsoleErrMsg": "양식 {formId}에 대한 모든 사용자 역할 설정 오류: {error}", + "setUserFormsErrMsg": "사용자의 역할을 업데이트하는 동안 오류가 발생했습니다.", + "setUserFormsConsoleErrMsg": "양식 {formId}에 대한 사용자 역할 설정 오류: {error}" + }, + "floatButton": { + "publish": "게시", + "manage": "관리하다", + "redo": "다시 하다", + "undo": "실행 취소", + "preview": "시사", + "bottom": "맨 아래", + "top": "맨 위", + "actions": "행위", + "collapse": "무너지다", + "saved": "저장됨", + "save": "구하다", + "saving": "절약", + "notSaved": "저장되지 않음" + }, + "formViewer": { + "lateFormSubmissions": "양식 제출 기간이 만료되었습니다! 여전히 아래 버튼을 클릭하여 늦은 제출을 생성할 수 있습니다.", + "createLateSubmission": "늦은 제출 만들기", + "draftSaved": "초안이 저장됨", + "saving": "절약", + "pleaseConfirm": "확인 해주세요", + "submitFormWarningMsg": "양식을 제출하시겠습니까?", + "submit": "제출하다", + "wantToSaveDraft": "초안을 저장하시겠습니까?", + "version": "버전: {version}", + "formScheduleExpireMessage": "예정된 제출 기간이 만료되어 양식 제출이 불가능합니다.", + "getUsersSubmissionsErrMsg": "이 양식에 대한 제출물을 가져오는 중에 오류가 발생했습니다.", + "getUsersSubmissionsConsoleErrMsg": "양식 제출 데이터 {submissionId} 로드 오류: {error}", + "multiDraftUploadSuccess": "여러 초안 업로드가 성공적으로 완료되었습니다!", + "readVersionErrMsg": "응답에 스키마가 없습니다. 버전 ID: {versionId}", + "readDraftErrMsg": "응답에 스키마가 없습니다. 초안 ID: {draftId}", + "alertRouteMsg": "양식 소유자가 양식을 게시하지 않았으며 제출할 수 없습니다.", + "fecthingFormErrMsg": "이 양식을 가져오는 중에 오류가 발생했습니다.", + "fecthingFormConsoleErrMsg": "양식 스키마 {versionId} 로드 오류: {error}", + "savingDraftErrMsg": "초안을 저장하는 중에 오류가 발생했습니다.", + "savingDraftConsoleErrMsg": "초안을 저장하는 중에 오류가 발생했습니다. 제출 ID: {submissionId}. 오류: {error}", + "submissionsPreviewAlert": "양식 미리보기 중 제출이 비활성화됨", + "submissionsSubmitErrMsg": "양식 제출 오류: {errors}", + "sendSubmissionErrMsg": "제출 끝점에서 실패한 응답입니다. 응답 코드: {status}", + "errMsg": "이 양식을 제출하는 중에 오류가 발생했습니다.", + "customEventAlert": "사용자 정의 버튼 이벤트는 아직 지원되지 않습니다. 이벤트 유형: {event}", + "formLoading": "폼이 로딩되는 동안 기다려주세요!!!", + "yes": "예", + "no": "아니요", + "failedResSubmissn": "제출 끝점에서 실패한 응답입니다. 응답 코드: {status}", + "errSubmittingForm": "이 양식을 제출하는 중에 오류가 발생했습니다.", + "errorSavingFile": "파일을 저장하는 중에 오류가 발생했습니다. 파일 이름: {fileName}. 오류: {error}", + "submittingDraftErrMsg": "초안을 저장하는 중에 오류가 발생했습니다.", + "submittingDraftConsErrMsg": "초안을 저장하는 중에 오류가 발생했습니다. 제출 ID: {submissionId}. 오류: {error}", + "formDraftAccessErrMsg": "요청한 제출이 이미 제출되었으며 보기 페이지로 리디렉션됩니다." + }, + "bCGovFooter": { + "home": "집", + "about": "gov.bc.ca 소개", + "disclaimer": "부인 성명", + "privacy": "은둔", + "accessibility": "접근성", + "copyRight": "저작권", + "contactUs": "문의하기" + }, + "bCGovNavBar": { + "about": "에 대한", + "myForms": "내 양식", + "createNewForm": "새 양식 만들기", + "help": "돕다", + "feedback": "피드백", + "admin": "관리자" + }, + "homePage": { + "title": "Common Hosted Forms Service를 사용하여 양식을 만들고 게시하고 제출물을 받습니다.", + "subTitle": "모든 B.C. IDIR 계정이 있는 공무원 또는 계약자는 호스팅된 CHEFS(Common Hosted Forms Service) 버전을 사용하여 양식을 만들 수 있습니다.", + "takeATourOfChefs": "CHEFS를 둘러보고 실제로 작동하는 모습을 확인하세요.", + "logInToGetStarted": "시작하려면 로그인하세요.", + "loginToStart": "시작하려면 IDIR로 로그인하세요.", + "login": "로그인", + "createFormLabel": "양식 만들기", + "manageAccessTitle": "양식에 대한 액세스 관리", + "manageAccessSub1": "CHEFS를 사용하면 공개 양식을 만들거나 IDIR 또는 BCeID 인증을 통해 액세스를 관리할 수 있습니다.", + "manageAccessSub2": "모든 제출물을 관리하기 위해 팀에 역할을 할당할 수도 있습니다.", + "createCustomFormTitle": "CHEFS 양식 작성기로 사용자 정의 양식 만들기", + "createCustomFormSub1": "CHEFS를 사용하면 직관적인 끌어서 놓기 인터페이스로 안전한 양식을 만들 수 있습니다. 양식 구성 요소를 추가하고 재정렬하고 다른 레이아웃 구성에 놓을 수 있습니다.", + "chefsHowToTitle": "셰프 사용법 비디오", + "chefsHowToSub": "빠른 시작 가이드는 CHEFS의 기본 기능 중 일부를 소개합니다.", + "getStartedToChefs": "CHEFS를 사용하여 시작하기", + "createOnlineTitle": "클라이언트로부터 정보를 수집하고 작업 흐름을 개선하기 위한 온라인 양식을 만드십시오.", + "getStarted": "시작하다" + }, + "baseStepper": { + "setUpForm": "양식 설정", + "designForm": "디자인 양식", + "manageForm": "양식 관리" + }, + "create": { + "formSettings": "양식 설정", + "disclaimer": "부인 성명", + "disclaimerStmt": "양식 디자이너에 대한 면책 조항 및 책임 진술에 동의합니다.", + "continue": "계속하다", + "back": "뒤쪽에", + "confirmPageNav": "이 페이지에서 나가시겠습니까? 변경 사항은 저장되지 않습니다.", + "agreementErrMsg": "위에 표시된 개인 정보 면책 조항에 동의해야 합니다." + }, + "addTeamMember": { + "cantFindChefsUsers": "사람을 찾을 수 없습니까? CHEFS에 로그인하지 않았을 수 있습니다.
그들에게 CHEFS에 대한 링크를 보내고 로그인하도록 요청하십시오.", + "cancel": "취소", + "add": "추가하다", + "mustSelectAUser": "이 사용자를 추가하려면 하나 이상의 역할을 선택해야 합니다.", + "addNewMember": "새 구성원 추가", + "enterUsername": "이름, 이메일 또는 사용자 이름을 입력하세요.", + "enterExactUsername": "정확한 이메일 또는 사용자 이름을 입력하세요.", + "BCeIDInputSearchMaxLen": "BCeID 사용자 이름/이메일에 대한 검색 입력은 6자보다 커야 합니다.", + "BCeIDMustBeExact": "BCeID에 대한 이메일 검색은 정확해야 합니다.", + "errorGettingUsers": "사용자를 가져오는 중에 오류가 발생했습니다 {error}" + }, + "baseFilter": { + "cancel": "취소", + "columnName": "열 이름", + "exampleText": "예제 텍스트", + "exampleText2": "예제 텍스트 2", + "filterPlaceholderTxt": "자리 표시자 텍스트 필터링", + "filter": "필터", + "value": "값", + "resetColumns": "열 재설정" + }, + "formViewerActions": { + "viewMyDraftOrSubmissions": "내 초안/제출물 보기", + "saveAsADraft": "초안으로 저장", + "editThisDraft": "이 초안 편집", + "switchSingleSubmssn": "단일 제출로 전환", + "switchMultiSubmssn": "다중 제출로 전환" + }, + "baseCopyToClipboard": { + "linkToClipboard": "클립보드에 복사된 링크", + "copyToClipboard": "클립 보드에 복사", + "errCopyToClipboard": "클립보드에 복사하는 동안 오류가 발생했습니다." + }, + "sucess": { + "sucessFormSubmissn": "귀하의 양식이 성공적으로 제출되었습니다", + "keepRecord": "이 제출 기록을 보관하려면 다음을 보관할 수 있습니다.", + "confirmationId": "확인 ID" + }, + "bcGovAlertBanner": { + "defaultErrMsg": "오류: 문제가 발생했습니다.", + "error": "오류" + }, + "permissionUtils": { + "formNotAvailable": "현재 양식을 사용할 수 없습니다. 링크가 잘못되었거나 소유자가 양식을 삭제했기 때문일 수 있습니다.", + "missingFormIdAndSubmssId": "formId 및 submitId가 모두 누락된 옵션", + "loadingFormErrMsg": "이 양식을 로드하는 동안 오류가 발생했습니다.", + "loadingForm": "{options} 로드 중 오류: {error}", + "idpHintMsg": "이 양식에는 {idpHint} 인증이 필요합니다. 다시 로그인하고 다시 시도하십시오.", + "formIdpMissMatch": "양식 IDP 불일치. 양식에는 {idpHint}가 필요하지만 사용자에게는 {userIdp}가 있습니다." + }, + "download": { + "chefsDataExport": "CHEFS 데이터 내보내기", + "preparingForDownloading": "다운로드 준비 중...", + "downloadInfoA": "파일이 자동으로 다운로드되지 않는 경우", + "downloadInfoB": "다시 시도하려면 여기를 클릭하세요." + }, + "history": { + "submissnHistory": "귀하의 제출 내역(미정)" + }, + "error": { + "logout": "로그 아웃", + "somethingWentWrong": "오류: 문제가 발생했습니다... :(" + }, + "login": { + "authenticateWith": "인증:", + "alreadyLoggedIn": "이미 로그인", + "home": "집", + "about": "에 대한" + }, + "notFound": { + "about": "에 대한", + "pageNotFound": "404 페이지를 찾을 수 없습니다. :(" + }, + "store": { + "admin": { + "addFormOwnerRole": "이 양식의 소유자 역할을 {fullName}에 추가했습니다.", + "addRowError": "역할을 추가하는 동안 오류가 발생했습니다.", + "addRowConsoleErr": "사용자 {userId}을(를) 양식 {formId}에 추가하는 중 오류 발생: {error}", + "apiKeyDelMsg": "이 양식의 API 키가 삭제되었습니다.", + "errDeletingApiKey": "API 키를 삭제하는 중에 오류가 발생했습니다.", + "consErrDeletingApiKey": "양식 {formId}에 대한 API 키 삭제 오류: {error}", + "fecthingFormsErrMsg": "양식을 가져오는 동안 오류가 발생했습니다.", + "fecthingFormsConsErrMsg": "관리 양식 데이터 가져오기 오류: {error}", + "fecthingFormErrMsg": "이 양식을 가져오는 동안 오류가 발생했습니다.", + "fecthingFormConsErrMsg": "관리 양식 {formId} 데이터 가져오기 오류: {error}", + "fecthFormUserRolesErrMsg": "양식 사용자 역할을 가져오는 동안 오류가 발생했습니다.", + "fecthFormUserRolesConsErrMsg": "관리자 역할 데이터 가져오기 오류: {error}", + "fecthApiDetailsErrMsg": "이 양식의 API 세부정보를 가져오는 중에 오류가 발생했습니다.", + "fecthApiDetailsConsErrMsg": "양식 {formId} 데이터에서 관리 API 세부정보를 가져오는 중 오류 발생: {error}", + "restoreFormErrMsg": "이 양식을 복원하는 동안 오류가 발생했습니다.", + "restoreFormConsErrMsg": "양식 {formId} 데이터 복원 오류: {error}", + "getUsersErrMsg": "사용자를 가져오는 중에 오류가 발생했습니다.", + "getUsersConsErrMsg": "관리 사용자 데이터를 가져오는 중 오류 발생: {error}", + "getUserErrMsg": "이 사용자를 가져오는 중에 오류가 발생했습니다.", + "getUserConsErrMsg": "관리 사용자 {userId} 데이터를 가져오는 중 오류 발생: {error}", + "storingFCHelpInfoErrMsg": "양식 구성 요소 도움말 정보를 저장하는 동안 오류가 발생했습니다.", + "storingFCHelpInfoConsErrMsg": "양식 구성요소 도움말 정보를 저장하는 중 오류 발생: {error}", + "gettingFCImgUrlErrMsg": "이미지 URL을 가져오는 중에 오류가 발생했습니다.", + "gettingFCImgUrlConsErrMsg": "이미지 URL 가져오기 오류: {error}", + "updatingFCStatusErrMsg": "게시 상태를 업데이트하는 동안 오류가 발생했습니다.", + "updatingFCStatusConsErrMsg": "게시 상태 업데이트 오류: {error}", + "fecthingFormBuilderCompsErrMsg": "양식 작성기 구성 요소를 가져오는 동안 오류가 발생했습니다.", + "fecthingFormBuilderCompsConsErrMsg": "양식 작성기 구성요소 가져오기 오류: {error}" + }, + "form": { + "fetchEmailTemplatesConsErrMsg": "{formId}에 대한 이메일 템플릿을 로드하는 중에 오류가 발생했습니다. {error}", + "fetchEmailTemplatesErrMsg": "이 양식에 대한 이메일 템플릿을 가져오는 중 오류가 발생했습니다.", + "getCurrUserFormsErrMsg": "양식을 가져오는 동안 오류가 발생했습니다.", + "getCurrUserFormsConsErrMsg": "사용자 데이터 가져오기 오류: {error}", + "getUserFormPermErrMsg": "이 양식에 대한 사용자 데이터를 가져오는 동안 오류가 발생했습니다.", + "getUserFormPermConsErrMsg": "formID {formId}를 사용하여 사용자 데이터를 가져오는 중 오류 발생: {error}", + "getUserFormRolesErrmsg": "이 양식에 대한 사용자 데이터를 가져오는 동안 오류가 발생했습니다.", + "getUserFormRolesConsErrmsg": "formID {formId}를 사용하여 사용자 데이터를 가져오는 중 오류 발생: {error}", + "updCurrUserFormPrefErrMsg": "이 양식에 대한 기본 설정을 저장하는 동안 오류가 발생했습니다.", + "updCurrUserFormPrefConsErrMsg": "formID {formId} 및 기본 설정 {preferences}을(를) 사용하여 사용자 양식 환경 설정을 업데이트하는 중 오류 발생: {error}", + "getCurrUserFormPrefErrMsg": "이 양식에 대한 기본 설정을 가져오는 동안 오류가 발생했습니다.", + "getCurrUserFormPrefConsErrMsg": "formID {formId}를 사용하여 사용자 양식 환경 설정을 가져오는 중 오류 발생: {error}", + "delCurrformNotiMsg": "{name} 양식이 성공적으로 삭제되었습니다.", + "delCurrFormConsErMsg": "양식 {id} 삭제 오류: {error}", + "delDraftErrMsg": "초안을 삭제하는 중에 오류가 발생했습니다.", + "delDraftConsErrMsg": "{draftId} 삭제 오류: {error}", + "fecthDraftErrMsg": "이 양식의 초안을 스캔하는 동안 오류가 발생했습니다.", + "fecthDraftConsErrMsg": "양식 {formId}에 대한 초안 가져오기 오류: {error}", + "fecthFormErrMsg": "이 양식을 가져오는 동안 오류가 발생했습니다.", + "fecthFormConsErrMsg": "양식 {formId} 가져오기 오류: {error}", + "fetchFormFieldsErrMsg": "이 양식의 필드 목록을 가져오는 동안 오류가 발생했습니다.", + "fetchFormFieldsConsErrMsg": "양식 {formId} 가져오기 오류: {error}", + "publishDraftErrMsg": "게시하는 동안 오류가 발생했습니다.", + "publishDraftConsErrMsg": "{draftId} 게시 오류: {error}", + "toggleVersnPublConsErrMsg": "toggleVersionPublish {versionId} {publish} 오류: {error}", + "updateEmailTemplateConsErrMsg": "{formId} 양식의 이메일 템플릿을 업데이트하는 중에 오류가 발생했습니다. {error}", + "updateEmailTemplateErrMsg": "이 양식의 이메일 템플릿을 업데이트하는 동안 오류가 발생했습니다.", + "updateFormErrMsg": "이 양식의 설정을 업데이트하는 동안 오류가 발생했습니다.", + "updateFormConsErrMsg": "양식 {id} 업데이트 오류: {error}", + "deleteSubmissionNotifyMsg": "제출이 성공적으로 삭제되었습니다.", + "deleteSubmissionErrMsg": "이 제출을 삭제하는 동안 오류가 발생했습니다.", + "deleteSubmissionConsErrMsg": "제출물 {submissionId} 삭제 오류: {error}", + "deleteSubmissionsNotifyMsg": "제출이 성공적으로 삭제되었습니다.", + "deleteSubmissionsErrMsg": "선택한 제출물을 삭제하는 동안 오류가 발생했습니다.", + "deleteSubmissionsConsErrMsg": "제출물 삭제 오류: {error}", + "restoreSubmissionsNotiMsg": "제출물이 성공적으로 복원되었습니다.", + "restoreSubmissionsErrMsg": "이 제출을 복원하는 동안 오류가 발생했습니다.", + "restoreSubmissionsConsErrMsg": "제출 복원 오류: {error}", + "restoreSubmissionNotiMsg": "제출이 성공적으로 복원되었습니다.", + "restoreSubmissionErrMsg": "이 제출을 복원하는 동안 오류가 발생했습니다.", + "restoreSubmissionConsErrMsg": "제출물 {submissionId} 복원 오류: {error}", + "fecthSubmissnUsersErrMsg": "이 제출물에 대한 수신자 이메일을 가져오는 동안 오류가 발생했습니다.", + "fecthSubmissnUsersConsErrMsg": "제출 {formSubmissionId}에 대한 수신자 이메일 가져오기 오류: {error}", + "fetchSubmissnErrMsg": "이 제출물을 가져오는 동안 오류가 발생했습니다.", + "fetchSubmissnConsErrMsg": "제출물 {submissionId} 가져오기 오류: {error}", + "fetchFormCSVExptFieldsErrMsg": "이 양식의 필드 목록을 가져오는 동안 오류가 발생했습니다.", + "fetchFormCSVExptFieldsConsErrMsg": "양식 {formId} 가져오기 오류: {error}", + "fetchSubmissnsErrMsg": "이 양식에 대한 제출물을 가져오는 동안 오류가 발생했습니다.", + "fetchSubmissnsConsErrMsg": "{formId}에 대한 제출물 가져오기 오류: {error}", + "fetchVersionErrMsg": "이 양식을 가져오는 동안 오류가 발생했습니다.", + "fetchVersionConsErrMsg": "{formId} 양식의 {versionId} 버전 가져오기 오류: {error}", + "deleteApiKeyNotifyMsg": "이 양식의 API 키가 삭제되었습니다.", + "deleteApiKeyErrMsg": "API 키를 삭제하는 중에 오류가 발생했습니다.", + "deleteApiKeyConsErrMsg": "양식 {formId}에 대한 API 키 삭제 오류: {error}", + "generateApiKeyNotifyMsg": "이 양식에 대한 API 키가 생성되었습니다.", + "generateApiKeyErrMsg": "API 키를 생성하는 중에 오류가 발생했습니다.", + "generateApiKeyConsErrMsg": "양식 {formId}에 대한 API 키 생성 오류: {error}", + "readApiKeyErrMsg": "API 키를 가져오는 중에 오류가 발생했습니다.", + "readApiKeyConsErrMsg": "양식 {formId}에 대한 API 키를 가져오는 중에 오류가 발생했습니다: {error}.", + "getFCPHImageUrlErrMsg": "이미지 URL을 가져오는 중에 오류가 발생했습니다.", + "getFCPHImageUrlConsErrMsg": "이미지 URL 가져오기 오류: {error}", + "listFCPHErrMsg": "양식 작성기 구성 요소를 가져오는 동안 오류가 발생했습니다.", + "listFCPHConsErrMsg": "양식 작성기 구성요소 가져오기 오류: {error}", + "downloadFileErrMsg": "파일을 다운로드하는 동안 오류가 발생했습니다", + "downloadFileConsErrMsg": "파일 다운로드 오류: 오류", + "readSubscriptionSettingsErrMsg": "구독 설정을 가져오는 중에 오류가 발생했습니다.", + "readSubscriptionSettingsConsErrMsg": "양식 {formId}에 대한 구독 설정을 가져오는 중에 오류가 발생했습니다: {error}.", + "saveSubscriptionSettingsNotifyMsg": "이 양식에 대한 구독 설정이 저장되었습니다.", + "saveSubscriptionSettingsErrMsg": "구독 설정을 저장하는 동안 오류가 발생했습니다.", + "saveSubscriptionSettingsConsErrMsg": "양식 {formId}에 대한 구독 설정 저장 오류: {error}" + } + }, + "admin": { + "root": { + "admin": "관리자" + }, + "form": { + "administerForm": "양식 관리" + }, + "user": { + "administerUser": "사용자 관리" + } + }, + "user": { + "root": { + "myForms": "내 양식", + "history": "역사", + "user": "사용자" + } + } +} diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/pa/index.js b/frontend/app/frontend/src/internationalization/trans/chefs/pa/index.js new file mode 100644 index 0000000..7d38c9d --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/pa/index.js @@ -0,0 +1,4 @@ +import pa from '~/internationalization/trans/chefs/pa/pa.json'; +export default { + trans: pa, +}; diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/pa/pa.json b/frontend/app/frontend/src/internationalization/trans/chefs/pa/pa.json new file mode 100644 index 0000000..04f6274 --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/pa/pa.json @@ -0,0 +1,995 @@ +{ + "date": { + "date": "yyyy-mm-dd" + }, + "emailManagement": { + "emailManagement": "ਈਮੇਲ ਪ੍ਰਬੰਧਨ", + "manageForm": "ਫਾਰਮ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ", + "submissionConfirmation": "ਸਪੁਰਦਗੀ ਦੀ ਪੁਸ਼ਟੀ" + }, + "emailTemplate": { + "body": "ਸਰੀਰ", + "save": "ਬਚਾਓ", + "saveEmailTemplateConsoleErrMsg": "ਫਾਰਮ {formId} ਲਈ ਈਮੇਲ ਟੈਮਪਲੇਟ ਅੱਪਡੇਟ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "saveEmailTemplateErrMsg": "ਈਮੇਲ ਟੈਮਪਲੇਟ ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦੇ ਸਮੇਂ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "subject": "ਵਿਸ਼ਾ", + "title": "ਸਿਰਲੇਖ", + "validBodyRequired": "ਕਿਰਪਾ ਕਰਕੇ ਈਮੇਲ ਲਈ ਇੱਕ ਮੁੱਖ ਭਾਗ ਦਾਖਲ ਕਰੋ", + "validSubjectRequired": "ਕਿਰਪਾ ਕਰਕੇ ਈਮੇਲ ਲਈ ਵਿਸ਼ਾ ਲਾਈਨ ਦਾਖਲ ਕਰੋ", + "validTitleRequired": "ਕਿਰਪਾ ਕਰਕੇ ਈਮੇਲ ਲਈ ਇੱਕ ਸਿਰਲੇਖ ਦਾਖਲ ਕਰੋ" + }, + "formsTable": { + "myForms": "ਮੇਰੇ ਫਾਰਮ", + "createNewForm": "ਇੱਕ ਨਵਾਂ ਫਾਰਮ ਬਣਾਓ", + "search": "ਖੋਜ", + "manage": "ਪ੍ਰਬੰਧ ਕਰਨਾ, ਕਾਬੂ ਕਰਨਾ", + "submissions": "ਬੇਨਤੀਆਂ", + "formTitle": "ਫਾਰਮ ਦਾ ਸਿਰਲੇਖ", + "viewForm": "ਫਾਰਮ ਦੇਖੋ", + "description": "ਵਰਣਨ", + "Description": "ਵਰਣਨ:", + "action": "ਕਾਰਵਾਈਆਂ", + "loadingText": "ਲੋਡ ਹੋ ਰਿਹਾ ਹੈ... ਕਿਰਪਾ ਕਰਕੇ ਉਡੀਕ ਕਰੋ" + }, + "preview": { + "preview": "ਝਲਕ", + "previewToolTip": "ਇਹ ਫਾਰਮ ਸੰਸਕਰਣ ਡਿਜ਼ਾਈਨ ਅਤੇ ਵਿਵਹਾਰ ਦਾ ਪੂਰਵਦਰਸ਼ਨ ਦਿਖਾਉਂਦਾ ਹੈ ਕਿਉਂਕਿ ਤੁਹਾਡੇ ਸਬਮਿਟਰ ਇਸਨੂੰ ਦੇਖਣਗੇ। ਤੁਸੀਂ ਇਸ ਪੰਨੇ ਤੋਂ ਫਾਰਮ ਜਮ੍ਹਾਂ ਨਹੀਂ ਕਰ ਸਕਦੇ।" + }, + "manageLayout": { + "manageForm": "ਫਾਰਮ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ" + }, + "shareForm": { + "shareForm": "ਫਾਰਮ ਸਾਂਝਾ ਕਰੋ", + "shareLink": "ਲਿੰਕ ਸਾਂਝਾ ਕਰੋ", + "copyQRCode": "ਹੇਠਾਂ ਦਿੱਤੇ ਲਿੰਕ ਨੂੰ ਕਾਪੀ ਕਰੋ ਜਾਂ QR ਕੋਡ ਡਾਊਨਲੋਡ ਕਰੋ।", + "warningMessage": "ਇਸ ਸਮੇਂ ਫਾਰਮ ਦਾ ਕੋਈ ਪ੍ਰਕਾਸ਼ਿਤ ਸੰਸਕਰਣ ਨਹੀਂ ਹੈ। ਹੇਠਾਂ ਦਿੱਤਾ ਲਿੰਕ ਉਦੋਂ ਤੱਕ ਪਹੁੰਚਯੋਗ ਨਹੀਂ ਹੋਵੇਗਾ ਜਦੋਂ ਤੱਕ ਇੱਕ ਸੰਸਕਰਣ ਪ੍ਰਕਾਸ਼ਿਤ ਨਹੀਂ ਹੁੰਦਾ।", + "openThisForm": "ਇਸ ਫਾਰਮ ਨੂੰ ਖੋਲ੍ਹੋ", + "downloadQRCode": "QR ਕੋਡ ਡਾਊਨਲੋਡ ਕਰੋ", + "close": "ਬੰਦ ਕਰੋ", + "copyURLToClipboard": "URL ਨੂੰ ਕਲਿੱਪਬੋਰਡ ਵਿੱਚ ਕਾਪੀ ਕਰੋ" + }, + "manageFormActions": { + "emailManagement": "ਈਮੇਲ ਪ੍ਰਬੰਧਨ", + "viewSubmissions": "ਬੇਨਤੀਆਂ ਦੇਖੋ", + "teamManagement": "ਟੀਮ ਪ੍ਰਬੰਧਨ", + "deleteForm": "ਫਾਰਮ ਮਿਟਾਓ", + "confirmDeletion": "ਮਿਟਾਉਣ ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ", + "deleteMessageA": "ਕੀ ਤੁਸੀਂ ਯਕੀਨਨ ਮਿਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ", + "deleteMessageB": "ਇਹ ਫਾਰਮ ਹੁਣ ਪਹੁੰਚਯੋਗ ਨਹੀਂ ਰਹੇਗਾ।", + "delete": "ਮਿਟਾਓ" + }, + "manageForm": { + "formSettings": "ਫਾਰਮ ਸੈਟਿੰਗਾਂ", + "apiKey": "ਆਪਿ ਕੁੰਜੀ", + "updated": "ਅੱਪਡੇਟ ਕੀਤਾ", + "created": "ਬਣਾਇਆ", + "formDesignHistory": "ਫਾਰਮ ਡਿਜ਼ਾਈਨ ਇਤਿਹਾਸ", + "totalVersions": "ਕੁੱਲ ਸੰਸਕਰਣ", + "status": "ਸਥਿਤੀ", + "update": "ਅੱਪਡੇਟ ਕਰੋ", + "cancel": "ਰੱਦ ਕਰੋ", + "eventSubscription": "د پیښې ګډون" + }, + "formSettings": { + "pressToAddMultiEmail": "ਕਈ ਈਮੇਲ ਪਤੇ ਜੋੜਨ ਲਈ ਐਂਟਰ ਜਾਂ ਸਪੇਸ ਦਬਾਓ", + "allowMultiDraft": "ਮਲਟੀਪਲ ਡਰਾਫਟ ਅੱਪਲੋਡ ਕਰਨ ਦਿਓ", + "formTitle": "ਫਾਰਮ ਦਾ ਸਿਰਲੇਖ", + "formDescription": "ਫਾਰਮ ਦਾ ਵੇਰਵਾ", + "formAccess": "ਫਾਰਮ ਪਹੁੰਚ", + "info": "ਜੇਕਰ ਤੁਸੀਂ ਇਸ ਫਾਰਮ ਦੀ ਵਰਤੋਂ ਆਮ ਲੋਕਾਂ ਤੋਂ ਆਮ ਲੋਕਾਂ ਦੀ ਦਿਲਚਸਪੀ ਵਾਲੇ ਵਿਸ਼ਿਆਂ 'ਤੇ ਜਾਣਕਾਰੀ ਇਕੱਠੀ ਕਰਨ ਲਈ ਕਰ ਰਹੇ ਹੋ, ਤਾਂ ਤੁਹਾਨੂੰ GCPE ਨਾਲ ਸੰਪਰਕ ਕਰਨ ਦੀ ਲੋੜ ਹੈ ਤਾਂ ਜੋ ਤੁਹਾਡੀ ਸ਼ਮੂਲੀਅਤ ਨੂੰ ਸੂਚੀਬੱਧ ਕੀਤਾ ਜਾ ਸਕੇ।", + "important": "ਮਹੱਤਵਪੂਰਨ", + "idimNotifyA": "ਤੁਹਾਨੂੰ ਈਮੇਲ ਦੁਆਰਾ ਪਛਾਣ ਜਾਣਕਾਰੀ ਪ੍ਰਬੰਧਨ (IDIM) ਟੀਮ ਨੂੰ ਸੂਚਿਤ ਕਰਨਾ ਚਾਹੀਦਾ ਹੈ", + "idimNotifyB": "ਤੁਹਾਡੇ ਫਾਰਮ ਜਮ੍ਹਾਂ ਕਰਨ ਵਾਲਿਆਂ ਦੀ ਪਛਾਣ ਦੀ ਪੁਸ਼ਟੀ ਕਰਨ ਲਈ BCeID ਦਾ ਲਾਭ ਲੈਣ ਦਾ ਤੁਹਾਡਾ ਇਰਾਦਾ।", + "referenceGuideA": "ਕਿਰਪਾ ਕਰਕੇ ਸਾਡਾ ਹਵਾਲਾ ਦਿਓ", + "referenceGuideB": "ਉਪਭੋਗਤਾ ਗਾਈਡ", + "referenceGuideC": "ਹੋਰ ਵੇਰਵਿਆਂ ਲਈ", + "specificTeamMembers": "ਖਾਸ ਟੀਮ ਦੇ ਮੈਂਬਰ", + "formFunctionality": "ਫਾਰਮ ਕਾਰਜਕੁਸ਼ਲਤਾ", + "formSubmissinScheduleMsg": "ਫਾਰਮ ਪ੍ਰਕਾਸ਼ਿਤ ਹੋਣ ਤੋਂ ਬਾਅਦ ਫਾਰਮ ਸਬਮਿਸ਼ਨ ਅਨੁਸੂਚੀ ਫਾਰਮ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਉਪਲਬਧ ਹੋਵੇਗੀ।", + "formSubmissionsSchedule": "ਫਾਰਮ ਸਬਮਿਸ਼ਨ ਅਨੁਸੂਚੀ", + "experimental": "ਪ੍ਰਯੋਗਾਤਮਕ", + "learnMore": "ਜਿਆਦਾ ਜਾਣੋ", + "afterSubmission": "ਸਬਮਿਸ਼ਨ ਤੋਂ ਬਾਅਦ", + "submissionConfirmation": "ਸਪੁਰਦਗੀ ਪੁਸ਼ਟੀ ਵੇਰਵੇ ਦਿਖਾਓ", + "theConfirmationID": "ਪੁਸ਼ਟੀ ID", + "infoB": "ਉਪਭੋਗਤਾ ਲਈ ਆਪਣੇ ਆਪ ਨੂੰ ਇੱਕ ਸਬਮਿਸ਼ਨ ਪੁਸ਼ਟੀਕਰਨ ਈਮੇਲ ਕਰਨ ਦਾ ਵਿਕਲਪ", + "loginRequired": "ਲੌਗ-ਇਨ ਦੀ ਲੋੜ ਹੈ", + "canSaveAndEditDraftLabel": "ਸਬਮਿਟਰ ਡਰਾਫਟ ਨੂੰ ਸੁਰੱਖਿਅਤ ਅਤੇ ਸੰਪਾਦਿਤ ਕਰ ਸਕਦੇ ਹਨ", + "canUpdateStatusAsReviewer": "ਸਮੀਖਿਅਕ ਇਸ ਫਾਰਮ ਦੀ ਸਥਿਤੀ ਨੂੰ ਅੱਪਡੇਟ ਕਰ ਸਕਦੇ ਹਨ (ਜਿਵੇਂ ਕਿ ਸਪੁਰਦ ਕੀਤਾ, ਨਿਰਧਾਰਤ ਕੀਤਾ, ਪੂਰਾ ਕੀਤਾ ਗਿਆ)", + "submitterCanCopyExistingSubmissn": "ਸਬਮਿਟਰ ਮੌਜੂਦਾ ਸਬਮਿਸ਼ਨ ਨੂੰ ਕਾਪੀ ਕਰ ਸਕਦੇ ਹਨ", + "submissionConfirmationToolTip": "ਇਸ ਵਿਕਲਪ ਨੂੰ ਚੁਣਨਾ ਨਿਯੰਤਰਿਤ ਕਰਦਾ ਹੈ ਕਿ ਇਸ ਫ਼ਾਰਮ ਦੇ ਸਪੁਰਦ ਕਰਨ ਵਾਲੇ ਉਪਭੋਗਤਾ ਸਫਲਤਾਪੂਰਵਕ ਸਪੁਰਦਗੀ 'ਤੇ ਕੀ ਵੇਖਣਗੇ।
ਜੇਕਰ ਜਾਂਚ ਕੀਤੀ ਜਾਂਦੀ ਹੈ, ਤਾਂ ਇਹ ਪ੍ਰਦਰਸ਼ਿਤ ਹੋਵੇਗਾ", + "emailNotificatnToTeam": "ਮੇਰੀ ਟੀਮ ਨੂੰ ਇੱਕ ਸੂਚਨਾ ਈਮੇਲ ਭੇਜੋ", + "emailNotificatnToTeamToolTip": "ਜਦੋਂ ਕੋਈ ਉਪਭੋਗਤਾ ਇਸ ਫਾਰਮ ਨੂੰ ਸਪੁਰਦ ਕਰਦਾ ਹੈ ਤਾਂ ਆਪਣੇ ਨਿਸ਼ਚਿਤ ਈਮੇਲ ਪਤੇ 'ਤੇ ਇੱਕ ਸੂਚਨਾ ਭੇਜੋ", + "notificationEmailAddrs": "ਸੂਚਨਾ ਈਮੇਲ ਪਤੇ", + "addMoreValidEmailAddrs": "ਇੱਕ ਜਾਂ ਇੱਕ ਤੋਂ ਵੱਧ ਵੈਧ ਈਮੇਲ ਪਤੇ ਸ਼ਾਮਲ ਕਰੋ", + "formScheduleSettings": "ਫਾਰਮ ਅਨੁਸੂਚੀ ਸੈਟਿੰਗਾਂ", + "opensubmissions": "ਸਪੁਰਦਗੀ ਖੋਲ੍ਹੋ", + "submissionsDeadline": "ਤੁਸੀਂ ਕਿੰਨੀ ਦੇਰ ਤੱਕ ਬੇਨਤੀਆਂ ਪ੍ਰਾਪਤ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?", + "keepSubmissnOpenTilUnplished": "ਹੱਥੀਂ ਅਪ੍ਰਕਾਸ਼ਿਤ ਹੋਣ ਤੱਕ ਖੁੱਲ੍ਹਾ ਰੱਖੋ", + "submissionsClosingDate": "ਇੱਕ ਸਮਾਪਤੀ ਮਿਤੀ ਤਹਿ ਕਰੋ", + "submissionPeriod": "ਸਪੁਰਦਗੀ ਦੀ ਮਿਆਦ ਸੈੱਟ ਕਰੋ", + "closeSubmissions": "ਸਬਮਿਸ਼ਨ ਬੰਦ ਕਰੋ", + "keepOpenFor": "ਲਈ ਖੁੱਲ੍ਹਾ ਰੱਖੋ", + "period": "ਮਿਆਦ", + "allowLateSubmissions": "ਦੇਰ ਨਾਲ ਸਬਮਿਸ਼ਨ ਦੀ ਆਗਿਆ ਦਿਓ", + "allowLateSubmissionsInfoTip": "ਜੇਕਰ ਜਾਂਚ ਕੀਤੀ ਜਾਂਦੀ ਹੈ, ਤਾਂ ਸਬਮਿਟਰ ਸਮਾਪਤੀ ਮਿਤੀ ਤੋਂ ਬਾਅਦ ਡਾਟਾ ਸਪੁਰਦ ਕਰਨ ਦੇ ਯੋਗ ਹੋਣਗੇ।", + "afterCloseDateFor": "ਲਈ ਬੰਦ ਮਿਤੀ ਦੇ ਬਾਅਦ", + "repeatPeriod": "ਮਿਆਦ ਨੂੰ ਦੁਹਰਾਓ", + "every": "ਹਰ", + "repeatUntil": "ਤੱਕ ਦੁਹਰਾਓ", + "summary": "ਸੰਖੇਪ", + "submissionsOpenDateRange": "ਇਹ ਫਾਰਮ ਸਬਮਿਸ਼ਨ ਲਈ ਖੁੱਲ੍ਹਾ ਹੋਵੇਗਾ", + "to": "ਨੂੰ", + "scheduleRepetition": "ਅਨੁਸੂਚੀ ਹਰ ਵਾਰ ਦੁਹਰਾਈ ਜਾਵੇਗੀ", + "allowLateSubmissnInterval": "ਲਈ ਦੇਰ ਨਾਲ ਸਬਮਿਸ਼ਨ ਦੀ ਇਜਾਜ਼ਤ ਦੇ ਰਿਹਾ ਹੈ", + "until": "ਜਦ ਤੱਕ", + "datesOfSubmissnInfo": "ਸੈਟਿੰਗਾਂ ਦੇ ਅਨੁਸਾਰ ਇਹ ਸਬਮਿਸ਼ਨ ਦੀਆਂ ਉਪਲਬਧ ਤਾਰੀਖਾਂ ਹਨ:", + "formOpenInterval": "ਇਹ ਫਾਰਮ ਸਬਮਿਸ਼ਨ ਲਈ ਖੁੱਲ੍ਹਾ ਹੋਵੇਗਾ", + "allowDateSubmissionDate": "ਤੱਕ ਦੇਰ ਨਾਲ ਪੇਸ਼ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਦੇ ਨਾਲ", + "customClosingMessage": "ਕਸਟਮ ਕਲੋਜ਼ਿੰਗ ਸੁਨੇਹਾ ਸੈੱਟ ਕਰੋ", + "customClosingMessageToolTip": "ਤੁਹਾਨੂੰ ਤੁਹਾਡੇ ਉਪਭੋਗਤਾਵਾਂ ਲਈ ਇੱਕ ਅਨੁਕੂਲਿਤ ਸੁਨੇਹਾ ਜੋੜਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿੰਦਾ ਹੈ ਜਦੋਂ ਉਹ ਇੱਕ ਬੰਦ ਫਾਰਮ 'ਤੇ ਜਾਂਦੇ ਹਨ।", + "closingMessage": "ਸਮਾਪਤੀ ਸੁਨੇਹਾ", + "sendReminderEmail": "ਰੀਮਾਈਂਡਰ ਈਮੇਲ ਭੇਜੋ", + "autoReminderNotificatn": "ਆਟੋਮੈਟਿਕ ਰੀਮਾਈਂਡਰ ਸੂਚਨਾ ਨੂੰ ਸਮਰੱਥ ਬਣਾਓ", + "autoReminderNotificatnToolTip": "ਸਪੁਰਦਗੀ ਦੀ ਮਿਆਦ ਦੇ ਦੌਰਾਨ ਫਾਰਮ ਲਿੰਕ ਦੇ ਨਾਲ ਰੀਮਾਈਂਡਰ ਈਮੇਲ ਭੇਜੋ।", + "selectLoginType": "ਕਿਰਪਾ ਕਰਕੇ 1 ਲੌਗ-ਇਨ ਕਿਸਮ ਚੁਣੋ", + "formDescriptnMaxChars": "ਫਾਰਮ ਵਰਣਨ 255 ਅੱਖਰ ਜਾਂ ਘੱਟ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ", + "formTitlemaxChars": "ਫਾਰਮ ਦਾ ਸਿਰਲੇਖ 255 ਅੱਖਰ ਜਾਂ ਘੱਟ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ", + "formTitleReq": "ਫਾਰਮ ਦਾ ਸਿਰਲੇਖ ਲੋੜੀਂਦਾ ਹੈ", + "atLeastOneEmailReq": "ਕਿਰਪਾ ਕਰਕੇ ਘੱਟੋ-ਘੱਟ 1 ਈਮੇਲ ਪਤਾ ਦਾਖਲ ਕਰੋ", + "validEmailRequired": "ਕਿਰਪਾ ਕਰਕੇ ਸਾਰੇ ਵੈਧ ਈਮੇਲ ਪਤੇ ਦਾਖਲ ਕਰੋ", + "fieldRequired": "ਇਸ ਫੀਲਡ ਦੀ ਲੋੜ ਹੈ.", + "correctDateFormat": "ਮਿਤੀ ਸਹੀ ਫਾਰਮੈਟ ਵਿੱਚ ਹੋਣੀ ਚਾਹੀਦੀ ਹੈ। ਭਾਵ yyyy-mm-dd", + "dateDiffMsg": "ਬੰਦ ਸਪੁਰਦਗੀ ਦੀ ਮਿਤੀ ਖੁੱਲ੍ਹੀ ਜਮ੍ਹਾਂ ਮਿਤੀ ਤੋਂ ਵੱਧ ਹੋਣੀ ਚਾਹੀਦੀ ਹੈ।", + "valueMustBeNumber": "ਮੁੱਲ ਇੱਕ ਨੰਬਰ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ। ਭਾਵ 1,2,3,5,99", + "selectAnOptions": "ਕਿਰਪਾ ਕਰਕੇ ਘੱਟੋ-ਘੱਟ 1 ਵਿਕਲਪ ਚੁਣੋ", + "validInterval": "ਇਹ ਇੱਕ ਵੈਧ ਅੰਤਰਾਲ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ।", + "fieldRequiredAndInterval": "ਇਹ ਖੇਤਰ ਲੋੜੀਂਦਾ ਹੈ ਅਤੇ ਇੱਕ ਅੰਤਰਾਲ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ।", + "dateGrtOpenSubmissnDate": "ਉਦੋਂ ਤੱਕ ਦੁਹਰਾਓ ਜਦੋਂ ਤੱਕ ਮਿਤੀ ਖੁੱਲੀ ਸਪੁਰਦਗੀ ਮਿਤੀ ਤੋਂ ਵੱਧ ਨਹੀਂ ਹੋਣੀ ਚਾਹੀਦੀ", + "public": "ਜਨਤਕ (ਅਗਿਆਤ)", + "allowEventSubscription": "د پیښې ګډون ته اجازه ورکړئ", + "eventSubscription": "د پیښې ګډون", + "validEndpointRequired": "مهرباني وکړئ یو معتبر پای ټکی دننه کړئ چې پیل کیږي https://", + "validBearerTokenRequired": "89abddfb-2cff-4fda-83e6-13221f0c3d4f د اعتبار وړ وړونکي نښه مثال داخل کړئ" + }, + "subscribeEvent": { + "eventType": "د پیښې ډول", + "endpointUrl": "د پای ټکی URL", + "eventSubmission": "سپارل", + "eventAssignment": "دنده", + "eventStatusChange": "د وضعیت بدلون", + "endpointToken": "د پای ټکی نښه", + "urlPlaceholder": "https://endpoint.gov.bc.ca/api/v1/", + "save": "ਸੇਵ ਕਰੋ", + "text": "ਟੈਕਸਟ", + "password": "ਪਾਸਵਰਡ", + "hideSecret": "ਗੁਪਤ ਲੁਕਾਓ", + "showSecret": "ਗੁਪਤ ਦਿਖਾਓ", + "key": "ਕੁੰਜੀ", + "saveSettingsErrMsg": "ਇਸ ਫਾਰਮ ਲਈ ਸੈਟਿੰਗਾਂ ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦੇ ਸਮੇਂ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "updateSettingsConsoleErrMsg": "ਫਾਰਮ {formId} ਲਈ ਸੈਟਿੰਗਾਂ ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}" + }, + "apiKey": { + "disclaimer": "ਬੇਦਾਅਵਾ", + "infoA": "ਯਕੀਨੀ ਬਣਾਓ ਕਿ ਤੁਹਾਡੀ API ਕੁੰਜੀ ਗੁਪਤ ਇੱਕ ਸੁਰੱਖਿਅਤ ਸਥਾਨ (ਜਿਵੇਂ ਕਿ ਕੁੰਜੀ ਵਾਲਟ) ਵਿੱਚ ਸਟੋਰ ਕੀਤੀ ਗਈ ਹੈ।", + "infoB": "ਤੁਹਾਡੀ API ਕੁੰਜੀ ਤੁਹਾਡੇ ਫਾਰਮ ਤੱਕ ਅਪ੍ਰਬੰਧਿਤ ਪਹੁੰਚ ਪ੍ਰਦਾਨ ਕਰਦੀ ਹੈ। ਆਪਣੀ API ਕੁੰਜੀ ਕਿਸੇ ਨੂੰ ਨਾ ਦਿਓ।", + "infoC": "API ਕੁੰਜੀ ਦੀ ਵਰਤੋਂ ਸਿਰਫ਼ ਆਟੋਮੇਟਿਡ ਸਿਸਟਮ ਪਰਸਪਰ ਕ੍ਰਿਆਵਾਂ ਲਈ ਕੀਤੀ ਜਾਣੀ ਚਾਹੀਦੀ ਹੈ। ਉਪਭੋਗਤਾ ਅਧਾਰਤ ਪਹੁੰਚ ਲਈ ਆਪਣੀ API ਕੁੰਜੀ ਦੀ ਵਰਤੋਂ ਨਾ ਕਰੋ", + "deleteKey": "ਕੁੰਜੀ ਮਿਟਾਓ", + "apiKey": "api ਕੁੰਜੀ", + "hideSecret": "ਗੁਪਤ ਲੁਕਾਓ", + "showSecret": "ਗੁਪਤ ਦਿਖਾਓ", + "sCTC": "ਗੁਪਤ ਕਲਿੱਪਬੋਰਡ 'ਤੇ ਕਾਪੀ ਕੀਤਾ ਗਿਆ", + "cSTC": "ਗੁਪਤ ਨੂੰ ਕਲਿੱਪਬੋਰਡ ਵਿੱਚ ਕਾਪੀ ਕਰੋ", + "key": "ਕੁੰਜੀ", + "confirmDeletion": "ਮਿਟਾਉਣ ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ", + "deleteMsg": "ਕੀ ਤੁਸੀਂ ਯਕੀਨੀ ਤੌਰ 'ਤੇ ਆਪਣੀ API ਕੁੰਜੀ ਨੂੰ ਮਿਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ?", + "delete": "ਮਿਟਾਓ", + "confirmKeyGen": "ਕੁੰਜੀ ਜਨਰੇਸ਼ਨ ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ", + "createAPIKey": "ਕੀ ਇਸ ਫਾਰਮ ਲਈ ਇੱਕ API ਕੁੰਜੀ ਬਣਾਉਣਾ ਹੈ?
ਯਕੀਨੀ ਬਣਾਓ ਕਿ ਤੁਸੀਂ ਇਸ ਪੰਨੇ 'ਤੇ ਬੇਦਾਅਵਾ ਦੀ ਪਾਲਣਾ ਕਰਦੇ ਹੋ।", + "regenerateAPIKey": "ਕੀ API ਕੁੰਜੀ ਨੂੰ ਮੁੜ-ਬਣਾਉਣਾ ਹੈ?
ਜਾਰੀ ਰੱਖਣ ਨਾਲ ਤੁਹਾਡੀ ਮੌਜੂਦਾ API ਕੁੰਜੀ ਪਹੁੰਚ ਮਿਟਾ ਦਿੱਤੀ ਜਾਵੇਗੀ ।", + "formOwnerKeyAcess": "API ਕੁੰਜੀਆਂ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਲਈ ਤੁਹਾਨੂੰ ਫਾਰਮ ਦਾ ਮਾਲਕ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ।", + "regenerate": "ਪੁਨਰਜਨਮ", + "generate": "ਪੈਦਾ ਕਰੋ", + "secret": "ਗੁਪਤ" + }, + "manageVersions": { + "important": "ਮਹੱਤਵਪੂਰਨ!", + "infoA": "ਜੇਕਰ ਕੋਈ ਪ੍ਰਕਾਸ਼ਿਤ ਸੰਸਕਰਣ ਨਹੀਂ ਹਨ, ਤਾਂ ਉਪਭੋਗਤਾ ਇਸ ਫਾਰਮ ਤੱਕ ਪਹੁੰਚਣ ਵਿੱਚ ਅਸਮਰੱਥ ਹਨ ਜਦੋਂ ਤੱਕ ਪ੍ਰਕਾਸ਼ਿਤ ਸੰਸਕਰਣ ਨਿਰਧਾਰਤ ਨਹੀਂ ਕੀਤਾ ਜਾਂਦਾ ਹੈ। ਇੱਕ ਵਾਰ ਇੱਕ ਸੰਸਕਰਣ ਪ੍ਰਕਾਸ਼ਿਤ ਹੋਣ ਤੋਂ ਬਾਅਦ, ਉਹ ਸੰਸਕਰਣ ਹੁਣ ਸੰਪਾਦਨਯੋਗ ਨਹੀਂ ਰਹੇਗਾ। ਸੰਪਾਦਨ ਜਾਰੀ ਰੱਖਣ ਲਈ ਤੁਹਾਨੂੰ ਪਿਛਲੇ ਫਾਰਮ ਸੰਸਕਰਣਾਂ ਵਿੱਚੋਂ ਇੱਕ ਦੇ ਆਧਾਰ 'ਤੇ ਇੱਕ ਨਵਾਂ ਸੰਸਕਰਣ ਬਣਾਉਣਾ ਚਾਹੀਦਾ ਹੈ।", + "infoB": "ਨੋਟ: ਕੇਵਲ ਇੱਕ ਸੰਸਕਰਣ ਪ੍ਰਕਾਸ਼ਿਤ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ।", + "version": "ਸੰਸਕਰਣ", + "draft": "ਡਰਾਫਟ", + "clickToPreview": "ਪ੍ਰੀਵਿਊ ਕਰਨ ਲਈ ਕਲਿੱਕ ਕਰੋ", + "editVersion": "ਸੰਸਕਰਣ ਦਾ ਸੰਪਾਦਨ ਕਰੋ", + "exportDesign": "ਨਿਰਯਾਤ ਡਿਜ਼ਾਈਨ", + "infoC": "ਕਿਰਪਾ ਕਰਕੇ ਨਵਾਂ ਸੰਸਕਰਣ ਸ਼ੁਰੂ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਆਪਣੇ ਨਵੀਨਤਮ ਡਰਾਫਟ ਸੰਸਕਰਣ ਨੂੰ ਪ੍ਰਕਾਸ਼ਿਤ ਕਰੋ ਜਾਂ ਮਿਟਾਓ।", + "deleteVersion": "ਸੰਸਕਰਣ ਮਿਟਾਓ", + "draftAlreadyExists": "ਡਰਾਫਟ ਪਹਿਲਾਂ ਹੀ ਮੌਜੂਦ ਹੈ", + "infoD": "ਕਿਰਪਾ ਕਰਕੇ ਨਵਾਂ ਡਰਾਫਟ ਸ਼ੁਰੂ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਮੌਜੂਦਾ ਡਰਾਫਟ ਨੂੰ ਸੰਪਾਦਿਤ ਕਰੋ, ਪ੍ਰਕਾਸ਼ਿਤ ਕਰੋ ਜਾਂ ਮਿਟਾਓ।", + "publishVersion": "ਸੰਸਕਰਣ ਪ੍ਰਕਾਸ਼ਿਤ ਕਰੋ", + "unpublishVersion": "ਸੰਸਕਰਣ ਨੂੰ ਅਣਪ੍ਰਕਾਸ਼ਿਤ ਕਰੋ", + "infoE": "ਇਸ ਫ਼ਾਰਮ ਨੂੰ ਅਪ੍ਰਕਾਸ਼ਿਤ ਕਰਨ ਨਾਲ ਫ਼ਾਰਮ ਸਰਕੂਲੇਸ਼ਨ ਤੋਂ ਬਾਹਰ ਹੋ ਜਾਵੇਗਾ ਜਦੋਂ ਤੱਕ ਇੱਕ ਸੰਸਕਰਣ ਦੁਬਾਰਾ ਪ੍ਰਕਾਸ਼ਿਤ ਨਹੀਂ ਹੁੰਦਾ।", + "confirmDeletion": "ਮਿਟਾਉਣ ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ", + "infoF": "ਕੀ ਤੁਸੀਂ ਯਕੀਨੀ ਤੌਰ 'ਤੇ ਇਸ ਸੰਸਕਰਣ ਨੂੰ ਮਿਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ?", + "delete": "ਮਿਟਾਓ", + "status": "ਸਥਿਤੀ", + "dateCreated": "ਬਣਾਉਣ ਦੀ ਮਿਤੀ", + "createdBy": "ਦੁਆਰਾ ਬਣਾਇਆ ਗਿਆ", + "actions": "ਕਾਰਵਾਈਆਂ", + "published": "ਪ੍ਰਕਾਸ਼ਿਤ", + "unpublished": "ਅਪ੍ਰਕਾਸ਼ਿਤ", + "useVersionInfo": "ਨਵੇਂ ਸੰਸਕਰਣ ਲਈ ਆਧਾਰ ਵਜੋਂ ਵਰਜਨ {version} ਦੀ ਵਰਤੋਂ ਕਰੋ", + "publishingVersionInfo": "ਇਹ ਤੁਹਾਡੇ ਫਾਰਮ ਦੇ ਸੰਸਕਰਣ {version} ਨੂੰ ਲਾਈਵ ਬਣਾ ਦੇਵੇਗਾ।" + }, + "addOwner": { + "infoA": "ਇਹ ਸਿਰਫ਼ ਉਸ ਸਥਿਤੀ ਵਿੱਚ ਕੀਤਾ ਜਾਣਾ ਚਾਹੀਦਾ ਹੈ ਜਦੋਂ ਮੌਜੂਦਾ ਫਾਰਮ ਮਾਲਕ ਹੁਣ ਕਿਰਿਆਸ਼ੀਲ ਨਹੀਂ ਹੈ ਜਾਂ ਕਿਸੇ ਤਰਜੀਹੀ ਘਟਨਾ ਵਿੱਚ ਸੰਪਰਕ ਤੋਂ ਬਾਹਰ ਹੈ। ਨਹੀਂ ਤਾਂ ਫਾਰਮ ਲਈ ਮੌਜੂਦਾ ਮਾਲਕ ਜਾਂ ਟੀਮ ਪ੍ਰਸ਼ਾਸਕ ਨੂੰ ਇਹ ਖੁਦ ਕਰਨ ਲਈ ਕਹੋ।", + "hint": "ਲੋੜੀਂਦਾ ਉਪਭੋਗਤਾ ID ਲੱਭਣ ਲਈ ਤੁਸੀਂ ਐਡਮਿਨ ਪੋਰਟਲ ਵਿੱਚ 'USERS' ਟੈਬ 'ਤੇ ਜਾ ਸਕਦੇ ਹੋ ਅਤੇ ਉਹਨਾਂ ਦੀ ਖੋਜ ਕਰ ਸਕਦੇ ਹੋ।", + "addowner": "ਮਾਲਕ ਸ਼ਾਮਲ ਕਰੋ", + "label": "ਉਪਭੋਗਤਾ ID (ਗਾਈਡ)" + }, + "adminFormsTable": { + "showDeletedForms": "ਮਿਟਾਏ ਗਏ ਫਾਰਮ ਦਿਖਾਓ", + "search": "ਖੋਜ", + "loadingText": "ਲੋਡਿੰਗ-ਟੈਕਸਟ", + "noDataText": "ਤੁਹਾਡੇ ਸਿਸਟਮ ਵਿੱਚ ਕੋਈ ਫਾਰਮ ਨਹੀਂ ਹਨ", + "admin": "ਐਡਮਿਨ", + "launch": "ਲਾਂਚ ਕਰੋ", + "formTitle": "ਫਾਰਮ ਦਾ ਸਿਰਲੇਖ", + "created": "ਬਣਾਇਆ", + "deleted": "ਮਿਟਾਇਆ ਗਿਆ", + "actions": "ਕਾਰਵਾਈਆਂ", + "delete": "ਮਿਟਾਓ" + }, + "administerForm": { + "deleted": "ਮਿਟਾਇਆ ਗਿਆ", + "restoreForm": "ਇਸ ਫਾਰਮ ਨੂੰ ਰੀਸਟੋਰ ਕਰੋ", + "formDetails": "ਫਾਰਮ ਵੇਰਵੇ", + "apiKeyDetails": "API ਮੁੱਖ ਵੇਰਵੇ", + "deleteApiKey": "API ਕੁੰਜੀ ਮਿਟਾਓ", + "formUsers": "ਫਾਰਮ ਉਪਭੋਗਤਾ", + "formVersions": "ਫਾਰਮ ਸੰਸਕਰਣ", + "assignANewOwner": "ਇੱਕ ਨਵਾਂ ਮਾਲਕ ਨਿਰਧਾਰਤ ਕਰੋ", + "restoring": "ਬਹਾਲ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ", + "restore": "ਰੀਸਟੋਰ ਕਰੋ", + "toActiveState": "ਸਰਗਰਮ ਰਾਜ ਨੂੰ", + "confirmDeletion": "ਮਿਟਾਉਣ ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ", + "confirmDeletionMsg": "ਕੀ ਤੁਸੀਂ ਯਕੀਨੀ ਤੌਰ 'ਤੇ ਇਸ API ਕੁੰਜੀ ਨੂੰ ਮਿਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ?", + "delete": "ਮਿਟਾਓ", + "confirmRestore": "ਰੀਸਟੋਰ ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ" + }, + "administerUser": { + "userDetails": "ਉਪਭੋਗਤਾ ਵੇਰਵੇ", + "openSSOConsole": "SSO ਕੰਸੋਲ ਖੋਲ੍ਹੋ" + }, + "adminPage": { + "forms": "ਫਾਰਮ", + "users": "ਉਪਭੋਗਤਾ", + "developer": "ਵਿਕਾਸਕਾਰ", + "infoLinks": "ਜਾਣਕਾਰੀ ਲਿੰਕ", + "metrics": "ਮੈਟ੍ਰਿਕਸ" + }, + "adminUsersTable": { + "search": "ਖੋਜ", + "loadingText": "ਲੋਡ ਹੋ ਰਿਹਾ ਹੈ... ਕਿਰਪਾ ਕਰਕੇ ਉਡੀਕ ਕਰੋ", + "admin": "ਐਡਮਿਨ", + "fullName": "ਪੂਰਾ ਨਾਂਮ", + "userID": "ਯੂਜਰ ਆਈਡੀ", + "created": "ਬਣਾਇਆ", + "actions": "ਕਾਰਵਾਈਆਂ" + }, + "adminVersions": { + "exportDesign": "ਨਿਰਯਾਤ ਡਿਜ਼ਾਈਨ", + "versions": "ਸੰਸਕਰਣ", + "status": "ਸਥਿਤੀ", + "created": "ਬਣਾਇਆ", + "lastUpdated": "ਆਖਰੀ ਵਾਰ ਅੱਪਡੇਟ ਕੀਤਾ", + "actions": "ਕਾਰਵਾਈਆਂ", + "published": "ਪ੍ਰਕਾਸ਼ਿਤ", + "unpublished": "ਅਪ੍ਰਕਾਸ਼ਿਤ", + "version": "ਸੰਸਕਰਣ {versionNo}", + "notificationMsg": "ਫਾਰਮ ਡਿਜ਼ਾਈਨ ਨੂੰ ਲੋਡ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।" + }, + "developer": { + "user": "ਉਪਭੋਗਤਾ", + "name": "ਨਾਮ", + "userName": "ਉਪਭੋਗਤਾ ਨਾਮ", + "JWTContents": "JWT ਸਮੱਗਰੀ", + "JWTContentsSBTxt": "JWT ਸਮੱਗਰੀ ਕਲਿੱਪਬੋਰਡ 'ਤੇ ਕਾਪੀ ਕੀਤੀ ਗਈ", + "JWTContentsTTTxt": "JWT ਸਮੱਗਰੀ ਨੂੰ ਕਲਿੱਪਬੋਰਡ ਵਿੱਚ ਕਾਪੀ ਕਰੋ", + "JWTToken": "JWT ਟੋਕਨ", + "JWTTokenSBTxt": "JWT ਟੋਕਨ ਕਲਿੱਪਬੋਰਡ 'ਤੇ ਕਾਪੀ ਕੀਤਾ ਗਿਆ", + "JWTTokenTTTxt": "JWT ਟੋਕਨ ਨੂੰ ਕਲਿੱਪਬੋਰਡ ਵਿੱਚ ਕਾਪੀ ਕਰੋ", + "chefsAPI": "CHEFS API", + "RBACSBTxt": "RBAC ਜਵਾਬ ਕਲਿੱਪਬੋਰਡ 'ਤੇ ਕਾਪੀ ਕੀਤਾ ਗਿਆ", + "RBACTTTxt": "RBAC ਜਵਾਬ ਨੂੰ ਕਲਿੱਪਬੋਰਡ 'ਤੇ ਕਾਪੀ ਕਰੋ", + "notificationMsg": "RBAC ਤੋਂ ਉਪਭੋਗਤਾ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਅਸਫਲ, ਕੰਸੋਲ ਦੇਖੋ", + "notificationConsErr": "RBAC ਤੋਂ ਉਪਭੋਗਤਾ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ" + }, + "baseAuthButton": { + "logout": "ਲਾੱਗ ਆਊਟ, ਬਾਹਰ ਆਉਣਾ", + "login": "ਲਾਗਿਨ" + }, + "baseDialog": { + "defaultText": "ਡਿਫਾਲਟ ਟੈਕਸਟ", + "ok": "ਠੀਕ ਹੈ", + "continue": "ਜਾਰੀ ਰੱਖੋ", + "cancel": "ਰੱਦ ਕਰੋ", + "custom": "ਪ੍ਰਥਾ" + }, + "baseSecure": { + "about": "ਬਾਰੇ", + "loginInfo": "ਤੁਹਾਨੂੰ ਇਸ ਵਿਸ਼ੇਸ਼ਤਾ ਦੀ ਵਰਤੋਂ ਕਰਨ ਲਈ ਲੌਗਇਨ ਕਰਨਾ ਚਾਹੀਦਾ ਹੈ।", + "login": "ਲਾਗਿਨ", + "401NotAuthorized": "401: ਅਧਿਕਾਰਤ ਨਹੀਂ। :", + "401ErrorMsg": "ਤੁਹਾਡਾ ਖਾਤਾ ਸਹੀ ਢੰਗ ਨਾਲ ਸੈੱਟਅੱਪ ਨਹੀਂ ਕੀਤਾ ਗਿਆ ਹੈ।
ਕਿਰਪਾ ਕਰਕੇ ਸੰਪਰਕ ਕਰੋ", + "403Forbidden": "403: ਵਰਜਿਤ। :", + "403ErrorMsg": "ਇਸ ਪੰਨੇ ਨੂੰ {idp} ਪ੍ਰਮਾਣੀਕਰਨ ਦੀ ਲੋੜ ਹੈ।", + "401UnAuthorized": "401: ਅਣਅਧਿਕਾਰਤ। :", + "401UnAuthorizedErrMsg": "ਤੁਹਾਨੂੰ ਇਸ ਪੰਨੇ ਤੱਕ ਪਹੁੰਚ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ।" + }, + "formDesigner": { + "formDesign": "ਫਾਰਮ ਡਿਜ਼ਾਈਨ", + "exportDesign": "ਨਿਰਯਾਤ ਡਿਜ਼ਾਈਨ", + "importDesign": "ਡਿਜ਼ਾਈਨ ਆਯਾਤ ਕਰੋ", + "important": "ਮਹੱਤਵਪੂਰਨ", + "formDesignInfoA": "ਜਦੋਂ ਤੁਸੀਂ ਇਸ ਫਾਰਮ ਨੂੰ ਬਣਾਉਣਾ ਪੂਰਾ ਕਰ ਲੈਂਦੇ ਹੋ ਤਾਂ ਸੇਵ ਡਿਜ਼ਾਈਨ ਬਟਨ ਦੀ ਵਰਤੋਂ ਕਰੋ।", + "formDesignInfoB": "ਤੁਹਾਡੇ ਉਪਭੋਗਤਾ ਨੂੰ ਇਹ ਫਾਰਮ ਜਮ੍ਹਾਂ ਕਰਾਉਣ ਲਈ SUBMIT ਬਟਨ ਦਿੱਤਾ ਗਿਆ ਹੈ ਅਤੇ ਇਸਨੂੰ ਸੁਰੱਖਿਅਤ ਕਰਨ ਤੋਂ ਬਾਅਦ ਕਿਰਿਆਸ਼ੀਲ ਹੋ ਜਾਵੇਗਾ।", + "formLoadErrMsg": "ਫਾਰਮ ਡਿਜ਼ਾਈਨ ਨੂੰ ਲੋਡ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "formLoadConsoleErrMsg": "ਫਾਰਮ {formId} ਸਕੀਮਾ ਲੋਡ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ (ਵਰਜਨ: {versionId} ਡਰਾਫਟ: {draftId}): {error}", + "formSchemaImportErrMsg": "ਫਾਰਮ ਸਕੀਮਾ ਨੂੰ ਆਯਾਤ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "formSchemaImportConsoleErrMsg": "ਫਾਰਮ ਸਕੀਮਾ ਨੂੰ ਆਯਾਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ : {error}", + "formDesignSaveErrMsg": "ਇਸ ਫਾਰਮ ਡਿਜ਼ਾਈਨ ਨੂੰ ਸੁਰੱਖਿਅਤ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦੇ ਸਮੇਂ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ। ਜੇਕਰ ਤੁਹਾਨੂੰ ਬਾਅਦ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰਨ ਲਈ ਤਾਜ਼ਾ ਕਰਨ ਜਾਂ ਛੱਡਣ ਦੀ ਲੋੜ ਹੈ, ਤਾਂ ਤੁਸੀਂ ਬਾਅਦ ਵਿੱਚ ਸੁਰੱਖਿਅਤ ਕਰਨ ਲਈ ਪੰਨੇ 'ਤੇ ਮੌਜੂਦਾ ਡਿਜ਼ਾਈਨ ਨੂੰ ਨਿਰਯਾਤ ਕਰ ਸਕਦੇ ਹੋ।", + "formDesignSaveConsoleErrMsg": "ਫਾਰਮ ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਜਾਂ ਬਣਾਉਣ ਵਿੱਚ ਤਰੁੱਟੀ (FormID: {formId}, versionId: {versionId}, draftId: {draftId}) ਤਰੁੱਟੀ: {error}", + "collapse": "ਸਮੇਟਣਾ", + "actions": "ਕਾਰਵਾਈਆਂ", + "version": "ਸੰਸਕਰਣ", + "save": "ਸੇਵ ਕਰੋ", + "saving": "ਸੰਭਾਲ ਰਿਹਾ ਹੈ", + "notSaved": "ਸੰਭਾਲਿਆ ਨਹੀਂ ਗਿਆ", + "fieldnameError": "ਤੁਸੀਂ `form` ਕੀਵਰਡ ਨੂੰ {label} ਫੀਲਡਨਾਮ ਵਜੋਂ ਨਹੀਂ ਵਰਤ ਸਕਦੇ ਹੋ" + }, + "formViewerMultiUpload": { + "important": "ਮਹੱਤਵਪੂਰਨ", + "uploadSucessMsg": "ਮਲਟੀਪਲ ਡਰਾਫਟਾਂ ਦੇ ਸਫਲ ਅਪਲੋਡ ਨੂੰ ਯਕੀਨੀ ਬਣਾਉਣ ਲਈ, ਕਿਰਪਾ ਕਰਕੇ ਪ੍ਰਦਾਨ ਕੀਤੇ ਟੈਮਪਲੇਟ ਨੂੰ ਡਾਊਨਲੋਡ ਅਤੇ ਵਰਤੋਂ ਕਰੋ।", + "confirmDownload": "ਕੀ ਤੁਸੀਂ ਇਸਨੂੰ ਡਾਊਨਲੋਡ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?", + "jsonFileUpload": "ਅੱਪਲੋਡ ਕਰਨ ਲਈ JSON ਫ਼ਾਈਲ ਚੁਣੋ", + "dragNDrop": "ਜਾਂ ਇਸਨੂੰ ਇੱਥੇ ਖਿੱਚੋ ਅਤੇ ਸੁੱਟੋ", + "chooseAFile": "ਇੱਕ ਫਾਈਲ ਚੁਣੋ", + "downloadDraftSubmns": "ਕਿਰਪਾ ਕਰਕੇ ਡਰਾਫਟ ਸਪੁਰਦਗੀ ਰਿਪੋਰਟ ਨੂੰ ਡਾਉਨਲੋਡ ਕਰੋ ਅਤੇ ਯਕੀਨੀ ਬਣਾਓ ਕਿ ਡੇਟਾ ਸਹੀ ਤਰ੍ਹਾਂ ਦਾਖਲ ਕੀਤਾ ਗਿਆ ਹੈ।", + "downloadReport": "ਰਿਪੋਰਟ ਡਾਊਨਲੋਡ ਕਰੋ", + "doYouWantToDownload": "ਕੀ ਤੁਸੀਂ ਇਸਨੂੰ ਡਾਊਨਲੋਡ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?", + "uploadNewFile": "ਨਵੀਂ ਫ਼ਾਈਲ ਅੱਪਲੋਡ ਕਰੋ", + "uploadMultipleFileErr": "ਮਾਫ਼ ਕਰਨਾ, ਤੁਸੀਂ ਸਿਰਫ਼ ਇੱਕ ਫ਼ਾਈਲ ਅੱਪਲੋਡ ਕਰ ਸਕਦੇ ਹੋ", + "dragMultipleFileErr": "ਮਾਫ਼ ਕਰਨਾ, ਤੁਸੀਂ ਸਿਰਫ਼ ਇੱਕ ਫ਼ਾਈਲ ਨੂੰ ਖਿੱਚ ਸਕਦੇ ਹੋ", + "fileFormatErr": "ਮਾਫ਼ ਕਰਨਾ, ਅਸੀਂ ਸਿਰਫ਼ json ਫ਼ਾਈਲਾਂ ਨੂੰ ਸਵੀਕਾਰ ਕਰਦੇ ਹਾਂ", + "fileSizeErr": "ਅਧਿਕਤਮ ਫਾਈਲ ਆਕਾਰ 5MB ਹੈ", + "parseJsonErr": "ਅਸੀਂ ਫਾਈਲ ਤੋਂ json ਡੇਟਾ ਨੂੰ ਪਾਰਸ ਨਹੀਂ ਕਰ ਸਕਦੇ ਹਾਂ", + "jsonObjNotArray": "ਗਲਤ json ਫ਼ਾਈਲ ਫਾਰਮੈਟ", + "jsonObjNotArrayConsErr": "ਇੱਕ ਅਚਾਨਕ ਗਲਤੀ ਆਈ ਹੈ।", + "jsonArrayEmpty": "ਇਹ json ਫਾਈਲ ਖਾਲੀ ਹੈ।", + "errorWhileValidate": "ਇਸ ਫ਼ਾਈਲ ਵਿੱਚ ਕੁਝ ਗੜਬੜ ਹੈ", + "errWhileCheckValidity": "ਇਸ ਫ਼ਾਈਲ ਵਿੱਚ ਕੁਝ ਗੜਬੜ ਹੈ", + "errAfterValidate": "ਕੁਝ ਗਲਤੀਆਂ ਮਿਲੀਆਂ, ਹੋਰ ਜਾਣਕਾਰੀ ਲਈ ਹੇਠਾਂ ਦੇਖੋ।", + "fileIsEmpty": "ਇਹ ਫਾਈਲ ਖਾਲੀ ਹੈ।", + "download": "ਡਾਊਨਲੋਡ ਕਰੋ" + }, + "formDisclaimer": { + "disclaimerAndStatement": "ਬੇਦਾਅਵਾ ਅਤੇ ਫਾਰਮ ਡਿਜ਼ਾਈਨਰਾਂ ਲਈ ਜ਼ਿੰਮੇਵਾਰੀ ਦਾ ਬਿਆਨ:", + "privacyLaw": "ਨਿੱਜੀ ਤੌਰ 'ਤੇ ਪਛਾਣਨ ਯੋਗ ਜਾਣਕਾਰੀ ਦੇ ਸੰਗ੍ਰਹਿ, ਵਰਤੋਂ ਅਤੇ ਖੁਲਾਸੇ ਨੂੰ ਨਿਯੰਤਰਿਤ ਕਰਨ ਵਾਲੇ ਗੋਪਨੀਯਤਾ ਕਾਨੂੰਨਾਂ ਦੀ ਪਾਲਣਾ ਕਰਨਾ ਤੁਹਾਡੀ ਜ਼ਿੰਮੇਵਾਰੀ ਹੈ।", + "disclosure": "ਇਸ ਫਾਰਮ ਡਿਜ਼ਾਈਨਰ ਟੂਲ ਤੱਕ ਪਹੁੰਚ ਕਿਸੇ ਵੀ ਨਿੱਜੀ ਤੌਰ 'ਤੇ ਪਛਾਣਨ ਯੋਗ ਜਾਣਕਾਰੀ ਨੂੰ ਇਕੱਠਾ ਕਰਨ, ਵਰਤਣ ਜਾਂ ਪ੍ਰਗਟ ਕਰਨ ਦੀ ਕੁਦਰਤੀ ਤੌਰ 'ਤੇ ਇਜਾਜ਼ਤ ਨਹੀਂ ਦਿੰਦੀ ਹੈ।", + "consent": "ਕਨੂੰਨ ਦੁਆਰਾ ਲੋੜੀਂਦੀ ਜਾਣਕਾਰੀ ਇਕੱਠੀ ਕਰਨ ਲਈ ਸਹਿਮਤੀ ਪ੍ਰਾਪਤ ਕਰਨਾ ਤੁਹਾਡੀ ਜ਼ਿੰਮੇਵਾਰੀ ਹੈ।", + "formIntention": "ਆਪਣੇ ਫਾਰਮ ਨੂੰ ਪ੍ਰਕਾਸ਼ਿਤ ਕਰਨ ਜਾਂ ਵੰਡਣ ਤੋਂ ਪਹਿਲਾਂ ਤੁਹਾਨੂੰ ਫਾਰਮ ਦੇ ਇਰਾਦੇ ਬਾਰੇ ਆਪਣੇ ਨਾਲ ਚਰਚਾ ਕਰਨ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ", + "privacyOfficer": "ਮੰਤਰਾਲੇ ਦੇ ਗੋਪਨੀਯਤਾ ਅਧਿਕਾਰੀ", + "assement": "ਅਤੇ ਲੋੜ ਅਨੁਸਾਰ ਮੁਲਾਂਕਣਾਂ ਨੂੰ ਪੂਰਾ ਕਰਨਾ।" + }, + "requestReceipt": { + "emailPriority": "ਈਮੇਲ ਤਰਜੀਹ", + "emailReceipt": "ਇਸ ਸਬਮਿਸ਼ਨ ਦੀ ਇੱਕ ਰਸੀਦ ਈਮੇਲ ਕਰੋ", + "high": "ਉੱਚ", + "low": "ਘੱਟ", + "normal": "ਸਧਾਰਣ", + "send": "ਭੇਜੋ", + "sendToEmailAddress": "ਈਮੇਲ ਪਤੇ 'ਤੇ ਭੇਜੋ", + "emailSent": "{to} ਨੂੰ ਇੱਕ ਈਮੇਲ ਭੇਜੀ ਗਈ ਹੈ।", + "sendingEmailErrMsg": "ਤੁਹਾਡੀ ਈਮੇਲ ਭੇਜਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦੇ ਸਮੇਂ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "sendingEmailConsErrMsg": "{to} ਨੂੰ ਈਮੇਲ ਪੁਸ਼ਟੀਕਰਨ ਅਸਫਲ: {error}", + "emailRequired": "ਈਮੇਲ ਦੀ ਲੋੜ ਹੈ" + }, + "submissionsTable": { + "noMatchingRecordText": "ਕੋਈ ਮੇਲ ਖਾਂਦਾ ਰਿਕਾਰਡ ਨਹੀਂ ਮਿਲਿਆ", + "submissions": "ਬੇਨਤੀਆਂ", + "submissionsTable": "ਸਬਮਿਸ਼ਨ ਟੇਬਲ", + "selectColumns": "ਕਾਲਮ ਚੁਣੋ", + "manageForm": "ਫਾਰਮ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ", + "submissionsToFiles": "ਫਾਈਲਾਂ ਵਿੱਚ ਬੇਨਤੀਆਂ ਨੂੰ ਨਿਰਯਾਤ ਕਰੋ", + "showDeletedSubmissions": "ਮਿਟਾਈਆਂ ਗਈਆਂ ਬੇਨਤੀਆਂ ਦਿਖਾਓ", + "showMySubmissions": "ਮੇਰੀਆਂ ਬੇਨਤੀਆਂ ਦਿਖਾਓ", + "search": "ਖੋਜ", + "loadingText": "ਲੋਡ ਹੋ ਰਿਹਾ ਹੈ... ਕਿਰਪਾ ਕਰਕੇ ਉਡੀਕ ਕਰੋ", + "noDataText": "ਇਸ ਫਾਰਮ ਲਈ ਕੋਈ ਸਬਮਿਸ਼ਨ ਨਹੀਂ ਹਨ", + "delSelectedSubmissions": "ਚੁਣੀਆਂ ਗਈਆਂ ਬੇਨਤੀਆਂ ਨੂੰ ਮਿਟਾਓ", + "resSelectedSubmissions": "ਚੁਣੀਆਂ ਗਈਆਂ ਬੇਨਤੀਆਂ ਨੂੰ ਰੀਸਟੋਰ ਕਰੋ", + "yes": "ਹਾਂ", + "no": "ਸੰ", + "viewSubmission": "ਸਪੁਰਦਗੀ ਦੇਖੋ", + "deleteSubmission": "ਸਪੁਰਦਗੀ ਨੂੰ ਮਿਟਾਓ", + "restore": "ਰੀਸਟੋਰ ਕਰੋ", + "confirmDeletion": "ਮਿਟਾਉਣ ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ", + "delete": "ਮਿਟਾਓ", + "confirmRestoration": "ਬਹਾਲੀ ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ", + "searchSubmissionFields": "ਸਪੁਰਦਗੀ ਖੇਤਰ ਖੋਜੋ", + "save": "ਸੇਵ ਕਰੋ", + "searchTitle": "ਆਪਣੇ ਡੈਸ਼ਬੋਰਡ ਦੇ ਹੇਠਾਂ ਦਿਖਾਉਣ ਲਈ ਕਾਲਮ ਖੋਜੋ ਅਤੇ ਚੁਣੋ", + "status": "ਸਥਿਤੀ", + "submitter": "ਸਬਮਿਟਰ", + "submissionDate": "ਸਪੁਰਦਗੀ ਦੀ ਮਿਤੀ", + "event": "ਘਟਨਾ", + "view": "ਦੇਖੋ", + "lateSubmission": "ਦੇਰ ਨਾਲ ਸਪੁਰਦਗੀ", + "confirmationID": "ਪੁਸ਼ਟੀ ਆਈ.ਡੀ", + "multiDelWarning": "ਕੀ ਤੁਸੀਂ ਯਕੀਨੀ ਤੌਰ 'ਤੇ ਚੁਣੀਆਂ ਗਈਆਂ ਬੇਨਤੀਆਂ ਨੂੰ ਮਿਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ?", + "singleDelWarning": "ਕੀ ਤੁਸੀਂ ਯਕੀਨੀ ਤੌਰ 'ਤੇ ਇਸ ਸਬਮਿਸ਼ਨ ਨੂੰ ਮਿਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ?", + "multiRestoreWarning": "ਕੀ ਤੁਸੀਂ ਯਕੀਨੀ ਤੌਰ 'ਤੇ ਇਹਨਾਂ ਸਬਮਿਸ਼ਨਾਂ ਨੂੰ ਰੀਸਟੋਰ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?", + "singleRestoreWarning": "ਕੀ ਤੁਸੀਂ ਯਕੀਨੀ ਤੌਰ 'ਤੇ ਇਸ ਸਬਮਿਸ਼ਨ ਨੂੰ ਰੀਸਟੋਰ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?" + }, + "auditHistory": { + "viewEditHistory": "ਸੰਪਾਦਨ ਇਤਿਹਾਸ ਦੇਖੋ", + "editHistory": "ਇਤਿਹਾਸ ਦਾ ਸੰਪਾਦਨ ਕਰੋ", + "auditLogMsg": "ਇਹ ਇੱਕ ਆਡਿਟ ਲੌਗ ਹੈ ਜਿਸਨੇ ਅਸਲ ਸਬਮਿਸ਼ਨ ਤੋਂ ਬਾਅਦ ਇਸ ਸਬਮਿਸ਼ਨ ਵਿੱਚ ਬਦਲਾਅ ਕੀਤੇ ਹਨ।", + "loadingText": "ਲੋਡ ਹੋ ਰਿਹਾ ਹੈ... ਕਿਰਪਾ ਕਰਕੇ ਉਡੀਕ ਕਰੋ", + "close": "ਬੰਦ ਕਰੋ", + "userName": "ਉਪਭੋਗਤਾ ਨਾਮ", + "date": "ਤਾਰੀਖ਼", + "errorMsg": "ਇਤਿਹਾਸ ਪ੍ਰਾਪਤ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦੇ ਸਮੇਂ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "consoleErrMsg": "ਲਈ ਆਡਿਟ ਇਤਿਹਾਸ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ" + }, + "deleteSubmission": { + "deleteThis": "ਇਸਨੂੰ ਮਿਟਾਓ", + "draft": "ਡਰਾਫਟ", + "submission": "ਸਬਮਿਸ਼ਨ", + "confirmDeletion": "ਮਿਟਾਉਣ ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ", + "deleteWarning": "ਕੀ ਤੁਸੀਂ ਯਕੀਨਨ ਇਸਨੂੰ ਮਿਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ", + "drafts": "ਡਰਾਫਟ", + "formSubmission": "ਫਾਰਮ ਸਪੁਰਦਗੀ", + "delete": "ਮਿਟਾਓ" + }, + "manageSubmissionUsers": { + "manageTeamMembers": "ਟੀਮ ਦੇ ਮੈਂਬਰਾਂ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ", + "add": "ਸ਼ਾਮਲ ਕਰੋ", + "draftFormInvite": "ਤੁਸੀਂ ਸਿਰਫ਼ ਟੀਮ ਦੇ ਮੈਂਬਰਾਂ ਨੂੰ ਸੱਦਾ ਅਤੇ ਪ੍ਰਬੰਧਨ ਕਰ ਸਕਦੇ ਹੋ ਜਦੋਂ ਕਿ ਇਹ ਫਾਰਮ ਇੱਕ ਡਰਾਫਟ ਹੈ", + "submissionTeamMembers": "ਇਸ ਸਬਮਿਸ਼ਨ ਲਈ ਟੀਮ ਦੇ ਮੈਂਬਰ", + "actions": "ਕਾਰਵਾਈਆਂ", + "close": "ਬੰਦ ਕਰੋ", + "remove": "ਹਟਾਓ", + "userNotFoundErrMsg": "ਕਿਸੇ ਨੂੰ ਨਹੀਂ ਲੱਭ ਸਕਦੇ? ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਉਹਨਾਂ ਨੇ CHEFS ਵਿੱਚ ਲੌਗਇਨ ਨਾ ਕੀਤਾ ਹੋਵੇ।
ਕਿਰਪਾ ਕਰਕੇ ਉਹਨਾਂ ਨੂੰ CHEFS ਨੂੰ ਇੱਕ ਲਿੰਕ ਭੇਜੋ ਅਤੇ ਉਹਨਾਂ ਨੂੰ ਲੌਗ ਇਨ ਕਰਨ ਲਈ ਕਹੋ।", + "name": "ਨਾਮ", + "username": "ਯੂਜ਼ਰਨੇਮ", + "email": "ਈ - ਮੇਲ", + "removeUserWarningMsg1": "ਕੀ ਤੁਸੀਂ ਯਕੀਨੀ ਤੌਰ 'ਤੇ ਹਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ", + "removeUserWarningMsg2": "ਉਹਨਾਂ ਕੋਲ ਹੁਣ ਇਸ ਸਪੁਰਦਗੀ ਲਈ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੋਵੇਗੀ।", + "userExistInListMsg": "ਯੂਜ਼ਰ {username} ਪਹਿਲਾਂ ਹੀ ਟੀਮ ਦੇ ਮੈਂਬਰਾਂ ਦੀ ਸੂਚੀ ਵਿੱਚ ਹੈ।", + "getSubmissionUsersErr": "ਇਸ ਸਬਮਿਸ਼ਨ ਲਈ ਉਪਭੋਗਤਾਵਾਂ ਨੂੰ ਪ੍ਰਾਪਤ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦੇ ਸਮੇਂ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "getSubmissionUsersConsoleErr": "{submissionId} ਲਈ ਉਪਭੋਗਤਾਵਾਂ ਨੂੰ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ : {error}", + "sentInviteEmailTo": "ਨੂੰ ਸੱਦਾ ਪੱਤਰ ਭੇਜਿਆ ਹੈ", + "sentUninvitedEmailTo": "ਨੂੰ ਬਿਨਾਂ ਬੁਲਾਏ ਈਮੇਲ ਭੇਜੀ", + "updateUserErrMsg": "ਇਸ ਸਬਮਿਸ਼ਨ ਲਈ ਉਪਭੋਗਤਾਵਾਂ ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦੇ ਸਮੇਂ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "updateUserConsoleErrMsg": "ਉਪਭੋਗਤਾ ਅਨੁਮਤੀਆਂ ਨੂੰ ਸੈੱਟ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ। ਉਪ: {submissionId} ਉਪਭੋਗਤਾ: {userId} ਤਰੁੱਟੀ: {error}", + "searchInputLength": "BCeID ਉਪਭੋਗਤਾ ਨਾਮ/ਈਮੇਲ ਲਈ ਖੋਜ ਇਨਪੁਟ 6 ਅੱਖਰਾਂ ਤੋਂ ਵੱਧ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ।", + "exactBCEIDSearch": "BCeID ਲਈ ਈਮੇਲ ਖੋਜਾਂ ਸਟੀਕ ਹੋਣੀਆਂ ਚਾਹੀਦੀਆਂ ਹਨ।", + "getUsersErrMsg": "ਉਪਭੋਗਤਾਵਾਂ ਨੂੰ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "exactEmailOrUsername": "ਇੱਕ ਸਹੀ ਈ-ਮੇਲ ਜਾਂ ਉਪਭੋਗਤਾ ਨਾਮ ਦਰਜ ਕਰੋ।", + "requiredFiled": "ਇੱਕ ਨਾਮ, ਈ-ਮੇਲ, ਜਾਂ ਉਪਭੋਗਤਾ ਨਾਮ ਦਰਜ ਕਰੋ" + }, + "mySubmissionsActions": { + "viewThisSubmission": "ਇਸ ਸਬਮਿਸ਼ਨ ਨੂੰ ਦੇਖੋ", + "copyThisSubmission": "ਇਸ ਸਬਮਿਸ਼ਨ ਨੂੰ ਕਾਪੀ ਕਰੋ", + "editThisDraft": "ਇਸ ਡਰਾਫਟ ਨੂੰ ਸੰਪਾਦਿਤ ਕਰੋ" + }, + "mySubmissionsTable": { + "noMatchingRecordText": "ਕੋਈ ਮੇਲ ਖਾਂਦਾ ਰਿਕਾਰਡ ਨਹੀਂ ਮਿਲਿਆ", + "previousSubmissions": "ਪਿਛਲੀਆਂ ਬੇਨਤੀਆਂ", + "selectColumns": "ਕਾਲਮ ਚੁਣੋ", + "createNewSubmission": "ਇੱਕ ਨਵੀਂ ਸਬਮਿਸ਼ਨ ਬਣਾਓ", + "search": "ਖੋਜ", + "loadingText": "ਲੋਡ ਹੋ ਰਿਹਾ ਹੈ... ਕਿਰਪਾ ਕਰਕੇ ਉਡੀਕ ਕਰੋ", + "noDataText": "ਤੁਹਾਡੇ ਕੋਲ ਕੋਈ ਸਪੁਰਦਗੀ ਨਹੀਂ ਹੈ", + "searchSubmissionFields": "ਸਪੁਰਦਗੀ ਖੇਤਰ ਖੋਜੋ", + "save": "ਸੇਵ ਕਰੋ", + "filterTitle": "ਆਪਣੇ ਡੈਸ਼ਬੋਰਡ ਦੇ ਹੇਠਾਂ ਦਿਖਾਉਣ ਲਈ ਕਾਲਮ ਖੋਜੋ ਅਤੇ ਚੁਣੋ", + "confirmationId": "ਪੁਸ਼ਟੀ ਆਈ.ਡੀ", + "actions": "ਕਾਰਵਾਈਆਂ", + "createdBy": "ਦੁਆਰਾ ਬਣਾਇਆ ਗਿਆ", + "statusUpdatedBy": "ਦੁਆਰਾ ਸਥਿਤੀ ਅੱਪਡੇਟ ਕੀਤੀ ਗਈ", + "status": "ਸਥਿਤੀ", + "submissionDate": "ਸਪੁਰਦਗੀ ਦੀ ਮਿਤੀ", + "draftUpdatedBy": "ਡਰਾਫਟ ਦੁਆਰਾ ਅੱਪਡੇਟ ਕੀਤਾ ਗਿਆ", + "draftLastEdited": "ਡਰਾਫਟ ਆਖਰੀ ਵਾਰ ਸੰਪਾਦਿਤ ਕੀਤਾ ਗਿਆ", + "createLateSubmissn": "ਦੇਰ ਨਾਲ ਸਬਮਿਸ਼ਨ ਬਣਾਓ", + "formLoading": "ਕਿਰਪਾ ਕਰਕੇ ਫਾਰਮ ਲੋਡ ਹੋਣ ਤੱਕ ਉਡੀਕ ਕਰੋ !!!", + "pleaseConfirm": "ਕ੍ਰਿਪਾ ਕਰਕੇ ਪੁਸ਼ਟੀ ਕਰੋ", + "wantToSaveDraft": "ਕੀ ਤੁਸੀਂ ਡਰਾਫਟ ਨੂੰ ਸੁਰੱਖਿਅਤ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?", + "yes": "ਹਾਂ", + "no": "ਨੰ", + "multiDraftUploadSuccess": "ਤੁਹਾਡਾ ਮਲਟੀਪਲ ਡਰਾਫਟ ਅੱਪਲੋਡ ਸਫਲ ਰਿਹਾ ਹੈ!", + "failedResSubmissn": "ਸਪੁਰਦਗੀ ਅੰਤਮ ਬਿੰਦੂ ਤੋਂ ਅਸਫਲ ਜਵਾਬ। ਜਵਾਬ ਕੋਡ: {status}", + "errSubmittingForm": "ਇਸ ਫਾਰਮ ਨੂੰ ਸਪੁਰਦ ਕਰਨ ਵਿੱਚ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ", + "errorSavingFile": "ਫ਼ਾਈਲਾਂ ਨੂੰ ਰੱਖਿਅਤ ਕਰਨ ਵਿੱਚ ਗੜਬੜ ਹੋਈ। ਫ਼ਾਈਲ ਦਾ ਨਾਮ: {fileName}। ਗਲਤੀ: {error}", + "submittingDraftErrMsg": "ਡਰਾਫਟ ਨੂੰ ਸੁਰੱਖਿਅਤ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ", + "submittingDraftConsErrMsg": "ਡਰਾਫਟ ਸੁਰੱਖਿਅਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ। SubmissionId: {submissionId}। ਗਲਤੀ: {error}" + }, + "notesPanel": { + "addNewNote": "ਨਵਾਂ ਨੋਟ ਸ਼ਾਮਲ ਕਰੋ", + "cancel": "ਰੱਦ ਕਰੋ", + "addNote": "ਨੋਟ ਸ਼ਾਮਲ ਕਰੋ", + "noResponseErr": "ਫਾਰਮ ਜਮ੍ਹਾਂ ਕਰਦੇ ਸਮੇਂ API ਤੋਂ ਕੋਈ ਜਵਾਬ ਡੇਟਾ ਨਹੀਂ ਹੈ", + "errorMesg": "ਨੋਟ ਜੋੜਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦੇ ਸਮੇਂ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "consoleErrMsg": "ਨੋਟ ਜੋੜਨ ਵਿੱਚ ਤਰੁੱਟੀ:", + "fetchErrMsg": "ਇਸ ਸਬਮਿਸ਼ਨ ਲਈ ਨੋਟਸ ਪ੍ਰਾਪਤ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦੇ ਸਮੇਂ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "fetchConsoleErrMsg": "ਨੋਟ ਜੋੜਨ ਵਿੱਚ ਤਰੁੱਟੀ:", + "notes": "ਨੋਟਸ", + "note": "ਨੋਟ ਕਰੋ", + "maxChars": "ਅਧਿਕਤਮ 4000 ਅੱਖਰ" + }, + "statusPanel": { + "currentStatus": "ਮੌਜੂਦਾ ਸਥਿਤੀ:", + "assignedTo": "ਨੂੰ ਦਿੱਤਾ:", + "assignOrUpdateStatus": "ਸਥਿਤੀ ਨੂੰ ਨਿਰਧਾਰਤ ਕਰੋ ਜਾਂ ਅੱਪਡੇਟ ਕਰੋ", + "display": "ਡਿਸਪਲੇ", + "statusIsRequired": "ਸਥਿਤੀ ਦੀ ਲੋੜ ਹੈ", + "assignTo": "ਨੂੰ ਸੌਂਪੋ", + "noDataText": "ਖੋਜ ਨਾਲ ਕੋਈ ਫਾਰਮ ਸਮੀਖਿਅਕ ਨਹੀਂ ਮਿਲੇ। ਪ੍ਰਬੰਧਿਤ ਪੰਨੇ 'ਤੇ ਫਾਰਮ ਸਮੀਖਿਅਕ ਸ਼ਾਮਲ ਕਰੋ।", + "assigneeIsRequired": "ਜ਼ਿੰਮੇਦਾਰ ਲੋੜੀਂਦਾ ਹੈ", + "assignToMe": "ਮੈਨੂੰ ਸੌਂਪੋ", + "recipientEmail": "ਪ੍ਰਾਪਤਕਰਤਾ ਈਮੇਲ", + "attachCommentToEmail": "ਈਮੇਲ ਨਾਲ ਟਿੱਪਣੀ ਨੱਥੀ ਕਰੋ", + "emailComment": "ਈਮੇਲ ਟਿੱਪਣੀ", + "maxChars": "ਅਧਿਕਤਮ 4000 ਅੱਖਰ", + "viewHistory": "ਇਤਿਹਾਸ ਦੇਖੋ", + "statusHistory": "ਸਥਿਤੀ ਇਤਿਹਾਸ", + "close": "ਬੰਦ ਕਰੋ", + "addNoteNoReponserErr": "ਸਥਿਤੀ ਅੱਪਡੇਟ ਲਈ ਨੋਟ ਸਪੁਰਦ ਕਰਨ ਦੌਰਾਨ API ਤੋਂ ਕੋਈ ਜਵਾਬ ਡਾਟਾ ਨਹੀਂ ਹੈ", + "addNoteConsoleErrMsg": "ਸਥਿਤੀ ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "addNoteErrMsg": "ਸਥਿਤੀ ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦੇ ਸਮੇਂ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ", + "updtSubmissionsStatusErr": "ਸਥਿਤੀ ਅੱਪਡੇਟ ਫਾਰਮ ਜਮ੍ਹਾਂ ਕਰਦੇ ਸਮੇਂ API ਤੋਂ ਕੋਈ ਜਵਾਬ ਡਾਟਾ ਨਹੀਂ ਹੈ", + "noStatus": "ਕੋਈ ਸਥਿਤੀ ਨਹੀਂ", + "noStatusesFound": "ਕੋਈ ਸਥਿਤੀ ਨਹੀਂ ਮਿਲੀ", + "statusCodesErr": "ਸਥਿਤੀ ਕੋਡ ਲੱਭਣ ਵਿੱਚ ਗਲਤੀ", + "notifyErrorCode": "ਇਸ ਸਪੁਰਦਗੀ ਲਈ ਸਥਿਤੀ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਗਲਤੀ ਆਈ ਹੈ।", + "notifyConsoleErrorCode": "ਸਥਿਤੀਆਂ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ:", + "fetchSubmissionUsersErr": "ਇਸ ਸਬਮਿਸ਼ਨ ਲਈ ਪ੍ਰਾਪਤਕਰਤਾ ਈਮੇਲਾਂ ਨੂੰ ਪ੍ਰਾਪਤ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦੇ ਸਮੇਂ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "fetchSubmissionUsersConsErr": "ਲਈ ਪ੍ਰਾਪਤਕਰਤਾ ਦੀਆਂ ਈਮੇਲਾਂ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ", + "assignSubmissnToFormReviewer": "ਸਬਮਿਸ਼ਨਾਂ ਨੂੰ ਫਾਰਮ ਸਮੀਖਿਅਕਾਂ ਨੂੰ ਸੌਂਪਿਆ ਜਾ ਸਕਦਾ ਹੈ।
ਫਾਰਮ ਸਮੀਖਿਅਕਾਂ ਵਜੋਂ ਟੀਮ ਦੇ ਹੋਰ ਮੈਂਬਰਾਂ ਨੂੰ ਸ਼ਾਮਲ ਕਰਨ ਲਈ, ਇਸ ਫਾਰਮ ਦੇ ਪ੍ਰਬੰਧਨ ਪੰਨੇ 'ਤੇ ਜਾਓ।", + "update": "ਅੱਪਡੇਟ ਕਰੋ", + "revise": "ਸੰਸ਼ੋਧਨ ਕਰੋ", + "complete": "ਸੰਪੂਰਨ", + "assign": "ਅਸਾਈਨ ਕਰੋ" + }, + "statusTable": { + "loadingText": "ਲੋਡ ਹੋ ਰਿਹਾ ਹੈ... ਕਿਰਪਾ ਕਰਕੇ ਉਡੀਕ ਕਰੋ", + "status": "ਸਥਿਤੀ", + "dateStatusChanged": "ਮਿਤੀ ਸਥਿਤੀ ਬਦਲੀ ਗਈ", + "assignee": "ਸੌਂਪਣ ਵਾਲਾ", + "updatedBy": "ਦੁਆਰਾ ਅੱਪਡੇਟ ਕੀਤਾ ਗਿਆ", + "getSubmissionStatusErr": "ਸਥਿਤੀਆਂ ਪ੍ਰਾਪਤ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦੇ ਸਮੇਂ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "getSubmissionStatusConsErr": "ਨੋਟ ਜੋੜਨ ਵਿੱਚ ਤਰੁੱਟੀ:" + }, + "exportSubmissions": { + "exportSubmissionsToFile": "ਫਾਈਲ ਵਿੱਚ ਬੇਨਤੀਆਂ ਨੂੰ ਨਿਰਯਾਤ ਕਰੋ", + "viewSubmissions": "ਬੇਨਤੀਆਂ ਦੇਖੋ", + "fileType": "ਫਾਈਲ ਦੀ ਕਿਸਮ", + "json": "JSON", + "csv": "CSV", + "formVersion": "ਫਾਰਮ ਸੰਸਕਰਣ", + "versionIsRequired": "ਸੰਸਕਰਣ ਦੀ ਲੋੜ ਹੈ।", + "dataFields": "ਡਾਟਾ ਖੇਤਰ", + "searchFields": "ਖੋਜ ਖੇਤਰ", + "selectedForExports": "ਨਿਰਯਾਤ ਲਈ ਚੁਣਿਆ ਗਿਆ ਹੈ", + "submissionDate": "ਸਪੁਰਦਗੀ ਦੀ ਮਿਤੀ", + "all": "ਸਾਰੇ", + "selectDateRange": "ਮਿਤੀ ਸੀਮਾ ਚੁਣੋ", + "SelectdateRange": "ਮਿਤੀ ਰੇਂਜ ਚੁਣੋ", + "from": "ਤੋਂ", + "to": "ਨੂੰ", + "CSVFormat": "CSV ਫਾਰਮੈਟ", + "multiRowPerSubmissionA": "1 - ਇੰਡੈਂਟੇਸ਼ਨ ਸਪੇਸ ਦੇ ਨਾਲ ਪ੍ਰਤੀ ਸਪੁਰਦਗੀ ਲਈ ਕਈ ਕਤਾਰਾਂ", + "multiRowPerSubmissionB": "2 - ਪ੍ਰਤੀ ਸਪੁਰਦਗੀ ਲਈ ਕਈ ਕਤਾਰਾਂ", + "singleRowPerSubmission": "3 - ਪ੍ਰਤੀ ਸਪੁਰਦਗੀ ਲਈ ਸਿੰਗਲ ਕਤਾਰ", + "unformatted": "4 - ਗੈਰ-ਫਾਰਮੈਟ ਕੀਤਾ", + "fileNameAndType": "ਫਾਈਲ ਦਾ ਨਾਮ ਅਤੇ ਕਿਸਮ", + "export": "ਨਿਰਯਾਤ", + "noResponseDataErr": "ਐਕਸਪੋਰਟਸਬਮਿਸ਼ਨ ਕਾਲ ਦੇ ਜਵਾਬ ਵਿੱਚ ਕੋਈ ਡਾਟਾ ਨਹੀਂ ਹੈ", + "apiCallErrorMsg": "ਇਸ ਫਾਰਮ ਲਈ ਬੇਨਤੀਆਂ ਨੂੰ ਨਿਰਯਾਤ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦੇ ਸਮੇਂ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "apiCallConsErrorMsg": "ਲਈ ਗਲਤੀ ਨਿਰਯਾਤ ਸਪੁਰਦਗੀ", + "selectAllFields": "ਸਾਰੇ ਖੇਤਰ ਚੁਣੋ", + "emailSentMsg": "{email} 'ਤੇ ਇੱਕ ਈਮੇਲ ਭੇਜੀ ਜਾਵੇਗੀ ਜਿਸ ਵਿੱਚ ਤੁਹਾਡਾ ਡੇਟਾ ਤਿਆਰ ਹੋਣ 'ਤੇ ਡਾਊਨਲੋਡ ਕਰਨ ਲਈ ਇੱਕ ਲਿੰਕ ਸ਼ਾਮਲ ਹੋਵੇਗਾ", + "exportInProgress": "ਨਿਰਯਾਤ ਜਾਰੀ ਹੈ", + "of": "ਦੇ" + }, + "printOptions": { + "submitButtonTxt": "CDOGS ਨੂੰ ਜਮ੍ਹਾਂ ਕਰੋ ਅਤੇ ਡਾਊਨਲੋਡ ਕਰੋ", + "templatePrint": "ਟੈਂਪਲੇਟ ਪ੍ਰਿੰਟ", + "uploadTemplateFile": "ਟੈਮਪਲੇਟ ਫਾਈਲ ਅੱਪਲੋਡ ਕਰੋ", + "downloadOptions": "ਡਾਊਨਲੋਡ ਵਿਕਲਪ", + "print": "ਛਾਪੋ", + "browserPrint": "ਬ੍ਰਾਊਜ਼ਰ ਪ੍ਰਿੰਟ", + "pageFromBrowser": "ਤੁਹਾਡੇ ਬ੍ਰਾਊਜ਼ਰ ਤੋਂ ਪੰਨਾ", + "uploadA": "ਅੱਪਲੋਡ ਏ", + "uploadB": "ਇੱਕ ਢਾਂਚਾਗਤ ਸੰਸਕਰਣ ਹੋਣਾ", + "docGrnSucess": "ਦਸਤਾਵੇਜ਼ ਸਫਲਤਾਪੂਰਵਕ ਸਿਰਜਿਆ ਗਿਆ", + "failedDocGenErrMsg": "ਦਸਤਾਵੇਜ਼ ਬਣਾਉਣ ਵਿੱਚ ਅਸਫਲ", + "failedDocGenConsErrMsg": "ਟੈਮਪਲੇਟ ਦਰਜ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "cDogsTemplate": "CDOGS ਟੈਂਪਲੇਟ" + }, + "proactiveHelpDialog": { + "componentInfoLink": "ਕੰਪੋਨੈਂਟ ਜਾਣਕਾਰੀ ਲਿੰਕ", + "learnMoreLinkTxt": "ਹੋਰ ਜਾਣੋ ਲਿੰਕ ਖੇਤਰ ਖਾਲੀ ਨਹੀਂ ਹੋ ਸਕਦਾ।", + "largeImgTxt": "ਵੱਡਾ ਚਿੱਤਰ। ਚਿੱਤਰ ਦਾ ਆਕਾਰ .5mb ਤੋਂ ਵੱਡਾ ਨਹੀਂ ਹੋ ਸਕਦਾ", + "componentName": "ਕੰਪੋਨੈਂਟ ਦਾ ਨਾਮ:", + "learnMoreLink": "ਹੋਰ ਜਾਣੋ ਲਿੰਕ:", + "clickToEnableLink": "ਲਿੰਕ ਨੂੰ ਯੋਗ ਕਰਨ ਲਈ ਕਲਿੱਕ ਕਰੋ", + "clickToDisableLink": "ਲਿੰਕ ਨੂੰ ਅਯੋਗ ਕਰਨ ਲਈ ਕਲਿੱਕ ਕਰੋ", + "imageUpload": "ਚਿੱਤਰ ਅੱਪਲੋਡ:", + "cancel": "ਰੱਦ ਕਰੋ", + "save": "ਸੇਵ ਕਰੋ", + "description": "ਵਰਣਨ" + }, + "proactiveHelpPreviewDialog": { + "learnMore": "ਜਿਆਦਾ ਜਾਣੋ" + }, + "preview": { + "preview": "ਝਲਕ", + "previewToolTip": "ਇਹ ਫਾਰਮ ਸੰਸਕਰਣ ਡਿਜ਼ਾਈਨ ਅਤੇ ਵਿਵਹਾਰ ਦਾ ਪੂਰਵਦਰਸ਼ਨ ਦਿਖਾਉਂਦਾ ਹੈ ਕਿਉਂਕਿ ਤੁਹਾਡੇ ਸਬਮਿਟਰ ਇਸਨੂੰ ਦੇਖਣਗੇ। ਤੁਸੀਂ ਇਸ ਪੰਨੇ ਤੋਂ ਫਾਰਮ ਜਮ੍ਹਾਂ ਨਹੀਂ ਕਰ ਸਕਦੇ।" + }, + "generalLayout": { + "loadingText": "ਲੋਡ ਹੋ ਰਿਹਾ ਹੈ... ਕਿਰਪਾ ਕਰਕੇ ਉਡੀਕ ਕਰੋ", + "preview": "ਝਲਕ", + "published": "ਪ੍ਰਕਾਸ਼ਿਤ", + "unpublished": "ਅਣਪ੍ਰਕਾਸ਼ਿਤ", + "edit": "ਸੰਪਾਦਿਤ ਕਰੋ", + "formTitle": "ਫਾਰਮ ਦਾ ਸਿਰਲੇਖ", + "actions": "ਕਾਰਵਾਈਆਂ" + }, + "formSubmission": { + "editThisSubmission": "ਇਸ ਸਬਮਿਸ਼ਨ ਨੂੰ ਸੰਪਾਦਿਤ ਕਰੋ", + "submission": "ਸਬਮਿਸ਼ਨ", + "alertInfo": "ਸੰਪਾਦਨ ਕਰਨ ਤੋਂ ਬਾਅਦ, ਆਪਣੀਆਂ ਤਬਦੀਲੀਆਂ ਨੂੰ ਸੁਰੱਖਿਅਤ ਕਰਨ ਲਈ ਫਾਰਮ ਨੂੰ ਮੁੜ-ਸਪੁਰਦ ਕਰੋ।", + "viewAllSubmissions": "ਸਾਰੀਆਂ ਬੇਨਤੀਆਂ ਦੇਖੋ", + "submitted": "ਸਪੁਰਦ ਕੀਤਾ:", + "confirmationID": "ਪੁਸ਼ਟੀ ID:", + "submittedBy": "ਦੁਆਰਾ ਦਰਜ:", + "cancel": "ਰੱਦ ਕਰੋ", + "status": "ਸਥਿਤੀ", + "updatedAt": "ਸੋਧਿਆ ਗਿਆ", + "updatedBy": "ਦੁਆਰਾ ਸੋਧਿਆ ਗਿਆ" + }, + "teamManagement": { + "noMatchingRecordText": "ਕੋਈ ਮੇਲ ਖਾਂਦਾ ਰਿਕਾਰਡ ਨਹੀਂ ਮਿਲਿਆ", + "teamManagement": "ਟੀਮ ਪ੍ਰਬੰਧਨ", + "selectColumns": "ਕਾਲਮ ਚੁਣੋ", + "manageForm": "ਫਾਰਮ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ", + "search": "ਖੋਜ", + "loadingText": "ਲੋਡ ਹੋ ਰਿਹਾ ਹੈ... ਕਿਰਪਾ ਕਰਕੇ ਉਡੀਕ ਕਰੋ", + "noDataText": "ਟੀਮ ਰੋਲ ਡੇਟਾ ਲੋਡ ਕਰਨ ਵਿੱਚ ਅਸਫਲ", + "removeSelectedUsers": "ਚੁਣੇ ਗਏ ਉਪਭੋਗਤਾਵਾਂ ਨੂੰ ਹਟਾਓ", + "removeThisUser": "ਇਸ ਉਪਭੋਗਤਾ ਨੂੰ ਹਟਾਓ", + "confirmRemoval": "ਹਟਾਉਣ ਦੀ ਪੁਸ਼ਟੀ ਕਰੋ", + "remove": "ਹਟਾਓ", + "searchTeamManagementFields": "ਟੀਮ ਪ੍ਰਬੰਧਨ ਖੇਤਰਾਂ ਦੀ ਖੋਜ ਕਰੋ", + "save": "ਸੇਵ ਕਰੋ", + "teamMebersTitle": "ਆਪਣੇ ਡੈਸ਼ਬੋਰਡ ਦੇ ਹੇਠਾਂ ਦਿਖਾਉਣ ਲਈ ਕਾਲਮ ਖੋਜੋ ਅਤੇ ਚੁਣੋ", + "fullName": "ਪੂਰਾ ਨਾਂਮ", + "username": "ਯੂਜ਼ਰਨੇਮ", + "identityProvider": "ਪਛਾਣ ਪ੍ਰਦਾਤਾ", + "delSelectedMembersWarning": "ਕੀ ਤੁਸੀਂ ਯਕੀਨੀ ਤੌਰ 'ਤੇ ਚੁਣੇ ਗਏ ਮੈਂਬਰਾਂ ਨੂੰ ਹਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ?", + "delSelectedMemberWarning": "ਕੀ ਤੁਸੀਂ ਯਕੀਨੀ ਤੌਰ 'ਤੇ ਚੁਣੇ ਗਏ ਮੈਂਬਰ ਨੂੰ ਹਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ?", + "idpMessage": "ਟੀਮ ਵਿੱਚ ਪਹਿਲਾਂ ਹੀ ਹੈ।", + "formOwnerErrMsg": "ਹਮੇਸ਼ਾ ਘੱਟੋ-ਘੱਟ ਇੱਕ ਫਾਰਮ ਮਾਲਕ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ", + "formOwnerConsoleErrMsg": "{userId} ਨੂੰ ਹਟਾਇਆ ਨਹੀਂ ਜਾ ਸਕਦਾ ਕਿਉਂਕਿ ਉਹ ਹੀ ਇਸ ਫਾਰਮ ਦੇ ਬਾਕੀ ਬਚੇ ਹੋਏ ਮਾਲਕ ਹਨ।", + "insufficientPermissnMsg": "ਟੀਮ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਲਈ ਨਾਕਾਫ਼ੀ ਇਜਾਜ਼ਤਾਂ", + "getUserErrMsg": "ਫਾਰਮ ਉਪਭੋਗਤਾਵਾਂ ਨੂੰ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ:", + "getRolesErrMsg": "ਭੂਮਿਕਾਵਾਂ ਦੀ ਸੂਚੀ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ:", + "formOwnerRemovalWarning": "ਹਟਾਇਆ ਨਹੀਂ ਜਾ ਸਕਦਾ ਕਿਉਂਕਿ ਉਹ ਹੀ ਇਸ ਫਾਰਮ ਦੇ ਬਾਕੀ ਬਚੇ ਮਾਲਕ ਹਨ।", + "removeUsersErrMsg": "ਚੁਣੇ ਗਏ ਉਪਭੋਗਤਾਵਾਂ ਨੂੰ ਮਿਟਾਉਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦੇ ਸਮੇਂ ਇੱਕ ਗਲਤੀ ਆਈ ਹੈ", + "removeUserConsoleErrMsg": "ਫਾਰਮ {formId} ਤੋਂ ਉਪਭੋਗਤਾਵਾਂ ਨੂੰ ਮਿਟਾਉਣ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "updUserRolesErrMsg": "ਸਾਰੀਆਂ ਉਪਭੋਗਤਾ ਭੂਮਿਕਾਵਾਂ ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦੇ ਸਮੇਂ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ", + "updUserRolesConsoleErrMsg": "ਫਾਰਮ {formId} ਲਈ ਸਾਰੀਆਂ ਉਪਭੋਗਤਾ ਭੂਮਿਕਾਵਾਂ ਨੂੰ ਸੈੱਟ ਕਰਨ ਵਿੱਚ ਗੜਬੜ: {error}", + "setUserFormsErrMsg": "ਇੱਕ ਉਪਭੋਗਤਾ ਲਈ ਰੋਲ ਅੱਪਡੇਟ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦੇ ਸਮੇਂ ਇੱਕ ਤਰੁੱਟੀ ਆਈ ਹੈ", + "setUserFormsConsoleErrMsg": "ਫਾਰਮ {formId} ਲਈ ਉਪਭੋਗਤਾ ਰੋਲ ਸੈੱਟ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}" + }, + "floatButton": { + "publish": "ਪ੍ਰਕਾਸ਼ਿਤ ਕਰੋ", + "manage": "ਪ੍ਰਬੰਧ ਕਰਨਾ, ਕਾਬੂ ਕਰਨਾ", + "redo": "ਦੁਬਾਰਾ ਕਰੋ", + "undo": "ਵਾਪਿਸ", + "preview": "ਝਲਕ", + "bottom": "ਥੱਲੇ", + "top": "ਸਿਖਰ", + "actions": "ਕਾਰਵਾਈਆਂ", + "collapse": "ਸਮੇਟਣਾ", + "saved": "ਸੰਭਾਲੀ ਗਈ", + "save": "ਸੇਵ ਕਰੋ", + "saving": "ਸੰਭਾਲ ਰਿਹਾ ਹੈ", + "notSaved": "ਸੰਭਾਲਿਆ ਨਹੀਂ ਗਿਆ" + }, + "formViewer": { + "lateFormSubmissions": "ਫਾਰਮ ਜਮ੍ਹਾਂ ਕਰਨ ਦੀ ਮਿਆਦ ਸਮਾਪਤ ਹੋ ਗਈ ਹੈ! ਤੁਸੀਂ ਅਜੇ ਵੀ ਹੇਠਾਂ ਦਿੱਤੇ ਬਟਨ 'ਤੇ ਕਲਿੱਕ ਕਰਕੇ ਦੇਰ ਨਾਲ ਸਬਮਿਸ਼ਨ ਬਣਾ ਸਕਦੇ ਹੋ।", + "createLateSubmission": "ਦੇਰ ਨਾਲ ਸਬਮਿਸ਼ਨ ਬਣਾਓ", + "draftSaved": "ਡਰਾਫਟ ਸੁਰੱਖਿਅਤ ਕੀਤਾ ਗਿਆ", + "saving": "ਸੰਭਾਲ ਰਿਹਾ ਹੈ", + "pleaseConfirm": "ਕ੍ਰਿਪਾ ਕਰਕੇ ਪੁਸ਼ਟੀ ਕਰੋ", + "submitFormWarningMsg": "ਕੀ ਤੁਸੀਂ ਯਕੀਨੀ ਤੌਰ 'ਤੇ ਆਪਣਾ ਫਾਰਮ ਜਮ੍ਹਾਂ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?", + "submit": "ਜਮ੍ਹਾਂ ਕਰੋ", + "wantToSaveDraft": "ਕੀ ਤੁਸੀਂ ਡਰਾਫਟ ਨੂੰ ਸੁਰੱਖਿਅਤ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?", + "version": "ਸੰਸਕਰਣ: {version}", + "formScheduleExpireMessage": "ਫਾਰਮ ਸਬਮਿਸ਼ਨ ਉਪਲਬਧ ਨਹੀਂ ਹੈ ਕਿਉਂਕਿ ਅਨੁਸੂਚਿਤ ਸਬਮਿਸ਼ਨ ਦੀ ਮਿਆਦ ਖਤਮ ਹੋ ਗਈ ਹੈ।", + "getUsersSubmissionsErrMsg": "ਇਸ ਫਾਰਮ ਲਈ ਸਪੁਰਦਗੀ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ", + "getUsersSubmissionsConsoleErrMsg": "ਫਾਰਮ ਸਬਮਿਸ਼ਨ ਡਾਟਾ ਲੋਡ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ {submissionId}: {error}", + "multiDraftUploadSuccess": "ਤੁਹਾਡਾ ਮਲਟੀਪਲ ਡਰਾਫਟ ਅੱਪਲੋਡ ਸਫਲ ਰਿਹਾ ਹੈ!", + "readVersionErrMsg": "ਜਵਾਬ ਵਿੱਚ ਕੋਈ ਸਕੀਮਾ ਨਹੀਂ। VersionId: {versionId}", + "readDraftErrMsg": "ਜਵਾਬ ਵਿੱਚ ਕੋਈ ਸਕੀਮਾ ਨਹੀਂ। draftId: {draftId}", + "alertRouteMsg": "ਫਾਰਮ ਮਾਲਕ ਨੇ ਫਾਰਮ ਪ੍ਰਕਾਸ਼ਿਤ ਨਹੀਂ ਕੀਤਾ ਹੈ, ਅਤੇ ਇਹ ਸਬਮਿਸ਼ਨ ਲਈ ਉਪਲਬਧ ਨਹੀਂ ਹੈ।", + "fecthingFormErrMsg": "ਇਸ ਫਾਰਮ ਨੂੰ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਇੱਕ ਤਰੁੱਟੀ ਆਈ ਹੈ", + "fecthingFormConsoleErrMsg": "ਫਾਰਮ ਸਕੀਮਾ {versionId} ਲੋਡ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "savingDraftErrMsg": "ਡਰਾਫਟ ਨੂੰ ਸੁਰੱਖਿਅਤ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ", + "savingDraftConsoleErrMsg": "ਡਰਾਫਟ ਸੁਰੱਖਿਅਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ। SubmissionId: {submissionId}। ਗਲਤੀ: {error}", + "submissionsPreviewAlert": "ਫਾਰਮ ਪੂਰਵਦਰਸ਼ਨ ਦੌਰਾਨ ਸਪੁਰਦਗੀ ਅਯੋਗ ਕੀਤੀ ਗਈ", + "submissionsSubmitErrMsg": "ਫਾਰਮ ਜਮ੍ਹਾਂ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {errors}", + "sendSubmissionErrMsg": "ਸਪੁਰਦਗੀ ਅੰਤਮ ਬਿੰਦੂ ਤੋਂ ਅਸਫਲ ਜਵਾਬ। ਜਵਾਬ ਕੋਡ: {status}", + "errMsg": "ਇਸ ਫਾਰਮ ਨੂੰ ਸਪੁਰਦ ਕਰਨ ਵਿੱਚ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ", + "customEventAlert": "ਕਸਟਮ ਬਟਨ ਇਵੈਂਟ ਅਜੇ ਸਮਰਥਿਤ ਨਹੀਂ ਹਨ। ਘਟਨਾ ਦੀ ਕਿਸਮ: {event}", + "formLoading": "ਕਿਰਪਾ ਕਰਕੇ ਫਾਰਮ ਲੋਡ ਹੋਣ ਤੱਕ ਉਡੀਕ ਕਰੋ !!!", + "yes": "ਹਾਂ", + "no": "ਨੰ", + "failedResSubmissn": "ਸਪੁਰਦਗੀ ਅੰਤਮ ਬਿੰਦੂ ਤੋਂ ਅਸਫਲ ਜਵਾਬ। ਜਵਾਬ ਕੋਡ: {status}", + "errSubmittingForm": "ਇਸ ਫਾਰਮ ਨੂੰ ਸਪੁਰਦ ਕਰਨ ਵਿੱਚ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ", + "errorSavingFile": "ਫ਼ਾਈਲਾਂ ਨੂੰ ਰੱਖਿਅਤ ਕਰਨ ਵਿੱਚ ਗੜਬੜ ਹੋਈ। ਫ਼ਾਈਲ ਦਾ ਨਾਮ: {fileName}। ਗਲਤੀ: {error}", + "submittingDraftErrMsg": "ਡਰਾਫਟ ਨੂੰ ਸੁਰੱਖਿਅਤ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ", + "submittingDraftConsErrMsg": "ਡਰਾਫਟ ਸੁਰੱਖਿਅਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ। SubmissionId: {submissionId}। ਗਲਤੀ: {error}", + "formDraftAccessErrMsg": "ਬੇਨਤੀ ਕੀਤੀ ਸਪੁਰਦਗੀ ਪਹਿਲਾਂ ਹੀ ਸਪੁਰਦ ਕੀਤੀ ਗਈ ਹੈ, ਵੇਖੋ ਪੰਨੇ 'ਤੇ ਰੀਡਾਇਰੈਕਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ" + }, + "bCGovFooter": { + "home": "ਘਰ", + "about": "gov.bc.ca ਬਾਰੇ", + "disclaimer": "ਬੇਦਾਅਵਾ", + "privacy": "ਗੋਪਨੀਯਤਾ", + "accessibility": "ਪਹੁੰਚਯੋਗਤਾ", + "copyRight": "ਕਾਪੀਰਾਈਟ", + "contactUs": "ਸਾਡੇ ਨਾਲ ਸੰਪਰਕ ਕਰੋ" + }, + "bCGovNavBar": { + "about": "ਬਾਰੇ", + "myForms": "ਮੇਰੇ ਫਾਰਮ", + "createNewForm": "ਇੱਕ ਨਵਾਂ ਫਾਰਮ ਬਣਾਓ", + "help": "ਮਦਦ ਕਰੋ", + "feedback": "ਸੁਝਾਅ", + "admin": "ਐਡਮਿਨ" + }, + "homePage": { + "title": "ਕਾਮਨ ਹੋਸਟਡ ਫਾਰਮ ਸਰਵਿਸ ਨਾਲ ਫਾਰਮ ਬਣਾਓ, ਪ੍ਰਕਾਸ਼ਿਤ ਕਰੋ ਅਤੇ ਸਬਮਿਸ਼ਨ ਪ੍ਰਾਪਤ ਕਰੋ।", + "subTitle": "ਸਾਰੇ ਬੀ.ਸੀ. IDIR ਖਾਤੇ ਵਾਲੇ ਸਰਕਾਰੀ ਕਰਮਚਾਰੀ ਜਾਂ ਠੇਕੇਦਾਰ ਫਾਰਮ ਬਣਾਉਣ ਲਈ ਕਾਮਨ ਹੋਸਟਡ ਫਾਰਮ ਸਰਵਿਸ (CHEFS) ਦੇ ਸਾਡੇ ਹੋਸਟ ਕੀਤੇ ਸੰਸਕਰਣ ਦੀ ਵਰਤੋਂ ਕਰ ਸਕਦੇ ਹਨ।", + "takeATourOfChefs": "ਇਸ ਨੂੰ ਕਾਰਵਾਈ ਵਿੱਚ ਦੇਖਣ ਲਈ CHEFS ਦਾ ਦੌਰਾ ਕਰੋ।", + "logInToGetStarted": "ਸ਼ੁਰੂ ਕਰਨ ਲਈ ਲੌਗ ਇਨ ਕਰੋ", + "loginToStart": "ਸ਼ੁਰੂਆਤ ਕਰਨ ਲਈ IDIR ਨਾਲ ਲੌਗ ਇਨ ਕਰੋ", + "login": "ਲਾਗਿਨ", + "createFormLabel": "ਇੱਕ ਫਾਰਮ ਬਣਾਓ", + "manageAccessTitle": "ਆਪਣੇ ਫਾਰਮ ਤੱਕ ਪਹੁੰਚ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ", + "manageAccessSub1": "CHEFS ਤੁਹਾਨੂੰ ਜਨਤਕ ਫਾਰਮ ਬਣਾਉਣ ਦੀ ਇਜਾਜ਼ਤ ਦਿੰਦਾ ਹੈ, ਜਾਂ ਤੁਸੀਂ IDIR ਜਾਂ BCeID ਪ੍ਰਮਾਣੀਕਰਨ ਰਾਹੀਂ ਪਹੁੰਚ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰ ਸਕਦੇ ਹੋ।", + "manageAccessSub2": "ਤੁਸੀਂ ਆਪਣੀਆਂ ਸਾਰੀਆਂ ਬੇਨਤੀਆਂ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰਨ ਲਈ ਆਪਣੀ ਟੀਮ ਨੂੰ ਭੂਮਿਕਾਵਾਂ ਵੀ ਸੌਂਪ ਸਕਦੇ ਹੋ।", + "createCustomFormTitle": "CHEFS ਫਾਰਮ ਬਿਲਡਰ ਨਾਲ ਕਸਟਮ ਫਾਰਮ ਬਣਾਓ", + "createCustomFormSub1": "CHEFS ਦੇ ਨਾਲ, ਤੁਸੀਂ ਇੱਕ ਅਨੁਭਵੀ ਡਰੈਗ-ਐਂਡ-ਡ੍ਰੌਪ ਇੰਟਰਫੇਸ ਨਾਲ ਸੁਰੱਖਿਅਤ ਫਾਰਮ ਬਣਾ ਸਕਦੇ ਹੋ। ਤੁਸੀਂ ਫਾਰਮ ਕੰਪੋਨੈਂਟ ਜੋੜ ਸਕਦੇ ਹੋ, ਉਹਨਾਂ ਨੂੰ ਮੁੜ-ਵਿਵਸਥਿਤ ਕਰ ਸਕਦੇ ਹੋ, ਅਤੇ ਉਹਨਾਂ ਨੂੰ ਵੱਖ-ਵੱਖ ਲੇਆਉਟ ਸੰਰਚਨਾਵਾਂ ਵਿੱਚ ਛੱਡ ਸਕਦੇ ਹੋ।", + "chefsHowToTitle": "CHEFS ਕਿਵੇਂ-ਕਰਨ ਵੀਡੀਓ", + "chefsHowToSub": "ਸਾਡੀ ਕਵਿੱਕਸਟਾਰਟ ਗਾਈਡ ਤੁਹਾਨੂੰ CHEFS ਦੇ ਕੁਝ ਬੁਨਿਆਦੀ ਫੰਕਸ਼ਨਾਂ ਤੋਂ ਜਾਣੂ ਕਰਵਾਏਗੀ।", + "getStartedToChefs": "CHEFS ਦੀ ਵਰਤੋਂ ਸ਼ੁਰੂ ਕਰੋ", + "createOnlineTitle": "ਆਪਣੇ ਗਾਹਕਾਂ ਤੋਂ ਜਾਣਕਾਰੀ ਇਕੱਠੀ ਕਰਨ ਅਤੇ ਆਪਣੇ ਵਰਕਫਲੋ ਨੂੰ ਬਿਹਤਰ ਬਣਾਉਣ ਲਈ ਔਨਲਾਈਨ ਫਾਰਮ ਬਣਾਓ।", + "getStarted": "ਸ਼ੁਰੂ ਕਰੋ" + }, + "baseStepper": { + "setUpForm": "ਫਾਰਮ ਸੈਟ ਅਪ ਕਰੋ", + "designForm": "ਡਿਜ਼ਾਈਨ ਫਾਰਮ", + "manageForm": "ਫਾਰਮ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ" + }, + "create": { + "formSettings": "ਫਾਰਮ ਸੈਟਿੰਗਾਂ", + "disclaimer": "ਬੇਦਾਅਵਾ", + "disclaimerStmt": "ਮੈਂ ਫਾਰਮ ਡਿਜ਼ਾਈਨਰਾਂ ਲਈ ਬੇਦਾਅਵਾ ਅਤੇ ਜ਼ਿੰਮੇਵਾਰੀ ਦੇ ਬਿਆਨ ਨਾਲ ਸਹਿਮਤ ਹਾਂ", + "continue": "ਜਾਰੀ ਰੱਖੋ", + "back": "ਵਾਪਸ", + "confirmPageNav": "ਕੀ ਤੁਸੀਂ ਸੱਚਮੁੱਚ ਇਸ ਪੰਨੇ ਨੂੰ ਛੱਡਣਾ ਚਾਹੁੰਦੇ ਹੋ? ਤੁਹਾਡੇ ਦੁਆਰਾ ਕੀਤੀਆਂ ਤਬਦੀਲੀਆਂ ਨੂੰ ਸੁਰੱਖਿਅਤ ਨਹੀਂ ਕੀਤਾ ਜਾਵੇਗਾ।", + "agreementErrMsg": "ਤੁਹਾਨੂੰ ਉੱਪਰ ਦਿਖਾਏ ਗਏ ਗੋਪਨੀਯਤਾ ਬੇਦਾਅਵਾ ਨਾਲ ਸਹਿਮਤ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ।" + }, + "addTeamMember": { + "cantFindChefsUsers": "ਕਿਸੇ ਨੂੰ ਨਹੀਂ ਲੱਭ ਸਕਦੇ? ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਉਹਨਾਂ ਨੇ CHEFS ਵਿੱਚ ਲੌਗਇਨ ਨਾ ਕੀਤਾ ਹੋਵੇ।
ਕਿਰਪਾ ਕਰਕੇ ਉਹਨਾਂ ਨੂੰ CHEFS ਨੂੰ ਇੱਕ ਲਿੰਕ ਭੇਜੋ ਅਤੇ ਉਹਨਾਂ ਨੂੰ ਲੌਗ ਇਨ ਕਰਨ ਲਈ ਕਹੋ।", + "cancel": "ਰੱਦ ਕਰੋ", + "add": "ਸ਼ਾਮਲ ਕਰੋ", + "mustSelectAUser": "ਤੁਹਾਨੂੰ ਇਸ ਉਪਭੋਗਤਾ ਨੂੰ ਸ਼ਾਮਲ ਕਰਨ ਲਈ ਘੱਟੋ-ਘੱਟ ਇੱਕ ਭੂਮਿਕਾ ਦੀ ਚੋਣ ਕਰਨੀ ਚਾਹੀਦੀ ਹੈ।", + "addNewMember": "ਇੱਕ ਨਵਾਂ ਮੈਂਬਰ ਸ਼ਾਮਲ ਕਰੋ", + "enterUsername": "ਇੱਕ ਨਾਮ, ਈ-ਮੇਲ, ਜਾਂ ਉਪਭੋਗਤਾ ਨਾਮ ਦਰਜ ਕਰੋ", + "enterExactUsername": "ਇੱਕ ਸਹੀ ਈ-ਮੇਲ ਜਾਂ ਉਪਭੋਗਤਾ ਨਾਮ ਦਰਜ ਕਰੋ", + "BCeIDInputSearchMaxLen": "BCeID ਉਪਭੋਗਤਾ ਨਾਮ/ਈਮੇਲ ਲਈ ਖੋਜ ਇਨਪੁਟ 6 ਅੱਖਰਾਂ ਤੋਂ ਵੱਧ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ।", + "BCeIDMustBeExact": "BCeID ਲਈ ਈਮੇਲ ਖੋਜਾਂ ਸਟੀਕ ਹੋਣੀਆਂ ਚਾਹੀਦੀਆਂ ਹਨ।", + "errorGettingUsers": "ਉਪਭੋਗਤਾਵਾਂ ਨੂੰ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਗੜਬੜ {error}" + }, + "baseFilter": { + "cancel": "ਰੱਦ ਕਰੋ", + "columnName": "ਕਾਲਮ ਦਾ ਨਾਮ", + "exampleText": "ਉਦਾਹਰਨ ਟੈਕਸਟ", + "exampleText2": "ਉਦਾਹਰਨ ਟੈਕਸਟ 2", + "filterPlaceholderTxt": "ਫਿਲਟਰ ਪਲੇਸਹੋਲਡਰ ਟੈਕਸਟ", + "filter": "ਫਿਲਟਰ", + "value": "ਮੁੱਲ", + "resetColumns": "ਕਾਲਮ ਰੀਸੈਟ ਕਰੋ" + }, + "formViewerActions": { + "viewMyDraftOrSubmissions": "ਮੇਰਾ ਡਰਾਫਟ/ਸਬਮਿਸ਼ਨ ਦੇਖੋ", + "saveAsADraft": "ਇੱਕ ਡਰਾਫਟ ਦੇ ਰੂਪ ਵਿੱਚ ਸੁਰੱਖਿਅਤ ਕਰੋ", + "editThisDraft": "ਇਸ ਡਰਾਫਟ ਨੂੰ ਸੰਪਾਦਿਤ ਕਰੋ", + "switchSingleSubmssn": "ਸਿੰਗਲ ਸਬਮਿਸ਼ਨ 'ਤੇ ਸਵਿਚ ਕਰੋ", + "switchMultiSubmssn": "ਕਈ ਸਬਮਿਸ਼ਨਾਂ 'ਤੇ ਸਵਿਚ ਕਰੋ" + }, + "baseCopyToClipboard": { + "linkToClipboard": "ਲਿੰਕ ਕਲਿੱਪਬੋਰਡ 'ਤੇ ਕਾਪੀ ਕੀਤਾ ਗਿਆ", + "copyToClipboard": "ਕਲਿੱਪਬੋਰਡ ਵਿੱਚ ਕਾਪੀ ਕਰੋ", + "errCopyToClipboard": "ਕਲਿੱਪਬੋਰਡ 'ਤੇ ਕਾਪੀ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਵਿੱਚ ਤਰੁੱਟੀ।" + }, + "sucess": { + "sucessFormSubmissn": "ਤੁਹਾਡਾ ਫਾਰਮ ਸਫਲਤਾਪੂਰਵਕ ਜਮ੍ਹਾਂ ਹੋ ਗਿਆ ਹੈ", + "keepRecord": "ਜੇਕਰ ਤੁਸੀਂ ਇਸ ਸਬਮਿਸ਼ਨ ਦਾ ਰਿਕਾਰਡ ਰੱਖਣਾ ਚਾਹੁੰਦੇ ਹੋ, ਤਾਂ ਤੁਸੀਂ ਹੇਠ ਲਿਖੀਆਂ ਗੱਲਾਂ ਰੱਖ ਸਕਦੇ ਹੋ", + "confirmationId": "ਪੁਸ਼ਟੀ ਆਈ.ਡੀ" + }, + "bcGovAlertBanner": { + "defaultErrMsg": "ਤਰੁੱਟੀ: ਕੁਝ ਗਲਤ ਹੋ ਗਿਆ", + "error": "ਗਲਤੀ" + }, + "permissionUtils": { + "formNotAvailable": "ਫਾਰਮ ਇਸ ਸਮੇਂ ਉਪਲਬਧ ਨਹੀਂ ਹੈ। ਇਹ ਇੱਕ ਗਲਤ ਲਿੰਕ ਦੇ ਕਾਰਨ ਹੋ ਸਕਦਾ ਹੈ, ਜਾਂ ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਫਾਰਮ ਇਸਦੇ ਮਾਲਕ ਦੁਆਰਾ ਮਿਟਾ ਦਿੱਤਾ ਗਿਆ ਹੋਵੇ।", + "missingFormIdAndSubmssId": "ਵਿਕਲਪਾਂ ਵਿੱਚ formId ਅਤੇ submissionId ਦੋਵੇਂ ਮੌਜੂਦ ਨਹੀਂ ਹਨ", + "loadingFormErrMsg": "ਇਸ ਫਾਰਮ ਨੂੰ ਲੋਡ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "loadingForm": "{options} ਲੋਡ ਕਰਨ ਦੌਰਾਨ ਤਰੁੱਟੀ: {error}", + "idpHintMsg": "ਇਸ ਫਾਰਮ ਲਈ {idpHint} ਪ੍ਰਮਾਣੀਕਰਨ ਦੀ ਲੋੜ ਹੈ। ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਲੌਗਇਨ ਕਰੋ ਅਤੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।", + "formIdpMissMatch": "ਫਾਰਮ IDP ਬੇਮੇਲ। ਫਾਰਮ ਲਈ {idpHint} ਦੀ ਲੋੜ ਹੈ ਪਰ ਉਪਭੋਗਤਾ ਕੋਲ {userIdp} ਹੈ।" + }, + "download": { + "chefsDataExport": "CHEFS ਡਾਟਾ ਨਿਰਯਾਤ", + "preparingForDownloading": "ਡਾਊਨਲੋਡ ਕਰਨ ਲਈ ਤਿਆਰੀ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ...", + "downloadInfoA": "ਜੇਕਰ ਤੁਹਾਡੀ ਫਾਈਲ ਆਪਣੇ ਆਪ ਡਾਊਨਲੋਡ ਨਹੀਂ ਹੁੰਦੀ ਹੈ", + "downloadInfoB": "ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰਨ ਲਈ ਇੱਥੇ ਕਲਿੱਕ ਕਰੋ" + }, + "history": { + "submissnHistory": "ਤੁਹਾਡਾ ਸਬਮਿਸ਼ਨ ਇਤਿਹਾਸ (TBD)" + }, + "error": { + "logout": "ਲਾੱਗ ਆਊਟ, ਬਾਹਰ ਆਉਣਾ", + "somethingWentWrong": "ਗਲਤੀ: ਕੁਝ ਗਲਤ ਹੋ ਗਿਆ... :(" + }, + "login": { + "authenticateWith": "ਇਸ ਨਾਲ ਪ੍ਰਮਾਣਿਤ ਕਰੋ:", + "alreadyLoggedIn": "ਪਹਿਲਾਂ ਹੀ ਲੌਗ ਇਨ ਹੈ", + "home": "ਘਰ", + "about": "ਬਾਰੇ" + }, + "notFound": { + "about": "ਬਾਰੇ", + "pageNotFound": "404: ਪੰਨਾ ਨਹੀਂ ਮਿਲਿਆ। :(" + }, + "store": { + "admin": { + "addFormOwnerRole": "ਇਸ ਫਾਰਮ ਲਈ ਮਾਲਕ ਦੀ ਭੂਮਿਕਾ ਨੂੰ {fullName} ਵਿੱਚ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ", + "addRowError": "ਭੂਮਿਕਾ ਨੂੰ ਜੋੜਦੇ ਸਮੇਂ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "addRowConsoleErr": "ਵਰਤੋਂਕਾਰ {userId} ਨੂੰ ਫਾਰਮ {formId} ਵਿੱਚ ਸ਼ਾਮਲ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "apiKeyDelMsg": "ਇਸ ਫਾਰਮ ਲਈ API ਕੁੰਜੀ ਨੂੰ ਮਿਟਾ ਦਿੱਤਾ ਗਿਆ ਹੈ।", + "errDeletingApiKey": "API ਕੁੰਜੀ ਨੂੰ ਮਿਟਾਉਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦੇ ਸਮੇਂ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "consErrDeletingApiKey": "ਫਾਰਮ {formId} ਲਈ API ਕੁੰਜੀ ਨੂੰ ਮਿਟਾਉਣ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "fecthingFormsErrMsg": "ਫਾਰਮ ਪ੍ਰਾਪਤ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "fecthingFormsConsErrMsg": "ਐਡਮਿਨ ਫਾਰਮ ਡੇਟਾ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "fecthingFormErrMsg": "ਇਸ ਫਾਰਮ ਨੂੰ ਪ੍ਰਾਪਤ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "fecthingFormConsErrMsg": "ਐਡਮਿਨ ਫਾਰਮ {formId} ਡਾਟਾ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "fecthFormUserRolesErrMsg": "ਫਾਰਮ ਉਪਭੋਗਤਾ ਰੋਲ ਪ੍ਰਾਪਤ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਆਈ ਹੈ।", + "fecthFormUserRolesConsErrMsg": "ਐਡਮਿਨ ਰੋਲ ਡੇਟਾ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "fecthApiDetailsErrMsg": "ਇਸ ਫਾਰਮ ਦੇ API ਵੇਰਵੇ ਪ੍ਰਾਪਤ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "fecthApiDetailsConsErrMsg": "ਫਾਰਮ {formId} ਡੇਟਾ ਤੋਂ ਐਡਮਿਨ API ਵੇਰਵੇ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "restoreFormErrMsg": "ਇਸ ਫਾਰਮ ਨੂੰ ਰੀਸਟੋਰ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "restoreFormConsErrMsg": "ਫਾਰਮ {formId} ਡੇਟਾ ਨੂੰ ਬਹਾਲ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "getUsersErrMsg": "ਉਪਭੋਗਤਾਵਾਂ ਨੂੰ ਪ੍ਰਾਪਤ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਆਈ ਹੈ।", + "getUsersConsErrMsg": "ਪ੍ਰਸ਼ਾਸਕ ਉਪਭੋਗਤਾ ਡੇਟਾ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "getUserErrMsg": "ਇਸ ਉਪਭੋਗਤਾ ਨੂੰ ਪ੍ਰਾਪਤ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਆਈ ਹੈ।", + "getUserConsErrMsg": "ਪ੍ਰਸ਼ਾਸਕ ਉਪਭੋਗਤਾ {userId} ਡੇਟਾ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "storingFCHelpInfoErrMsg": "ਫਾਰਮ ਕੰਪੋਨੈਂਟ ਮਦਦ ਜਾਣਕਾਰੀ ਨੂੰ ਸਟੋਰ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ", + "storingFCHelpInfoConsErrMsg": "ਫਾਰਮ ਕੰਪੋਨੈਂਟ ਮਦਦ ਜਾਣਕਾਰੀ ਨੂੰ ਸਟੋਰ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "gettingFCImgUrlErrMsg": "ਚਿੱਤਰ url ਪ੍ਰਾਪਤ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ", + "gettingFCImgUrlConsErrMsg": "ਚਿੱਤਰ url ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "updatingFCStatusErrMsg": "ਪ੍ਰਕਾਸ਼ਿਤ ਸਥਿਤੀ ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ", + "updatingFCStatusConsErrMsg": "ਪ੍ਰਕਾਸ਼ਿਤ ਸਥਿਤੀ ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "fecthingFormBuilderCompsErrMsg": "ਫਾਰਮ ਬਿਲਡਰ ਭਾਗਾਂ ਨੂੰ ਪ੍ਰਾਪਤ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ", + "fecthingFormBuilderCompsConsErrMsg": "ਫਾਰਮ ਬਿਲਡਰ ਕੰਪੋਨੈਂਟਸ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}" + }, + "form": { + "fetchEmailTemplatesConsErrMsg": "{formId} ਲਈ ਈਮੇਲ ਟੈਮਪਲੇਟ ਲੋਡ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "fetchEmailTemplatesErrMsg": "ਇਸ ਫਾਰਮ ਲਈ ਈਮੇਲ ਟੈਮਪਲੇਟਾਂ ਨੂੰ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ", + "getCurrUserFormsErrMsg": "ਤੁਹਾਡੇ ਫਾਰਮ ਪ੍ਰਾਪਤ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "getCurrUserFormsConsErrMsg": "ਉਪਭੋਗਤਾ ਡੇਟਾ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "getUserFormPermErrMsg": "ਇਸ ਫਾਰਮ ਲਈ ਤੁਹਾਡੇ ਉਪਭੋਗਤਾ ਡੇਟਾ ਨੂੰ ਪ੍ਰਾਪਤ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਆਈ ਹੈ।", + "getUserFormPermConsErrMsg": "formID {formId} ਦੀ ਵਰਤੋਂ ਕਰਦੇ ਹੋਏ ਉਪਭੋਗਤਾ ਡੇਟਾ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "getUserFormRolesErrmsg": "ਇਸ ਫਾਰਮ ਲਈ ਤੁਹਾਡੇ ਉਪਭੋਗਤਾ ਡੇਟਾ ਨੂੰ ਪ੍ਰਾਪਤ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਆਈ ਹੈ।", + "getUserFormRolesConsErrmsg": "formID {formId} ਦੀ ਵਰਤੋਂ ਕਰਦੇ ਹੋਏ ਉਪਭੋਗਤਾ ਡੇਟਾ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "updCurrUserFormPrefErrMsg": "ਇਸ ਫਾਰਮ ਲਈ ਤੁਹਾਡੀਆਂ ਤਰਜੀਹਾਂ ਨੂੰ ਸੁਰੱਖਿਅਤ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "updCurrUserFormPrefConsErrMsg": "formID {formId}, ਅਤੇ prefs {preferences} ਦੀ ਵਰਤੋਂ ਕਰਦੇ ਹੋਏ ਉਪਭੋਗਤਾ ਫਾਰਮ ਪ੍ਰੀਫਸ ਨੂੰ ਅਪਡੇਟ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "getCurrUserFormPrefErrMsg": "ਇਸ ਫਾਰਮ ਲਈ ਤੁਹਾਡੀਆਂ ਤਰਜੀਹਾਂ ਨੂੰ ਪ੍ਰਾਪਤ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "getCurrUserFormPrefConsErrMsg": "formID {formId} ਦੀ ਵਰਤੋਂ ਕਰਦੇ ਹੋਏ ਉਪਭੋਗਤਾ ਫਾਰਮ ਪ੍ਰੀਫਸ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "delCurrformNotiMsg": "ਫਾਰਮ {name} ਨੂੰ ਸਫਲਤਾਪੂਰਵਕ ਮਿਟਾ ਦਿੱਤਾ ਗਿਆ ਹੈ।", + "delCurrFormConsErMsg": "ਫਾਰਮ {id} ਨੂੰ ਮਿਟਾਉਣ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "delDraftErrMsg": "ਇਸ ਡਰਾਫਟ ਨੂੰ ਮਿਟਾਉਣ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "delDraftConsErrMsg": "{draftId} ਨੂੰ ਮਿਟਾਉਣ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "fecthDraftErrMsg": "ਇਸ ਫਾਰਮ ਲਈ ਡਰਾਫਟ ਨੂੰ ਸਕੈਨ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "fecthDraftConsErrMsg": "ਫਾਰਮ {formId} ਲਈ ਡਰਾਫਟ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "fecthFormErrMsg": "ਇਸ ਫਾਰਮ ਨੂੰ ਪ੍ਰਾਪਤ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "fecthFormConsErrMsg": "ਫਾਰਮ {formId} ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "fetchFormFieldsErrMsg": "ਇਸ ਫਾਰਮ ਲਈ ਖੇਤਰਾਂ ਦੀ ਸੂਚੀ ਪ੍ਰਾਪਤ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "fetchFormFieldsConsErrMsg": "ਫਾਰਮ {formId} ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "publishDraftErrMsg": "ਪ੍ਰਕਾਸ਼ਿਤ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "publishDraftConsErrMsg": "{draftId} ਪ੍ਰਕਾਸ਼ਿਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "toggleVersnPublConsErrMsg": "toggleVersionPublish {versionId} {publish} ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "updateEmailTemplateConsErrMsg": "ਫਾਰਮ {formId} ਲਈ ਈਮੇਲ ਟੈਮਪਲੇਟ ਅੱਪਡੇਟ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "updateEmailTemplateErrMsg": "ਇਸ ਫਾਰਮ ਲਈ ਈਮੇਲ ਟੈਮਪਲੇਟਸ ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "updateFormErrMsg": "ਇਸ ਫਾਰਮ ਲਈ ਸੈਟਿੰਗਾਂ ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "updateFormConsErrMsg": "ਫਾਰਮ {id} ਨੂੰ ਅੱਪਡੇਟ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "deleteSubmissionNotifyMsg": "ਸਪੁਰਦਗੀ ਸਫਲਤਾਪੂਰਵਕ ਮਿਟਾਈ ਗਈ।", + "deleteSubmissionErrMsg": "ਇਸ ਸਬਮਿਸ਼ਨ ਨੂੰ ਮਿਟਾਉਣ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "deleteSubmissionConsErrMsg": "ਸਬਮਿਸ਼ਨ {submissionId} ਨੂੰ ਮਿਟਾਉਣ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "deleteSubmissionsNotifyMsg": "ਸਬਮਿਸ਼ਨਾਂ ਨੂੰ ਸਫਲਤਾਪੂਰਵਕ ਮਿਟਾਇਆ ਗਿਆ।", + "deleteSubmissionsErrMsg": "ਚੁਣੀਆਂ ਗਈਆਂ ਸਬਮਿਸ਼ਨਾਂ ਨੂੰ ਮਿਟਾਉਣ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "deleteSubmissionsConsErrMsg": "ਸਬਮਿਸ਼ਨਾਂ ਨੂੰ ਮਿਟਾਉਣ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "restoreSubmissionsNotiMsg": "ਸਬਮਿਸ਼ਨਾਂ ਨੂੰ ਸਫਲਤਾਪੂਰਵਕ ਰੀਸਟੋਰ ਕੀਤਾ ਗਿਆ।", + "restoreSubmissionsErrMsg": "ਇਸ ਸਬਮਿਸ਼ਨ ਨੂੰ ਰੀਸਟੋਰ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "restoreSubmissionsConsErrMsg": "ਸਬਮਿਸ਼ਨਾਂ ਨੂੰ ਬਹਾਲ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "restoreSubmissionNotiMsg": "ਸਪੁਰਦਗੀ ਸਫਲਤਾਪੂਰਵਕ ਰੀਸਟੋਰ ਕੀਤੀ ਗਈ।", + "restoreSubmissionErrMsg": "ਇਸ ਸਬਮਿਸ਼ਨ ਨੂੰ ਰੀਸਟੋਰ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "restoreSubmissionConsErrMsg": "ਸਬਮਿਸ਼ਨ {submissionId} ਨੂੰ ਬਹਾਲ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "fecthSubmissnUsersErrMsg": "ਇਸ ਸਬਮਿਸ਼ਨ ਲਈ ਪ੍ਰਾਪਤਕਰਤਾ ਈਮੇਲ ਪ੍ਰਾਪਤ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "fecthSubmissnUsersConsErrMsg": "ਸਬਮਿਸ਼ਨ {formSubmissionId} ਲਈ ਪ੍ਰਾਪਤਕਰਤਾ ਈਮੇਲ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "fetchSubmissnErrMsg": "ਇਸ ਸਬਮਿਸ਼ਨ ਨੂੰ ਪ੍ਰਾਪਤ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਆਈ ਹੈ।", + "fetchSubmissnConsErrMsg": "ਸਬਮਿਸ਼ਨ {submissionId} ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "fetchFormCSVExptFieldsErrMsg": "ਇਸ ਫਾਰਮ ਲਈ ਖੇਤਰਾਂ ਦੀ ਸੂਚੀ ਪ੍ਰਾਪਤ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "fetchFormCSVExptFieldsConsErrMsg": "ਫਾਰਮ {formId} ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "fetchSubmissnsErrMsg": "ਇਸ ਫਾਰਮ ਲਈ ਸਬਮਿਸ਼ਨਾਂ ਨੂੰ ਪ੍ਰਾਪਤ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "fetchSubmissnsConsErrMsg": "{formId} ਲਈ ਬੇਨਤੀਆਂ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "fetchVersionErrMsg": "ਇਸ ਫਾਰਮ ਨੂੰ ਪ੍ਰਾਪਤ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "fetchVersionConsErrMsg": "ਫਾਰਮ {formId} ਲਈ ਸੰਸਕਰਣ {versionId} ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "deleteApiKeyNotifyMsg": "ਇਸ ਫਾਰਮ ਲਈ API ਕੁੰਜੀ ਨੂੰ ਮਿਟਾ ਦਿੱਤਾ ਗਿਆ ਹੈ।", + "deleteApiKeyErrMsg": "API ਕੁੰਜੀ ਨੂੰ ਮਿਟਾਉਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦੇ ਸਮੇਂ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "deleteApiKeyConsErrMsg": "ਫਾਰਮ {formId} ਲਈ API ਕੁੰਜੀ ਨੂੰ ਮਿਟਾਉਣ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "generateApiKeyNotifyMsg": "ਇਸ ਫਾਰਮ ਲਈ ਇੱਕ API ਕੁੰਜੀ ਬਣਾਈ ਗਈ ਹੈ।", + "generateApiKeyErrMsg": "API ਕੁੰਜੀ ਬਣਾਉਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦੇ ਸਮੇਂ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "generateApiKeyConsErrMsg": "ਫਾਰਮ {formId} ਲਈ API ਕੁੰਜੀ ਬਣਾਉਣ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "readApiKeyErrMsg": "API ਕੁੰਜੀ ਪ੍ਰਾਪਤ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦੇ ਸਮੇਂ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "readApiKeyConsErrMsg": "ਫਾਰਮ {formId} ਲਈ API ਕੁੰਜੀ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}।", + "getFCPHImageUrlErrMsg": "ਚਿੱਤਰ url ਪ੍ਰਾਪਤ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ", + "getFCPHImageUrlConsErrMsg": "ਚਿੱਤਰ url ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "listFCPHErrMsg": "ਫਾਰਮ ਬਿਲਡਰ ਭਾਗਾਂ ਨੂੰ ਪ੍ਰਾਪਤ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ", + "listFCPHConsErrMsg": "ਫਾਰਮ ਬਿਲਡਰ ਕੰਪੋਨੈਂਟਸ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}", + "downloadFileErrMsg": "ਫ਼ਾਈਲ ਡਾਊਨਲੋਡ ਕਰਨ ਦੌਰਾਨ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ", + "downloadFileConsErrMsg": "ਫਾਈਲ ਡਾਊਨਲੋਡ ਕਰਨ ਵਿੱਚ ਗਲਤੀ: ਗਲਤੀ", + "readSubscriptionSettingsErrMsg": "ਗਾਹਕੀ ਸੈਟਿੰਗਾਂ ਨੂੰ ਪ੍ਰਾਪਤ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦੇ ਸਮੇਂ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "readSubscriptionSettingsConsErrMsg": "ਫਾਰਮ {formId} ਲਈ ਗਾਹਕੀ ਸੈਟਿੰਗਾਂ ਪ੍ਰਾਪਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}।", + "saveSubscriptionSettingsNotifyMsg": "ਇਸ ਫਾਰਮ ਲਈ ਗਾਹਕੀ ਸੈਟਿੰਗਾਂ ਨੂੰ ਸੁਰੱਖਿਅਤ ਕੀਤਾ ਗਿਆ ਹੈ।", + "saveSubscriptionSettingsErrMsg": "ਗਾਹਕੀ ਸੈਟਿੰਗਾਂ ਨੂੰ ਸੁਰੱਖਿਅਤ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦੇ ਸਮੇਂ ਇੱਕ ਤਰੁੱਟੀ ਉਤਪੰਨ ਹੋਈ।", + "saveSubscriptionSettingsConsErrMsg": "ਫਾਰਮ {formId} ਲਈ ਗਾਹਕੀ ਸੈਟਿੰਗਾਂ ਨੂੰ ਸੁਰੱਖਿਅਤ ਕਰਨ ਵਿੱਚ ਤਰੁੱਟੀ: {error}" + } + }, + "admin": { + "root": { + "admin": "ਐਡਮਿਨ" + }, + "form": { + "administerForm": "ਫਾਰਮ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ" + }, + "user": { + "administerUser": "ਉਪਭੋਗਤਾ ਦਾ ਪ੍ਰਬੰਧਨ ਕਰੋ" + } + }, + "user": { + "root": { + "myForms": "ਮੇਰੇ ਫਾਰਮ", + "history": "ਇਤਿਹਾਸ", + "user": "ਉਪਭੋਗਤਾ" + } + } +} diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/pt/index.js b/frontend/app/frontend/src/internationalization/trans/chefs/pt/index.js new file mode 100644 index 0000000..e23c1d2 --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/pt/index.js @@ -0,0 +1,4 @@ +import pt from '~/internationalization/trans/chefs/pt/pt.json'; +export default { + trans: pt, +}; diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/pt/pt.json b/frontend/app/frontend/src/internationalization/trans/chefs/pt/pt.json new file mode 100644 index 0000000..c0ce6ea --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/pt/pt.json @@ -0,0 +1,996 @@ +{ + "date": { + "date": "aaaa-mm-dd" + }, + "emailManagement": { + "emailManagement": "Gerenciamento de e-mail", + "manageForm": "Gerenciar formulário", + "submissionConfirmation": "Confirmação de envio" + }, + "emailTemplate": { + "body": "Corpo", + "save": "Salvar", + "saveEmailTemplateConsoleErrMsg": "Erro ao atualizar o modelo de e-mail do formulário {formId}: {error}", + "saveEmailTemplateErrMsg": "Ocorreu um erro ao tentar atualizar o modelo de e-mail.", + "subject": "Assunto", + "title": "Título", + "validBodyRequired": "Por favor insira um corpo para o e-mail", + "validSubjectRequired": "Insira uma linha de assunto para o e-mail", + "validTitleRequired": "Insira um título para o e-mail" + }, + "formsTable": { + "myForms": "Meus formulários", + "createNewForm": "Criar um novo formulário", + "search": "Procurar", + "manage": "Gerenciar", + "submissions": "Envios", + "formTitle": "Título do formulário", + "viewForm": "Ver formulário", + "description": "descrição", + "Description": "Descrição:", + "action": "Ações", + "loadingText": "Carregando, por favor espere" + }, + "preview": { + "preview": "Visualização", + "previewToolTip": "Isso mostra uma visualização do design e do comportamento da versão do formulário, conforme seus remetentes o verão. Você não pode enviar o formulário desta página." + }, + "manageLayout": { + "manageForm": "Gerenciar formulário" + }, + "shareForm": { + "shareForm": "Formulário de compartilhamento", + "shareLink": "Compartilhar link", + "copyQRCode": "Copie o link abaixo ou baixe o código QR.", + "warningMessage": "Não há nenhuma versão publicada do formulário neste momento. O link abaixo não estará acessível até que uma versão seja publicada.", + "openThisForm": "Abra este formulário", + "downloadQRCode": "Baixar código QR", + "close": "Fechar", + "copyURLToClipboard": "Copiar URL para a área de transferência" + }, + "manageFormActions": { + "emailManagement": "Gerenciamento de e-mail", + "viewSubmissions": "Ver envios", + "teamManagement": "Gerenciamento de equipe", + "deleteForm": "Excluir formulário", + "confirmDeletion": "Confirmar exclusão", + "deleteMessageA": "Tem certeza que deseja deletar", + "deleteMessageB": "Este formulário não estará mais acessível.", + "delete": "Excluir" + }, + "manageForm": { + "formSettings": "Configurações do formulário", + "apiKey": "Chave API", + "updated": "Atualizada", + "created": "Criada", + "formDesignHistory": "História do design do formulário", + "totalVersions": "Versões totais", + "status": "Status", + "update": "Atualizar", + "cancel": "Cancelar", + "eventSubscription": "Assinatura de evento" + }, + "formSettings": { + "pressToAddMultiEmail": "Pressione enter ou , ou espaço para adicionar vários endereços de e-mail", + "allowMultiDraft": "Permitir upload de vários rascunhos", + "formTitle": "Título do formulário", + "formDescription": "Descrição do formulário", + "formAccess": "Acesso ao formulário", + "info": "Se você usar este formulário para coletar informações do público em geral sobre tópicos de interesse geral do público, deverá entrar em contato com o GCPE para que seu envolvimento possa ser listado no", + "important": "IMPORTANTE", + "idimNotifyA": "Você deve notificar a equipe de gerenciamento de informações de identidade (IDIM) por e-mail", + "idimNotifyB": "sua intenção de aproveitar o BCeID para verificar as identidades de seus remetentes de formulário.", + "referenceGuideA": "Consulte nosso", + "referenceGuideB": "guia de usuario", + "referenceGuideC": "para mais detalhes", + "specificTeamMembers": "Membros Específicos da Equipe", + "formFunctionality": "Funcionalidade do formulário", + "formSubmissinScheduleMsg": "A Agenda de envios de formulários estará disponível nas Configurações de formulários após a publicação do formulário.", + "formSubmissionsSchedule": "Cronograma de Envios de Formulários", + "experimental": "Experimental", + "learnMore": "Saber mais", + "afterSubmission": "Após o envio", + "submissionConfirmation": "Mostrar os detalhes de confirmação de envio", + "theConfirmationID": "o ID de confirmação", + "infoB": "a opção para o usuário enviar a si mesmo uma confirmação de envio por e-mail", + "loginRequired": "Login obrigatório", + "canSaveAndEditDraftLabel": "Os remetentes podem salvar e editar rascunhos", + "canUpdateStatusAsReviewer": "Os revisores podem atualizar o status deste formulário (ou seja, enviado, atribuído, concluído)", + "submitterCanCopyExistingSubmissn": "Os remetentes podem copiar um envio existente", + "submissionConfirmationToolTip": "Selecionar esta opção controla o que o usuário que enviou este formulário verá no envio bem-sucedido.
Se marcado, ele exibirá", + "emailNotificatnToTeam": "Enviar um e-mail de notificação para minha equipe", + "emailNotificatnToTeamToolTip": "Envie uma notificação para o endereço de e-mail especificado quando qualquer usuário enviar este formulário", + "notificationEmailAddrs": "Endereços de e-mail de notificação", + "addMoreValidEmailAddrs": "Adicione um ou mais endereços de e-mail válidos", + "formScheduleSettings": "Configurações de agendamento de formulário", + "opensubmissions": "Submissões abertas", + "submissionsDeadline": "Por quanto tempo você deseja receber envios?", + "keepSubmissnOpenTilUnplished": "Manter aberto até que não seja publicado manualmente", + "submissionsClosingDate": "Agende uma data de encerramento", + "submissionPeriod": "Configurar período de envio", + "closeSubmissions": "Encerrar envios", + "keepOpenFor": "Manter aberto para", + "period": "Período", + "allowLateSubmissions": "Permitir envios tardios", + "allowLateSubmissionsInfoTip": "Se marcada, os remetentes poderão enviar dados após a data de encerramento.", + "afterCloseDateFor": "Após a data de fechamento para", + "repeatPeriod": "período de repetição", + "every": "Todo", + "repeatUntil": "Repetir até", + "summary": "Resumo", + "submissionsOpenDateRange": "Este formulário estará aberto para envios de", + "to": "para", + "scheduleRepetition": "A programação se repetirá a cada", + "allowLateSubmissnInterval": "permitindo submissões tardias para", + "until": "até", + "datesOfSubmissnInfo": "De acordo com as configurações, estas são as datas disponíveis para envios:", + "formOpenInterval": "Este formulário estará aberto para envios de", + "allowDateSubmissionDate": "permitindo a apresentação tardia até", + "customClosingMessage": "Definir mensagem de fechamento personalizada", + "customClosingMessageToolTip": "Permite adicionar uma mensagem personalizada para seus usuários quando eles visitam um formulário fechado.", + "closingMessage": "Mensagem de encerramento", + "sendReminderEmail": "ENVIAR e-mail de lembrete", + "autoReminderNotificatn": "Ativar notificação automática de lembrete", + "autoReminderNotificatnToolTip": "Envie e-mails de lembrete com o link do formulário durante o período de envio.", + "selectLoginType": "Selecione 1 tipo de login", + "formDescriptnMaxChars": "A descrição do formulário deve ter 255 caracteres ou menos", + "formTitlemaxChars": "O título do formulário deve ter 255 caracteres ou menos", + "formTitleReq": "O título do formulário é obrigatório", + "atLeastOneEmailReq": "Insira pelo menos 1 endereço de e-mail", + "validEmailRequired": "Insira todos os endereços de e-mail válidos", + "fieldRequired": "Este campo é obrigatório.", + "correctDateFormat": "A data deve estar no formato correto. ou seja aaaa-mm-dd", + "dateDiffMsg": "A data de fechamento do envio deve ser posterior à data de abertura do envio.", + "valueMustBeNumber": "O valor deve ser um número. ou seja 1,2,3,5,99", + "selectAnOptions": "Selecione pelo menos 1 opção", + "validInterval": "Este deve ser um intervalo válido.", + "fieldRequiredAndInterval": "Este campo é obrigatório e deve ser um intervalo.", + "dateGrtOpenSubmissnDate": "Repita até que a data seja maior que a data de envio aberto", + "public": "Público (anônimo)", + "allowEventSubscription": "Permitir assinatura de evento", + "eventSubscription": "Assinatura de evento", + "validEndpointRequired": "Insira um endpoint válido começando com https://", + "validBearerTokenRequired": "Insira um exemplo de token de portador válido: 89abddfb-2cff-4fda-83e6-13221f0c3d4f" + }, + "subscribeEvent": { + "eventType": "Tipo de evento", + "endpointUrl": "URL do terminal", + "eventSubmission": "Submissão", + "eventAssignment": "Assignment", + "eventStatusChange": "Mudança de status", + "endpointToken": "Token de terminal", + "urlPlaceholder": "https://endpoint.gov.bc.ca/api/v1/", + "save": "Salvar", + "text": "texto", + "password": "senha", + "hideSecret": "Ocultar Segredo", + "showSecret": "Mostrar Segredo", + "key": "Chave", + "saveSettingsErrMsg": "Ocorreu um erro ao tentar atualizar as configurações deste formulário.", + "updateSettingsConsoleErrMsg": "Erro ao atualizar as configurações do formulário {formId}: {error}" + }, + "apiKey": { + "disclaimer": "Isenção de responsabilidade", + "infoA": "Certifique-se de que o segredo da sua chave de API esteja armazenado em um local seguro (ou seja, cofre de chaves).", + "infoB": "Sua chave de API concede acesso irrestrito ao seu formulário. Não dê sua chave de API para ninguém.", + "infoC": "A chave de API APENAS deve ser usada para interações automatizadas do sistema. Não use sua chave de API para acesso baseado no usuário", + "deleteKey": "Excluir chave", + "apiKey": "Chave API", + "hideSecret": "Ocultar Segredo", + "showSecret": "Mostrar Segredo", + "sCTC": "Segredo copiado para a área de transferência", + "cSTC": "Copiar segredo para a área de transferência", + "key": "Chave", + "confirmDeletion": "Confirmar exclusão", + "deleteMsg": "Tem certeza de que deseja excluir sua chave de API?", + "delete": "Excluir", + "confirmKeyGen": "Confirmar geração de chave", + "createAPIKey": "Criar uma chave de API para este formulário?
Certifique-se de seguir o aviso de isenção nesta página.", + "regenerateAPIKey": "Gerar novamente a chave de API?
Continuar excluirá seu acesso atual à chave de API .", + "formOwnerKeyAcess": "Você deve ser o proprietário do formulário para gerenciar chaves de API.", + "regenerate": "Regenerado", + "generate": "Gerar", + "secret": "Segredo" + }, + "manageVersions": { + "important": "IMPORTANTE!", + "infoA": "Se não houver versões publicadas, os usuários não poderão acessar este formulário até que haja uma versão publicada atribuída. Depois que uma versão é publicada, essa versão não é mais editável. Você deve criar uma nova versão com base em uma das versões de formulário anteriores para continuar editando.", + "infoB": "Nota: Apenas uma versão pode ser publicada.", + "version": "Versão", + "draft": "Rascunho", + "clickToPreview": "Clique para visualizar", + "editVersion": "Editar versão", + "exportDesign": "Projeto de exportação", + "infoC": "Publique ou exclua sua versão de rascunho mais recente antes de iniciar uma nova versão.", + "deleteVersion": "Excluir versão", + "draftAlreadyExists": "O rascunho já existe", + "infoD": "Edite, publique ou exclua o rascunho existente antes de iniciar um novo rascunho.", + "publishVersion": "Publicar versão", + "unpublishVersion": "Cancelar publicação da versão", + "infoE": "Cancelar a publicação deste formulário o tirará de circulação até que uma versão seja publicada novamente.", + "confirmDeletion": "Confirmar exclusão", + "infoF": "Tem certeza de que deseja excluir esta versão?", + "delete": "Excluir", + "status": "Status", + "dateCreated": "Data Criada", + "createdBy": "Criado por", + "actions": "Ações", + "published": "Publicados", + "unpublished": "não publicado", + "useVersionInfo": "Use a versão {version} como base para uma nova versão", + "publishingVersionInfo": "Isso tornará a versão {version} do seu formulário ativa." + }, + "addOwner": { + "infoA": "Isso só deve ser feito caso o proprietário do formulário atual não esteja mais ativo ou esteja fora de contato em um evento prioritário. Caso contrário, faça com que o proprietário atual ou um administrador de equipe do formulário façam isso sozinhos.", + "hint": "Para encontrar o ID de usuário necessário, você pode ir até a guia 'USUÁRIOS' no portal do administrador e procurá-los.", + "addowner": "Adicionar proprietário", + "label": "ID do usuário (guid)" + }, + "adminFormsTable": { + "showDeletedForms": "Mostrar formulários excluídos", + "search": "Procurar", + "loadingText": "carregando-texto", + "noDataText": "Não há formulários em seu sistema", + "admin": "Administrador", + "launch": "Lançar", + "formTitle": "Título do formulário", + "created": "Criada", + "deleted": "Excluído", + "actions": "Ações", + "delete": "Excluir" + }, + "administerForm": { + "deleted": "EXCLUÍDO", + "restoreForm": "Restaurar este formulário", + "formDetails": "Detalhes do formulário", + "apiKeyDetails": "Detalhes da chave de API", + "deleteApiKey": "Excluir chave de API", + "formUsers": "Usuários do formulário", + "formVersions": "Versões de formulário", + "assignANewOwner": "Atribuir um novo proprietário", + "restoring": "Restaurando", + "restore": "Restaurar", + "toActiveState": "para estado ativo", + "confirmDeletion": "Confirmar exclusão", + "confirmDeletionMsg": "Tem certeza de que deseja excluir esta chave de API?", + "delete": "Excluir", + "confirmRestore": "Confirmar restauração" + }, + "administerUser": { + "userDetails": "Detalhes do usuario", + "openSSOConsole": "Abra o console SSO" + }, + "adminPage": { + "forms": "Formulários", + "users": "Usuários", + "developer": "Desenvolvedor", + "infoLinks": "Links de informações", + "metrics": "Métricas" + }, + "adminUsersTable": { + "search": "Procurar", + "loadingText": "Carregando, por favor espere", + "admin": "Administrador", + "fullName": "Nome completo", + "userID": "ID do usuário", + "created": "Criada", + "actions": "Ações" + }, + "adminVersions": { + "exportDesign": "Projeto de exportação", + "versions": "Versões", + "status": "Status", + "created": "Criada", + "lastUpdated": "Ultima atualização", + "actions": "Ações", + "published": "Publicados", + "unpublished": "não publicado", + "version": "Versão {versionNo}", + "notificationMsg": "Ocorreu um erro ao carregar o design do formulário." + }, + "developer": { + "user": "Do utilizador", + "name": "Nome", + "userName": "Nome de usuário", + "JWTContents": "Conteúdo JWT", + "JWTContentsSBTxt": "Conteúdo JWT copiado para a área de transferência", + "JWTContentsTTTxt": "Copie o conteúdo do JWT para a área de transferência", + "JWTToken": "Token JWT", + "JWTTokenSBTxt": "Token JWT copiado para a área de transferência", + "JWTTokenTTTxt": "Copie o token JWT para a área de transferência", + "chefsAPI": "API CHEFS", + "RBACSBTxt": "Resposta RBAC copiada para a área de transferência", + "RBACTTTxt": "Copiar resposta RBAC para a área de transferência", + "notificationMsg": "Falha ao obter o usuário do RBAC, consulte o console", + "notificationConsErr": "Erro ao obter o usuário do RBAC" + }, + "baseAuthButton": { + "logout": "Sair", + "login": "Conecte-se" + }, + "baseDialog": { + "defaultText": "texto padrão", + "ok": "OK", + "continue": "Continuar", + "cancel": "Cancelar", + "custom": "Personalizado" + }, + "baseSecure": { + "about": "Sobre", + "loginInfo": "Você precisa estar logado para usar esta ferramenta.", + "login": "Conecte-se", + "401NotAuthorized": "401: não autorizado. :", + "401ErrorMsg": "Sua conta não está configurada corretamente.
Por favor entre em contato", + "403Forbidden": "403: Proibido. :", + "403ErrorMsg": "Esta página requer autenticação {idp}.", + "401UnAuthorized": "401 não autorizado. :", + "401UnAuthorizedErrMsg": "Você não tem permissão para acessar esta página." + }, + "formDesigner": { + "formDesign": "Design de formulário", + "exportDesign": "Projeto de exportação", + "importDesign": "Design de Importação", + "important": "IMPORTANTE", + "formDesignInfoA": "Use o botão SALVAR DESIGN quando terminar de criar este formulário.", + "formDesignInfoB": "O botão ENVIAR é fornecido para o usuário enviar este formulário e será ativado após ser salvo.", + "formLoadErrMsg": "Ocorreu um erro ao carregar o design do formulário.", + "formLoadConsoleErrMsg": "Erro ao carregar o esquema do formulário {formId} (versão: rascunho {versionId}: {draftId}): {error}", + "formSchemaImportErrMsg": "Ocorreu um erro ao importar o esquema do formulário.", + "formSchemaImportConsoleErrMsg": "Erro ao importar o esquema do formulário: {error}", + "formDesignSaveErrMsg": "Ocorreu um erro ao tentar salvar este design de formulário. Se precisar atualizar ou deixar para tentar novamente mais tarde, você pode exportar o design existente na página para salvar para mais tarde.", + "formDesignSaveConsoleErrMsg": "Erro ao atualizar ou criar formulário (FormID: {formId}, versionId: {versionId}, draftId: {draftId}) Erro: {error}", + "collapse": "Colapso", + "actions": "Ações", + "version": "Versão", + "save": "Salvar", + "saving": "salvando", + "notSaved": "Não salvo", + "fieldnameError": "Você NÃO PODE usar a palavra-chave `form` como nome de campo {label}" + }, + "formViewerMultiUpload": { + "important": "IMPORTANTE", + "uploadSucessMsg": "Para garantir o upload bem-sucedido de vários rascunhos, faça o download e utilize o modelo fornecido.", + "confirmDownload": "Deseja baixá-lo?", + "jsonFileUpload": "Selecione o arquivo JSON para fazer upload", + "dragNDrop": "ou arraste e solte aqui", + "chooseAFile": "Escolha um arquivo", + "downloadDraftSubmns": "Faça o download do rascunho do relatório de envio e verifique se os dados foram inseridos corretamente.", + "downloadReport": "Baixar relatório", + "doYouWantToDownload": "Deseja baixá-lo?", + "uploadNewFile": "Carregar novo arquivo", + "uploadMultipleFileErr": "Desculpe, você pode enviar apenas um arquivo", + "dragMultipleFileErr": "Desculpe, você pode arrastar apenas um arquivo", + "fileFormatErr": "Desculpe, só aceitamos arquivos json", + "fileSizeErr": "O tamanho máximo de arquivo permitido é de 5 MB", + "parseJsonErr": "Não podemos analisar dados json do arquivo", + "jsonObjNotArray": "Formato de arquivo json incorreto", + "jsonObjNotArrayConsErr": "Um erro inesperado ocorreu.", + "jsonArrayEmpty": "Este arquivo json está vazio.", + "errorWhileValidate": "Há algo errado com este arquivo", + "errWhileCheckValidity": "Há algo errado com este arquivo", + "errAfterValidate": "Alguns erros encontrados, veja abaixo para mais informações.", + "fileIsEmpty": "este arquivo está vazio.", + "download": "Download" + }, + "formDisclaimer": { + "disclaimerAndStatement": "Isenção de responsabilidade e declaração de responsabilidade para Form Designers:", + "privacyLaw": "É sua responsabilidade cumprir as leis de privacidade que regem a coleta, uso e divulgação de informações de identificação pessoal.", + "disclosure": "O acesso a esta ferramenta de criação de formulários não concede inerentemente permissão para coletar, usar ou divulgar qualquer informação de identificação pessoal.", + "consent": "É sua responsabilidade obter consentimento para coletar informações conforme exigido por lei.", + "formIntention": "Antes de publicar ou distribuir seu formulário, você deve discutir a intenção do formulário com seu", + "privacyOfficer": "Oficial de Privacidade do Ministério", + "assement": "e para completar as avaliações conforme necessário." + }, + "requestReceipt": { + "emailPriority": "Prioridade de e-mail", + "emailReceipt": "Enviar por e-mail o recibo desta submissão", + "high": "Alta", + "low": "Baixo", + "normal": "Normal", + "send": "ENVIAR", + "sendToEmailAddress": "Enviar para endereço de e-mail", + "emailSent": "Um e-mail foi enviado para {to}.", + "sendingEmailErrMsg": "Ocorreu um erro ao tentar enviar seu e-mail.", + "sendingEmailConsErrMsg": "A confirmação do e-mail para {to} falhou: {error}", + "emailRequired": "E-mail é obrigatório" + }, + "submissionsTable": { + "noMatchingRecordText": "Nenhum registro correspondente encontrado", + "submissions": "Envios", + "submissionsTable": "Tabela de Envios", + "selectColumns": "Selecionar colunas", + "manageForm": "Gerenciar formulário", + "submissionsToFiles": "Exportar envios para arquivos", + "showDeletedSubmissions": "Mostrar envios excluídos", + "showMySubmissions": "Mostrar meus envios", + "search": "Procurar", + "loadingText": "Carregando, por favor espere", + "noDataText": "Não há envios para este formulário", + "delSelectedSubmissions": "Excluir envios selecionados", + "resSelectedSubmissions": "Restaurar envios selecionados", + "yes": "SIM", + "no": "NÃO", + "viewSubmission": "Ver Envio", + "deleteSubmission": "Excluir Envio", + "restore": "Restaurar", + "confirmDeletion": "Confirmar exclusão", + "delete": "Excluir", + "confirmRestoration": "Confirmar restauração", + "searchSubmissionFields": "Pesquisar campos de envio", + "save": "Salvar", + "searchTitle": "Pesquise e selecione colunas para mostrar em seu painel", + "status": "Status", + "submitter": "Remetente", + "submissionDate": "Data de submissão", + "event": "evento", + "view": "Visualizar", + "lateSubmission": "Submissão atrasada", + "confirmationID": "ID de confirmação", + "multiDelWarning": "Tem certeza de que deseja excluir os envios selecionados?", + "singleDelWarning": "Tem certeza de que deseja excluir este envio?", + "multiRestoreWarning": "Tem certeza de que deseja restaurar esses envios?", + "singleRestoreWarning": "Tem certeza de que deseja restaurar este envio?" + }, + "auditHistory": { + "viewEditHistory": "Ver Histórico de Edição", + "editHistory": "Editar Histórico", + "auditLogMsg": "Este é um log de auditoria de quem fez alterações neste envio após o envio original.", + "loadingText": "Carregando, por favor espere", + "close": "Fechar", + "userName": "Nome de usuário", + "date": "Data", + "errorMsg": "Ocorreu um erro ao tentar buscar o histórico.", + "consoleErrMsg": "Erro ao obter histórico de auditoria para" + }, + "deleteSubmission": { + "deleteThis": "Delete isso", + "draft": "Rascunho", + "submission": "Submissão", + "confirmDeletion": "Confirmar exclusão", + "deleteWarning": "Tem certeza de que deseja excluir isso", + "drafts": "rascunho", + "formSubmission": "submissão de formulário", + "delete": "Excluir" + }, + "manageSubmissionUsers": { + "manageTeamMembers": "Gerenciar membros da equipe", + "add": "Adicionar", + "draftFormInvite": "Você só pode convidar e gerenciar membros da equipe enquanto este formulário for um rascunho", + "submissionTeamMembers": "Membros da equipe para este envio", + "actions": "Ações", + "close": "Fechar", + "remove": "Remover", + "userNotFoundErrMsg": "Não consegue encontrar alguém? Eles podem não ter logado no CHEFS.
Por favor, envie-lhes um link para CHEFS e peça-lhes para fazer login.", + "name": "Nome", + "username": "Nome de usuário", + "email": "E-mail", + "removeUserWarningMsg1": "Tem certeza de que deseja remover", + "removeUserWarningMsg2": "Eles não terão mais permissões para este envio.", + "userExistInListMsg": "O usuário {username} já está na lista de membros da equipe.", + "getSubmissionUsersErr": "Ocorreu um erro ao tentar buscar usuários para este envio.", + "getSubmissionUsersConsoleErr": "Erro ao obter usuários para {submissionId}: {error}", + "sentInviteEmailTo": "Enviou e-mail de convite para", + "sentUninvitedEmailTo": "Enviou e-mail não convidado para", + "updateUserErrMsg": "Ocorreu um erro ao tentar atualizar os usuários para este envio.", + "updateUserConsoleErrMsg": "Erro ao definir as permissões do usuário. Sub: {submissionId} Usuário: {userId} Erro: {error}", + "searchInputLength": "A entrada de pesquisa para nome de usuário/e-mail BCeID deve ter mais de 6 caracteres.", + "exactBCEIDSearch": "As pesquisas de e-mail para BCeID devem ser exatas.", + "getUsersErrMsg": "Erro ao obter usuários: {error}", + "exactEmailOrUsername": "Digite um e-mail ou nome de usuário exato.", + "requiredFiled": "Digite um nome, e-mail ou nome de usuário" + }, + "mySubmissionsActions": { + "viewThisSubmission": "Ver este envio", + "copyThisSubmission": "Copiar este envio", + "editThisDraft": "Editar este rascunho" + }, + "mySubmissionsTable": { + "noMatchingRecordText": "Nenhum registro correspondente encontrado", + "previousSubmissions": "Envios anteriores", + "selectColumns": "Selecionar colunas", + "createNewSubmission": "Criar um novo envio", + "search": "Procurar", + "loadingText": "Carregando, por favor espere", + "noDataText": "Você não tem envios", + "searchSubmissionFields": "Pesquisar campos de envio", + "save": "Salvar", + "filterTitle": "Pesquise e selecione colunas para mostrar em seu painel", + "confirmationId": "ID de confirmação", + "actions": "ações", + "createdBy": "Criado por", + "statusUpdatedBy": "Estado atualizado por", + "status": "Status", + "submissionDate": "Data de submissão", + "draftUpdatedBy": "Rascunho atualizado por", + "draftLastEdited": "Rascunho da última edição", + "createLateSubmissn": "Criar envio tardio", + "formLoading": "Aguarde enquanto o formulário está carregando!!!", + "pleaseConfirm": "Por favor confirme", + "wantToSaveDraft": "Deseja salvar o rascunho?", + "yes": "Sim", + "no": "Não", + "multiDraftUploadSuccess": "O upload de vários rascunhos foi bem-sucedido!", + "failedResSubmissn": "Falha na resposta do endpoint de envio. Código de resposta: {status}", + "errSubmittingForm": "Ocorreu um erro ao enviar este formulário", + "errorSavingFile": "Erro ao salvar arquivos. Nome do arquivo: {fileName}. Erro: {error}", + "submittingDraftErrMsg": "Ocorreu um erro ao salvar um rascunho", + "submittingDraftConsErrMsg": "Erro ao salvar rascunho. SubmissãoId: {submissionId}. Erro: {error}" + }, + "notesPanel": { + "addNewNote": "Adicionar nova nota", + "cancel": "Cancelar", + "addNote": "ADICIONAR NOTA", + "noResponseErr": "Nenhum dado de resposta da API ao enviar o formulário", + "errorMesg": "Ocorreu um erro ao tentar adicionar a nota.", + "consoleErrMsg": "Erro ao adicionar nota:", + "fetchErrMsg": "Ocorreu um erro ao tentar buscar notas para este envio.", + "fetchConsoleErrMsg": "Erro ao adicionar nota:", + "notes": "Notas", + "note": "Observação", + "maxChars": "Máximo de 4.000 caracteres" + }, + "statusPanel": { + "currentStatus": "Status atual:", + "assignedTo": "Atribuído a:", + "assignOrUpdateStatus": "Atribuir ou atualizar status", + "display": "mostrar", + "statusIsRequired": "O status é obrigatório", + "assignTo": "Atribuir a", + "noDataText": "Nenhum Revisor de formulário encontrado na pesquisa. Adicione revisores de formulário na página Gerenciar.", + "assigneeIsRequired": "O cessionário é obrigatório", + "assignToMe": "ATRIBUIR PARA MIM", + "recipientEmail": "E-mail do destinatário", + "attachCommentToEmail": "Anexar comentário ao e-mail", + "emailComment": "Comentário de e-mail", + "maxChars": "Máximo de 4.000 caracteres", + "viewHistory": "VER HISTÓRICO", + "statusHistory": "Histórico de status", + "close": "FECHAR", + "addNoteNoReponserErr": "Nenhum dado de resposta da API ao enviar nota para atualização de status", + "addNoteConsoleErrMsg": "Erro ao atualizar o status: {error}", + "addNoteErrMsg": "Ocorreu um erro ao tentar atualizar o status", + "updtSubmissionsStatusErr": "Nenhum dado de resposta da API ao enviar o formulário de atualização de status", + "noStatus": "Sem status", + "noStatusesFound": "Nenhum status encontrado", + "statusCodesErr": "erro ao encontrar códigos de status", + "notifyErrorCode": "Ocorreu um erro ao buscar o status deste envio.", + "notifyConsoleErrorCode": "Erro ao obter status:", + "fetchSubmissionUsersErr": "Ocorreu um erro ao tentar buscar e-mails de destinatários para este envio.", + "fetchSubmissionUsersConsErr": "Erro ao obter e-mails de destinatários para", + "assignSubmissnToFormReviewer": "Os envios podem ser atribuídos a revisores de formulários.
Para adicionar mais membros da equipe como revisores de formulário, vá para a página Gerenciar deste formulário.", + "update": "ATUALIZAR", + "revise": "REVER", + "complete": "COMPLETO", + "assign": "ATRIBUIR" + }, + "statusTable": { + "loadingText": "Carregando, por favor espere", + "status": "Status", + "dateStatusChanged": "Status da data alterado", + "assignee": "Cessionário", + "updatedBy": "Atualizado por", + "getSubmissionStatusErr": "Ocorreu um erro ao tentar buscar os status.", + "getSubmissionStatusConsErr": "Erro ao adicionar nota:" + }, + "exportSubmissions": { + "exportSubmissionsToFile": "Exportar envios para arquivo", + "viewSubmissions": "Ver envios", + "fileType": "Tipo de arquivo", + "json": "JSON", + "csv": "CSV", + "formVersion": "Versão do formulário", + "versionIsRequired": "A versão é necessária.", + "dataFields": "Campos de dados", + "searchFields": "Campos de pesquisa", + "selectedForExports": "selecionado para exportação", + "submissionDate": "Data de submissão", + "all": "Todos", + "selectDateRange": "Selecione o intervalo de datas", + "SelectdateRange": "Selecione o intervalo de datas", + "from": "De", + "to": "Para", + "CSVFormat": "Formato CSV", + "multiRowPerSubmissionA": "1 - Várias linhas por envio com espaços de recuo", + "multiRowPerSubmissionB": "2 - Múltiplas linhas por envio", + "singleRowPerSubmission": "3 - Linha única por envio", + "unformatted": "4 - Não formatado", + "fileNameAndType": "Nome e tipo de arquivo", + "export": "Exportar", + "noResponseDataErr": "Nenhum dado em resposta da chamada exportSubmissions", + "apiCallErrorMsg": "Ocorreu um erro ao tentar exportar envios para este formulário.", + "apiCallConsErrorMsg": "Erro ao exportar envios para", + "selectAllFields": "Selecione todos os campos", + "emailSentMsg": "Um e-mail será enviado para {email} contendo um link para baixar seus dados quando estiver pronto", + "exportInProgress": "Exportação em andamento", + "of": "de" + }, + "printOptions": { + "submitButtonTxt": "Envie para o CDOGS e faça o download", + "templatePrint": "Modelo de impressão", + "uploadTemplateFile": "Carregar arquivo de modelo", + "downloadOptions": "Opções de download", + "print": "Imprimir", + "browserPrint": "Impressão do navegador", + "pageFromBrowser": "a página do seu navegador", + "uploadA": "Carregar um", + "uploadB": "ter uma versão estruturada", + "docGrnSucess": "Documento gerado com sucesso", + "failedDocGenErrMsg": "Falha ao gerar documento", + "failedDocGenConsErrMsg": "Erro ao enviar modelo: {error}", + "cDogsTemplate": "modelo CDOGS" + }, + "proactiveHelpDialog": { + "componentInfoLink": "Link de informações do componente", + "learnMoreLinkTxt": "Saiba mais O campo Link não pode ficar vazio.", + "largeImgTxt": "Imagem grande. O tamanho da imagem não pode ser maior que 0,5 MB", + "componentName": "Nome do componente:", + "learnMoreLink": "Link Saiba mais:", + "clickToEnableLink": "Clique para ativar o link", + "clickToDisableLink": "Clique para desativar o link", + "imageUpload": "Carregamento de imagem:", + "cancel": "Cancelar", + "save": "Salvar", + "description": "Descrição" + }, + "proactiveHelpPreviewDialog": { + "learnMore": "Saber mais" + }, + "preview": { + "preview": "Visualização", + "previewToolTip": "Isso mostra uma visualização do design e do comportamento da versão do formulário, conforme seus remetentes o verão. Você não pode enviar o formulário desta página." + }, + "generalLayout": { + "loadingText": "Carregando, por favor espere", + "preview": "VISUALIZAR", + "published": "PUBLICADOS", + "unpublished": "NÃO PUBLICADO", + "edit": "EDITAR", + "formTitle": "Título do formulário", + "actions": "Ações" + }, + "formSubmission": { + "editThisSubmission": "Editar este envio", + "submission": "Submissão", + "alertInfo": "Após a edição, reenvie o formulário para salvar suas alterações.", + "viewAllSubmissions": "Ver todos os envios", + "submitted": "Submetido:", + "confirmationID": "ID de confirmação:", + "submittedBy": "Enviado por:", + "cancel": "CANCELAR", + "status": "Status", + "updatedAt": "Modificada", + "updatedBy": "Modificado por" + }, + "teamManagement": { + "noMatchingRecordText": "Nenhum registro correspondente encontrado", + "teamManagement": "Gerenciamento de equipe", + "selectColumns": "Selecionar colunas", + "manageForm": "Gerenciar formulário", + "search": "Procurar", + "loadingText": "Carregando, por favor espere", + "noDataText": "Falha ao carregar os dados da função da equipe", + "removeSelectedUsers": "Remover usuários selecionados", + "removeThisUser": "Remover este usuário", + "confirmRemoval": "Confirmar remoção", + "remove": "Remover", + "searchTeamManagementFields": "Campos de gerenciamento de equipe de pesquisa", + "save": "Salvar", + "teamMebersTitle": "Pesquise e selecione colunas para mostrar em seu painel", + "fullName": "Nome completo", + "username": "Nome de usuário", + "identityProvider": "provedor de identidade", + "delSelectedMembersWarning": "Tem certeza de que deseja remover os membros selecionados?", + "delSelectedMemberWarning": "Tem certeza de que deseja remover o membro selecionado?", + "idpMessage": "já está na equipe.", + "formOwnerErrMsg": "Sempre deve haver pelo menos um proprietário de formulário", + "formOwnerConsoleErrMsg": "Não é possível remover {userId} porque ele é o único proprietário restante deste formulário.", + "insufficientPermissnMsg": "Permissões insuficientes para gerenciar a equipe", + "getUserErrMsg": "Erro ao obter usuários do formulário:", + "getRolesErrMsg": "Erro ao obter a lista de papéis:", + "formOwnerRemovalWarning": "Não é possível remover porque ele é o único proprietário restante deste formulário.", + "removeUsersErrMsg": "Ocorreu um erro ao tentar excluir os usuários selecionados", + "removeUserConsoleErrMsg": "Erro ao excluir usuários do formulário {formId}: {error}", + "updUserRolesErrMsg": "Ocorreu um erro ao tentar atualizar todas as funções do usuário", + "updUserRolesConsoleErrMsg": "Erro ao definir todas as funções de usuário para o formulário {formId}: {error}", + "setUserFormsErrMsg": "Ocorreu um erro ao tentar atualizar as funções de um usuário", + "setUserFormsConsoleErrMsg": "Erro ao definir funções de usuário para o formulário {formId}: {error}" + }, + "floatButton": { + "publish": "Publicar", + "manage": "Gerenciar", + "redo": "refazer", + "undo": "Desfazer", + "preview": "Visualização", + "bottom": "Fundo", + "top": "Principal", + "actions": "Ações", + "collapse": "Colapso", + "saved": "Salvou", + "save": "Salvar", + "saving": "salvando", + "notSaved": "Não salvo" + }, + "formViewer": { + "lateFormSubmissions": "O período de envio do formulário expirou! Você ainda pode criar um envio tardio clicando no botão abaixo.", + "createLateSubmission": "Criar envio tardio", + "draftSaved": "Rascunho salvo", + "saving": "salvando", + "pleaseConfirm": "Por favor confirme", + "submitFormWarningMsg": "Tem certeza que deseja enviar seu formulário?", + "submit": "Enviar", + "wantToSaveDraft": "Deseja salvar o rascunho?", + "version": "Versão: {version}", + "formScheduleExpireMessage": "O envio do formulário não está disponível porque o período de envio agendado expirou.", + "getUsersSubmissionsErrMsg": "Ocorreu um erro ao buscar o envio para este formulário", + "getUsersSubmissionsConsoleErrMsg": "Erro ao carregar os dados de envio do formulário {submissionId}: {error}", + "multiDraftUploadSuccess": "O upload de vários rascunhos foi bem-sucedido!", + "readVersionErrMsg": "Nenhum esquema em resposta. VersionId: {versionId}", + "readDraftErrMsg": "Nenhum esquema em resposta. RascunhoId: {draftId}", + "alertRouteMsg": "O proprietário do formulário não publicou o formulário e ele não está disponível para envio.", + "fecthingFormErrMsg": "Ocorreu um erro ao buscar este formulário", + "fecthingFormConsoleErrMsg": "Erro ao carregar esquema de formulário {versionId}: {error}", + "savingDraftErrMsg": "Ocorreu um erro ao salvar um rascunho", + "savingDraftConsoleErrMsg": "Erro ao salvar rascunho. SubmissãoId: {submissionId}. Erro: {error}", + "submissionsPreviewAlert": "Envio desativado durante a visualização do formulário", + "submissionsSubmitErrMsg": "Erro ao enviar o formulário: {errors}", + "sendSubmissionErrMsg": "Falha na resposta do endpoint de envio. Código de resposta: {status}", + "errMsg": "Ocorreu um erro ao enviar este formulário", + "customEventAlert": "Eventos de botão personalizados ainda não são suportados. Tipo de evento: {event}", + "formLoading": "Aguarde enquanto o formulário está carregando!!!", + "yes": "Sim", + "no": "Não", + "failedResSubmissn": "Falha na resposta do endpoint de envio. Código de resposta: {status}", + "errSubmittingForm": "Ocorreu um erro ao enviar este formulário", + "errorSavingFile": "Erro ao salvar arquivos. Nome do arquivo: {fileName}. Erro: {error}", + "submittingDraftErrMsg": "Ocorreu um erro ao salvar um rascunho", + "submittingDraftConsErrMsg": "Erro ao salvar rascunho. SubmissãoId: {submissionId}. Erro: {error}", + "formDraftAccessErrMsg": "O envio solicitado já foi enviado, redirecionando para a página Exibir" + }, + "bCGovFooter": { + "home": "Lar", + "about": "Sobre gov.bc.ca", + "disclaimer": "Isenção de responsabilidade", + "privacy": "Privacidade", + "accessibility": "Acessibilidade", + "copyRight": "direito autoral", + "contactUs": "Contate-nos" + }, + "bCGovNavBar": { + "about": "Sobre", + "myForms": "Meus formulários", + "createNewForm": "Criar um novo formulário", + "help": "Ajuda", + "feedback": "Opinião", + "admin": "Administrador" + }, + "homePage": { + "title": "Crie, publique formulários e receba envios com o Common Hosted Forms Service.", + "subTitle": "Tudo a.C. Funcionários do governo ou contratados com uma conta IDIR podem usar nossa versão hospedada do Common Hosted Forms Service (CHEFS) para criar formulários.", + "takeATourOfChefs": "Faça um tour pelo CHEFS para vê-lo em ação.", + "logInToGetStarted": "Faça login para começar", + "loginToStart": "Faça login com IDIR para começar", + "login": "Conecte-se", + "createFormLabel": "Criar um formulário", + "manageAccessTitle": "Gerencie o acesso ao seu formulário", + "manageAccessSub1": "O CHEFS permite criar formulários públicos ou gerenciar o acesso por meio da autenticação IDIR ou BCeID.", + "manageAccessSub2": "Você também pode atribuir funções à sua equipe para gerenciar todos os seus envios.", + "createCustomFormTitle": "Crie formulários personalizados com o construtor de formulários CHEFS", + "createCustomFormSub1": "Com o CHEFS, você pode criar formulários seguros com uma interface intuitiva de arrastar e soltar. Você pode adicionar componentes de formulário, reorganizá-los e soltá-los em diferentes configurações de layouts.", + "chefsHowToTitle": "Vídeos de instruções do CHEFS", + "chefsHowToSub": "Nosso Guia de início rápido apresentará algumas das funções básicas do CHEFS.", + "getStartedToChefs": "Comece a usar o CHEFS", + "createOnlineTitle": "Crie formulários online para coletar informações de seus clientes e melhorar seus fluxos de trabalho.", + "getStarted": "iniciar" + }, + + "baseStepper": { + "setUpForm": "Configurar formulário", + "designForm": "Forma de desenho", + "manageForm": "Gerenciar formulário" + }, + "create": { + "formSettings": "Configurações do formulário", + "disclaimer": "Isenção de responsabilidade", + "disclaimerStmt": "Eu concordo com a isenção de responsabilidade e declaração de responsabilidade para Form Designers", + "continue": "Continuar", + "back": "Voltar", + "confirmPageNav": "Você realmente deseja sair desta página? As alterações feitas não serão salvas.", + "agreementErrMsg": "Você deve concordar com o aviso de privacidade mostrado acima." + }, + "addTeamMember": { + "cantFindChefsUsers": "Não consegue encontrar alguém? Eles podem não ter logado no CHEFS.
Por favor, envie-lhes um link para CHEFS e peça-lhes para fazer login.", + "cancel": "Cancelar", + "add": "Adicionar", + "mustSelectAUser": "Você deve selecionar pelo menos uma função para adicionar este usuário.", + "addNewMember": "Adicionar um novo membro", + "enterUsername": "Digite um nome, e-mail ou nome de usuário", + "enterExactUsername": "Digite um e-mail ou nome de usuário exato", + "BCeIDInputSearchMaxLen": "A entrada de pesquisa para nome de usuário/e-mail BCeID deve ter mais de 6 caracteres.", + "BCeIDMustBeExact": "As pesquisas de e-mail para BCeID devem ser exatas.", + "errorGettingUsers": "Erro ao obter usuários {error}" + }, + "baseFilter": { + "cancel": "Cancelar", + "columnName": "Nome da coluna", + "exampleText": "Texto de Exemplo", + "exampleText2": "Texto de Exemplo 2", + "filterPlaceholderTxt": "Filtrar texto de espaço reservado", + "filter": "Filtro", + "value": "valor", + "resetColumns": "Redefinir colunas" + }, + "formViewerActions": { + "viewMyDraftOrSubmissions": "Ver meus rascunhos/envios", + "saveAsADraft": "Salve como um rascunho", + "editThisDraft": "Editar este rascunho", + "switchSingleSubmssn": "Alternar para envio único", + "switchMultiSubmssn": "Mudar para vários envios" + }, + "baseCopyToClipboard": { + "linkToClipboard": "Link copiado para a área de transferência", + "copyToClipboard": "Copiar para área de transferência", + "errCopyToClipboard": "Erro ao tentar copiar para a área de transferência." + }, + "sucess": { + "sucessFormSubmissn": "Seu formulário foi submetido com sucesso", + "keepRecord": "Se você deseja manter um registro desta submissão, você pode manter o seguinte", + "confirmationId": "ID de confirmação" + }, + "bcGovAlertBanner": { + "defaultErrMsg": "Erro: algo deu errado", + "error": "erro" + }, + "permissionUtils": { + "formNotAvailable": "O formulário está indisponível no momento. Isso pode ocorrer devido a um link incorreto ou o formulário pode ter sido excluído pelo proprietário.", + "missingFormIdAndSubmssId": "Opções faltando formId e submitId", + "loadingFormErrMsg": "Ocorreu um erro ao carregar este formulário.", + "loadingForm": "Erro ao carregar {options}: {error}", + "idpHintMsg": "Este formulário requer autenticação {idpHint}. Faça login novamente e tente novamente.", + "formIdpMissMatch": "Incompatibilidade de IDP de formulário. O formulário requer {idpHint}, mas o usuário tem {userIdp}." + }, + "download": { + "chefsDataExport": "Exportação de Dados CHEFS", + "preparingForDownloading": "Preparando para download...", + "downloadInfoA": "Se o seu arquivo não baixar automaticamente", + "downloadInfoB": "Clique Aqui Para Tentar Novamente" + }, + "history": { + "submissnHistory": "Seu histórico de envios (TBD)" + }, + "error": { + "logout": "Sair", + "somethingWentWrong": "Erro: Algo deu errado... :(" + }, + "login": { + "authenticateWith": "Autenticar com:", + "alreadyLoggedIn": "já logado", + "home": "Lar", + "about": "Sobre" + }, + "notFound": { + "about": "Sobre", + "pageNotFound": "404 Página Não Encontrada. :(" + }, + "store": { + "admin": { + "addFormOwnerRole": "Adicionada a função de Proprietário para este formulário a {fullName}", + "addRowError": "Ocorreu um erro ao adicionar a função.", + "addRowConsoleErr": "Erro ao adicionar o usuário {userId} ao formulário {formId}: {error}", + "apiKeyDelMsg": "A chave de API para este formulário foi excluída.", + "errDeletingApiKey": "Ocorreu um erro ao tentar excluir a chave de API.", + "consErrDeletingApiKey": "Erro ao excluir chave de API para o formulário {formId}: {error}", + "fecthingFormsErrMsg": "Ocorreu um erro ao buscar os formulários.", + "fecthingFormsConsErrMsg": "Erro ao obter dados do formulário de administrador: {error}", + "fecthingFormErrMsg": "Ocorreu um erro ao buscar este formulário.", + "fecthingFormConsErrMsg": "Erro ao obter dados do formulário {formId} do administrador: {error}", + "fecthFormUserRolesErrMsg": "Ocorreu um erro ao buscar as funções de usuário do formulário.", + "fecthFormUserRolesConsErrMsg": "Erro ao obter dados de funções administrativas: {error}", + "fecthApiDetailsErrMsg": "Ocorreu um erro ao buscar os detalhes da API deste formulário.", + "fecthApiDetailsConsErrMsg": "Erro ao obter detalhes da API de administrador dos dados do formulário {formId}: {error}", + "restoreFormErrMsg": "Ocorreu um erro ao restaurar este formulário.", + "restoreFormConsErrMsg": "Erro ao restaurar os dados do formulário {formId}: {error}", + "getUsersErrMsg": "Ocorreu um erro ao buscar usuários.", + "getUsersConsErrMsg": "Erro ao obter dados de usuários administradores: {error}", + "getUserErrMsg": "Ocorreu um erro ao buscar este usuário.", + "getUserConsErrMsg": "Erro ao obter os dados do usuário administrador {userId}: {error}", + "storingFCHelpInfoErrMsg": "Ocorreu um erro ao armazenar as informações de ajuda do componente de formulário", + "storingFCHelpInfoConsErrMsg": "Erro ao armazenar informações de ajuda do componente de formulário: {error}", + "gettingFCImgUrlErrMsg": "Ocorreu um erro ao obter o URL da imagem", + "gettingFCImgUrlConsErrMsg": "Erro ao obter o URL da imagem: {error}", + "updatingFCStatusErrMsg": "Ocorreu um erro ao atualizar o status de publicação", + "updatingFCStatusConsErrMsg": "Erro ao atualizar o status de publicação: {error}", + "fecthingFormBuilderCompsErrMsg": "Ocorreu um erro ao buscar os componentes do construtor de formulários", + "fecthingFormBuilderCompsConsErrMsg": "Erro ao obter os componentes do construtor de formulário: {error}" + }, + "form": { + "fetchEmailTemplatesConsErrMsg": "Erro ao carregar modelos de e-mail para {formId}: {error}", + "fetchEmailTemplatesErrMsg": "Ocorreu um erro ao buscar os modelos de e-mail para este formulário", + "getCurrUserFormsErrMsg": "Ocorreu um erro ao buscar seus formulários.", + "getCurrUserFormsConsErrMsg": "Erro ao obter dados do usuário: {error}", + "getUserFormPermErrMsg": "Ocorreu um erro ao buscar seus dados de usuário para este formulário.", + "getUserFormPermConsErrMsg": "Erro ao obter dados do usuário usando formID {formId}: {error}", + "getUserFormRolesErrmsg": "Ocorreu um erro ao buscar seus dados de usuário para este formulário.", + "getUserFormRolesConsErrmsg": "Erro ao obter dados do usuário usando formID {formId}: {error}", + "updCurrUserFormPrefErrMsg": "Ocorreu um erro ao salvar suas preferências para este formulário.", + "updCurrUserFormPrefConsErrMsg": "Erro ao atualizar as preferências de formulário do usuário usando formID {formId} e preferências {preferences}: {error}", + "getCurrUserFormPrefErrMsg": "Ocorreu um erro ao buscar suas preferências para este formulário.", + "getCurrUserFormPrefConsErrMsg": "Erro ao obter preferências de formulário do usuário usando formID {formId}: {error}", + "delCurrformNotiMsg": "O formulário {name} foi excluído com sucesso.", + "delCurrFormConsErMsg": "Erro ao excluir o formulário {id}: {error}", + "delDraftErrMsg": "Ocorreu um erro ao excluir este rascunho.", + "delDraftConsErrMsg": "Erro ao excluir {draftId}: {error}", + "fecthDraftErrMsg": "Ocorreu um erro ao digitalizar rascunhos para este formulário.", + "fecthDraftConsErrMsg": "Erro ao obter rascunhos para o formulário {formId}: {error}", + "fecthFormErrMsg": "Ocorreu um erro ao buscar este formulário.", + "fecthFormConsErrMsg": "Erro ao obter o formulário {formId}: {error}", + "fetchFormFieldsErrMsg": "Ocorreu um erro ao buscar a lista de campos para este formulário.", + "fetchFormFieldsConsErrMsg": "Erro ao obter o formulário {formId}: {error}", + "publishDraftErrMsg": "Ocorreu um erro durante a publicação.", + "publishDraftConsErrMsg": "Erro ao publicar {draftId}: {error}", + "toggleVersnPublConsErrMsg": "Erro em toggleVersionPublish {versionId} {publish}: {error}", + "updateEmailTemplateConsErrMsg": "Erro ao atualizar modelos de e-mail para o formulário {formId}: {error}", + "updateEmailTemplateErrMsg": "Ocorreu um erro ao atualizar os modelos de e-mail deste formulário.", + "updateFormErrMsg": "Ocorreu um erro ao atualizar as configurações deste formulário.", + "updateFormConsErrMsg": "Erro ao atualizar o formulário {id}: {error}", + "deleteSubmissionNotifyMsg": "Submissão excluída com sucesso.", + "deleteSubmissionErrMsg": "Ocorreu um erro ao excluir este envio.", + "deleteSubmissionConsErrMsg": "Erro ao excluir o envio {submissionId}: {error}", + "deleteSubmissionsNotifyMsg": "Envios excluídos com sucesso.", + "deleteSubmissionsErrMsg": "Ocorreu um erro ao excluir os envios selecionados.", + "deleteSubmissionsConsErrMsg": "Erro ao excluir envios: {error}", + "restoreSubmissionsNotiMsg": "Envios restaurados com sucesso.", + "restoreSubmissionsErrMsg": "Ocorreu um erro ao restaurar este envio.", + "restoreSubmissionsConsErrMsg": "Erro ao restaurar envios: {error}", + "restoreSubmissionNotiMsg": "Envio restaurado com sucesso.", + "restoreSubmissionErrMsg": "Ocorreu um erro ao restaurar este envio.", + "restoreSubmissionConsErrMsg": "Erro ao restaurar o envio {submissionId}: {error}", + "fecthSubmissnUsersErrMsg": "Ocorreu um erro ao buscar o e-mail do destinatário para este envio.", + "fecthSubmissnUsersConsErrMsg": "Erro ao obter o e-mail do destinatário para envio {formSubmissionId}: {error}", + "fetchSubmissnErrMsg": "Ocorreu um erro ao buscar este envio.", + "fetchSubmissnConsErrMsg": "Erro ao obter o envio {submissionId}: {error}", + "fetchFormCSVExptFieldsErrMsg": "Ocorreu um erro ao buscar a lista de campos para este formulário.", + "fetchFormCSVExptFieldsConsErrMsg": "Erro ao obter o formulário {formId}: {error}", + "fetchSubmissnsErrMsg": "Ocorreu um erro ao buscar envios para este formulário.", + "fetchSubmissnsConsErrMsg": "Erro ao obter envios para {formId}: {error}", + "fetchVersionErrMsg": "Ocorreu um erro ao buscar este formulário.", + "fetchVersionConsErrMsg": "Erro ao obter a versão {versionId} para o formulário {formId}: {error}", + "deleteApiKeyNotifyMsg": "A chave de API para este formulário foi excluída.", + "deleteApiKeyErrMsg": "Ocorreu um erro ao tentar excluir a chave de API.", + "deleteApiKeyConsErrMsg": "Erro ao excluir chave de API para o formulário {formId}: {error}", + "generateApiKeyNotifyMsg": "Uma chave de API para este formulário foi criada.", + "generateApiKeyErrMsg": "Ocorreu um erro ao tentar gerar uma chave de API.", + "generateApiKeyConsErrMsg": "Erro ao gerar chave de API para o formulário {formId}: {error}", + "readApiKeyErrMsg": "Ocorreu um erro ao tentar buscar a chave de API.", + "readApiKeyConsErrMsg": "Erro ao obter chave de API para o formulário {formId}: {error}.", + "getFCPHImageUrlErrMsg": "Ocorreu um erro ao obter o URL da imagem", + "getFCPHImageUrlConsErrMsg": "Erro ao obter URL da imagem: {error}", + "listFCPHErrMsg": "Ocorreu um erro ao buscar os componentes do construtor de formulários", + "listFCPHConsErrMsg": "Erro ao obter os componentes do construtor de formulário: {error}", + "downloadFileErrMsg": "Ocorreu um erro durante o download do arquivo", + "downloadFileConsErrMsg": "Erro ao baixar o arquivo: erro", + "readSubscriptionSettingsErrMsg": "Ocorreu um erro ao tentar buscar as configurações de assinatura.", + "readSubscriptionSettingsConsErrMsg": "Erro ao obter configurações de assinatura para o formulário {formId}: {error}.", + "saveSubscriptionSettingsNotifyMsg": "As configurações de inscrição para este formulário foram salvas.", + "saveSubscriptionSettingsErrMsg": "Ocorreu um erro ao tentar salvar as configurações de assinatura.", + "saveSubscriptionSettingsConsErrMsg": "Erro ao salvar as configurações de assinatura para o formulário {formId}: {error}" + } + }, + "admin": { + "root": { + "admin": "Administrador" + }, + "form": { + "administerForm": "Administrar formulário" + }, + "user": { + "administerUser": "Administrar usuário" + } + }, + "user": { + "root": { + "myForms": "MEUS FORMULÁRIOS", + "history": "HISTÓRIA", + "user": "Do utilizador" + } + } +} diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/ru/index.js b/frontend/app/frontend/src/internationalization/trans/chefs/ru/index.js new file mode 100644 index 0000000..0ff34e8 --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/ru/index.js @@ -0,0 +1,4 @@ +import ru from '~/internationalization/trans/chefs/ru/ru.json'; +export default { + trans: ru, +}; diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/ru/ru.json b/frontend/app/frontend/src/internationalization/trans/chefs/ru/ru.json new file mode 100644 index 0000000..1d7357e --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/ru/ru.json @@ -0,0 +1,995 @@ +{ + "date": { + "date": "гггг-мм-дд" + }, + "emailManagement": { + "emailManagement": "Управление электронной почтой", + "manageForm": "Управление формой", + "submissionConfirmation": "Подтверждение отправки" + }, + "emailTemplate": { + "body": "Тело", + "save": "сохранять", + "saveEmailTemplateConsoleErrMsg": "Ошибка обновления шаблона электронной почты для формы {formId}: {error}", + "saveEmailTemplateErrMsg": "Произошла ошибка при попытке обновить шаблон электронной почты.", + "subject": "Предмет", + "title": "Заголовок", + "validBodyRequired": "Пожалуйста, введите текст электронного письма", + "validSubjectRequired": "Пожалуйста, введите тему письма", + "validTitleRequired": "Пожалуйста, введите заголовок для электронного письма" + }, + "formsTable": { + "myForms": "Мои формы", + "createNewForm": "Создать новую форму", + "search": "Поиск", + "manage": "Управление", + "submissions": "Записи", + "formTitle": "Название формы", + "viewForm": "Просмотреть форму", + "description": "описание", + "Description": "Описание:", + "action": "Действия", + "loadingText": "Загрузка, пожалуйста подождите" + }, + "manageLayout": { + "manageForm": "Управление формой" + }, + "preview": { + "preview": "Предварительный просмотр", + "previewToolTip": "Это показывает предварительный просмотр дизайна и поведения версии формы, как ее увидят отправители. Вы не можете отправить форму с этой страницы." + }, + "shareForm": { + "shareForm": "Поделиться формой", + "shareLink": "Поделиться ссылкой", + "copyQRCode": "Скопируйте ссылку ниже или загрузите QR-код.", + "warningMessage": "На данный момент нет опубликованной версии формы. Ссылка ниже будет недоступна, пока версия не будет опубликована.", + "openThisForm": "Открыть эту форму", + "downloadQRCode": "Скачать QR-код", + "close": "Закрыть", + "copyURLToClipboard": "Скопировать URL в буфер обмена" + }, + "manageFormActions": { + "emailManagement": "Управление электронной почтой", + "viewSubmissions": "Просмотр записей", + "teamManagement": "Управление командой", + "deleteForm": "Удалить форму", + "confirmDeletion": "Подтвердить удаление", + "deleteMessageA": "Вы уверены, что хотите удалить", + "deleteMessageB": "Эта форма больше не будет доступна.", + "delete": "Удалить" + }, + "manageForm": { + "formSettings": "Настройки формы", + "apiKey": "API-ключ", + "updated": "Обновлено", + "created": "Создан", + "formDesignHistory": "История изменений форм", + "totalVersions": "Всего версий", + "status": "Статус", + "update": "Обновление", + "cancel": "Отмена", + "eventSubscription": "Подписка на события" + }, + "formSettings": { + "pressToAddMultiEmail": "Нажмите Enter или пробел , чтобы добавить несколько адресов электронной почты.", + "allowMultiDraft": "Разрешить загрузку нескольких черновиков", + "formTitle": "Название формы", + "formDescription": "Описание формы", + "formAccess": "Доступ к форме", + "info": "Если вы будете использовать эту форму для сбора публичной информации по темам, которые представляют общий интерес, вам необходимо связаться с GCPE, чтобы ваше участие могло быть указано на", + "important": "ВАЖНО", + "idimNotifyA": "Вы должны уведомить группу управления идентификационной информацией (IDIM) по электронной почте.", + "idimNotifyB": "ваше намерение использовать BCeID для проверки личности отправителей форм.", + "referenceGuideA": "Пожалуйста, обратитесь к нашему", + "referenceGuideB": "руководству пользователя", + "referenceGuideC": "для подробностей", + "specificTeamMembers": "Конкретные члены команды", + "formFunctionality": "Функциональность формы", + "formSubmissinScheduleMsg": "Расписание отправки формы будет доступно в настройках формы после публикации формы.", + "formSubmissionsSchedule": "Расписание отправки формы", + "experimental": "Экспериментальный", + "learnMore": "Узнать больше", + "afterSubmission": "После отправки", + "submissionConfirmation": "Показать детали подтверждения отправки", + "theConfirmationID": "идентификатор подтверждения", + "infoB": "возможность для пользователя отправить себе по электронной почте подтверждение отправки", + "loginRequired": "Требуется вход", + "canSaveAndEditDraftLabel": "Отправители могут сохранять и редактировать черновики", + "canUpdateStatusAsReviewer": "Рецензенты могут обновлять статус этой формы (т. е. «Отправлено», «Назначено», «Завершено»).", + "submitterCanCopyExistingSubmissn": "Отправители могут копировать существующую отправку", + "submissionConfirmationToolTip": "Выбор этого параметра определяет, что увидит пользователь, отправивший эту форму, при успешной отправке.
Если флажок установлен, он будет отображать", + "emailNotificatnToTeam": "Отправить моей команде уведомление по электронной почте", + "emailNotificatnToTeamToolTip": "Отправлять уведомление на указанный вами адрес электронной почты, когда любой пользователь отправляет эту форму", + "notificationEmailAddrs": "Адреса электронной почты для уведомлений", + "addMoreValidEmailAddrs": "Добавьте один или несколько адресов электронной почты", + "formScheduleSettings": "Настройки расписания форм", + "opensubmissions": "Открытые записи", + "submissionsDeadline": "Как долго вы хотите получать записи?", + "keepSubmissnOpenTilUnplished": "Держите открытым до тех пор, пока не будет вручную удалена публикация", + "submissionsClosingDate": "Назначить дату закрытия", + "submissionPeriod": "Установить период отправки", + "closeSubmissions": "Закрыть запись", + "keepOpenFor": "Держите открытым для", + "period": "Период", + "allowLateSubmissions": "Разрешить поздние отправки", + "allowLateSubmissionsInfoTip": "Если этот флажок установлен, отправители смогут отправлять данные после даты закрытия", + "afterCloseDateFor": "После даты закрытия для", + "repeatPeriod": "Период повторения", + "every": "Каждый", + "repeatUntil": "Повторять до", + "summary": "Итог", + "submissionsOpenDateRange": "Эта форма будет открыта для отправки от", + "to": "к", + "scheduleRepetition": "Расписание будет повторяться каждые", + "allowLateSubmissnInterval": "Разрешить позднию отправку", + "until": "до", + "datesOfSubmissnInfo": "В соответствии с настройками это доступные даты отправки:", + "formOpenInterval": "Эта форма будет открыта для отправки от", + "allowDateSubmissionDate": "с возможностью поздней отправки до", + "customClosingMessage": "Установить пользовательское сообщение закрытия", + "customClosingMessageToolTip": "Позвольте вам добавить индивидуальное сообщение для ваших пользователей, когда они посещают закрытую форму.", + "closingMessage": "Заключительное сообщение", + "sendReminderEmail": "ОТПРАВИТЬ Напоминание по электронной почте", + "autoReminderNotificatn": "Включить автоматическое уведомление о напоминании", + "autoReminderNotificatnToolTip": "Отправьте электронное письмо с напоминанием со ссылкой на форму в течение периода отправки", + "selectLoginType": "Пожалуйста, выберите тип входа", + "formDescriptnMaxChars": "Описание формы должно содержать не более 255 символов", + "formTitlemaxChars": "Название формы должно содержать не более 255 символов", + "formTitleReq": "Укажите название формы", + "atLeastOneEmailReq": "Пожалуйста, введите хотя бы 1 адрес электронной почты", + "validEmailRequired": "Пожалуйста, введите все действительные адреса электронной почты", + "fieldRequired": "Это поле обязательно к заполнению", + "correctDateFormat": "Дата должна быть в правильном формате. т.е. гггг-мм-дд", + "dateDiffMsg": "Дата закрытия записи должна быть больше даты открытия", + "valueMustBeNumber": "Значение должно быть числом, т.е. 1,2,3,5,99", + "selectAnOptions": "Пожалуйста, выберите хотя бы 1 вариант", + "validInterval": "Это должен быть допустимый интервал", + "fieldRequiredAndInterval": "Это поле является обязательным и должно быть интервалом", + "dateGrtOpenSubmissnDate": "Повторяйте до тех пор, пока дата не станет больше, чем дата отправки", + "public": "Публичный (анонимный)", + "allowEventSubscription": "Разрешить подписку на событие", + "eventSubscription": "Подписка на события", + "validEndpointRequired": "Введите допустимый URL, начинающуюся с https://", + "validBearerTokenRequired": "Введите допустимый пример токена: 89abddfb-2cff-4fda-83e6-13221f0c3d4f" + }, + "subscribeEvent": { + "eventType": "Тип события", + "endpointUrl": "URL-адрес сервера", + "eventSubmission": "Событие новой записи", + "eventAssignment": "Событие назначения", + "eventStatusChange": "Изменение статуса", + "endpointToken": "Токен для URL", + "urlPlaceholder": "https://endpoint.gov.bc.ca/api/v1/", + "save": "Сохранять", + "text": "текст", + "password": "пароль", + "hideSecret": "Скрыть секрет", + "showSecret": "Показать секрет", + "key": "Ключ", + "saveSettingsErrMsg": "Произошла ошибка при попытке обновить настройки этой формы.", + "updateSettingsConsoleErrMsg": "Ошибка при обновлении настроек для формы {formId}: {error}" + }, + "apiKey": { + "disclaimer": "Отказ от ответственности", + "infoA": "Убедитесь, что ваш секрет ключа API хранится в безопасном месте (например, в хранилище ключей).", + "infoB": "Ваш ключ API предоставляет неограниченный доступ к вашей форме. Никому не передавайте свой ключ API.", + "infoC": "Ключ API следует использовать ТОЛЬКО для взаимодействия с автоматизированной системой. Не используйте свой ключ API для пользовательского доступа", + "deleteKey": "Удалить ключ", + "apiKey": "API-ключ", + "hideSecret": "Скрыть секрет", + "showSecret": "Показать секрет", + "sCTC": "Секрет скопирован в буфер обмена", + "cSTC": "Скопировать секрет в буфер обмена", + "key": "Ключ", + "confirmDeletion": "Подтвердить удаление", + "deleteMsg": "Вы уверены, что хотите удалить свой ключ API?", + "delete": "Удалить", + "confirmKeyGen": "Подтвердите генерацию ключа", + "createAPIKey": "Создать ключ API для этой формы?
Убедитесь, что вы следуете Отказу от ответственности на этой странице.", + "regenerateAPIKey": "Восстановить ключ API?
Если продолжить, ваш текущий доступ к ключу API будет удален .", + "formOwnerKeyAcess": "Вы должны быть владельцем формы для управления ключами API.", + "regenerate": "Регенерировать", + "generate": "Создать", + "secret": "Секрет" + }, + "manageVersions": { + "important": "ВАЖНО!", + "infoA": "Если нет опубликованных версий, пользователи не смогут получить доступ к этой форме, пока не будет назначена опубликованная версия. После публикации версия становится недоступной для редактирования. Чтобы продолжить редактирование, необходимо создать новую версию на основе одной из предыдущих версий формы.", + "infoB": "Примечание. Можно опубликовать только одну версию.", + "version": "Версия", + "draft": "Черновик", + "clickToPreview": "Нажмите, чтобы просмотреть", + "editVersion": "Изменить версию", + "exportDesign": "Экспорт дизайна", + "infoC": "Пожалуйста, опубликуйте или удалите последнюю черновую версию перед запуском новой версии.", + "deleteVersion": "Удалить версию", + "draftAlreadyExists": "Проект уже существует", + "infoD": "Пожалуйста, отредактируйте, опубликуйте или удалите существующий черновик перед созданием нового черновика.", + "publishVersion": "Опубликовать версию", + "unpublishVersion": "Отменить публикацию версии", + "infoE": "Если вы отмените публикацию этой формы, она будет удалена из обращения до тех пор, пока ее версия не будет опубликована снова.", + "confirmDeletion": "Подтвердить удаление", + "infoF": "Вы уверены, что хотите удалить эту версию?", + "delete": "Удалить", + "status": "Статус", + "dateCreated": "Дата создания", + "createdBy": "Создано", + "actions": "Действия", + "published": "Опубликовано", + "unpublished": "Неопубликовано", + "useVersionInfo": "Использовать версию {version} в качестве основы для новой версии", + "publishingVersionInfo": "Это запустит версию {version} вашей формы." + }, + "addOwner": { + "infoA": "Это следует делать только в том случае, если текущий владелец формы больше не активен или не выходит на связь в приоритетном событии. В противном случае попросите текущего владельца или администратора группы сделать это самостоятельно.", + "hint": "Чтобы найти нужный идентификатор пользователя, вы можете перейти на вкладку «ПОЛЬЗОВАТЕЛИ» на портале администрирования и выполнить поиск.", + "addowner": "Добавить владельца", + "label": "Идентификатор пользователя (GUID)" + }, + "adminFormsTable": { + "showDeletedForms": "Показать удаленные формы", + "search": "Поиск", + "loadingText": "Загрузка, пожалуйста подождите", + "noDataText": "В вашей системе нет форм", + "admin": "Админ", + "launch": "Запуск", + "formTitle": "Название формы", + "created": "Созданный", + "deleted": "Удалено", + "actions": "Действия", + "delete": "Удалить" + }, + "administerForm": { + "deleted": "УДАЛЕНО", + "restoreForm": "Восстановить эту форму", + "formDetails": "Сведения о форме", + "apiKeyDetails": "Сведения о ключе API", + "deleteApiKey": "Удалить ключ API", + "formUsers": "Пользователи формы", + "formVersions": "Версии формы", + "assignANewOwner": "Назначить нового владельца", + "restoring": "Восстановление", + "restore": "Восстановить", + "toActiveState": "в активное состояние", + "confirmDeletion": "Подтвердить удаление", + "confirmDeletionMsg": "Вы уверены, что хотите удалить этот ключ API?", + "delete": "Удалить", + "confirmRestore": "Подтвердить восстановление" + }, + "administerUser": { + "userDetails": "Сведения о пользователе", + "openSSOConsole": "Открыть консоль SSO входа" + }, + "adminPage": { + "forms": "Формы", + "users": "Пользователи", + "developer": "Разработчик", + "infoLinks": "Информационные ссылки", + "metrics": "Метрики" + }, + "adminUsersTable": { + "search": "Поиск", + "loadingText": "Загрузка, пожалуйста подождите", + "admin": "Админ", + "fullName": "Полное имя", + "userID": "ID пользователя", + "created": "Созданно", + "actions": "Действия" + }, + "adminVersions": { + "exportDesign": "Экспорт дизайна", + "versions": "Версии", + "status": "Статус", + "created": "Созданно", + "lastUpdated": "Последнее обновление", + "actions": "Действия", + "published": "Опубликовано", + "unpublished": "Неопубликовано", + "version": "Версия {versionNo}", + "notificationMsg": "Произошла ошибка при загрузке дизайна формы" + }, + "developer": { + "user": "Пользователь", + "name": "Имя", + "userName": "Имя пользователя", + "JWTContents": "JWT Содержание", + "JWTContentsSBTxt": "Содержимое JWT скопировано в буфер обмена", + "JWTContentsTTTxt": "Скопировать содержимое JWT в буфер обмена", + "JWTToken": "Токен JWT", + "JWTTokenSBTxt": "Токен JWT скопирован в буфер обмена", + "JWTTokenTTTxt": "Скопировать токен JWT в буфер обмена", + "chefsAPI": "CHEFS-API", + "RBACSBTxt": "Ответ RBAC скопирован в буфер обмена", + "RBACTTTxt": "Скопировать ответ RBAC в буфер обмена", + "notificationMsg": "Не удалось получить пользователя из RBAC, см. консоль", + "notificationConsErr": "Ошибка получения пользователя из RBAC" + }, + "baseAuthButton": { + "logout": "Выйти", + "login": "Авторизоваться" + }, + "baseDialog": { + "defaultText": "текст по умолчанию", + "ok": "OK", + "continue": "Продолжать", + "cancel": "Отмена", + "custom": "пользовательский" + }, + "baseSecure": { + "about": "О", + "loginInfo": "Вы должны войти в систему, чтобы воспользоваться этой функцией", + "login": "Авторизоваться", + "401NotAuthorized": "401: не авторизован:", + "401ErrorMsg": "Ваша учетная запись настроена неправильно.
Пожалуйста свяжитесь с нами", + "403Forbidden": "403: Запрещено:", + "403ErrorMsg": "Для этой страницы требуется аутентификация {idp}.", + "401UnAuthorized": "401: Неавторизованный. :", + "401UnAuthorizedErrMsg": "Вы не имеете доступа к этой странице." + }, + "formDesigner": { + "formDesign": "Дизайн формы", + "exportDesign": "Экспорт дизайна", + "importDesign": "Импорт дизайна", + "important": "ВАЖНО", + "formDesignInfoA": "Используйте кнопку СОХРАНИТЬ ДИЗАЙН , когда закончите создание этой формы.", + "formDesignInfoB": "Кнопка SUBMIT предназначена для того, чтобы ваш пользователь отправил эту форму, и она будет активирована после ее сохранения.", + "formLoadErrMsg": "Произошла ошибка при загрузке дизайна формы.", + "formLoadConsoleErrMsg": "Ошибка при загрузке схемы формы {formId} (версия: {versionId}, черновик: {draftId}): {error}", + "formSchemaImportErrMsg": "Произошла ошибка при импорте схемы формы.", + "formSchemaImportConsoleErrMsg": "Ошибка импорта схемы формы: {error}", + "formDesignSaveErrMsg": "Произошла ошибка при попытке сохранить дизайн этой формы. Если вам нужно обновить или оставить, чтобы повторить попытку позже, вы можете Экспортировать существующий дизайн на странице, чтобы сохранить его на потом.", + "formDesignSaveConsoleErrMsg": "Ошибка при обновлении или создании формы (FormID: {formId}, versionId: {versionId}, draftId: {draftId}) Ошибка: {error}", + "collapse": "Свернуть", + "actions": "Действия", + "version": "Версия", + "save": "Сохранять", + "saving": "Сохранение", + "notSaved": "Не сохранено", + "fieldnameError": "Вы НЕ МОЖЕТЕ использовать ключевое слово `form` в качестве имени поля {label}." + }, + "formViewerMultiUpload": { + "important": "ВАЖНО", + "uploadSucessMsg": "Чтобы обеспечить успешную загрузку нескольких черновиков, загрузите и используйте предоставленный шаблон", + "confirmDownload": "Вы хотите скачать его?", + "jsonFileUpload": "Выберите файл JSON для загрузки", + "dragNDrop": "или перетащите сюда", + "chooseAFile": "Выберите файл", + "downloadDraftSubmns": "Пожалуйста, загрузите черновик отчета об отправке и убедитесь, что данные введены правильно.", + "downloadReport": "Скачать отчет", + "doYouWantToDownload": "Вы хотите скачать его?", + "uploadNewFile": "Загрузить новый файл", + "uploadMultipleFileErr": "Извините, вы можете загрузить только один файл", + "dragMultipleFileErr": "Извините, вы можете перетащить только один файл", + "fileFormatErr": "Извините, мы принимаем только файлы json", + "fileSizeErr": "Максимально допустимый размер файла составляет 5 МБ", + "parseJsonErr": "Не можем разобрать json данные из файла", + "jsonObjNotArray": "Неправильный формат json-файла", + "jsonObjNotArrayConsErr": "Произошла непредвиденная ошибка", + "jsonArrayEmpty": "Этот файл json пуст.", + "errorWhileValidate": "Что-то не так с этим файлом", + "errWhileCheckValidity": "Что-то не так с этим файлом", + "errAfterValidate": "Обнаружены некоторые ошибки, дополнительную информацию см. ниже", + "fileIsEmpty": "этот файл пустой.", + "download": "Скачать" + }, + "formDisclaimer": { + "disclaimerAndStatement": "Отказ от ответственности и заявление об ответственности дизайнеров форм:", + "privacyLaw": "Вы несете ответственность за соблюдение законов о конфиденциальности, регулирующих сбор, использование и раскрытие личной информации.", + "disclosure": "Доступ к этому инструменту дизайнера форм по своей сути не дает разрешения на сбор, использование или раскрытие какой-либо информации, позволяющей установить личность.", + "consent": "Вы несете ответственность за получение согласия на сбор информации в соответствии с требованиями закона.", + "formIntention": "Перед публикацией или распространением вашей формы вы должны обсудить назначение формы с вашим", + "privacyOfficer": "Сотрудник министерства по вопросам конфиденциальности", + "assement": "и завершить оценку по мере необходимости." + }, + "requestReceipt": { + "emailPriority": "Приоритет электронной почты", + "emailReceipt": "Отправить по электронной почте отчет об этом отправке", + "high": "Высокий", + "low": "Низкий", + "normal": "Нормальный", + "send": "ОТПРАВИТЬ", + "sendToEmailAddress": "Отправить на адрес электронной почты", + "emailSent": "Электронное письмо было отправлено на {to}.", + "sendingEmailErrMsg": "Произошла ошибка при попытке отправить письмо.", + "sendingEmailConsErrMsg": "Подтверждение по электронной почте для {to} не удалось: {error}", + "emailRequired": "Электронная почта обязательна" + }, + "submissionsTable": { + "noMatchingRecordText": "Совпадающих записей не найдено", + "submissions": "Записи", + "submissionsTable": "Таблица записей", + "selectColumns": "Выберите столбцы", + "manageForm": "Управление формой", + "submissionsToFiles": "Экспорт материалов в файлы", + "showDeletedSubmissions": "Показать удаленные материалы", + "showMySubmissions": "Показать мои материалы", + "search": "Поиск", + "loadingText": "Загрузка, пожалуйста подождите", + "noDataText": "Для этой формы нет записей", + "delSelectedSubmissions": "Удалить выбранные записи", + "resSelectedSubmissions": "Восстановить выбранные записи", + "yes": "ДА", + "no": "НЕТ", + "viewSubmission": "Просмотр записей", + "deleteSubmission": "Удалить запись", + "restore": "Восстановить", + "confirmDeletion": "Подтвердить удаление", + "delete": "Удалить", + "confirmRestoration": "Подтвердить восстановление", + "searchSubmissionFields": "Поля отправки поиска", + "save": "Сохранять", + "searchTitle": "Найдите и выберите столбцы, которые будут отображаться под вашей информационной панелью.", + "status": "Статус", + "submitter": "Отправитель", + "submissionDate": "Дата отправления", + "event": "событие", + "view": "Вид", + "lateSubmission": "Поздняя отправка", + "confirmationID": "Идентификатор подтверждения", + "multiDelWarning": "Вы уверены, что хотите удалить выбранные записи?", + "singleDelWarning": "Вы уверены, что хотите удалить эту запись?", + "multiRestoreWarning": "Вы уверены, что хотите восстановить эту запись?", + "singleRestoreWarning": "Вы уверены, что хотите восстановить эту запись?" + }, + "auditHistory": { + "viewEditHistory": "Посмотреть историю изменений", + "editHistory": "Изменить историю", + "auditLogMsg": "Это журнал аудита тех, кто вносил изменения в эту отправку после исходной отправки.", + "loadingText": "Загрузка, пожалуйста подождите", + "close": "Закрыть", + "userName": "Имя пользователя", + "date": "Дата", + "errorMsg": "Произошла ошибка при попытке получить историю.", + "consoleErrMsg": "Ошибка получения истории аудита для" + }, + "deleteSubmission": { + "deleteThis": "Удалить это", + "draft": "Черновик", + "submission": "Подчинение", + "confirmDeletion": "Подтвердить удаление", + "deleteWarning": "Вы уверены, что хотите удалить это", + "drafts": "черновик", + "formSubmission": "отправка формы", + "delete": "Удалить" + }, + "manageSubmissionUsers": { + "manageTeamMembers": "Управление членами команды", + "add": "Добавить", + "draftFormInvite": "Вы можете приглашать членов команды и управлять ими только в том случае, если эта форма является черновиком.", + "submissionTeamMembers": "Члены команды для этого представления", + "actions": "Действия", + "close": "Закрыть", + "remove": "Удалить", + "userNotFoundErrMsg": "Не можете найти кого-нибудь? Возможно, они не вошли в систему CHEFS.
Пожалуйста, отправьте им ссылку на CHEFS и попросите их войти.", + "name": "Имя", + "username": "Имя пользователя", + "email": "Электронная почта", + "removeUserWarningMsg1": "Вы уверены, что хотите удалить", + "removeUserWarningMsg2": "У них больше не будет разрешений на эту отправку.", + "userExistInListMsg": "Пользователь {username} уже есть в списке членов команды.", + "getSubmissionUsersErr": "Произошла ошибка при попытке получить пользователей для этой отправки.", + "getSubmissionUsersConsoleErr": "Ошибка при получении пользователей для {submissionId} : {error}", + "sentInviteEmailTo": "Отправлено письмо с приглашением на", + "sentUninvitedEmailTo": "Отправлено письмо без приглашения на", + "updateUserErrMsg": "Произошла ошибка при попытке обновить пользователей для этой отправки.", + "updateUserConsoleErrMsg": "Ошибка установки разрешений пользователя. Sub: {submissionId} Пользователь: {userId} Ошибка: {error}", + "searchInputLength": "Введите для поиска имя пользователя/адрес электронной почты BCeID, длина которого должна превышать 6 символов.", + "exactBCEIDSearch": "Поиск по электронной почте для BCeID должен быть точным.", + "getUsersErrMsg": "Ошибка при получении пользователей: {error}", + "exactEmailOrUsername": "Введите точную электронную почту или имя пользователя.", + "requiredFiled": "Введите имя, адрес электронной почты или имя пользователя" + }, + "mySubmissionsActions": { + "viewThisSubmission": "Посмотреть эту запись", + "copyThisSubmission": "Скопируйте эту запись", + "editThisDraft": "Изменить этот черновик" + }, + "mySubmissionsTable": { + "noMatchingRecordText": "Совпадающих записей не найдено", + "previousSubmissions": "Предыдущие записи", + "selectColumns": "Выберите столбцы", + "createNewSubmission": "Создать новую запись", + "search": "Поиск", + "loadingText": "Загрузка, пожалуйста подождите", + "noDataText": "У вас нет записей", + "searchSubmissionFields": "Поля отправки поиска", + "save": "Сохранять", + "filterTitle": "Найдите и выберите столбцы, которые будут отображаться под вашей информационной панелью.", + "confirmationId": "Идентификатор подтверждения", + "actions": "действия", + "createdBy": "Сделано", + "statusUpdatedBy": "Статус обновлен", + "status": "Положение дел", + "submissionDate": "Дата подачи", + "draftUpdatedBy": "Черновик обновлен", + "draftLastEdited": "Последнее редактирование черновика", + "createLateSubmissn": "Создать позднию отправку", + "formLoading": "Пожалуйста, подождите пока форма загружается!!!", + "pleaseConfirm": "Пожалуйста подтвердите", + "wantToSaveDraft": "Сохранить черновик?", + "yes": "Да", + "no": "Нет", + "multiDraftUploadSuccess": "Загрузка нескольких черновиков прошла успешно!", + "failedResSubmissn": "Неудачный ответ от конечной точки отправки. Код ответа: {status}", + "errSubmittingForm": "При отправке этой формы произошла ошибка", + "errorSavingFile": "Ошибка сохранения файлов. Имя файла: {fileName}. Ошибка: {error}", + "submittingDraftErrMsg": "Произошла ошибка при сохранении черновика", + "submittingDraftConsErrMsg": "Не удалось сохранить черновик. Идентификатор представления: {submissionId}. Ошибка: {error}" + }, + "notesPanel": { + "addNewNote": "Добавить новую заметку", + "cancel": "Отмена", + "addNote": "ДОБАВИТЬ ЗАМЕТКУ", + "noResponseErr": "Нет данных ответа от API при отправке формы", + "errorMesg": "Произошла ошибка при попытке добавить заметку.", + "consoleErrMsg": "Ошибка при добавлении заметки:", + "fetchErrMsg": "Произошла ошибка при попытке получить заметки для этой отправки.", + "fetchConsoleErrMsg": "Ошибка при добавлении заметки:", + "notes": "Примечания", + "note": "Примечание", + "maxChars": "Максимум 4000 символов" + }, + "statusPanel": { + "currentStatus": "Текущее состояние:", + "assignedTo": "Назначено:", + "assignOrUpdateStatus": "Назначить или обновить статус", + "display": "отобразить", + "statusIsRequired": "Требуется статус", + "assignTo": "Назначить в", + "noDataText": "Рецензенты формы не найдены с помощью поиска. Добавьте рецензентов форм на странице «Управление».", + "assigneeIsRequired": "Требуется правопреемник", + "assignToMe": "НАЗНАЧИТЬ МНЕ", + "recipientEmail": "Электронная почта получателя", + "attachCommentToEmail": "Прикрепить комментарий к электронной почте", + "emailComment": "Комментарий по электронной почте", + "maxChars": "Максимум 4000 символов", + "viewHistory": "ПОСМОТРЕТЬ ИСТОРИЮ", + "statusHistory": "История статусов", + "close": "ЗАКРЫТЬ", + "addNoteNoReponserErr": "Нет данных ответа от API при отправке примечания для обновления статуса", + "addNoteConsoleErrMsg": "Ошибка при обновлении статуса: {error}", + "addNoteErrMsg": "Произошла ошибка при попытке обновить статус", + "updtSubmissionsStatusErr": "Нет данных ответа от API при отправке формы обновления статуса", + "noStatus": "Нет статуса", + "noStatusesFound": "Статусы не найдены", + "statusCodesErr": "ошибка при поиске кодов состояния", + "notifyErrorCode": "Произошла ошибка при получении статуса для этой отправки.", + "notifyConsoleErrorCode": "Ошибка получения статусов:", + "fetchSubmissionUsersErr": "Произошла ошибка при попытке получить адреса электронной почты получателей для этой отправки.", + "fetchSubmissionUsersConsErr": "Ошибка получения писем получателя для", + "assignSubmissnToFormReviewer": "Материалы могут быть назначены рецензентам форм.
Чтобы добавить других членов команды в качестве рецензентов формы, перейдите на страницу «Управление» для этой формы.", + "update": "ОБНОВИТЬ", + "revise": "ИСПРАВИТЬ", + "complete": "ЗАВЕРШЕНО", + "assign": "НАЗНАЧИТЬ" + }, + "statusTable": { + "loadingText": "Загрузка, пожалуйста подождите", + "status": "Статус", + "dateStatusChanged": "Дата изменения статуса", + "assignee": "Правопреемник", + "updatedBy": "Обновлено", + "getSubmissionStatusErr": "Произошла ошибка при попытке получить статусы.", + "getSubmissionStatusConsErr": "Ошибка при добавлении заметки:" + }, + "exportSubmissions": { + "exportSubmissionsToFile": "Экспорт материалов в файл", + "viewSubmissions": "Просмотр представленных материалов", + "fileType": "Тип файла", + "json": "JSON", + "csv": "CSV", + "formVersion": "Версия формы", + "versionIsRequired": "Требуется версия.", + "dataFields": "Поля данных", + "searchFields": "Поля поиска", + "selectedForExports": "выбран для экспорта", + "submissionDate": "Дата подачи", + "all": "Все", + "selectDateRange": "Выберите диапазон дат", + "SelectdateRange": "Выберите диапазон дат", + "from": "От", + "to": "К", + "CSVFormat": "CSV-формат", + "multiRowPerSubmissionA": "1 — Несколько строк на отправку с отступами", + "multiRowPerSubmissionB": "2 — Несколько строк на отправку", + "singleRowPerSubmission": "3 – Одна строка на отправку", + "unformatted": "4 - Неформатированный", + "fileNameAndType": "Имя и тип файла", + "export": "Экспорт", + "noResponseDataErr": "Нет данных в ответ на вызов exportSubmissions", + "apiCallErrorMsg": "Произошла ошибка при попытке экспортировать материалы для этой формы.", + "apiCallConsErrorMsg": "Ошибка экспорта отправленных материалов для", + "selectAllFields": "Выбрать все поля", + "emailSentMsg": "На адрес {email} будет отправлено электронное письмо со ссылкой для загрузки ваших данных, когда они будут готовы.", + "exportInProgress": "Выполняется экспорт", + "of": "из" + }, + "printOptions": { + "submitButtonTxt": "Отправить в CDOGS и скачать", + "templatePrint": "Печать шаблона", + "uploadTemplateFile": "Загрузить файл шаблона", + "downloadOptions": "Параметры загрузки", + "print": "Распечатать", + "browserPrint": "Печать через браузер", + "pageFromBrowser": "страница из вашего браузера", + "uploadA": "Загрузить", + "uploadB": "иметь структурированную версию", + "docGrnSucess": "Документ успешно создан", + "failedDocGenErrMsg": "Не удалось создать документ", + "failedDocGenConsErrMsg": "Ошибка при отправке шаблона: {error}", + "cDogsTemplate": "Шаблон CDOGS" + }, + "proactiveHelpDialog": { + "componentInfoLink": "Ссылка на информацию о компоненте", + "learnMoreLinkTxt": "Поле «Узнать больше» не может быть пустым", + "largeImgTxt": "Большое изображение. Размер изображения не может быть больше 0,5МБ.", + "componentName": "Название компонента:", + "learnMoreLink": "Ссылка на подробности:", + "clickToEnableLink": "Нажмите, чтобы активировать ссылку", + "clickToDisableLink": "Нажмите, чтобы отключить ссылку", + "imageUpload": "Загрузка изображения:", + "cancel": "Отмена", + "save": "Сохранить", + "description": "Описание" + }, + "proactiveHelpPreviewDialog": { + "learnMore": "Узнать больше" + }, + "preview": { + "preview": "Предварительный просмотр", + "previewToolTip": "Это показывает предварительный просмотр дизайна и поведения версии формы, как ее увидят отправители. Вы не можете отправить форму с этой страницы." + }, + "generalLayout": { + "loadingText": "Загрузка, пожалуйста подождите", + "preview": "ПРЕДПРОСМОТР", + "published": "ОПУБЛИКОВАНО", + "unpublished": "НЕОПУБЛИКОВАНО", + "edit": "РЕДАКТИРОВАТЬ", + "formTitle": "Название формы", + "actions": "Действия" + }, + "formSubmission": { + "editThisSubmission": "Изменить эту запись", + "submission": "Запись", + "alertInfo": "После редактирования повторно отправьте форму, чтобы сохранить изменения.", + "viewAllSubmissions": "Просмотреть все записи", + "submitted": "Отправленно:", + "confirmationID": "Идентификатор подтверждения:", + "submittedBy": "Представленный:", + "cancel": "ОТМЕНА", + "status": "Статус", + "updatedAt": "Изменено", + "updatedBy": "Кем изменено" + }, + "teamManagement": { + "noMatchingRecordText": "Совпадающих записей не найдено", + "teamManagement": "Управление командой", + "selectColumns": "Выберите столбцы", + "manageForm": "Управление формой", + "search": "Поиск", + "loadingText": "Загрузка, пожалуйста подождите", + "noDataText": "Не удалось загрузить данные о роли команды.", + "removeSelectedUsers": "Удалить выбранных пользователей", + "removeThisUser": "Удалить этого пользователя", + "confirmRemoval": "Подтвердить удаление", + "remove": "Удалять", + "searchTeamManagementFields": "Поля управления командой поиска", + "save": "Сохранять", + "teamMebersTitle": "Найдите и выберите столбцы, которые будут отображаться под вашей информационной панелью.", + "fullName": "Полное имя", + "username": "Имя пользователя", + "identityProvider": "Идентификационной провайдер", + "delSelectedMembersWarning": "Вы уверены, что хотите удалить выбранных участников?", + "delSelectedMemberWarning": "Вы уверены, что хотите удалить выбранного участника?", + "idpMessage": "уже в команде.", + "formOwnerErrMsg": "Всегда должен быть хотя бы один владелец формы", + "formOwnerConsoleErrMsg": "Невозможно удалить {userId}, так как он является единственным оставшимся владельцем этой формы.", + "insufficientPermissnMsg": "Недостаточно прав для управления командой", + "getUserErrMsg": "Ошибка получения пользователей формы:", + "getRolesErrMsg": "Ошибка получения списка ролей:", + "formOwnerRemovalWarning": "Невозможно удалить, так как он единственный оставшийся владелец этой формы.", + "removeUsersErrMsg": "Произошла ошибка при попытке удалить выбранных пользователей", + "removeUserConsoleErrMsg": "Ошибка при удалении пользователей из формы {formId}: {error}", + "updUserRolesErrMsg": "Произошла ошибка при попытке обновить все роли пользователей", + "updUserRolesConsoleErrMsg": "Ошибка при установке всех ролей пользователей для формы {formId}: {error}", + "setUserFormsErrMsg": "Произошла ошибка при попытке обновить роли для пользователя", + "setUserFormsConsoleErrMsg": "Ошибка при настройке ролей пользователей для формы {formId}: {error}" + }, + "floatButton": { + "publish": "Опубликовать", + "manage": "Управлять", + "redo": "Повторить", + "undo": "Отменить", + "preview": "Предварительный просмотр", + "bottom": "Нижний", + "top": "Верхний", + "actions": "Действия", + "collapse": "Свернуть", + "saved": "Сохранено", + "save": "Сохранять", + "saving": "Сохранение", + "notSaved": "Не сохранено" + }, + "formViewer": { + "lateFormSubmissions": "Срок подачи формы истек! Вы по-прежнему можете создать отложенную отправку, нажав кнопку ниже.", + "createLateSubmission": "Создать просроченную отправку", + "draftSaved": "Черновик сохранен", + "saving": "Сохранение", + "pleaseConfirm": "Пожалуйста подтвердите", + "submitFormWarningMsg": "Вы уверены, что хотите отправить форму?", + "submit": "Отправить", + "wantToSaveDraft": "Вы хотите сохранить черновик?", + "version": "Версия: {version}", + "formScheduleExpireMessage": "Отправка формы недоступна, так как запланированный период подачи истек.", + "getUsersSubmissionsErrMsg": "Произошла ошибка при получении отправки для этой формы", + "getUsersSubmissionsConsoleErrMsg": "Ошибка при загрузке данных отправки формы {submissionId}: {error}", + "multiDraftUploadSuccess": "Загрузка нескольких черновиков прошла успешно!", + "readVersionErrMsg": "Схемы в ответ нет. Идентификатор версии: {versionId}", + "readDraftErrMsg": "Схемы в ответ нет. draftId: {draftId}", + "alertRouteMsg": "Владелец формы не опубликовал форму, и она недоступна для отправки.", + "fecthingFormErrMsg": "При получении этой формы произошла ошибка", + "fecthingFormConsoleErrMsg": "Ошибка при загрузке схемы формы {versionId}: {error}", + "savingDraftErrMsg": "Произошла ошибка при сохранении черновика", + "savingDraftConsoleErrMsg": "Не удалось сохранить черновик. Идентификатор представления: {submissionId}. Ошибка: {error}", + "submissionsPreviewAlert": "Отправка отключена во время предварительного просмотра формы", + "submissionsSubmitErrMsg": "Ошибка при отправке формы: {errors}", + "sendSubmissionErrMsg": "Неудачный ответ от конечной точки отправки. Код ответа: {status}", + "errMsg": "При отправке этой формы произошла ошибка", + "customEventAlert": "События пользовательских кнопок пока не поддерживаются. Тип события: {event}", + "formLoading": "Пожалуйста, подождите пока форма загружается!!!", + "yes": "Да", + "no": "Нет", + "failedResSubmissn": "Неудачный ответ от конечной точки отправки. Код ответа: {status}", + "errSubmittingForm": "При отправке этой формы произошла ошибка", + "errorSavingFile": "Ошибка сохранения файлов. Имя файла: {fileName}. Ошибка: {error}", + "submittingDraftErrMsg": "Произошла ошибка при сохранении черновика", + "submittingDraftConsErrMsg": "Не удалось сохранить черновик. Идентификатор записи: {submissionId}. Ошибка: {error}", + "formDraftAccessErrMsg": "Запрошенная отправка уже отправлена, перенаправление на страницу просмотра" + }, + "bCGovFooter": { + "home": "Главная страница", + "about": "О сайте gov.bc.ca", + "disclaimer": "Отказ от ответственности", + "privacy": "Конфиденциальность", + "accessibility": "Доступность", + "copyRight": "Авторские права", + "contactUs": "Связаться с нами" + }, + "bCGovNavBar": { + "about": "О", + "myForms": "Мои формы", + "createNewForm": "Создать новую форму", + "help": "Помощь", + "feedback": "Обратная связь", + "admin": "Админ" + }, + "homePage": { + "title": "Создавайте, публикуйте формы и получайте отправления с помощью Common Hosted Forms Service.", + "subTitle": "Все до н.э. Государственные служащие или подрядчики с учетной записью IDIR могут использовать нашу размещенную версию Common Hosted Forms Service (CHEFS) для создания форм.", + "takeATourOfChefs": "Совершите экскурсию по CHEFS, чтобы увидеть его в действии.", + "logInToGetStarted": "Войдите, чтобы начать", + "loginToStart": "Войдите в систему с IDIR, чтобы начать", + "login": "Авторизоваться", + "createFormLabel": "Создать форму", + "manageAccessTitle": "Управляйте доступом к своей форме", + "manageAccessSub1": "CHEFS позволяет создавать общедоступные формы или управлять доступом через аутентификацию IDIR или BCeID.", + "manageAccessSub2": "Вы также можете назначать роли своей команде для управления всеми вашими материалами.", + "createCustomFormTitle": "Создавайте собственные формы с помощью конструктора форм CHEFS", + "createCustomFormSub1": "С помощью CHEFS вы можете создавать безопасные формы с помощью интуитивно понятного интерфейса перетаскивания. Вы можете добавлять компоненты формы, переупорядочивать их и размещать в разных конфигурациях макетов.", + "chefsHowToTitle": "Видео с инструкциями CHEFS", + "chefsHowToSub": "Наше краткое руководство познакомит вас с некоторыми основными функциями программы CHEFS.", + "getStartedToChefs": "Начните использовать CHEFS", + "createOnlineTitle": "Создавайте онлайн-формы для сбора информации от ваших клиентов и улучшения рабочих процессов.", + "getStarted": "Начать" + }, + "baseStepper": { + "setUpForm": "Настройка формы", + "designForm": "Форма дизайна", + "manageForm": "Управление формой" + }, + "create": { + "formSettings": "Настройки формы", + "disclaimer": "Отказ от ответственности", + "disclaimerStmt": "Я согласен с заявлением об отказе от ответственности и заявлением об ответственности дизайнеров форм", + "continue": "Продолжать", + "back": "Назад", + "confirmPageNav": "Вы действительно хотите покинуть эту страницу? Внесенные вами изменения не будут сохранены", + "agreementErrMsg": "Вы должны согласиться с приведенным выше отказом от ответственности" + }, + "addTeamMember": { + "cantFindChefsUsers": "Не можете найти кого-нибудь? Возможно, они не вошли в систему CHEFS.
Пожалуйста, отправьте им ссылку на CHEFS и попросите их войти.", + "cancel": "Отмена", + "add": "Добавлять", + "mustSelectAUser": "Вы должны выбрать хотя бы одну роль, чтобы добавить этого пользователя.", + "addNewMember": "Добавить нового участника", + "enterUsername": "Введите имя, адрес электронной почты или имя пользователя", + "enterExactUsername": "Введите точную электронную почту или имя пользователя", + "BCeIDInputSearchMaxLen": "Введите для поиска имя пользователя/адрес электронной почты BCeID, длина которого должна превышать 6 символов.", + "BCeIDMustBeExact": "Поиск по электронной почте для BCeID должен быть точным.", + "errorGettingUsers": "Ошибка при получении пользователей {error}" + }, + "baseFilter": { + "cancel": "Отмена", + "columnName": "Имя столбца", + "exampleText": "Пример текста", + "exampleText2": "Пример текста 2", + "filterPlaceholderTxt": "Текст заполнителя фильтра", + "filter": "Фильтр", + "value": "ценить", + "resetColumns": "Сбросить столбцы" + }, + "formViewerActions": { + "viewMyDraftOrSubmissions": "Просмотреть мои черновики/представленные материалы", + "saveAsADraft": "Сохранить как черновик", + "editThisDraft": "Изменить этот черновик", + "switchSingleSubmssn": "Переключиться на одиночную отправку", + "switchMultiSubmssn": "Переключиться на несколько отправок" + }, + "baseCopyToClipboard": { + "linkToClipboard": "Ссылка скопирована в буфер обмена", + "copyToClipboard": "Скопировать в буфер обмена", + "errCopyToClipboard": "Ошибка при попытке скопировать в буфер обмена." + }, + "sucess": { + "sucessFormSubmissn": "Ваша форма успешно отправлена", + "keepRecord": "Если вы хотите сохранить запись этого представления, вы можете сохранить следующее", + "confirmationId": "Идентификатор подтверждения" + }, + "bcGovAlertBanner": { + "defaultErrMsg": "Ошибка: Что-то пошло не так", + "error": "ошибка" + }, + "permissionUtils": { + "formNotAvailable": "В настоящее время форма недоступна. Это может быть связано с неправильной ссылкой, или форма может быть удалена ее владельцем", + "missingFormIdAndSubmssId": "В параметрах отсутствуют как formId, так и submitId", + "loadingFormErrMsg": "При загрузке формы произошла ошибка.", + "loadingForm": "Ошибка при загрузке {options}: {error}", + "idpHintMsg": "Для этой формы требуется аутентификация {idpHint}. Пожалуйста, повторите вход и повторите попытку.", + "formIdpMissMatch": "Несоответствие формы IDP. Для формы требуется {idpHint}, но у пользователя есть {userIdp}." + }, + "download": { + "chefsDataExport": "Экспорт данных CHEFS", + "preparingForDownloading": "Подготовка к загрузке...", + "downloadInfoA": "Если ваш файл не загружается автоматически", + "downloadInfoB": "Нажмите сюда, чтобы попробовать еще раз" + }, + "history": { + "submissnHistory": "Ваша история отправки" + }, + "error": { + "logout": "Выйти", + "somethingWentWrong": "Ошибка: Что-то пошло не так... :(" + }, + "login": { + "authenticateWith": "Авторизоваться с помощью:", + "alreadyLoggedIn": "Уже вошли в систему", + "home": "Дом", + "about": "О" + }, + "notFound": { + "about": "О", + "pageNotFound": "404 Страница не найдена. :(" + }, + "store": { + "admin": { + "addFormOwnerRole": "Добавлена роль владельца для этой формы в {fullName}", + "addRowError": "При добавлении роли произошла ошибка", + "addRowConsoleErr": "Ошибка добавления пользователя {userId} в форму {formId}: {error}", + "apiKeyDelMsg": "Ключ API для этой формы был удален.", + "errDeletingApiKey": "Произошла ошибка при попытке удалить ключ API", + "consErrDeletingApiKey": "Ошибка удаления ключа API для формы {formId}: {error}", + "fecthingFormsErrMsg": "Произошла ошибка при получении форм", + "fecthingFormsConsErrMsg": "Ошибка при получении данных формы администратора: {error}", + "fecthingFormErrMsg": "При получении этой формы произошла ошибка", + "fecthingFormConsErrMsg": "Ошибка при получении данных административной формы {formId}: {error}", + "fecthFormUserRolesErrMsg": "Произошла ошибка при получении ролей пользователей из формы.", + "fecthFormUserRolesConsErrMsg": "Ошибка при получении данных ролей администратора: {error}", + "fecthApiDetailsErrMsg": "Произошла ошибка при получении данных API этой формы", + "fecthApiDetailsConsErrMsg": "Ошибка получения сведений об API администратора из данных формы {formId}: {error}", + "restoreFormErrMsg": "При восстановлении этой формы произошла ошибка", + "restoreFormConsErrMsg": "Ошибка восстановления данных формы {formId}: {error}", + "getUsersErrMsg": "При получении пользователей произошла ошибка.", + "getUsersConsErrMsg": "Ошибка при получении данных пользователей-администраторов: {error}", + "getUserErrMsg": "При получении этого пользователя произошла ошибка", + "getUserConsErrMsg": "Ошибка при получении данных пользователя-администратора {userId}: {error}", + "storingFCHelpInfoErrMsg": "Произошла ошибка при сохранении справочной информации компонента формы", + "storingFCHelpInfoConsErrMsg": "Ошибка при сохранении справочной информации о компоненте формы: {error}", + "gettingFCImgUrlErrMsg": "Произошла ошибка при получении URL изображения", + "gettingFCImgUrlConsErrMsg": "Ошибка при получении URL изображения: {error}", + "updatingFCStatusErrMsg": "Произошла ошибка при обновлении статуса публикации", + "updatingFCStatusConsErrMsg": "Ошибка при обновлении статуса публикации: {error}", + "fecthingFormBuilderCompsErrMsg": "Произошла ошибка при получении компонентов конструктора форм.", + "fecthingFormBuilderCompsConsErrMsg": "Ошибка при получении компонентов конструктора форм: {error}" + }, + "form": { + "fetchEmailTemplatesConsErrMsg": "Ошибка загрузки шаблонов электронной почты для {formId}: {error}.", + "fetchEmailTemplatesErrMsg": "Произошла ошибка при получении шаблонов электронных писем для этой формы.", + "getCurrUserFormsErrMsg": "При загрузке форм произошла ошибка", + "getCurrUserFormsConsErrMsg": "Ошибка при получении пользовательских данных: {error}", + "getUserFormPermErrMsg": "Произошла ошибка при получении ваших пользовательских данных для этой формы", + "getUserFormPermConsErrMsg": "Ошибка при получении пользовательских данных с помощью идентификатора формы {formId}: {error}", + "getUserFormRolesErrmsg": "Произошла ошибка при получении ваших пользовательских данных для этой формы", + "getUserFormRolesConsErrmsg": "Ошибка при получении пользовательских данных с помощью идентификатора формы {formId}: {error}", + "updCurrUserFormPrefErrMsg": "Произошла ошибка при сохранении ваших настроек для этой формы", + "updCurrUserFormPrefConsErrMsg": "Ошибка при обновлении настроек пользовательской формы с помощью formID {formId} и настроек {preferences}: {error}", + "getCurrUserFormPrefErrMsg": "Произошла ошибка при получении ваших предпочтений для этой формы.", + "getCurrUserFormPrefConsErrMsg": "Ошибка при получении настроек пользовательской формы с помощью formID {formId}: {error}", + "delCurrformNotiMsg": "Форма {name} успешно удалена.", + "delCurrFormConsErMsg": "Ошибка удаления формы {id}: {error}", + "delDraftErrMsg": "При удалении этого черновика произошла ошибка", + "delDraftConsErrMsg": "Ошибка при удалении {draftId}: {error}", + "fecthDraftErrMsg": "Произошла ошибка при сканировании черновиков этой формы.", + "fecthDraftConsErrMsg": "Ошибка при получении черновиков для формы {formId}: {error}", + "fecthFormErrMsg": "При получении этой формы произошла ошибка", + "fecthFormConsErrMsg": "Ошибка при получении формы {formId}: {error}", + "fetchFormFieldsErrMsg": "Произошла ошибка при получении списка полей для этой формы.", + "fetchFormFieldsConsErrMsg": "Ошибка при получении формы {formId}: {error}", + "publishDraftErrMsg": "При публикации произошла ошибка", + "publishDraftConsErrMsg": "Ошибка публикации {draftId}: {error}", + "toggleVersnPublConsErrMsg": "Ошибка в toggleVersionPublish {versionId} {publish}: {ошибка}", + "updateEmailTemplateConsErrMsg": "Ошибка обновления шаблонов электронной почты для формы {formId}: {error}", + "updateEmailTemplateErrMsg": "Произошла ошибка при обновлении шаблонов электронных писем для этой формы.", + "updateFormErrMsg": "Произошла ошибка при обновлении настроек этой формы.", + "updateFormConsErrMsg": "Ошибка при обновлении формы {id}: {error}", + "deleteSubmissionNotifyMsg": "Запись успешно удалена", + "deleteSubmissionErrMsg": "При удалении этой записи произошла ошибка", + "deleteSubmissionConsErrMsg": "Ошибка при удалении записи {submissionId}: {error}", + "deleteSubmissionsNotifyMsg": "Уведомления успешно удалены", + "deleteSubmissionsErrMsg": "Произошла ошибка при удалении выбранных записей", + "deleteSubmissionsConsErrMsg": "Ошибка при удалении отправленных записей: {error}", + "restoreSubmissionsNotiMsg": "Записи успешно восстановлены", + "restoreSubmissionsErrMsg": "При восстановлении этой записи произошла ошибка", + "restoreSubmissionsConsErrMsg": "Ошибка при восстановлении отправки: {error}", + "restoreSubmissionNotiMsg": "Запись успешно восстановлена", + "restoreSubmissionErrMsg": "При восстановлении этой записи произошла ошибка", + "restoreSubmissionConsErrMsg": "Ошибка при восстановлении отправки {submissionId}: {error}", + "fecthSubmissnUsersErrMsg": "Произошла ошибка при получении адреса электронной почты получателя для этой записи", + "fecthSubmissnUsersConsErrMsg": "Ошибка получения электронной почты получателя для отправки {formSubmissionId}: {error}", + "fetchSubmissnErrMsg": "При получении этой записи произошла ошибка.", + "fetchSubmissnConsErrMsg": "Ошибка при получении записи {submissionId}: {error}", + "fetchFormCSVExptFieldsErrMsg": "Произошла ошибка при получении списка полей для этой формы.", + "fetchFormCSVExptFieldsConsErrMsg": "Ошибка при получении формы {formId}: {error}", + "fetchSubmissnsErrMsg": "При получении материалов для этой формы произошла ошибка.", + "fetchSubmissnsConsErrMsg": "Ошибка при получении материалов для {formId}: {error}", + "fetchVersionErrMsg": "При получении этой формы произошла ошибка.", + "fetchVersionConsErrMsg": "Ошибка при получении версии {versionId} для формы {formId}: {error}", + "deleteApiKeyNotifyMsg": "Ключ API для этой формы был удален.", + "deleteApiKeyErrMsg": "Произошла ошибка при попытке удалить ключ API.", + "deleteApiKeyConsErrMsg": "Ошибка удаления ключа API для формы {formId}: {error}", + "generateApiKeyNotifyMsg": "Ключ API для этой формы создан.", + "generateApiKeyErrMsg": "Произошла ошибка при попытке сгенерировать ключ API.", + "generateApiKeyConsErrMsg": "Ошибка создания ключа API для формы {formId}: {error}", + "readApiKeyErrMsg": "Произошла ошибка при попытке получить ключ API.", + "readApiKeyConsErrMsg": "Ошибка при получении ключа API для формы {formId}: {error}.", + "getFCPHImageUrlErrMsg": "Произошла ошибка при получении URL изображения", + "getFCPHImageUrlConsErrMsg": "Ошибка при получении URL изображения: {error}", + "listFCPHErrMsg": "Произошла ошибка при загрузке компонентов конструктора форм.", + "listFCPHConsErrMsg": "Ошибка при получении компонентов конструктора форм: {error}", + "downloadFileErrMsg": "Произошла ошибка при загрузке файла", + "downloadFileConsErrMsg": "Ошибка загрузки файла: ошибка", + "readSubscriptionSettingsErrMsg": "Произошла ошибка при попытке получить настройки подписки.", + "readSubscriptionSettingsConsErrMsg": "Ошибка получения настроек подписки для формы {formId}: {ошибка}.", + "saveSubscriptionSettingsNotifyMsg": "Настройки подписки для этой формы сохранены.", + "saveSubscriptionSettingsErrMsg": "Произошла ошибка при попытке сохранить настройки подписки.", + "saveSubscriptionSettingsConsErrMsg": "Ошибка сохранения настроек подписки для формы {formId}: {error}" + } + }, + "admin": { + "root": { + "admin": "Админ" + }, + "form": { + "administerForm": "Форма администрирования" + }, + "user": { + "administerUser": "Администрирование пользователя" + } + }, + "user": { + "root": { + "myForms": "Мои формы", + "history": "История", + "user": "Пользователь" + } + } +} diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/tl/index.js b/frontend/app/frontend/src/internationalization/trans/chefs/tl/index.js new file mode 100644 index 0000000..e5d3726 --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/tl/index.js @@ -0,0 +1,4 @@ +import tl from '~/internationalization/trans/chefs/tl/tl.json'; +export default { + trans: tl, +}; diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/tl/tl.json b/frontend/app/frontend/src/internationalization/trans/chefs/tl/tl.json new file mode 100644 index 0000000..b66a276 --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/tl/tl.json @@ -0,0 +1,993 @@ +{ + "date": { + "date": "yyyy-mm-dd" + }, + "emailManagement": { + "emailManagement": "Pamamahala ng Email", + "manageForm": "Pamahalaan ang Form", + "submissionConfirmation": "Pagkumpirma ng Pagsusumite" + }, + "emailTemplate": { + "body": "Katawan", + "save": "Iligtas", + "saveEmailTemplateConsoleErrMsg": "Error sa pag-update ng template ng email para sa form {formId}: {error}", + "saveEmailTemplateErrMsg": "May naganap na error habang sinusubukang i-update ang template ng email.", + "subject": "Paksa", + "title": "Pamagat", + "validBodyRequired": "Mangyaring maglagay ng Body para sa email", + "validSubjectRequired": "Mangyaring magpasok ng linya ng Paksa para sa email", + "validTitleRequired": "Mangyaring maglagay ng Pamagat para sa email" + }, + "formsTable": { + "myForms": "Aking Mga Form", + "createNewForm": "Gumawa ng Bagong Form", + "search": "Maghanap", + "manage": "Pamahalaan", + "submissions": "Mga pagsusumite", + "formTitle": "Pamagat ng Form", + "viewForm": "Tingnan ang Form", + "description": "paglalarawan", + "Description": "Paglalarawan:", + "action": "Mga aksyon", + "loadingText": "Naglo-load... Mangyaring maghintay" + }, + "manageLayout": { + "manageForm": "Pamahalaan ang Form" + }, + "preview": { + "preview": "Silipin", + "previewToolTip": "Nagpapakita ito ng preview ng disenyo at gawi ng bersyon ng form habang makikita ito ng iyong mga nagsumite. Hindi mo maaaring isumite ang form mula sa pahinang ito." + }, + "shareForm": { + "shareForm": "Ibahagi ang Form", + "shareLink": "Ibahagi ang Link", + "copyQRCode": "Kopyahin ang link sa ibaba o i-download ang QR code.", + "warningMessage": "Walang nai-publish na bersyon ng form sa ngayon. Hindi maaabot ang link sa ibaba hanggang sa mai-publish ang isang bersyon.", + "openThisForm": "Buksan ang form na ito", + "downloadQRCode": "I-download ang QR Code", + "close": "Isara", + "copyURLToClipboard": "Kopyahin ang URL sa clipboard" + }, + "manageFormActions": { + "emailManagement": "Pamamahala ng Email", + "viewSubmissions": "Tingnan ang Mga Pagsusumite", + "teamManagement": "Pamamahala ng Koponan", + "deleteForm": "Tanggalin ang Form", + "confirmDeletion": "Kumpirmahin ang pagtanggal", + "deleteMessageA": "Sigurado ka bang gusto mong tanggalin", + "deleteMessageB": "Hindi na maa-access ang form na ito.", + "delete": "Tanggalin" + }, + "manageForm": { + "formSettings": "Mga Setting ng Form", + "apiKey": "Susi ng Api", + "updated": "Na-update", + "created": "Nilikha", + "formDesignHistory": "Kasaysayan ng Disenyo ng Form", + "totalVersions": "Kabuuang Mga Bersyon", + "status": "Katayuan", + "update": "Update", + "cancel": "Kanselahin", + "eventSubscription": "Subscription sa Kaganapan" + }, + "formSettings": { + "pressToAddMultiEmail": "Pindutin ang enter o , o space para magdagdag ng maraming email address", + "allowMultiDraft": "Payagan ang maramihang pag-upload ng draft", + "formTitle": "Pamagat ng Form", + "formDescription": "Paglalarawan ng Form", + "formAccess": "Pag-access sa Form", + "info": "Kung gagamitin mo ang form na ito upang mangalap ng impormasyon mula sa pangkalahatang publiko sa mga paksang pangkalahatang interes ng publiko, kinakailangan mong makipag-ugnayan sa GCPE upang mailista ang iyong pakikipag-ugnayan sa", + "important": "MAHALAGA", + "idimNotifyA": "Dapat mong ipaalam ang Identity Information Management (IDIM) team sa pamamagitan ng email", + "idimNotifyB": "ang iyong layunin na gamitin ang BceID upang i-verify ang mga pagkakakilanlan ng iyong mga nagsumite ng form.", + "referenceGuideA": "Mangyaring sumangguni sa aming", + "referenceGuideB": "gabay sa gumagamit", + "referenceGuideC": "para sa karagdagang detalye", + "specificTeamMembers": "Mga Partikular na Miyembro ng Koponan", + "formFunctionality": "Pag-andar ng Form", + "formSubmissinScheduleMsg": "Ang Iskedyul ng Pagsusumite ng Form ay magiging available sa Mga Setting ng Form pagkatapos mailathala ang form.", + "formSubmissionsSchedule": "Iskedyul ng Pagsusumite ng Form", + "experimental": "Pang-eksperimento", + "learnMore": "Matuto pa", + "afterSubmission": "Pagkatapos ng Pagsusumite", + "submissionConfirmation": "Ipakita ang mga detalye ng pagkumpirma ng pagsusumite", + "theConfirmationID": "ang Confirmation ID", + "infoB": "ang opsyon para sa user na mag-email sa kanilang sarili ng kumpirmasyon sa pagsusumite", + "loginRequired": "Kailangang mag-login", + "canSaveAndEditDraftLabel": "Maaaring Mag-save at Mag-edit ng mga Draft ang mga nagsumite", + "canUpdateStatusAsReviewer": "Maaaring I-update ng mga tagasuri ang Katayuan ng form na ito (ibig sabihin, Naisumite, Nakatalaga, Nakumpleto)", + "submitterCanCopyExistingSubmissn": "Maaaring Kopyahin ng mga nagsumite ang isang umiiral nang pagsusumite", + "submissionConfirmationToolTip": "Kinokontrol ng pagpili sa opsyong ito kung ano ang makikita ng nagsusumite ng user ng form na ito sa matagumpay na pagsusumite.
Kung naka-check, ito ay ipapakita", + "emailNotificatnToTeam": "Padalhan ang aking koponan ng email ng notification", + "emailNotificatnToTeamToolTip": "Magpadala ng notification sa iyong tinukoy na email address kapag isinumite ng sinumang user ang form na ito", + "notificationEmailAddrs": "Mga Email Address ng Notification", + "addMoreValidEmailAddrs": "Magdagdag ng isa o higit pang wastong email address", + "formScheduleSettings": "Mga Setting ng Iskedyul ng Form", + "opensubmissions": "Buksan ang mga pagsusumite", + "submissionsDeadline": "Gaano katagal mo gustong makatanggap ng mga pagsusumite?", + "keepSubmissnOpenTilUnplished": "Panatilihing bukas hanggang sa manu-manong i-unpublish", + "submissionsClosingDate": "Mag-iskedyul ng petsa ng pagsasara", + "submissionPeriod": "I-set up ang panahon ng pagsusumite", + "closeSubmissions": "Isara ang mga pagsusumite", + "keepOpenFor": "Panatilihing bukas para sa", + "period": "Panahon", + "allowLateSubmissions": "Payagan ang mga huling pagsusumite", + "allowLateSubmissionsInfoTip": "Kung nilagyan ng check, ang mga nagsumite ay makakapagsumite ng data pagkatapos ng petsa ng pagsasara.", + "afterCloseDateFor": "Pagkatapos ng malapit na petsa para sa", + "repeatPeriod": "Ulitin ang panahon", + "every": "Bawat", + "repeatUntil": "Ulitin hanggang", + "summary": "Buod", + "submissionsOpenDateRange": "Ang form na ito ay bukas para sa mga pagsusumite mula sa", + "to": "sa", + "scheduleRepetition": "Uulitin ang iskedyul tuwing", + "allowLateSubmissnInterval": "na nagpapahintulot sa mga huli na pagsusumite para sa", + "until": "hanggang", + "datesOfSubmissnInfo": "Ayon sa mga setting, ito ang mga available na petsa ng pagsusumite:", + "formOpenInterval": "Ang form na ito ay bukas para sa mga pagsusumite mula sa", + "allowDateSubmissionDate": "na may pagpapahintulot sa huli na pagsusumite hanggang", + "customClosingMessage": "Itakda ang custom na mensahe ng pagsasara", + "customClosingMessageToolTip": "Nagbibigay-daan sa iyong magdagdag ng naka-customize na mensahe para sa iyong mga user kapag bumisita sila sa isang saradong form.", + "closingMessage": "Pangwakas na Mensahe", + "sendReminderEmail": "IPADALA ang email ng Paalala", + "autoReminderNotificatn": "Paganahin ang awtomatikong paalala na abiso", + "autoReminderNotificatnToolTip": "Magpadala ng mga email ng paalala kasama ang link ng form sa panahon ng pagsusumite.", + "selectLoginType": "Mangyaring pumili ng 1 uri ng pag-log-in", + "formDescriptnMaxChars": "Ang Paglalarawan ng Form ay dapat na 255 character o mas kaunti", + "formTitlemaxChars": "Ang Pamagat ng Form ay dapat na 255 character o mas kaunti", + "formTitleReq": "Kinakailangan ang Pamagat ng Form", + "atLeastOneEmailReq": "Mangyaring magpasok ng hindi bababa sa 1 email address", + "validEmailRequired": "Pakilagay ang lahat ng wastong email address", + "fieldRequired": "Kinakailangan ang field na ito.", + "correctDateFormat": "Dapat nasa tamang format ang petsa. ibig sabihin. yyyy-mm-dd", + "dateDiffMsg": "Ang petsa ng pagsasara ng pagsusumite ay dapat na mas malaki kaysa sa bukas na petsa ng pagsusumite.", + "valueMustBeNumber": "Ang halaga ay dapat na isang numero. ibig sabihin. 1,2,3,5,99", + "selectAnOptions": "Mangyaring pumili ng hindi bababa sa 1 opsyon", + "validInterval": "Ito ay dapat na isang wastong agwat.", + "fieldRequiredAndInterval": "Kinakailangan ang field na ito at dapat na isang pagitan.", + "dateGrtOpenSubmissnDate": "Ulitin hanggang sa petsa ay dapat na mas malaki kaysa sa bukas na petsa ng pagsusumite", + "public": "Pampubliko (anonymous)", + "allowEventSubscription": "Payagan ang subscription sa kaganapan", + "eventSubscription": "Subscription sa Kaganapan", + "validEndpointRequired": "Mangyaring magpasok ng wastong endpoint na nagsisimula sa https://", + "validBearerTokenRequired": "Maglagay ng wastong halimbawa ng token ng maydala: 89abddfb-2cff-4fda-83e6-13221f0c3d4f" + }, + "subscribeEvent": { + "eventType": "Uri ng kaganapan", + "endpointUrl": "URL ng Endpoint", + "eventSubmission": "Pagsusumite", + "eventAssignment": "Assignment", + "eventStatusChange": "Pagbabago ng Katayuan", + "endpointToken": "Endpoint Token", + "urlPlaceholder": "https://endpoint.gov.bc.ca/api/v1/", + "save": "I-save", + "text": "text", + "password": "password", + "hideSecret": "Itago ang Lihim", + "showSecret": "Ipakita ang Lihim", + "key": "Susi", + "saveSettingsErrMsg": "May naganap na error habang sinusubukang i-update ang mga setting para sa form na ito.", + "updateSettingsConsoleErrMsg": "Error sa pag-update ng mga setting para sa form {formId}: {error}" + }, + "apiKey": { + "disclaimer": "Disclaimer", + "infoA": "Tiyaking nakaimbak ang iyong lihim ng API key sa isang secure na lokasyon (ibig sabihin, key vault).", + "infoB": "Ang iyong API key ay nagbibigay ng walang limitasyong pag-access sa iyong form. Huwag ibigay ang iyong API key sa sinuman.", + "infoC": "Dapat LAMANG gamitin ang API key para sa mga automated na pakikipag-ugnayan ng system. Huwag gamitin ang iyong API key para sa user based na access", + "deleteKey": "Tanggalin ang Susi", + "apiKey": "susi ng api", + "hideSecret": "Itago ang Lihim", + "showSecret": "Ipakita ang Lihim", + "sCTC": "Nakopya ang lihim sa clipboard", + "cSTC": "Kopyahin ang lihim sa clipboard", + "key": "Susi", + "confirmDeletion": "Kumpirmahin ang pagtanggal", + "deleteMsg": "Sigurado ka bang gusto mong tanggalin ang iyong API Key?", + "delete": "Tanggalin", + "confirmKeyGen": "Kumpirmahin ang Key Generation", + "createAPIKey": "Gumawa ng API Key para sa form na ito?
Tiyaking susundin mo ang Disclaimer sa page na ito.", + "regenerateAPIKey": "I-regenerate ang API Key?
Ang pagpapatuloy ay magtatanggal ng iyong kasalukuyang access sa API Key .", + "formOwnerKeyAcess": "Ikaw dapat ang May-ari ng Form para pamahalaan ang Mga API Key.", + "regenerate": "Magbagong-buhay", + "generate": "Bumuo", + "secret": "Lihim" + }, + "manageVersions": { + "important": "MAHALAGA!", + "infoA": "Kung walang mga nai-publish na bersyon, hindi maa-access ng mga user ang form na ito hanggang sa may nakatalagang nai-publish na bersyon. Kapag na-publish na ang isang bersyon, hindi na mae-edit ang bersyong iyon. Dapat kang lumikha ng bagong bersyon batay sa isa sa mga nakaraang bersyon ng form upang magpatuloy sa pag-edit.", + "infoB": "Tandaan: Isang bersyon lamang ang maaaring mai-publish.", + "version": "Bersyon", + "draft": "Draft", + "clickToPreview": "I-click upang i-preview", + "editVersion": "I-edit ang Bersyon", + "exportDesign": "I-export ang Disenyo", + "infoC": "Mangyaring i-publish o tanggalin ang iyong pinakabagong bersyon ng draft bago magsimula ng bagong bersyon.", + "deleteVersion": "Tanggalin ang Bersyon", + "draftAlreadyExists": "Umiiral na ang draft", + "infoD": "Mangyaring i-edit, i-publish o tanggalin ang kasalukuyang draft bago magsimula ng bagong draft.", + "publishVersion": "I-publish ang Bersyon", + "unpublishVersion": "I-unpublish ang Bersyon", + "infoE": "Kapag na-unpublish ang form na ito, aalisin sa sirkulasyon ang form hanggang sa muling ma-publish ang isang bersyon.", + "confirmDeletion": "Kumpirmahin ang pagtanggal", + "infoF": "Sigurado ka bang gusto mong tanggalin ang Bersyon na ito?", + "delete": "Tanggalin", + "status": "Katayuan", + "dateCreated": "Petsa ng Paggawa", + "createdBy": "Ginawa ni", + "actions": "Mga aksyon", + "published": "Nai-publish", + "unpublished": "Hindi na-publish", + "useVersionInfo": "Gamitin ang bersyon {version} bilang batayan para sa isang bagong bersyon", + "publishingVersionInfo": "Gagawin nitong live ang Bersyon {version} ng iyong form." + }, + "addOwner": { + "infoA": "Dapat lang itong gawin kung sakaling ang kasalukuyang may-ari ng form ay hindi na aktibo o wala nang contact sa isang priority event. Kung hindi, ipagawa ito sa kasalukuyang May-ari o isang Administrator ng Team para sa form.", + "hint": "Upang mahanap ang User ID na kailangan, maaari kang pumunta sa tab na 'USERS' sa Admin portal at hanapin sila.", + "addowner": "Magdagdag ng may-ari", + "label": "User ID (gabay)" + }, + "adminFormsTable": { + "showDeletedForms": "Ipakita ang mga tinanggal na form", + "search": "Maghanap", + "loadingText": "naglo-load-text", + "noDataText": "Walang mga form sa iyong system", + "admin": "Admin", + "launch": "Ilunsad", + "formTitle": "Pamagat ng Form", + "created": "Nilikha", + "deleted": "Tinanggal", + "actions": "Mga aksyon", + "delete": "Tanggalin" + }, + "administerForm": { + "deleted": "NABURA", + "restoreForm": "Ibalik ang form na ito", + "formDetails": "Mga Detalye ng Form", + "apiKeyDetails": "Mga Detalye ng Key ng API", + "deleteApiKey": "Tanggalin ang API Key", + "formUsers": "Mga Gumagamit ng Form", + "formVersions": "Mga Bersyon ng Form", + "assignANewOwner": "Magtalaga ng Bagong May-ari", + "restoring": "Ibinabalik", + "restore": "Ibalik", + "toActiveState": "sa aktibong estado", + "confirmDeletion": "Kumpirmahin ang pagtanggal", + "confirmDeletionMsg": "Sigurado ka bang gusto mong tanggalin ang API Key na ito?", + "delete": "Tanggalin", + "confirmRestore": "Kumpirmahin ang Pagpapanumbalik" + }, + "administerUser": { + "userDetails": "Mga Detalye ng User", + "openSSOConsole": "Buksan ang SSO console" + }, + "adminPage": { + "forms": "Mga porma", + "users": "Mga gumagamit", + "developer": "Developer", + "infoLinks": "Mga Link ng Impormasyon", + "metrics": "Mga sukatan" + }, + "adminUsersTable": { + "search": "Maghanap", + "loadingText": "Naglo-load... Mangyaring maghintay", + "admin": "Admin", + "fullName": "Buong pangalan", + "userID": "User ID", + "created": "Nilikha", + "actions": "Mga aksyon" + }, + "adminVersions": { + "exportDesign": "I-export ang Disenyo", + "versions": "Mga bersyon", + "status": "Katayuan", + "created": "Nilikha", + "lastUpdated": "Huling Na-update", + "actions": "Mga aksyon", + "published": "Nai-publish", + "unpublished": "Hindi na-publish", + "version": "Bersyon {versionNo}", + "notificationMsg": "May naganap na error habang nilo-load ang disenyo ng form." + }, + "developer": { + "user": "Gumagamit", + "name": "Pangalan", + "userName": "UserName", + "JWTContents": "Mga Nilalaman ng JWT", + "JWTContentsSBTxt": "Ang mga nilalaman ng JWT ay kinopya sa clipboard", + "JWTContentsTTTxt": "Kopyahin ang Mga Nilalaman ng JWT sa clipboard", + "JWTToken": "JWT Token", + "JWTTokenSBTxt": "Ang JWT Token ay kinopya sa clipboard", + "JWTTokenTTTxt": "Kopyahin ang JWT Token sa clipboard", + "chefsAPI": "CHEFS API", + "RBACSBTxt": "Nakopya ang RBAC Response sa clipboard", + "RBACTTTxt": "Kopyahin ang RBAC Response sa clipboard", + "notificationMsg": "Nabigong makuha ang user mula sa RBAC, tingnan ang console", + "notificationConsErr": "Error sa pagkuha ng User mula sa RBAC" + }, + "baseAuthButton": { + "logout": "Mag-logout", + "login": "Mag log in" + }, + "baseDialog": { + "defaultText": "default na teksto", + "ok": "OK", + "continue": "Magpatuloy", + "cancel": "Kanselahin", + "custom": "Custom" + }, + "baseSecure": { + "about": "Tungkol sa", + "loginInfo": "Dapat kang naka-log in upang magamit ang tampok na ito.", + "login": "Mag log in", + "401NotAuthorized": "401: hindi awtorisado. :", + "401ErrorMsg": "Ang iyong account ay hindi na-set up nang tama.
Mangyaring makipag-ugnayan", + "403Forbidden": "403 Ipinagbabawal. :", + "403ErrorMsg": "Nangangailangan ang page na ito ng {idp} authentication.", + "401UnAuthorized": "401: Hindi awtorisado. :", + "401UnAuthorizedErrMsg": "Wala kang pahintulot na i-access ang pahinang ito." + }, + "formDesigner": { + "formDesign": "Disenyo ng Form", + "exportDesign": "I-export ang Disenyo", + "importDesign": "Import na Disenyo", + "important": "MAHALAGA", + "formDesignInfoA": "Gamitin ang SAVE DESIGN button kapag tapos ka nang buuin ang form na ito.", + "formDesignInfoB": "Ang SUBMIT button ay ibinibigay para sa iyong user na isumite ang form na ito at isaaktibo pagkatapos itong ma-save.", + "formLoadErrMsg": "May naganap na error habang nilo-load ang disenyo ng form.", + "formLoadConsoleErrMsg": "Error sa paglo-load ng form {formId} schema (bersyon: {versionId} draft: {draftId}): {error}", + "formSchemaImportErrMsg": "May naganap na error habang ini-import ang form schema.", + "formSchemaImportConsoleErrMsg": "Error sa pag-import ng form schema : {error}", + "formDesignSaveErrMsg": "May naganap na error habang sinusubukang i-save ang disenyo ng form na ito. Kung kailangan mong mag-refresh o umalis upang subukang muli sa ibang pagkakataon, maaari mong I-export ang kasalukuyang disenyo sa page upang i-save para sa ibang pagkakataon.", + "formDesignSaveConsoleErrMsg": "Error sa pag-update o paggawa ng form (FormID: {formId}, versionId: {versionId}, draftId: {draftId}) Error: {error}", + "collapse": "Pagbagsak", + "actions": "Mga aksyon", + "version": "Bersyon", + "save": "I-save", + "saving": "Nagtitipid", + "notSaved": "Hindi Na-save", + "fieldnameError": "HINDI mo MAAARI gumamit ng `form` na keyword bilang {label} fieldname" + }, + "formViewerMultiUpload": { + "important": "MAHALAGA", + "uploadSucessMsg": "Upang matiyak ang matagumpay na pag-upload ng maraming draft, mangyaring i-download at gamitin ang ibinigay na template.", + "confirmDownload": "Gusto mo bang i-download ito?", + "jsonFileUpload": "Piliin ang JSON file na ia-upload", + "dragNDrop": "o i-drag at i-drop ito dito", + "chooseAFile": "Pumili ng file", + "downloadDraftSubmns": "Mangyaring i-download ang draft na ulat sa pagsusumite at tiyaking naipasok nang tama ang data.", + "downloadReport": "I-download ang ulat", + "doYouWantToDownload": "Gusto mo bang i-download ito?", + "uploadNewFile": "Mag-upload ng bagong file", + "uploadMultipleFileErr": "Paumanhin, maaari kang mag-upload lamang ng isang file", + "dragMultipleFileErr": "Paumanhin, maaari kang mag-drag lamang ng isang file", + "fileFormatErr": "Paumanhin, tumatanggap lang kami ng mga json file", + "fileSizeErr": "Ang maximum na laki ng file na pinapayagan ay 5MB", + "parseJsonErr": "Hindi namin mai-parse ang data ng json mula sa file", + "jsonObjNotArray": "Maling json file format", + "jsonObjNotArrayConsErr": "May naganap na hindi inaasahang error.", + "jsonArrayEmpty": "Walang laman ang json file na ito.", + "errorWhileValidate": "May mali sa file na ito", + "errWhileCheckValidity": "May mali sa file na ito", + "errAfterValidate": "May nakitang ilang error, tingnan sa ibaba para sa higit pang impormasyon.", + "fileIsEmpty": "walang laman ang file na ito.", + "download": "I-download" + }, + "formDisclaimer": { + "disclaimerAndStatement": "Disclaimer at pahayag ng responsibilidad para sa mga Form Designer:", + "privacyLaw": "Responsibilidad mong sumunod sa mga batas sa Privacy na namamahala sa pagkolekta, paggamit at pagsisiwalat ng impormasyong nagbibigay ng personal na pagkakakilanlan.", + "disclosure": "Ang pag-access sa tool ng taga-disenyo ng form na ito ay hindi likas na nagbibigay ng pahintulot na mangolekta, gumamit o magbunyag ng anumang impormasyong nagbibigay ng personal na pagkakakilanlan.", + "consent": "Responsibilidad mong kumuha ng pahintulot na mangolekta ng impormasyon ayon sa hinihingi ng batas.", + "formIntention": "Bago i-publish o ipamahagi ang iyong form kailangan mong talakayin ang intensyon ng form sa iyong", + "privacyOfficer": "Opisyal sa Privacy ng Ministri", + "assement": "at upang kumpletuhin ang mga pagtatasa kung kinakailangan." + }, + "requestReceipt": { + "emailPriority": "Priyoridad sa Email", + "emailReceipt": "Mag-email ng resibo ng pagsusumiteng ito", + "high": "Mataas", + "low": "Mababa", + "normal": "Normal", + "send": "IPADALA", + "sendToEmailAddress": "Ipadala sa Email Address", + "emailSent": "Isang email ang ipinadala kay {to}.", + "sendingEmailErrMsg": "May naganap na error habang sinusubukang ipadala ang iyong email.", + "sendingEmailConsErrMsg": "Nabigo ang pagkumpirma sa email kay {to}: {error}", + "emailRequired": "Kinakailangan ang email" + }, + "submissionsTable": { + "noMatchingRecordText": "Walang nakitang katugmang mga tala", + "submissions": "Mga pagsusumite", + "submissionsTable": "Talahanayan ng mga Pagsusumite", + "selectColumns": "Piliin ang Mga Column", + "manageForm": "Pamahalaan ang Form", + "submissionsToFiles": "I-export ang mga Pagsusumite sa Mga File", + "showDeletedSubmissions": "Ipakita ang mga tinanggal na pagsusumite", + "showMySubmissions": "Ipakita ang aking mga isinumite", + "search": "Maghanap", + "loadingText": "Naglo-load... Mangyaring maghintay", + "noDataText": "Walang mga pagsusumite para sa form na ito", + "delSelectedSubmissions": "Tanggalin ang mga napiling pagsusumite", + "resSelectedSubmissions": "Ibalik ang mga napiling isinumite", + "yes": "OO", + "no": "HINDI", + "viewSubmission": "Tingnan ang Pagsusumite", + "deleteSubmission": "Tanggalin ang Pagsusumite", + "restore": "Ibalik", + "confirmDeletion": "Kumpirmahin ang pagtanggal", + "delete": "Tanggalin", + "confirmRestoration": "Kumpirmahin ang Pagpapanumbalik", + "searchSubmissionFields": "Maghanap ng mga patlang ng pagsusumite", + "save": "I-save", + "searchTitle": "Maghanap at pumili ng mga column na ipapakita sa ilalim ng iyong dashboard", + "status": "Katayuan", + "submitter": "Nagsusumite", + "submissionDate": "Petsa ng Pagsumite", + "event": "kaganapan", + "view": "Tingnan", + "lateSubmission": "Huling Pagsusumite", + "confirmationID": "ID ng Pagkumpirma", + "multiDelWarning": "Sigurado ka bang gusto mong tanggalin ang mga napiling isinumite?", + "singleDelWarning": "Sigurado ka bang gusto mong tanggalin ang pagsusumiteng ito?", + "multiRestoreWarning": "Sigurado ka bang gusto mong ibalik ang mga pagsusumiteng ito?", + "singleRestoreWarning": "Sigurado ka bang gusto mong ibalik ang pagsusumiteng ito?" + }, + "auditHistory": { + "viewEditHistory": "Tingnan ang Kasaysayan ng Pag-edit", + "editHistory": "I-edit ang Kasaysayan", + "auditLogMsg": "Ito ay isang audit log kung sino ang gumawa ng mga pagbabago sa pagsusumiteng ito pagkatapos ng orihinal na pagsusumite.", + "loadingText": "Naglo-load... Mangyaring maghintay", + "close": "Isara", + "userName": "User Name", + "date": "Petsa", + "errorMsg": "Nagkaroon ng error habang sinusubukang kunin ang history.", + "consoleErrMsg": "Error sa pagkuha ng kasaysayan ng pag-audit para sa" + }, + "deleteSubmission": { + "deleteThis": "Tanggalin Ito", + "draft": "Draft", + "submission": "Pagsusumite", + "confirmDeletion": "Kumpirmahin ang pagtanggal", + "deleteWarning": "Sigurado ka bang gusto mong tanggalin ito", + "drafts": "burador", + "formSubmission": "pagsusumite ng form", + "delete": "Tanggalin" + }, + "manageSubmissionUsers": { + "manageTeamMembers": "Pamahalaan ang mga Miyembro ng Koponan", + "add": "Idagdag", + "draftFormInvite": "Maaari ka lamang mag-imbita at mamahala ng mga miyembro ng koponan habang ang form na ito ay isang draft", + "submissionTeamMembers": "Mga miyembro ng pangkat para sa pagsusumiteng ito", + "actions": "Mga aksyon", + "close": "Isara", + "remove": "Alisin", + "userNotFoundErrMsg": "Hindi mahanap ang isang tao? Maaaring hindi sila naka-log in sa CHEFS.
Mangyaring magpadala sa kanila ng link sa CHEFS at hilingin sa kanila na mag-log in.", + "name": "Pangalan", + "username": "Username", + "email": "Email", + "removeUserWarningMsg1": "Sigurado ka bang gusto mong tanggalin", + "removeUserWarningMsg2": "Wala na silang mga pahintulot para sa pagsusumiteng ito.", + "userExistInListMsg": "Ang user na si {username} ay nasa listahan na ng mga miyembro ng team.", + "getSubmissionUsersErr": "May naganap na error habang sinusubukang kunin ang mga user para sa pagsusumiteng ito.", + "getSubmissionUsersConsoleErr": "Error sa pagkuha ng mga user para sa {submissionId} : {error}", + "sentInviteEmailTo": "Nagpadala ng email ng imbitasyon kay", + "sentUninvitedEmailTo": "Nagpadala ng hindi inanyayahang email kay", + "updateUserErrMsg": "May naganap na error habang sinusubukang i-update ang mga user para sa pagsusumiteng ito.", + "updateUserConsoleErrMsg": "Error sa pagtatakda ng mga pahintulot ng user. Sub: {submissionId} User: {userId} Error: {error}", + "searchInputLength": "Ang input ng paghahanap para sa username/email ng BceID ay dapat na higit sa 6 na character.", + "exactBCEIDSearch": "Dapat na eksakto ang mga paghahanap sa email para sa BceID.", + "getUsersErrMsg": "Error sa pagkuha ng mga user: {error}", + "exactEmailOrUsername": "Maglagay ng eksaktong e-mail o username.", + "requiredFiled": "Maglagay ng pangalan, e-mail, o username" + }, + "mySubmissionsActions": { + "viewThisSubmission": "Tingnan ang Pagsusumite na Ito", + "copyThisSubmission": "Kopyahin ang Pagsusumite na Ito", + "editThisDraft": "I-edit ang Draft na ito" + }, + "mySubmissionsTable": { + "noMatchingRecordText": "Walang nakitang katugmang mga tala", + "previousSubmissions": "Nakaraang Mga Pagsusumite", + "selectColumns": "Piliin ang Mga Column", + "createNewSubmission": "Gumawa ng Bagong Pagsusumite", + "search": "Maghanap", + "loadingText": "Naglo-load... Mangyaring maghintay", + "noDataText": "Wala kang isinumite", + "searchSubmissionFields": "Maghanap ng mga patlang ng pagsusumite", + "save": "I-save", + "filterTitle": "Maghanap at pumili ng mga column na ipapakita sa ilalim ng iyong dashboard", + "confirmationId": "Confirmation Id", + "actions": "mga aksyon", + "createdBy": "Ginawa ni", + "statusUpdatedBy": "Status Na-update Ni", + "status": "Katayuan", + "submissionDate": "Petsa ng Pagsumite", + "draftUpdatedBy": "Draft Na-update Ni", + "draftLastEdited": "Draft Huling Na-edit", + "createLateSubmissn": "Gumawa ng huli na pagsusumite", + "formLoading": "Mangyaring maghintay habang naglo-load ang form !!!", + "pleaseConfirm": "Pakikumpirma", + "wantToSaveDraft": "Gusto mo bang i-save ang draft?", + "yes": "Oo", + "no": "Hindi", + "multiDraftUploadSuccess": "Ang iyong maramihang draft na pag-upload ay naging matagumpay!", + "failedResSubmissn": "Nabigong tugon mula sa endpoint ng pagsusumite. Code ng tugon: {status}", + "errSubmittingForm": "Nagkaroon ng error sa pagsusumite ng form na ito", + "errorSavingFile": "Error sa pag-save ng mga file. Filename: {fileName}. Error: {error}", + "submittingDraftErrMsg": "Nagkaroon ng error habang nagse-save ng draft", + "submittingDraftConsErrMsg": "Error sa pag-save ng draft. SubmissionId: {submissionId}. Error: {error}" + }, + "notesPanel": { + "addNewNote": "Magdagdag ng Bagong Tala", + "cancel": "Kanselahin", + "addNote": "MAGDAGDAG NG TALA", + "noResponseErr": "Walang data ng tugon mula sa API habang nagsusumite ng form", + "errorMesg": "Nagkaroon ng error habang sinusubukang idagdag ang tala.", + "consoleErrMsg": "Error sa pagdaragdag ng tala:", + "fetchErrMsg": "May naganap na error habang sinusubukang kumuha ng mga tala para sa pagsusumiteng ito.", + "fetchConsoleErrMsg": "Error sa pagdaragdag ng tala:", + "notes": "Mga Tala", + "note": "Tandaan", + "maxChars": "Max na 4000 character" + }, + "statusPanel": { + "currentStatus": "Kasalukuyang kalagayan:", + "assignedTo": "Nakatalaga sa:", + "assignOrUpdateStatus": "Magtalaga o Mag-update ng Katayuan", + "display": "display", + "statusIsRequired": "Kinakailangan ang katayuan", + "assignTo": "Italaga Kay", + "noDataText": "Walang nahanap na Mga Tagasuri ng Form na may paghahanap. Magdagdag ng Mga Tagasuri ng Form sa pahina ng Pamahalaan.", + "assigneeIsRequired": "Kinakailangan ang assignee", + "assignToMe": "ASSIGN TO ME", + "recipientEmail": "Email ng Tatanggap", + "attachCommentToEmail": "Maglakip ng Komento sa Email", + "emailComment": "Komento sa Email", + "maxChars": "Max na 4000 character", + "viewHistory": "TINGNAN ANG KASAYSAYAN", + "statusHistory": "Kasaysayan ng Katayuan", + "close": "Isara", + "addNoteNoReponserErr": "Walang data ng tugon mula sa API habang nagsusumite ng tala para sa pag-update ng status", + "addNoteConsoleErrMsg": "Error sa pag-update ng status: {error}", + "addNoteErrMsg": "Nagkaroon ng error habang sinusubukang i-update ang status", + "updtSubmissionsStatusErr": "Walang data ng tugon mula sa API habang nagsusumite ng form sa pag-update ng status", + "noStatus": "Walang estado", + "noStatusesFound": "Walang nakitang status", + "statusCodesErr": "error sa paghahanap ng mga status code", + "notifyErrorCode": "Nagkaroon ng error sa pagkuha ng status para sa pagsusumiteng ito.", + "notifyConsoleErrorCode": "Error sa pagkuha ng mga status:", + "fetchSubmissionUsersErr": "May naganap na error habang sinusubukang kunin ang mga email ng tatanggap para sa pagsusumiteng ito.", + "fetchSubmissionUsersConsErr": "Error sa pagkuha ng mga email ng tatanggap para sa", + "assignSubmissnToFormReviewer": "Maaaring italaga ang mga pagsusumite sa Mga Tagasuri ng Form.
Upang magdagdag ng higit pang mga miyembro ng koponan bilang Mga Tagasuri ng Form, pumunta sa pahina ng Pamahalaan para sa form na ito.", + "update": "I-UPDATE", + "revise": "REVISE", + "complete": "KUMPLETO", + "assign": "I-ASSIGN" + }, + "statusTable": { + "loadingText": "Naglo-load... Mangyaring maghintay", + "status": "Katayuan", + "dateStatusChanged": "Petsa Nagbago ang Katayuan", + "assignee": "Nakatalaga", + "updatedBy": "Na-update Ni", + "getSubmissionStatusErr": "May naganap na error habang sinusubukang kumuha ng mga status.", + "getSubmissionStatusConsErr": "Error sa pagdaragdag ng tala:" + }, + "exportSubmissions": { + "exportSubmissionsToFile": "I-export ang mga Pagsusumite sa File", + "viewSubmissions": "Tingnan ang Mga Pagsusumite", + "fileType": "Uri ng File", + "json": "JSON", + "csv": "CSV", + "formVersion": "Bersyon ng Form", + "versionIsRequired": "Kinakailangan ang bersyon.", + "dataFields": "Mga Patlang ng Data", + "searchFields": "Mga Field ng Paghahanap", + "selectedForExports": "pinili para sa pag-export", + "submissionDate": "Petsa ng Pagsumite", + "all": "Lahat", + "selectDateRange": "Piliin ang hanay ng petsa", + "SelectdateRange": "Pumili ng hanay ng petsa", + "from": "Mula sa", + "to": "Upang", + "CSVFormat": "CSV Format", + "multiRowPerSubmissionA": "1 - Maramihang mga hilera bawat pagsusumite na may mga puwang ng indentation", + "multiRowPerSubmissionB": "2 - Maramihang mga hilera sa bawat pagsusumite", + "singleRowPerSubmission": "3 - Isang hilera bawat pagsusumite", + "unformatted": "4 - Hindi naka-format", + "fileNameAndType": "Pangalan at Uri ng File", + "export": "I-export", + "noResponseDataErr": "Walang data bilang tugon mula sa tawag sa exportSubmissions", + "apiCallErrorMsg": "May naganap na error habang sinusubukang i-export ang mga pagsusumite para sa form na ito.", + "apiCallConsErrorMsg": "Error sa pag-export ng mga pagsusumite para sa", + "selectAllFields": "Piliin ang lahat ng field", + "emailSentMsg": "Magpapadala ng email sa {email} na naglalaman ng link upang i-download ang iyong data kapag handa na ito", + "exportInProgress": "Kasalukuyang isinasagawa ang pag-export", + "of": "ng" + }, + "printOptions": { + "submitButtonTxt": "Isumite sa CDOGS at I-download", + "templatePrint": "Pag-print ng Template", + "uploadTemplateFile": "Mag-upload ng template file", + "downloadOptions": "Mga Opsyon sa Pag-download", + "print": "Print", + "browserPrint": "Pag-print ng Browser", + "pageFromBrowser": "ang pahina mula sa iyong browser", + "uploadA": "Mag-upload ng a", + "uploadB": "para magkaroon ng structured na bersyon", + "docGrnSucess": "Matagumpay na nabuo ang dokumento", + "failedDocGenErrMsg": "Nabigong bumuo ng Dokumento", + "failedDocGenConsErrMsg": "Error sa pagsusumite ng template: {error}", + "cDogsTemplate": "template ng CDOGS" + }, + "proactiveHelpDialog": { + "componentInfoLink": "Link ng Impormasyon ng Bahagi", + "learnMoreLinkTxt": "Matuto Nang Higit Pa Link field ay hindi maaaring walang laman.", + "largeImgTxt": "Malaking imahe. Ang laki ng larawan ay hindi maaaring lumampas sa .5mb", + "componentName": "Pangalan ng Component:", + "learnMoreLink": "Matuto Pa Link:", + "clickToEnableLink": "I-click upang paganahin ang link", + "clickToDisableLink": "I-click upang huwag paganahin ang link", + "imageUpload": "Pag-upload ng Larawan:", + "cancel": "Kanselahin", + "save": "I-save", + "description": "Paglalarawan" + }, + "proactiveHelpPreviewDialog": { + "learnMore": "Matuto pa" + }, + "preview": { + "preview": "Silipin", + "previewToolTip": "Nagpapakita ito ng preview ng disenyo at gawi ng bersyon ng form habang makikita ito ng iyong mga nagsumite. Hindi mo maaaring isumite ang form mula sa pahinang ito." + }, + "generalLayout": { + "loadingText": "Naglo-load... Mangyaring maghintay", + "preview": "PREVIEW", + "published": "NA-publish", + "unpublished": "HINDI NA-PUBLISH", + "edit": "I-EDIT", + "formTitle": "Pamagat ng Form", + "actions": "Mga aksyon" + }, + "formSubmission": { + "editThisSubmission": "I-edit ang Pagsusumite na Ito", + "submission": "Pagsusumite", + "alertInfo": "Pagkatapos mag-edit, muling isumite ang form upang i-save ang iyong mga pagbabago.", + "viewAllSubmissions": "Tingnan ang Lahat ng Pagsusumite", + "submitted": "isinumite:", + "confirmationID": "ID ng Pagkumpirma:", + "submittedBy": "Ipinasa ni:", + "cancel": "KANSELAHIN", + "status": "Katayuan", + "updatedAt": "Binago", + "updatedBy": "Binago ni" + }, + "teamManagement": { + "noMatchingRecordText": "Walang nakitang katugmang mga tala", + "teamManagement": "Pamamahala ng Koponan", + "selectColumns": "Piliin ang Mga Column", + "manageForm": "Pamahalaan ang Form", + "search": "Maghanap", + "loadingText": "Naglo-load... Mangyaring maghintay", + "noDataText": "Nabigong i-load ang data ng tungkulin ng koponan", + "removeSelectedUsers": "Alisin ang mga napiling user", + "removeThisUser": "Alisin ang user na ito", + "confirmRemoval": "Kumpirmahin ang Pag-alis", + "remove": "Alisin", + "searchTeamManagementFields": "Mga field ng pamamahala ng pangkat ng paghahanap", + "save": "I-save", + "teamMebersTitle": "Maghanap at pumili ng mga column na ipapakita sa ilalim ng iyong dashboard", + "fullName": "Buong pangalan", + "username": "Username", + "identityProvider": "Tagapagbigay ng Pagkakakilanlan", + "delSelectedMembersWarning": "Sigurado ka bang gusto mong alisin ang mga napiling miyembro?", + "delSelectedMemberWarning": "Sigurado ka bang gusto mong alisin ang napiling miyembro?", + "idpMessage": "nasa team na.", + "formOwnerErrMsg": "Dapat palaging mayroong kahit isang may-ari ng form", + "formOwnerConsoleErrMsg": "Hindi maalis ang {userId} dahil sila na lang ang natitirang may-ari ng form na ito.", + "insufficientPermissnMsg": "Hindi sapat na mga pahintulot upang pamahalaan ang koponan", + "getUserErrMsg": "Error sa pagkuha ng mga user ng form:", + "getRolesErrMsg": "Error sa pagkuha ng listahan ng mga tungkulin:", + "formOwnerRemovalWarning": "Hindi maalis dahil sila na lang ang natitirang may-ari ng form na ito.", + "removeUsersErrMsg": "May naganap na error habang sinusubukang tanggalin ang mga napiling user", + "removeUserConsoleErrMsg": "Error sa pagtanggal ng mga user mula sa form na {formId}: {error}", + "updUserRolesErrMsg": "Nagkaroon ng error habang sinusubukang i-update ang lahat ng tungkulin ng user", + "updUserRolesConsoleErrMsg": "Error sa pagtatakda ng lahat ng tungkulin ng user para sa form na {formId}: {error}", + "setUserFormsErrMsg": "May naganap na error habang sinusubukang i-update ang mga tungkulin para sa isang user", + "setUserFormsConsoleErrMsg": "Error sa pagtatakda ng mga tungkulin ng user para sa form na {formId}: {error}" + }, + "floatButton": { + "publish": "I-publish", + "manage": "Pamahalaan", + "redo": "Gawin muli", + "undo": "Pawalang-bisa", + "preview": "Silipin", + "bottom": "Ibaba", + "top": "Nangunguna", + "actions": "Mga aksyon", + "collapse": "Pagbagsak", + "saved": "Nai-save", + "save": "I-save", + "saving": "Nagtitipid", + "notSaved": "Hindi Na-save" + }, + "formViewer": { + "lateFormSubmissions": "Ang panahon ng pagsusumite ng form ay nag-expire na! Maaari ka pa ring gumawa ng huli na pagsusumite sa pamamagitan ng pag-click sa button sa ibaba.", + "createLateSubmission": "Gumawa ng huli na pagsusumite", + "draftSaved": "Na-save ang Draft", + "saving": "Nagtitipid", + "pleaseConfirm": "Pakikumpirma", + "submitFormWarningMsg": "Sigurado ka bang gusto mong isumite ang iyong form?", + "submit": "Ipasa", + "wantToSaveDraft": "Gusto mo bang i-save ang draft?", + "version": "Bersyon: {version}", + "formScheduleExpireMessage": "Ang pagsusumite ng form ay hindi magagamit dahil ang nakatakdang panahon ng pagsusumite ay nag-expire na.", + "getUsersSubmissionsErrMsg": "Nagkaroon ng error sa pagkuha ng pagsusumite para sa form na ito", + "getUsersSubmissionsConsoleErrMsg": "Error sa paglo-load ng data ng pagsusumite ng form {submissionId}: {error}", + "multiDraftUploadSuccess": "Ang iyong maramihang draft na pag-upload ay naging matagumpay!", + "readVersionErrMsg": "Walang schema bilang tugon. VersionId: {versionId}", + "readDraftErrMsg": "Walang schema bilang tugon. draftId: {draftId}", + "alertRouteMsg": "Hindi nai-publish ng may-ari ng form ang form, at hindi ito available para sa mga pagsusumite.", + "fecthingFormErrMsg": "Nagkaroon ng error sa pagkuha ng form na ito", + "fecthingFormConsoleErrMsg": "Error sa paglo-load ng form schema {versionId}: {error}", + "savingDraftErrMsg": "Nagkaroon ng error habang nagse-save ng draft", + "savingDraftConsoleErrMsg": "Error sa pag-save ng draft. SubmissionId: {submissionId}. Error: {error}", + "submissionsPreviewAlert": "Hindi pinagana ang pagsusumite sa panahon ng pag-preview ng form", + "submissionsSubmitErrMsg": "Error sa pagsusumite ng form: {errors}", + "sendSubmissionErrMsg": "Nabigong tugon mula sa endpoint ng pagsusumite. Code ng tugon: {status}", + "errMsg": "Nagkaroon ng error sa pagsusumite ng form na ito", + "customEventAlert": "Hindi pa sinusuportahan ang mga kaganapan sa custom na button. Uri ng Kaganapan: {event}", + "formLoading": "Mangyaring maghintay habang naglo-load ang form !!!", + "yes": "Oo", + "no": "Hindi", + "failedResSubmissn": "Nabigong tugon mula sa endpoint ng pagsusumite. Code ng tugon: {status}", + "errSubmittingForm": "Nagkaroon ng error sa pagsusumite ng form na ito", + "errorSavingFile": "Error sa pag-save ng mga file. Filename: {fileName}. Error: {error}", + "submittingDraftErrMsg": "Nagkaroon ng error habang nagse-save ng draft", + "submittingDraftConsErrMsg": "Error sa pag-save ng draft. SubmissionId: {submissionId}. Error: {error}", + "formDraftAccessErrMsg": "Ang hiniling na pagsusumite ay naisumite na, nagre-redirect sa View page" + }, + "bCGovFooter": { + "home": "Bahay", + "about": "Tungkol sa gov.bc.ca", + "disclaimer": "Disclaimer", + "privacy": "Pagkapribado", + "accessibility": "Accessibility", + "copyRight": "Copyright", + "contactUs": "Makipag-ugnayan sa amin" + }, + "bCGovNavBar": { + "about": "Tungkol sa", + "myForms": "Aking Mga Form", + "createNewForm": "Gumawa ng Bagong Form", + "help": "Tulong", + "feedback": "Feedback", + "admin": "Admin" + }, + "homePage": { + "title": "Gumawa, mag-publish ng mga form, at tumanggap ng mga pagsusumite gamit ang Common Hosted Forms Service.", + "subTitle": "Lahat ng B.C. Maaaring gamitin ng mga empleyado ng gobyerno o mga kontratista na may IDIR account ang aming naka-host na bersyon ng Common Hosted Forms Service (CHEFS) upang lumikha ng mga form.", + "takeATourOfChefs": "Maglibot sa CHEFS para makita ito sa aksyon.", + "logInToGetStarted": "Mag-log in para makapagsimula", + "loginToStart": "Mag-log in gamit ang IDIR para makapagsimula", + "login": "Mag log in", + "createFormLabel": "Gumawa ng Form", + "manageAccessTitle": "Pamahalaan ang access sa iyong form", + "manageAccessSub1": "Binibigyang-daan ka ng CHEFS na lumikha ng mga pampublikong form, o maaari mong pamahalaan ang access sa pamamagitan ng IDIR o BceID authentication.", + "manageAccessSub2": "Maaari ka ring magtalaga ng mga tungkulin sa iyong koponan upang pamahalaan ang lahat ng iyong mga isinumite.", + "createCustomFormTitle": "Gumawa ng mga custom na form gamit ang CHEFS form builder", + "createCustomFormSub1": "Sa CHEFS, makakagawa ka ng mga secure na form na may intuitive na drag-and-drop na interface. Maaari kang magdagdag ng mga bahagi ng form, muling ayusin ang mga ito, at i-drop ang mga ito sa iba't ibang mga configuration ng layout.", + "chefsHowToTitle": "Mga Video na How-to ng CHEFS", + "chefsHowToSub": "Ang aming Quickstart Guide ay magpapakilala sa ilan sa mga pangunahing function ng CHEFS.", + "getStartedToChefs": "Magsimula sa paggamit ng CHEFS", + "createOnlineTitle": "Lumikha ng mga online na form upang mangolekta ng impormasyon mula sa iyong mga kliyente at pagbutihin ang iyong mga daloy ng trabaho.", + "getStarted": "Magsimula" + }, + "baseStepper": { + "setUpForm": "I-set up ang Form", + "designForm": "Form ng Disenyo", + "manageForm": "Pamahalaan ang Form" + }, + "create": { + "formSettings": "Mga Setting ng Form", + "disclaimer": "Disclaimer", + "disclaimerStmt": "Sumasang-ayon ako sa disclaimer at pahayag ng responsibilidad para sa mga Form Designer", + "continue": "Magpatuloy", + "back": "Bumalik", + "confirmPageNav": "Gusto mo ba talagang umalis sa page na ito? Hindi mase-save ang mga pagbabagong ginawa mo.", + "agreementErrMsg": "Dapat kang sumang-ayon sa disclaimer sa privacy na ipinapakita sa itaas." + }, + "addTeamMember": { + "cantFindChefsUsers": "Hindi mahanap ang isang tao? Maaaring hindi sila naka-log in sa CHEFS.
Mangyaring magpadala sa kanila ng link sa CHEFS at hilingin sa kanila na mag-log in.", + "cancel": "Kanselahin", + "add": "Idagdag", + "mustSelectAUser": "Dapat kang pumili ng hindi bababa sa isang tungkulin upang idagdag ang user na ito.", + "addNewMember": "Magdagdag ng Bagong Miyembro", + "enterUsername": "Maglagay ng pangalan, e-mail, o username", + "enterExactUsername": "Maglagay ng eksaktong e-mail o username", + "BCeIDInputSearchMaxLen": "Ang input ng paghahanap para sa username/email ng BceID ay dapat na higit sa 6 na character.", + "BCeIDMustBeExact": "Dapat na eksakto ang mga paghahanap sa email para sa BceID.", + "errorGettingUsers": "Error sa pagkuha ng mga user {error}" + }, + "baseFilter": { + "cancel": "Kanselahin", + "columnName": "Pangalan ng Column", + "exampleText": "Halimbawang Teksto", + "exampleText2": "Halimbawang Teksto 2", + "filterPlaceholderTxt": "I-filter ang Teksto ng Placeholder", + "filter": "Salain", + "value": "halaga", + "resetColumns": "I-reset ang Mga Column" + }, + "formViewerActions": { + "viewMyDraftOrSubmissions": "Tingnan ang Aking draft/mga isinumite", + "saveAsADraft": "I-save bilang Draft", + "editThisDraft": "I-edit ang Draft na ito", + "switchSingleSubmssn": "Lumipat sa iisang pagsusumite", + "switchMultiSubmssn": "Lumipat sa maramihang pagsusumite" + }, + "baseCopyToClipboard": { + "linkToClipboard": "Nakopya ang link sa clipboard", + "copyToClipboard": "Kopyahin sa clipboard", + "errCopyToClipboard": "Error sa pagtatangkang kopyahin sa clipboard." + }, + "sucess": { + "sucessFormSubmissn": "Ang iyong form ay matagumpay na naisumite", + "keepRecord": "Kung nais mong panatilihin ang isang talaan ng pagsusumiteng ito, maaari mong panatilihin ang mga sumusunod", + "confirmationId": "ID ng Pagkumpirma" + }, + "bcGovAlertBanner": { + "defaultErrMsg": "Error: Nagkaproblema", + "error": "pagkakamali" + }, + "permissionUtils": { + "formNotAvailable": "Kasalukuyang hindi available ang form. Ito ay maaaring dahil sa isang maling link, o ang form ay maaaring tinanggal ng may-ari nito.", + "missingFormIdAndSubmssId": "Nawawala ang mga opsyon sa parehong formId at submissionId", + "loadingFormErrMsg": "Nagkaroon ng error habang nilo-load ang form na ito.", + "loadingForm": "Error habang naglo-load ng {options}: {error}", + "idpHintMsg": "Ang form na ito ay nangangailangan ng {idpHint} authentication. Mangyaring muling mag-login at subukang muli.", + "formIdpMissMatch": "Hindi tugma sa form ng IDP. Ang form ay nangangailangan ng {idpHint} ngunit ang user ay may {userIdp}.", + "chefsDataExport": "Pag-export ng Data ng CHEFS", + "preparingForDownloading": "Naghahanda para sa pag-download...", + "downloadInfoA": "Kung hindi awtomatikong nagda-download ang iyong file", + "downloadInfoB": "mag-click dito upang subukang muli" + }, + "history": { + "submissnHistory": "Iyong Kasaysayan ng Pagsusumite (TBD)" + }, + "error": { + "logout": "Mag-logout", + "somethingWentWrong": "Error: Nagkaproblema... :(" + }, + "login": { + "authenticateWith": "Patotohanan gamit ang:", + "alreadyLoggedIn": "Naka-log in na", + "home": "Bahay", + "about": "Tungkol sa" + }, + "notFound": { + "about": "Tungkol sa", + "pageNotFound": "Hindi Natagpuan ang 404 Page. :(" + }, + "store": { + "admin": { + "addFormOwnerRole": "Idinagdag ang tungkulin ng May-ari para sa form na ito sa {fullName}", + "addRowError": "Nagkaroon ng error habang idinaragdag ang tungkulin.", + "addRowConsoleErr": "Error sa pagdaragdag ng user na {userId} sa form na {formId}: {error}", + "apiKeyDelMsg": "Ang API Key para sa form na ito ay tinanggal.", + "errDeletingApiKey": "May naganap na error habang sinusubukang tanggalin ang API Key.", + "consErrDeletingApiKey": "Error sa pagtanggal ng API Key para sa form {formId}: {error}", + "fecthingFormsErrMsg": "May naganap na error habang kumukuha ng mga form.", + "fecthingFormsConsErrMsg": "Error sa pagkuha ng data ng admin form: {error}", + "fecthingFormErrMsg": "Nagkaroon ng error habang kinukuha ang form na ito.", + "fecthingFormConsErrMsg": "Error sa pagkuha ng data ng admin form {formId}: {error}", + "fecthFormUserRolesErrMsg": "May naganap na error habang kinukuha ang mga tungkulin ng user ng form.", + "fecthFormUserRolesConsErrMsg": "Error sa pagkuha ng data ng mga tungkulin ng admin: {error}", + "fecthApiDetailsErrMsg": "May naganap na error habang kinukuha ang mga detalye ng API ng form na ito.", + "fecthApiDetailsConsErrMsg": "Error sa pagkuha ng mga detalye ng admin API mula sa data ng form {formId}: {error}", + "restoreFormErrMsg": "Nagkaroon ng error habang nire-restore ang form na ito.", + "restoreFormConsErrMsg": "Error sa pagpapanumbalik ng data ng form {formId}: {error}", + "getUsersErrMsg": "Nagkaroon ng error habang kinukuha ang mga user.", + "getUsersConsErrMsg": "Error sa pagkuha ng data ng mga user ng admin: {error}", + "getUserErrMsg": "May naganap na error habang kinukuha ang user na ito.", + "getUserConsErrMsg": "Error sa pagkuha ng data ng admin user {userId}: {error}", + "storingFCHelpInfoErrMsg": "Nagkaroon ng error habang iniimbak ang impormasyon ng tulong sa bahagi ng form", + "storingFCHelpInfoConsErrMsg": "Error sa pagkuha ng pag-iimbak ng impormasyon ng tulong sa bahagi ng form: {error}", + "gettingFCImgUrlErrMsg": "May naganap na error habang kinukuha ang url ng larawan", + "gettingFCImgUrlConsErrMsg": "Error sa pagkuha ng url ng larawan: {error}", + "updatingFCStatusErrMsg": "Nagkaroon ng error habang ina-update ang status ng pag-publish", + "updatingFCStatusConsErrMsg": "Error sa pag-update ng status ng pag-publish: {error}", + "fecthingFormBuilderCompsErrMsg": "May naganap na error habang kinukuha ang mga bahagi ng tagabuo ng form", + "fecthingFormBuilderCompsConsErrMsg": "Error sa pagkuha ng mga bahagi ng tagabuo ng form: {error}" + }, + "form": { + "fetchEmailTemplatesConsErrMsg": "Error sa paglo-load ng mga template ng email para sa {formId}: {error}", + "fetchEmailTemplatesErrMsg": "Nagkaroon ng error sa pagkuha ng mga template ng email para sa form na ito", + "getCurrUserFormsErrMsg": "May naganap na error habang kinukuha ang iyong mga form.", + "getCurrUserFormsConsErrMsg": "Error sa pagkuha ng data ng user: {error}", + "getUserFormPermErrMsg": "May naganap na error habang kinukuha ang iyong data ng user para sa form na ito.", + "getUserFormPermConsErrMsg": "Error sa pagkuha ng data ng user gamit ang formID {formId}: {error}", + "getUserFormRolesErrmsg": "May naganap na error habang kinukuha ang iyong data ng user para sa form na ito.", + "getUserFormRolesConsErrmsg": "Error sa pagkuha ng data ng user gamit ang formID {formId}: {error}", + "updCurrUserFormPrefErrMsg": "May naganap na error habang sine-save ang iyong mga kagustuhan para sa form na ito.", + "updCurrUserFormPrefConsErrMsg": "Error sa pag-update ng user form prefs gamit ang formID {formId}, at prefs {preferences}: {error}", + "getCurrUserFormPrefErrMsg": "May naganap na error habang kinukuha ang iyong mga kagustuhan para sa form na ito.", + "getCurrUserFormPrefConsErrMsg": "Error sa pagkuha ng user form prefs gamit ang formID {formId}: {error}", + "delCurrformNotiMsg": "Matagumpay na natanggal ang form na {name}.", + "delCurrFormConsErMsg": "Error sa pagtanggal ng form {id}: {error}", + "delDraftErrMsg": "Nagkaroon ng error habang tinatanggal ang draft na ito.", + "delDraftConsErrMsg": "Error sa pagtanggal ng {draftId}: {error}", + "fecthDraftErrMsg": "May naganap na error habang nag-ii-scan para sa mga draft para sa form na ito.", + "fecthDraftConsErrMsg": "Error sa pagkuha ng mga draft para sa form {formId}: {error}", + "fecthFormErrMsg": "Nagkaroon ng error habang kinukuha ang form na ito.", + "fecthFormConsErrMsg": "Error sa pagkuha ng form {formId}: {error}", + "fetchFormFieldsErrMsg": "May naganap na error habang kinukuha ang listahan ng mga field para sa form na ito.", + "fetchFormFieldsConsErrMsg": "Error sa pagkuha ng form {formId}: {error}", + "publishDraftErrMsg": "Nagkaroon ng error habang nagpa-publish.", + "publishDraftConsErrMsg": "Error sa pag-publish ng {draftId}: {error}", + "toggleVersnPublConsErrMsg": "Error sa toggleVersionPublish {versionId} {publish}: {error}", + "updateEmailTemplateConsErrMsg": "Error sa pag-update ng mga template ng email para sa form {formId}: {error}", + "updateEmailTemplateErrMsg": "May naganap na error habang ina-update ang mga template ng email para sa form na ito.", + "updateFormErrMsg": "May naganap na error habang ina-update ang mga setting para sa form na ito.", + "updateFormConsErrMsg": "Error sa pag-update ng form {id}: {error}", + "deleteSubmissionNotifyMsg": "Matagumpay na natanggal ang pagsusumite.", + "deleteSubmissionErrMsg": "Nagkaroon ng error habang tinatanggal ang pagsusumiteng ito.", + "deleteSubmissionConsErrMsg": "Error sa pagtanggal ng pagsusumite {submissionId}: {error}", + "deleteSubmissionsNotifyMsg": "Matagumpay na natanggal ang mga pagsusumite.", + "deleteSubmissionsErrMsg": "Nagkaroon ng error habang tinatanggal ang mga napiling isinumite.", + "deleteSubmissionsConsErrMsg": "Error sa pagtanggal ng mga isinumite: {error}", + "restoreSubmissionsNotiMsg": "Matagumpay na naibalik ang mga isinumite.", + "restoreSubmissionsErrMsg": "Nagkaroon ng error habang nire-restore ang pagsusumiteng ito.", + "restoreSubmissionsConsErrMsg": "Error sa pagpapanumbalik ng mga isinumite: {error}", + "restoreSubmissionNotiMsg": "Matagumpay na naibalik ang pagsusumite.", + "restoreSubmissionErrMsg": "Nagkaroon ng error habang nire-restore ang pagsusumiteng ito.", + "restoreSubmissionConsErrMsg": "Error sa pagpapanumbalik ng pagsusumite {submissionId}: {error}", + "fecthSubmissnUsersErrMsg": "May naganap na error habang kinukuha ang email ng tatanggap para sa pagsusumiteng ito.", + "fecthSubmissnUsersConsErrMsg": "Error sa pagkuha ng email ng tatanggap para sa pagsusumite {formSubmissionId}: {error}", + "fetchSubmissnErrMsg": "May naganap na error habang kinukuha ang pagsusumiteng ito.", + "fetchSubmissnConsErrMsg": "Error sa pagkuha ng pagsusumite {submissionId}: {error}", + "fetchFormCSVExptFieldsErrMsg": "May naganap na error habang kinukuha ang listahan ng mga field para sa form na ito.", + "fetchFormCSVExptFieldsConsErrMsg": "Error sa pagkuha ng form {formId}: {error}", + "fetchSubmissnsErrMsg": "May naganap na error habang kinukuha ang mga pagsusumite para sa form na ito.", + "fetchSubmissnsConsErrMsg": "Error sa pagkuha ng mga pagsusumite para sa {formId}: {error}", + "fetchVersionErrMsg": "Nagkaroon ng error habang kinukuha ang form na ito.", + "fetchVersionConsErrMsg": "Error sa pagkuha ng bersyon {versionId} para sa form {formId}: {error}", + "deleteApiKeyNotifyMsg": "Ang API Key para sa form na ito ay tinanggal.", + "deleteApiKeyErrMsg": "May naganap na error habang sinusubukang tanggalin ang API Key.", + "deleteApiKeyConsErrMsg": "Error sa pagtanggal ng API Key para sa form {formId}: {error}", + "generateApiKeyNotifyMsg": "Nagawa ang isang API Key para sa form na ito.", + "generateApiKeyErrMsg": "May naganap na error habang sinusubukang bumuo ng API Key.", + "generateApiKeyConsErrMsg": "Error sa pagbuo ng API Key para sa form {formId}: {error}", + "readApiKeyErrMsg": "May naganap na error habang sinusubukang kunin ang API Key.", + "readApiKeyConsErrMsg": "Error sa pagkuha ng API Key para sa form na {formId}: {error}.", + "getFCPHImageUrlErrMsg": "May naganap na error habang kinukuha ang url ng larawan", + "getFCPHImageUrlConsErrMsg": "Error sa pagkuha ng url ng larawan: {error}", + "listFCPHErrMsg": "May naganap na error habang kinukuha ang mga bahagi ng tagabuo ng form", + "listFCPHConsErrMsg": "Error sa pagkuha ng mga bahagi ng tagabuo ng form: {error}", + "downloadFileErrMsg": "Nagkaroon ng error habang nagda-download ng file", + "downloadFileConsErrMsg": "Error sa pag-download ng file: error", + "readSubscriptionSettingsErrMsg": "Nagkaroon ng error habang sinusubukang kunin ang mga setting ng subscription.", + "readSubscriptionSettingsConsErrMsg": "Error sa pagkuha ng mga setting ng subscription para sa form {formId}: {error}.", + "saveSubscriptionSettingsNotifyMsg": "Nai-save na ang mga setting ng subscription para sa form na ito.", + "saveSubscriptionSettingsErrMsg": "May naganap na error habang sinusubukang i-save ang mga setting ng subscription.", + "saveSubscriptionSettingsConsErrMsg": "Error sa pag-save ng mga setting ng subscription para sa form {formId}: {error}" + } + }, + "admin": { + "root": { + "admin": "Admin" + }, + "form": { + "administerForm": "Pangasiwaan ang Form" + }, + "user": { + "administerUser": "Pangasiwaan ang User" + } + }, + "user": { + "root": { + "myForms": "ANG AKING MGA FORM", + "history": "KASAYSAYAN", + "user": "Gumagamit" + } + } +} diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/uk/index.js b/frontend/app/frontend/src/internationalization/trans/chefs/uk/index.js new file mode 100644 index 0000000..b0a4ed9 --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/uk/index.js @@ -0,0 +1,4 @@ +import uk from '~/internationalization/trans/chefs/uk/uk.json'; +export default { + trans: uk, +}; diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/uk/uk.json b/frontend/app/frontend/src/internationalization/trans/chefs/uk/uk.json new file mode 100644 index 0000000..e8cc7c3 --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/uk/uk.json @@ -0,0 +1,995 @@ +{ + "date": { + "date": "рррр-мм-дд" + }, + "emailManagement": { + "emailManagement": "Управління електронною поштою", + "manageForm": "Керувати формою", + "submissionConfirmation": "Підтвердження подання" + }, + "emailTemplate": { + "body": "Тіло", + "save": "зберегти", + "saveEmailTemplateConsoleErrMsg": "Помилка оновлення шаблону електронної пошти для форми {formId}: {error}", + "saveEmailTemplateErrMsg": "Під час спроби оновити шаблон електронної пошти сталася помилка.", + "subject": "Тема", + "title": "Назва", + "validBodyRequired": "Будь ласка, введіть текст електронної пошти", + "validSubjectRequired": "Будь ласка, введіть тему електронного листа", + "validTitleRequired": "Будь ласка, введіть назву електронного листа" + }, + "formsTable": { + "myForms": "Мої форми", + "createNewForm": "Створіть нову форму", + "search": "Пошук", + "manage": "Керувати", + "submissions": "Подання", + "formTitle": "Назва форми", + "viewForm": "Переглянути форму", + "description": "опис", + "Description": "опис:", + "action": "Дії", + "loadingText": "Завантаження, будь ласка, зачекайте" + }, + "manageLayout": { + "manageForm": "Керувати формою" + }, + "preview": { + "preview": "Попередній перегляд", + "previewToolTip": "Це показує попередній перегляд дизайну та поведінки версії форми, як це побачать ваші субмітенти. Ви не можете надіслати форму з цієї сторінки." + }, + "shareForm": { + "shareForm": "Поділитися формою", + "shareLink": "Розповсюдити посилання", + "copyQRCode": "Скопіюйте посилання нижче або завантажте QR-код.", + "warningMessage": "Наразі опублікованої версії форми немає. Посилання нижче не буде доступним, доки не буде опубліковано версію.", + "openThisForm": "Відкрийте цю форму", + "downloadQRCode": "Завантажте QR-код", + "close": "Закрити", + "copyURLToClipboard": "Копіювати URL-адресу в буфер обміну" + }, + "manageFormActions": { + "emailManagement": "Управління електронною поштою", + "viewSubmissions": "Переглянути подання", + "teamManagement": "Керування командою", + "deleteForm": "Видалити форму", + "confirmDeletion": "Підтвердити видалення", + "deleteMessageA": "Ви впевнені, що бажаєте видалити", + "deleteMessageB": "Ця форма більше не буде доступна.", + "delete": "Видалити" + }, + "manageForm": { + "formSettings": "Налаштування форми", + "apiKey": "Ключ API", + "updated": "Оновлено", + "created": "Створено", + "formDesignHistory": "Історія дизайну форми", + "totalVersions": "Всього версій", + "status": "Статус", + "update": "оновлення", + "cancel": "Скасувати", + "eventSubscription": "Підписка на подію" + }, + "formSettings": { + "pressToAddMultiEmail": "Щоб додати кілька електронних адрес, натисніть enter або , або пробіл", + "allowMultiDraft": "Дозволити завантаження декількох чернеток", + "formTitle": "Назва форми", + "formDescription": "Опис форми", + "formAccess": "Доступ до форми", + "info": "Якщо ви збираєтеся використовувати цю форму для збору інформації від широкої громадськості на теми, які становлять загальний інтерес для громадськості, ви повинні зв’язатися з GCPE, щоб ваша участь могла бути включена до списку", + "important": "ВАЖЛИВО", + "idimNotifyA": "Ви повинні повідомити команду управління ідентифікаційною інформацією (IDIM) електронною поштою", + "idimNotifyB": "ваш намір використовувати BCeID для перевірки ідентичності відправників вашої форми.", + "referenceGuideA": "Будь ласка, посилайтеся на наш", + "referenceGuideB": "керівництво користувача", + "referenceGuideC": "для більш детальної інформації", + "specificTeamMembers": "Конкретні члени команди", + "formFunctionality": "Функціональність форми", + "formSubmissinScheduleMsg": "Розклад подання форми буде доступний у налаштуваннях форми після публікації форми.", + "formSubmissionsSchedule": "Графік подання форм", + "experimental": "Експериментальний", + "learnMore": "Вивчайте більше", + "afterSubmission": "Після подачі", + "submissionConfirmation": "Показати деталі підтвердження подання", + "theConfirmationID": "ідентифікатор підтвердження", + "infoB": "можливість для користувача надсилати собі електронною поштою підтвердження подання", + "loginRequired": "Необхідно ввійти", + "canSaveAndEditDraftLabel": "Автори можуть зберігати та редагувати чернетки", + "canUpdateStatusAsReviewer": "Рецензенти можуть оновити статус цієї форми (наприклад, подано, призначено, завершено)", + "submitterCanCopyExistingSubmissn": "Відправники можуть скопіювати наявне подання", + "submissionConfirmationToolTip": "Вибір цього параметра визначає, що користувач, який надсилає цю форму, бачитиме після успішного надсилання.
Якщо позначено, воно відображатиметься", + "emailNotificatnToTeam": "Надіслати моїй команді сповіщення електронною поштою", + "emailNotificatnToTeamToolTip": "Надсилайте сповіщення на вказану вами адресу електронної пошти, коли будь-який користувач надсилає цю форму", + "notificationEmailAddrs": "Адреси електронної пошти для сповіщень", + "addMoreValidEmailAddrs": "Додайте одну або кілька дійсних адрес електронної пошти", + "formScheduleSettings": "Налаштування розкладу форми", + "opensubmissions": "Відкриті подання", + "submissionsDeadline": "Як довго ви хочете отримувати подання?", + "keepSubmissnOpenTilUnplished": "Залишити відкритим, доки не буде скасовано публікацію вручну", + "submissionsClosingDate": "Заплануйте дату закриття", + "submissionPeriod": "Встановіть період подання", + "closeSubmissions": "Закрити подання", + "keepOpenFor": "Тримайте відкритим для", + "period": "Крапка", + "allowLateSubmissions": "Дозволити подання із запізненням", + "allowLateSubmissionsInfoTip": "Якщо позначено, заявники зможуть подавати дані після дати закриття.", + "afterCloseDateFor": "Після закінчення дати для", + "repeatPeriod": "Період повторення", + "every": "кожен", + "repeatUntil": "Повторюйте, поки", + "summary": "Резюме", + "submissionsOpenDateRange": "Ця форма буде відкрита для подання від", + "to": "до", + "scheduleRepetition": "Розклад повторюватиметься щоразу", + "allowLateSubmissnInterval": "дозволяючи пізнє подання для", + "until": "поки", + "datesOfSubmissnInfo": "Відповідно до налаштувань це доступні дати подання:", + "formOpenInterval": "Ця форма буде відкрита для подання від", + "allowDateSubmissionDate": "з можливістю несвоєчасного подання до", + "customClosingMessage": "Встановити спеціальне кінцеве повідомлення", + "customClosingMessageToolTip": "Дозволяє додавати персоналізоване повідомлення для ваших користувачів, коли вони відвідують закриту форму.", + "closingMessage": "Заключне повідомлення", + "sendReminderEmail": "НАДІСЛАТИ електронний лист із нагадуванням", + "autoReminderNotificatn": "Увімкнути автоматичне сповіщення про нагадування", + "autoReminderNotificatnToolTip": "Надсилайте електронні листи з нагадуваннями з посиланням на форму протягом періоду подання.", + "selectLoginType": "Будь ласка, виберіть 1 тип входу", + "formDescriptnMaxChars": "Опис форми має містити не більше 255 символів", + "formTitlemaxChars": "Назва форми має містити не більше 255 символів", + "formTitleReq": "Необхідно вказати назву форми", + "atLeastOneEmailReq": "Введіть принаймні 1 електронну адресу", + "validEmailRequired": "Введіть усі дійсні адреси електронної пошти", + "fieldRequired": "Це поле є обов'язковим.", + "correctDateFormat": "Дата має бути в правильному форматі. тобто. рррр-мм-дд", + "dateDiffMsg": "Дата закритого подання має бути більшою за дату відкритого подання.", + "valueMustBeNumber": "Значення має бути числом. тобто. 1,2,3,5,99", + "selectAnOptions": "Виберіть принаймні 1 варіант", + "validInterval": "Це має бути дійсний інтервал.", + "fieldRequiredAndInterval": "Це поле є обов’язковим і має бути інтервалом.", + "dateGrtOpenSubmissnDate": "Повторювати, доки дата не має бути більшою за дату відкритого подання", + "public": "Публічний (анонімний)", + "allowEventSubscription": "Дозволити підписку на події", + "eventSubscription": "Підписка на подію", + "validEndpointRequired": "Введіть дійсну кінцеву точку, починаючи з https://", + "validBearerTokenRequired": "Введіть дійсний приклад маркера носія: 89abddfb-2cff-4fda-83e6-13221f0c3d4f" + }, + "subscribeEvent": { + "eventType": "Тип події", + "endpointUrl": "URL кінцевої точки", + "eventSubmission": "Подання", + "eventAssignment": "призначення", + "eventStatusChange": "Зміна статусу", + "endpointToken": "Маркер кінцевої точки", + "urlPlaceholder": "https://endpoint.gov.bc.ca/api/v1/", + "save": "зберегти", + "text": "текст", + "password": "пароль", + "hideSecret": "Приховати секрет", + "showSecret": "Показати секрет", + "key": "ключ", + "saveSettingsErrMsg": "Під час спроби оновити налаштування цієї форми сталася помилка.", + "updateSettingsConsoleErrMsg": "Помилка оновлення налаштувань для форми {formId}: {error}" + }, + "apiKey": { + "disclaimer": "Відмова від відповідальності", + "infoA": "Переконайтеся, що ваш секретний ключ API зберігається в безпечному місці (тобто в сховищі ключів).", + "infoB": "Ваш ключ API надає необмежений доступ до вашої форми. Нікому не передавайте свій ключ API.", + "infoC": "Ключ API слід використовувати ЛИШЕ для автоматизованої взаємодії з системою. Не використовуйте свій ключ API для доступу на основі користувача", + "deleteKey": "Видалити ключ", + "apiKey": "ключ API", + "hideSecret": "Приховати секрет", + "showSecret": "Показати секрет", + "sCTC": "Секрет скопійовано в буфер обміну", + "cSTC": "Копіювати секрет у буфер обміну", + "key": "ключ", + "confirmDeletion": "Підтвердити видалення", + "deleteMsg": "Ви впевнені, що бажаєте видалити свій ключ API?", + "delete": "Видалити", + "confirmKeyGen": "Підтвердьте генерацію ключа", + "createAPIKey": "Створити ключ API для цієї форми?
Переконайтеся, що ви дотримуєтесь Відмови від відповідальності на цій сторінці.", + "regenerateAPIKey": "Повторно створити ключ API?
Якщо продовжити, ваш поточний доступ до ключа API буде видалено .", + "formOwnerKeyAcess": "Ви повинні бути власником форми , щоб керувати ключами API.", + "regenerate": "Регенерувати", + "generate": "Генерувати", + "secret": "Секрет" + }, + "manageVersions": { + "important": "ВАЖЛИВО!", + "infoA": "Якщо опублікованих версій немає, користувачі не зможуть отримати доступ до цієї форми, доки не буде призначено опубліковану версію. Після публікації версії її більше не можна редагувати. Щоб продовжити редагування, необхідно створити нову версію на основі однієї з попередніх версій форми.", + "infoB": "Примітка. Можна опублікувати лише одну версію.", + "version": "Версія", + "draft": "Чернетка", + "clickToPreview": "Натисніть, щоб переглянути", + "editVersion": "Редагувати версію", + "exportDesign": "Експортний дизайн", + "infoC": "Будь ласка, опублікуйте або видаліть останню чернетку перед початком нової версії.", + "deleteVersion": "Видалити версію", + "draftAlreadyExists": "Чернетка вже існує", + "infoD": "Будь ласка, відредагуйте, опублікуйте або видаліть наявну чернетку перед початком нової чернетки.", + "publishVersion": "Опублікувати версію", + "unpublishVersion": "Скасувати публікацію версії", + "infoE": "Якщо скасувати публікацію цієї форми, її буде вилучено з обігу, доки її версія не буде опублікована знову.", + "confirmDeletion": "Підтвердити видалення", + "infoF": "Ви впевнені, що бажаєте видалити цю версію?", + "delete": "Видалити", + "status": "Статус", + "dateCreated": "Дата створення", + "createdBy": "Створений", + "actions": "Дії", + "published": "Опубліковано", + "unpublished": "Неопублікований", + "useVersionInfo": "Використовуйте версію {version} як основу для нової версії", + "publishingVersionInfo": "Це опублікує версію {version} вашої форми." + }, + "addOwner": { + "infoA": "Це слід робити лише у випадку, якщо поточний власник форми більше не активний або не має зв’язку під час пріоритетної події. В іншому випадку попросіть поточного власника або адміністратора групи для форми зробити це самостійно.", + "hint": "Щоб знайти потрібний ідентифікатор користувача, перейдіть на вкладку «КОРИСТУВАЧІ» на порталі адміністратора та знайдіть їх.", + "addowner": "Додати власника", + "label": "ID користувача (guid)" + }, + "adminFormsTable": { + "showDeletedForms": "Показати видалені форми", + "search": "Пошук", + "loadingText": "завантажувальний текст", + "noDataText": "У вашій системі немає форм", + "admin": "адмін", + "launch": "Запуск", + "formTitle": "Назва форми", + "created": "Створено", + "deleted": "Видалено", + "actions": "Дії", + "delete": "Видалити" + }, + "administerForm": { + "deleted": "ВИДАЛЕНО", + "restoreForm": "Відновіть цю форму", + "formDetails": "Деталі форми", + "apiKeyDetails": "Деталі ключа API", + "deleteApiKey": "Видалити ключ API", + "formUsers": "Користувачі форми", + "formVersions": "Версії форми", + "assignANewOwner": "Призначити нового власника", + "restoring": "Відновлення", + "restore": "Відновлення", + "toActiveState": "в активний стан", + "confirmDeletion": "Підтвердити видалення", + "confirmDeletionMsg": "Ви впевнені, що хочете видалити цей ключ API?", + "delete": "Видалити", + "confirmRestore": "Підтвердити відновлення" + }, + "administerUser": { + "userDetails": "Відомості про користувача", + "openSSOConsole": "Відкрийте консоль SSO" + }, + "adminPage": { + "forms": "Форми", + "users": "Користувачі", + "developer": "Розробник", + "infoLinks": "Інформаційні посилання", + "metrics": "Метрики" + }, + "adminUsersTable": { + "search": "Пошук", + "loadingText": "Завантаження, будь ласка, зачекайте", + "admin": "адмін", + "fullName": "Повне ім'я", + "userID": "ідентифікатор користувача", + "created": "Створено", + "actions": "Дії" + }, + "adminVersions": { + "exportDesign": "Експортний дизайн", + "versions": "Версії", + "status": "Статус", + "created": "Створено", + "lastUpdated": "Останнє оновлення", + "actions": "Дії", + "published": "Опубліковано", + "unpublished": "Неопублікований", + "version": "Версія {versionNo}", + "notificationMsg": "Під час завантаження дизайну форми сталася помилка." + }, + "developer": { + "user": "Користувач", + "name": "Ім'я", + "userName": "Ім'я користувача", + "JWTContents": "Зміст JWT", + "JWTContentsSBTxt": "Вміст JWT скопійовано в буфер обміну", + "JWTContentsTTTxt": "Скопіюйте вміст JWT у буфер обміну", + "JWTToken": "Токен JWT", + "JWTTokenSBTxt": "Маркер JWT скопійовано в буфер обміну", + "JWTTokenTTTxt": "Скопіюйте маркер JWT у буфер обміну", + "chefsAPI": "API CHEFS", + "RBACSBTxt": "Відповідь RBAC скопійовано в буфер обміну", + "RBACTTTxt": "Копіювати відповідь RBAC у буфер обміну", + "notificationMsg": "Не вдалося отримати користувача з RBAC, див. консоль", + "notificationConsErr": "Помилка отримання користувача з RBAC" + }, + "baseAuthButton": { + "logout": "Вийти", + "login": "Логін" + }, + "baseDialog": { + "defaultText": "текст за замовчуванням", + "ok": "в порядку", + "continue": "Продовжити", + "cancel": "Скасувати", + "custom": "Custom" + }, + "baseSecure": { + "about": "про", + "loginInfo": "Ви повинні увійти в систему, щоб використовувати цю функцію.", + "login": "Логін", + "401NotAuthorized": "401: не авторизовано. :", + "401ErrorMsg": "Ваш обліковий запис налаштовано неправильно.
Будь ласка зв'яжіться", + "403Forbidden": "403 Заборонено. :", + "403ErrorMsg": "Для цієї сторінки потрібна автентифікація {idp}.", + "401UnAuthorized": "401: неавторизовано. :", + "401UnAuthorizedErrMsg": "Ви не маєте дозволу на доступ до цієї сторінки." + }, + "formDesigner": { + "formDesign": "Дизайн форми", + "exportDesign": "Експортний дизайн", + "importDesign": "Імпортний дизайн", + "important": "ВАЖЛИВО", + "formDesignInfoA": "Скористайтеся кнопкою ЗБЕРЕГТИ ДИЗАЙН, коли завершите створення цієї форми.", + "formDesignInfoB": "Кнопка НАДІСЛАТИ призначена для того, щоб ваш користувач міг надіслати цю форму, і вона буде активована після її збереження.", + "formLoadErrMsg": "Під час завантаження дизайну форми сталася помилка.", + "formLoadConsoleErrMsg": "Помилка завантаження схеми форми {formId} (версія: {versionId} проект: {draftId}): {error}", + "formSchemaImportErrMsg": "Під час імпорту схеми форми сталася помилка.", + "formSchemaImportConsoleErrMsg": "Помилка імпорту схеми форми: {error}", + "formDesignSaveErrMsg": "Під час спроби зберегти цей дизайн форми сталася помилка. Якщо вам потрібно оновити або залишити, щоб повторити спробу пізніше, ви можете експортувати наявний дизайн на сторінці, щоб зберегти на потім.", + "formDesignSaveConsoleErrMsg": "Помилка оновлення або створення форми (FormID: {formId}, versionId: {versionId}, draftId: {draftId}) Помилка: {error}", + "collapse": "Згорнути", + "actions": "Дії", + "version": "Версія", + "save": "зберегти", + "saving": "Збереження", + "notSaved": "Не збережено", + "fieldnameError": "Ви НЕ МОЖЕТЕ використовувати ключове слово `form` як назву поля {label}" + }, + "formViewerMultiUpload": { + "important": "ВАЖЛИВО", + "uploadSucessMsg": "Щоб забезпечити успішне завантаження кількох чернеток, завантажте та використовуйте наданий шаблон.", + "confirmDownload": "Ви хочете завантажити його?", + "jsonFileUpload": "Виберіть файл JSON для завантаження", + "dragNDrop": "або перетягніть його сюди", + "chooseAFile": "Виберіть файл", + "downloadDraftSubmns": "Будь ласка, завантажте проект звіту про подання та переконайтеся, що дані введені правильно.", + "downloadReport": "Завантажити звіт", + "doYouWantToDownload": "Ви хочете завантажити його?", + "uploadNewFile": "Завантажте новий файл", + "uploadMultipleFileErr": "Вибачте, ви можете завантажити лише один файл", + "dragMultipleFileErr": "Вибачте, ви можете перетягнути лише один файл", + "fileFormatErr": "Вибачте, ми приймаємо лише файли json", + "fileSizeErr": "Максимально допустимий розмір файлу становить 5 Мб", + "parseJsonErr": "Ми не можемо проаналізувати дані json із файлу", + "jsonObjNotArray": "Неправильний формат файлу json", + "jsonObjNotArrayConsErr": "Сталася неочікувана помилка.", + "jsonArrayEmpty": "Цей файл json порожній.", + "errorWhileValidate": "З цим файлом щось не так", + "errWhileCheckValidity": "З цим файлом щось не так", + "errAfterValidate": "Знайдено деякі помилки, див. нижче для отримання додаткової інформації.", + "fileIsEmpty": "цей файл порожній.", + "download": "Завантажити" + }, + "formDisclaimer": { + "disclaimerAndStatement": "Відмова від відповідальності та заява про відповідальність для дизайнерів форм:", + "privacyLaw": "Ви несете відповідальність за дотримання законів про конфіденційність, які регулюють збір, використання та розкриття особистої інформації.", + "disclosure": "Доступ до цього інструменту розробника форм за своєю суттю не надає дозволу збирати, використовувати чи розкривати будь-яку особисту інформацію.", + "consent": "Ви несете відповідальність за отримання згоди на збір інформації відповідно до законодавства.", + "formIntention": "Перед публікацією або розповсюдженням вашої форми ви повинні обговорити призначення форми з вашим", + "privacyOfficer": "Міністерство з питань конфіденційності", + "assement": "і завершити оцінювання за потреби." + }, + "requestReceipt": { + "emailPriority": "Пріоритет електронної пошти", + "emailReceipt": "Надішліть електронною поштою квитанцію про отримання цього подання", + "high": "Високий", + "low": "Низький", + "normal": "нормальний", + "send": "НАДІСЛАТИ", + "sendToEmailAddress": "Надіслати на електронну адресу", + "emailSent": "Електронний лист надіслано на адресу {to}.", + "sendingEmailErrMsg": "Під час спроби надіслати електронну пошту сталася помилка.", + "sendingEmailConsErrMsg": "Помилка підтвердження електронною поштою до {to}: {error}", + "emailRequired": "Електронна пошта обов'язкова" + }, + "submissionsTable": { + "noMatchingRecordText": "Відповідних записів не знайдено", + "submissions": "Подання", + "submissionsTable": "SubmissionsTable", + "selectColumns": "Виберіть Стовпці", + "manageForm": "Керувати формою", + "submissionsToFiles": "Експорт матеріалів у файли", + "showDeletedSubmissions": "Показати видалені подання", + "showMySubmissions": "Показати мої матеріали", + "search": "Пошук", + "loadingText": "Завантаження, будь ласка, зачекайте", + "noDataText": "Для цієї форми немає заявок", + "delSelectedSubmissions": "Видалити вибрані подання", + "resSelectedSubmissions": "Відновити вибрані подання", + "yes": "ТАК", + "no": "НІ", + "viewSubmission": "Переглянути подання", + "deleteSubmission": "Видалити подання", + "restore": "Відновлення", + "confirmDeletion": "Підтвердити видалення", + "delete": "Видалити", + "confirmRestoration": "Підтвердити відновлення", + "searchSubmissionFields": "Поля подання пошуку", + "save": "зберегти", + "searchTitle": "Знайдіть і виберіть стовпці, які відображатимуться під панеллю інструментів", + "status": "Статус", + "submitter": "Подавач", + "submissionDate": "Дата подання", + "event": "подія", + "view": "Переглянути", + "lateSubmission": "Пізнє подання", + "confirmationID": "ID підтвердження", + "multiDelWarning": "Ви впевнені, що бажаєте видалити вибрані подання?", + "singleDelWarning": "Ви впевнені, що бажаєте видалити це повідомлення?", + "multiRestoreWarning": "Ви впевнені, що бажаєте відновити ці подання?", + "singleRestoreWarning": "Ви впевнені, що бажаєте відновити це подання?" + }, + "auditHistory": { + "viewEditHistory": "Переглянути історію редагування", + "editHistory": "Історія редагування", + "auditLogMsg": "Це журнал перевірок того, хто вніс зміни до цього подання після початкового подання.", + "loadingText": "Завантаження, будь ласка, зачекайте", + "close": "Закрити", + "userName": "Ім'я користувача", + "date": "Дата", + "errorMsg": "Під час спроби отримати історію сталася помилка.", + "consoleErrMsg": "Помилка отримання журналу аудиту для" + }, + "deleteSubmission": { + "deleteThis": "Видалити це", + "draft": "Чернетка", + "submission": "Подання", + "confirmDeletion": "Підтвердити видалення", + "deleteWarning": "Ви впевнені, що бажаєте видалити це?", + "drafts": "проект", + "formSubmission": "подання форми", + "delete": "Видалити" + }, + "manageSubmissionUsers": { + "manageTeamMembers": "Керуйте членами команди", + "add": "додати", + "draftFormInvite": "Ви можете лише запрошувати та керувати членами команди, поки ця форма є чернеткою", + "submissionTeamMembers": "Члени команди для цього подання", + "actions": "Дії", + "close": "Закрити", + "remove": "видалити", + "userNotFoundErrMsg": "Не можете знайти когось? Можливо, вони не ввійшли в CHEFS.
Будь ласка, надішліть їм посилання на CHEFS і попросіть їх увійти.", + "name": "Ім'я", + "username": "Ім'я користувача", + "email": "Електронна пошта", + "removeUserWarningMsg1": "Ви впевнені, що бажаєте видалити", + "removeUserWarningMsg2": "Вони більше не матимуть дозволів на це подання.", + "userExistInListMsg": "Користувач {username} вже є в списку учасників команди.", + "getSubmissionUsersErr": "Під час спроби отримати користувачів для цього подання сталася помилка.", + "getSubmissionUsersConsoleErr": "Помилка отримання користувачів для {submissionId}: {error}", + "sentInviteEmailTo": "Надіслано електронний лист із запрошенням до", + "sentUninvitedEmailTo": "Надіслано незапрошений електронний лист до", + "updateUserErrMsg": "Під час спроби оновити користувачів для цього подання сталася помилка.", + "updateUserConsoleErrMsg": "Помилка налаштування дозволів користувача. Sub: {submissionId} Користувач: {userId} Помилка: {error}", + "searchInputLength": "Введення імені користувача/електронної адреси BCeID має містити більше 6 символів.", + "exactBCEIDSearch": "Пошук електронної пошти для BCeID має бути точним.", + "getUsersErrMsg": "Помилка отримання користувачів: {error}", + "exactEmailOrUsername": "Введіть точний e-mail або ім'я користувача.", + "requiredFiled": "Введіть ім'я, адресу електронної пошти або ім'я користувача" + }, + "mySubmissionsActions": { + "viewThisSubmission": "Переглянути цю заявку", + "copyThisSubmission": "Скопіюйте цей матеріал", + "editThisDraft": "Редагувати цю чернетку" + }, + "mySubmissionsTable": { + "noMatchingRecordText": "Відповідних записів не знайдено", + "previousSubmissions": "Попередні подання", + "selectColumns": "Виберіть Стовпці", + "createNewSubmission": "Створити нове подання", + "search": "Пошук", + "loadingText": "Завантаження, будь ласка, зачекайте", + "noDataText": "У вас немає заявок", + "searchSubmissionFields": "Поля подання пошуку", + "save": "зберегти", + "filterTitle": "Знайдіть і виберіть стовпці, які відображатимуться під панеллю інструментів", + "confirmationId": "Ідентифікатор підтвердження", + "actions": "дії", + "createdBy": "Створений", + "statusUpdatedBy": "Статус оновлено", + "status": "Статус", + "submissionDate": "Дата подання", + "draftUpdatedBy": "Чернетку оновлено", + "draftLastEdited": "Останнє редагування чернетки", + "createLateSubmissn": "Створіть пізнє подання", + "formLoading": "Будь ласка, зачекайте, поки завантажується форма!!!", + "pleaseConfirm": "Будь-ласка підтвердіть", + "wantToSaveDraft": "Ви хочете зберегти чернетку?", + "yes": "Так", + "no": "Немає", + "multiDraftUploadSuccess": "Ваше кілька чернеток завантажено успішно!", + "failedResSubmissn": "Помилка відповіді від кінцевої точки надсилання. Код відповіді: {status}", + "errSubmittingForm": "Під час надсилання цієї форми сталася помилка", + "errorSavingFile": "Помилка збереження файлів. Ім'я файлу: {fileName}. Помилка: {error}", + "submittingDraftErrMsg": "Під час збереження чернетки сталася помилка", + "submittingDraftConsErrMsg": "Помилка збереження чернетки. SubmissionId: {submissionId}. Помилка: {error}" + }, + "notesPanel": { + "addNewNote": "Додати нову примітку", + "cancel": "Скасувати", + "addNote": "ДОДАТИ КОМЕНТАР", + "noResponseErr": "Немає даних відповіді від API під час надсилання форми", + "errorMesg": "Під час спроби додати нотатку сталася помилка.", + "consoleErrMsg": "Помилка додавання примітки:", + "fetchErrMsg": "Під час спроби отримати нотатки для цього подання сталася помилка.", + "fetchConsoleErrMsg": "Помилка додавання примітки:", + "notes": "Примітки", + "note": "Примітка", + "maxChars": "Макс. 4000 символів" + }, + "statusPanel": { + "currentStatus": "Поточний стан:", + "assignedTo": "Присвоєно:", + "assignOrUpdateStatus": "Призначити або оновити статус", + "display": "дисплей", + "statusIsRequired": "Необхідний статус", + "assignTo": "Призначити", + "noDataText": "За допомогою пошуку не знайдено рецензентів форм. Додайте рецензентів форм на сторінці керування.", + "assigneeIsRequired": "Потрібен правонаступник", + "assignToMe": "ПРИЗНАЧИ МЕНІ", + "recipientEmail": "Електронна адреса одержувача", + "attachCommentToEmail": "Додайте коментар до електронного листа", + "emailComment": "Коментар електронною поштою", + "maxChars": "Макс. 4000 символів", + "viewHistory": "ПЕРЕГЛЯНУТИ ІСТОРІЮ", + "statusHistory": "Історія стану", + "close": "ЗАКРИТИ", + "addNoteNoReponserErr": "Немає даних відповіді від API під час надсилання примітки для оновлення статусу", + "addNoteConsoleErrMsg": "Помилка оновлення статусу: {error}", + "addNoteErrMsg": "Під час спроби оновити статус сталася помилка", + "updtSubmissionsStatusErr": "Немає даних відповіді від API під час надсилання форми оновлення статусу", + "noStatus": "Без статусу", + "noStatusesFound": "Статуси не знайдено", + "statusCodesErr": "помилка пошуку кодів стану", + "notifyErrorCode": "Під час отримання статусу цього подання сталася помилка.", + "notifyConsoleErrorCode": "Помилка отримання статусів:", + "fetchSubmissionUsersErr": "Під час спроби отримати електронні листи одержувачів для цього надсилання сталася помилка.", + "fetchSubmissionUsersConsErr": "Помилка отримання електронних листів одержувачів для", + "assignSubmissnToFormReviewer": "Подання можна призначити рецензентам форм.
Щоб додати більше членів команди як рецензентів форм, перейдіть на сторінку керування цією формою.", + "update": "ОНОВЛЕННЯ", + "revise": "ПЕРЕГЛЯНУТИ", + "complete": "ЗАВЕРШЕНО", + "assign": "ПРИЗНАЧИТИ" + }, + "statusTable": { + "loadingText": "Завантаження, будь ласка, зачекайте", + "status": "Статус", + "dateStatusChanged": "Статус дати змінено", + "assignee": "Цесіонарій", + "updatedBy": "Оновлено", + "getSubmissionStatusErr": "Під час спроби отримати статуси сталася помилка.", + "getSubmissionStatusConsErr": "Помилка додавання примітки:" + }, + "exportSubmissions": { + "exportSubmissionsToFile": "Експорт матеріалів у файл", + "viewSubmissions": "Переглянути подання", + "fileType": "Тип файлу", + "json": "JSON", + "csv": "CSV", + "formVersion": "Версія форми", + "versionIsRequired": "Необхідна версія.", + "dataFields": "Поля даних", + "searchFields": "Поля пошуку", + "selectedForExports": "вибрано для експорту", + "submissionDate": "Дата подання", + "all": "всі", + "selectDateRange": "Виберіть діапазон дат", + "SelectdateRange": "Виберіть діапазон дат", + "from": "Від", + "to": "до", + "CSVFormat": "Формат CSV", + "multiRowPerSubmissionA": "1 – Кілька рядків на подання з відступами", + "multiRowPerSubmissionB": "2 – Кілька рядків на подання", + "singleRowPerSubmission": "3 – Один рядок на подання", + "unformatted": "4 - Неформатований", + "fileNameAndType": "Назва та тип файлу", + "export": "Експорт", + "noResponseDataErr": "Немає даних у відповідь на виклик exportSubmissions", + "apiCallErrorMsg": "Сталася помилка під час спроби експортувати подання для цієї форми.", + "apiCallConsErrorMsg": "Помилка експорту документів для", + "selectAllFields": "Виберіть усі поля", + "emailSentMsg": "На адресу {email} буде надіслано електронний лист із посиланням для завантаження ваших даних, коли вони будуть готові", + "exportInProgress": "Виконується експорт", + "of": "з" + }, + "printOptions": { + "submitButtonTxt": "Надішліть до CDOGS і завантажте", + "templatePrint": "Друк шаблону", + "uploadTemplateFile": "Завантажте файл шаблону", + "downloadOptions": "Параметри завантаження", + "print": "Роздрукувати", + "browserPrint": "Друк з браузера", + "pageFromBrowser": "сторінку з вашого браузера", + "uploadA": "Завантажити a", + "uploadB": "мати структуровану версію", + "docGrnSucess": "Документ створено успішно", + "failedDocGenErrMsg": "Не вдалося створити документ", + "failedDocGenConsErrMsg": "Помилка надсилання шаблону: {error}", + "cDogsTemplate": "Шаблон CDOGS" + }, + "proactiveHelpDialog": { + "componentInfoLink": "Інформаційне посилання на компонент", + "learnMoreLinkTxt": "Дізнатися більше Поле посилання не може бути порожнім.", + "largeImgTxt": "Велике зображення. Розмір зображення не може перевищувати 0,5 Мб", + "componentName": "Назва компонента:", + "learnMoreLink": "Дізнатися більше Посилання:", + "clickToEnableLink": "Натисніть, щоб увімкнути посилання", + "clickToDisableLink": "Натисніть, щоб вимкнути посилання", + "imageUpload": "Завантаження зображення:", + "cancel": "Скасувати", + "save": "зберегти", + "description": "опис" + }, + "proactiveHelpPreviewDialog": { + "learnMore": "Вивчайте більше" + }, + "preview": { + "preview": "Попередній перегляд", + "previewToolTip": "Це показує попередній перегляд дизайну та поведінки версії форми, як це побачать ваші субмітенти. Ви не можете надіслати форму з цієї сторінки." + }, + "generalLayout": { + "loadingText": "Завантаження, будь ласка, зачекайте", + "preview": "ПОПЕРЕДНІЙ ПЕРЕГЛЯД", + "published": "ОПУБЛІКОВАНО", + "unpublished": "НЕ ОПУБЛІКОВАНО", + "edit": "РЕДАГУВАТИ", + "formTitle": "Назва форми", + "actions": "Дії" + }, + "formSubmission": { + "editThisSubmission": "Редагувати це подання", + "submission": "Подання", + "alertInfo": "Після редагування повторно надішліть форму, щоб зберегти зміни.", + "viewAllSubmissions": "Переглянути всі подання", + "submitted": "Надіслано:", + "confirmationID": "ID підтвердження:", + "submittedBy": "Представлений:", + "cancel": "СКАСУВАТИ", + "status": "Статус", + "updatedAt": "Змінено", + "updatedBy": "Змінено" + }, + "teamManagement": { + "noMatchingRecordText": "Відповідних записів не знайдено", + "teamManagement": "Керування командою", + "selectColumns": "Виберіть Стовпці", + "manageForm": "Керувати формою", + "search": "Пошук", + "loadingText": "Завантаження, будь ласка, зачекайте", + "noDataText": "Не вдалося завантажити дані ролі команди", + "removeSelectedUsers": "Видалити вибраних користувачів", + "removeThisUser": "Видалити цього користувача", + "confirmRemoval": "Підтвердити видалення", + "remove": "видалити", + "searchTeamManagementFields": "Пошук полів керування командою", + "save": "зберегти", + "teamMebersTitle": "Знайдіть і виберіть стовпці, які відображатимуться під панеллю інструментів", + "fullName": "Повне ім'я", + "username": "Ім'я користувача", + "identityProvider": "Постачальник ідентифікаційних даних", + "delSelectedMembersWarning": "Ви впевнені, що бажаєте видалити вибраних учасників?", + "delSelectedMemberWarning": "Ви впевнені, що бажаєте видалити вибраного учасника?", + "idpMessage": "вже в команді.", + "formOwnerErrMsg": "Завжди має бути принаймні один власник форми", + "formOwnerConsoleErrMsg": "Неможливо видалити {userId}, оскільки вони є єдиним власником цієї форми.", + "insufficientPermissnMsg": "Недостатньо дозволів для керування командою", + "getUserErrMsg": "Помилка отримання користувачів форми:", + "getRolesErrMsg": "Помилка отримання списку ролей:", + "formOwnerRemovalWarning": "Неможливо видалити, оскільки вони є єдиним власником цієї форми.", + "removeUsersErrMsg": "Під час спроби видалити вибраних користувачів сталася помилка", + "removeUserConsoleErrMsg": "Помилка видалення користувачів із форми {formId}: {error}", + "updUserRolesErrMsg": "Під час спроби оновити всі ролі користувачів сталася помилка", + "updUserRolesConsoleErrMsg": "Помилка встановлення всіх ролей користувача для форми {formId}: {error}", + "setUserFormsErrMsg": "Під час спроби оновити ролі користувача сталася помилка", + "setUserFormsConsoleErrMsg": "Помилка встановлення ролей користувача для форми {formId}: {error}" + }, + "floatButton": { + "publish": "Опублікувати", + "manage": "Керувати", + "redo": "Повторити", + "undo": "Скасувати", + "preview": "Попередній перегляд", + "bottom": "Дно", + "top": "Топ", + "actions": "Дії", + "collapse": "Згорнути", + "saved": "Збережено", + "save": "зберегти", + "saving": "Збереження", + "notSaved": "Не збережено" + }, + "formViewer": { + "lateFormSubmissions": "Термін подання форми закінчився! Ви все ще можете створити пізнє подання, натиснувши кнопку нижче.", + "createLateSubmission": "Створіть пізнє подання", + "draftSaved": "Чернетку збережено", + "saving": "Збереження", + "pleaseConfirm": "Будь-ласка підтвердіть", + "submitFormWarningMsg": "Ви впевнені, що бажаєте надіслати свою форму?", + "submit": "Надіслати", + "wantToSaveDraft": "Ви хочете зберегти чернетку?", + "version": "Версія: {version}", + "formScheduleExpireMessage": "Подання форми недоступне, оскільки запланований період подання минув.", + "getUsersSubmissionsErrMsg": "Під час отримання подання для цієї форми сталася помилка", + "getUsersSubmissionsConsoleErrMsg": "Помилка завантаження даних подання форми {submissionId}: {error}", + "multiDraftUploadSuccess": "Ваше кілька чернеток завантажено успішно!", + "readVersionErrMsg": "У відповіді немає схеми. VersionId: {versionId}", + "readDraftErrMsg": "У відповіді немає схеми. draftId: {draftId}", + "alertRouteMsg": "Власник форми не опублікував форму, і вона недоступна для подання.", + "fecthingFormErrMsg": "Під час отримання цієї форми сталася помилка", + "fecthingFormConsoleErrMsg": "Помилка завантаження схеми форми {versionId}: {error}", + "savingDraftErrMsg": "Під час збереження чернетки сталася помилка", + "savingDraftConsoleErrMsg": "Помилка збереження чернетки. SubmissionId: {submissionId}. Помилка: {error}", + "submissionsPreviewAlert": "Надсилання вимкнено під час попереднього перегляду форми", + "submissionsSubmitErrMsg": "Помилка надсилання форми: {errors}", + "sendSubmissionErrMsg": "Помилка відповіді від кінцевої точки надсилання. Код відповіді: {status}", + "errMsg": "Під час надсилання цієї форми сталася помилка", + "customEventAlert": "Спеціальні події кнопки ще не підтримуються. Тип події: {event}", + "formLoading": "Будь ласка, зачекайте, поки завантажується форма!!!", + "yes": "Так", + "no": "Немає", + "failedResSubmissn": "Помилка відповіді від кінцевої точки надсилання. Код відповіді: {status}", + "errSubmittingForm": "Під час надсилання цієї форми сталася помилка", + "errorSavingFile": "Помилка збереження файлів. Ім'я файлу: {fileName}. Помилка: {error}", + "submittingDraftErrMsg": "Під час збереження чернетки сталася помилка", + "submittingDraftConsErrMsg": "Помилка збереження чернетки. SubmissionId: {submissionId}. Помилка: {error}", + "formDraftAccessErrMsg": "Запитане подання вже подано, переспрямовує на сторінку перегляду" + }, + "bCGovFooter": { + "home": "додому", + "about": "Про gov.bc.ca", + "disclaimer": "Відмова від відповідальності", + "privacy": "Конфіденційність", + "accessibility": "Доступність", + "copyRight": "Авторське право", + "contactUs": "Зв'яжіться з нами" + }, + "bCGovNavBar": { + "about": "О нас", + "myForms": "Мої форми", + "createNewForm": "Створіть нову форму", + "help": "Довідка", + "feedback": "Зворотній зв'язок", + "admin": "адмін" + }, + "homePage": { + "title": "Створюйте, публікуйте форми та отримуйте подання за допомогою Common Hosted Forms Service.", + "subTitle": "Всі державні службовці Б.К. або підрядники з обліковим записом IDIR можуть використовувати нашу розміщену версію Common Hosted Forms Service (CHEFS) для створення форм.", + "takeATourOfChefs": "Здійсніть екскурсію по CHEFS, щоб побачити це в дії.", + "logInToGetStarted": "Увійдіть, щоб почати", + "loginToStart": "Щоб почати, увійдіть за допомогою IDIR", + "login": "Логін", + "createFormLabel": "Створіть форму", + "manageAccessTitle": "Керуйте доступом до своєї форми", + "manageAccessSub1": "CHEFS дозволяє створювати загальнодоступні форми або керувати доступом за допомогою автентифікації IDIR або BCeID.", + "manageAccessSub2": "Ви також можете призначити ролі своїй команді, щоб керувати всіма вашими заявками.", + "createCustomFormTitle": "Створюйте власні форми за допомогою конструктора форм CHEFS", + "createCustomFormSub1": "За допомогою CHEFS ви можете створювати безпечні форми за допомогою інтуїтивно зрозумілого інтерфейсу перетягування. Ви можете додавати компоненти форми, змінювати їх розташування та розміщувати в різних конфігураціях макетів.", + "chefsHowToTitle": "Відео з порадами для CHEFS", + "chefsHowToSub": "Наш короткий посібник познайомить вас із деякими основними функціями CHEFS.", + "getStartedToChefs": "Почніть використовувати CHEFS", + "createOnlineTitle": "Створюйте онлайн-форми для збору інформації від своїх клієнтів і вдосконалення робочих процесів.", + "getStarted": "Почати" + }, + "baseStepper": { + "setUpForm": "Налаштувати форму", + "designForm": "Форма оформлення", + "manageForm": "Керувати формою" + }, + "create": { + "formSettings": "Налаштування форми", + "disclaimer": "Відмова від відповідальності", + "disclaimerStmt": "Я погоджуюся із застереженням і заявою про відповідальність для дизайнерів форм", + "continue": "Продовжити", + "back": "Назад", + "confirmPageNav": "Ви дійсно хочете залишити цю сторінку? Внесені вами зміни не будуть збережені.", + "agreementErrMsg": "Ви повинні погодитися із застереженням щодо конфіденційності, наведеним вище." + }, + "addTeamMember": { + "cantFindChefsUsers": "Не можете знайти когось? Можливо, вони не ввійшли в CHEFS.
Будь ласка, надішліть їм посилання на CHEFS і попросіть їх увійти.", + "cancel": "Скасувати", + "add": "додати", + "mustSelectAUser": "Ви повинні вибрати принаймні одну роль, щоб додати цього користувача.", + "addNewMember": "Додати нового учасника", + "enterUsername": "Введіть ім'я, адресу електронної пошти або ім'я користувача", + "enterExactUsername": "Введіть точний e-mail або ім'я користувача", + "BCeIDInputSearchMaxLen": "Введення імені користувача/електронної адреси BCeID має містити більше 6 символів.", + "BCeIDMustBeExact": "Пошук електронної пошти для BCeID має бути точним.", + "errorGettingUsers": "Помилка отримання користувачів {error}" + }, + "baseFilter": { + "cancel": "Скасувати", + "columnName": "Назва стовпця", + "exampleText": "Приклад тексту", + "exampleText2": "Приклад тексту 2", + "filterPlaceholderTxt": "Фільтр тексту заповнювача", + "filter": "фільтр", + "value": "значення", + "resetColumns": "Скинути стовпці" + }, + "formViewerActions": { + "viewMyDraftOrSubmissions": "Переглянути мої чернетки/подання", + "saveAsADraft": "Зберегти як чернетку", + "editThisDraft": "Відредагуйте цю чернетку", + "switchSingleSubmssn": "Перейти до одноразової подачі", + "switchMultiSubmssn": "Переключитися на кілька повідомлень" + }, + "baseCopyToClipboard": { + "linkToClipboard": "Посилання скопійовано в буфер обміну", + "copyToClipboard": "Копіювати в буфер обміну", + "errCopyToClipboard": "Помилка спроби скопіювати в буфер обміну." + }, + "sucess": { + "sucessFormSubmissn": "Ваша форма успішно надіслана", + "keepRecord": "Якщо ви бажаєте вести облік цього подання, ви можете зберегти наступне", + "confirmationId": "ID підтвердження" + }, + "bcGovAlertBanner": { + "defaultErrMsg": "Помилка: щось пішло не так", + "error": "помилка" + }, + "permissionUtils": { + "formNotAvailable": "Наразі форма недоступна. Це може бути через неправильне посилання або форма може бути видалена її власником.", + "missingFormIdAndSubmssId": "У параметрах відсутні як formId, так і submissionId", + "loadingFormErrMsg": "Під час завантаження цієї форми сталася помилка.", + "loadingForm": "Помилка під час завантаження {options}: {error}", + "idpHintMsg": "Для цієї форми потрібна автентифікація {idpHint}. Увійдіть повторно та спробуйте ще раз.", + "formIdpMissMatch": "Невідповідність форми IDP. Для форми потрібен {idpHint}, але користувач має {userIdp}." + }, + "download": { + "chefsDataExport": "Експорт даних CHEFS", + "preparingForDownloading": "Підготовка до завантаження...", + "downloadInfoA": "Якщо ваш файл не завантажується автоматично", + "downloadInfoB": "натисніть тут, щоб спробувати ще раз" + }, + "history": { + "submissnHistory": "Ваша історія подання (уточнюється)" + }, + "error": { + "logout": "Вийти", + "somethingWentWrong": "Помилка: щось пішло не так... :(" + }, + "login": { + "authenticateWith": "Автентифікувати за допомогою:", + "alreadyLoggedIn": "Вже ввійшли", + "home": "додому", + "about": "про" + }, + "notFound": { + "about": "про", + "pageNotFound": "404: Сторінка не знайдена. :(" + }, + "store": { + "admin": { + "addFormOwnerRole": "Додано роль власника для цієї форми для {fullName}", + "addRowError": "Під час додавання ролі сталася помилка.", + "addRowConsoleErr": "Помилка додавання користувача {userId} до форми {formId}: {error}", + "apiKeyDelMsg": "Ключ API для цієї форми видалено.", + "errDeletingApiKey": "Під час спроби видалити ключ API сталася помилка.", + "consErrDeletingApiKey": "Помилка видалення ключа API для форми {formId}: {error}", + "fecthingFormsErrMsg": "Під час отримання форм сталася помилка.", + "fecthingFormsConsErrMsg": "Помилка отримання даних форми адміністратора: {error}", + "fecthingFormErrMsg": "Під час отримання цієї форми сталася помилка.", + "fecthingFormConsErrMsg": "Помилка отримання даних форми адміністратора {formId}: {error}", + "fecthFormUserRolesErrMsg": "Під час отримання ролей користувачів форми сталася помилка.", + "fecthFormUserRolesConsErrMsg": "Помилка отримання даних про ролі адміністратора: {error}", + "fecthApiDetailsErrMsg": "Під час отримання даних API цієї форми сталася помилка.", + "fecthApiDetailsConsErrMsg": "Помилка отримання даних API адміністратора з даних форми {formId}: {error}", + "restoreFormErrMsg": "Під час відновлення цієї форми сталася помилка.", + "restoreFormConsErrMsg": "Помилка відновлення даних форми {formId}: {error}", + "getUsersErrMsg": "Під час отримання користувачів сталася помилка.", + "getUsersConsErrMsg": "Помилка отримання даних користувачів адміністратора: {error}", + "getUserErrMsg": "Під час отримання цього користувача сталася помилка.", + "getUserConsErrMsg": "Помилка отримання даних користувача адміністратора {userId}: {error}", + "storingFCHelpInfoErrMsg": "Під час збереження довідкової інформації компонента форми сталася помилка", + "storingFCHelpInfoConsErrMsg": "Помилка отримання довідкової інформації компонента форми: {error}", + "gettingFCImgUrlErrMsg": "Під час отримання URL-адреси зображення сталася помилка", + "gettingFCImgUrlConsErrMsg": "Помилка отримання URL-адреси зображення: {error}", + "updatingFCStatusErrMsg": "Під час оновлення статусу публікації сталася помилка", + "updatingFCStatusConsErrMsg": "Помилка оновлення статусу публікації: {error}", + "fecthingFormBuilderCompsErrMsg": "Під час отримання компонентів конструктора форм сталася помилка", + "fecthingFormBuilderCompsConsErrMsg": "Помилка отримання компонентів конструктора форм: {error}" + }, + "form": { + "fetchEmailTemplatesConsErrMsg": "Помилка завантаження шаблонів електронних листів для {formId}: {error}", + "fetchEmailTemplatesErrMsg": "Під час отримання шаблонів електронної пошти для цієї форми сталася помилка", + "getCurrUserFormsErrMsg": "Під час отримання ваших форм сталася помилка.", + "getCurrUserFormsConsErrMsg": "Помилка отримання даних користувача: {error}", + "getUserFormPermErrMsg": "Під час отримання даних користувача для цієї форми сталася помилка.", + "getUserFormPermConsErrMsg": "Помилка отримання даних користувача за допомогою ідентифікатора форми {formId}: {error}", + "getUserFormRolesErrmsg": "Під час отримання даних користувача для цієї форми сталася помилка.", + "getUserFormRolesConsErrmsg": "Помилка отримання даних користувача за допомогою ідентифікатора форми {formId}: {error}", + "updCurrUserFormPrefErrMsg": "Під час збереження ваших налаштувань для цієї форми сталася помилка.", + "updCurrUserFormPrefConsErrMsg": "Помилка оновлення налаштувань форми користувача за допомогою ідентифікатора форми {formId} і налаштувань {preferences}: {error}", + "getCurrUserFormPrefErrMsg": "Під час отримання ваших налаштувань для цієї форми сталася помилка.", + "getCurrUserFormPrefConsErrMsg": "Помилка отримання налаштувань форми користувача за допомогою ідентифікатора форми {formId}: {error}", + "delCurrformNotiMsg": "Форма {name} була успішно видалена.", + "delCurrFormConsErMsg": "Помилка видалення форми {id}: {error}", + "delDraftErrMsg": "Під час видалення цієї чернетки сталася помилка.", + "delDraftConsErrMsg": "Помилка видалення {draftId}: {error}", + "fecthDraftErrMsg": "Під час сканування чернеток цієї форми сталася помилка.", + "fecthDraftConsErrMsg": "Помилка отримання чернеток для форми {formId}: {error}", + "fecthFormErrMsg": "Під час отримання цієї форми сталася помилка.", + "fecthFormConsErrMsg": "Помилка отримання форми {formId}: {error}", + "fetchFormFieldsErrMsg": "Під час отримання списку полів для цієї форми сталася помилка.", + "fetchFormFieldsConsErrMsg": "Помилка отримання форми {formId}: {error}", + "publishDraftErrMsg": "Під час публікації сталася помилка.", + "publishDraftConsErrMsg": "Помилка публікації {draftId}: {error}", + "toggleVersnPublConsErrMsg": "Помилка в toggleVersionPublish {versionId} {publish}: {error}", + "updateEmailTemplateConsErrMsg": "Помилка оновлення шаблонів електронних листів для форми {formId}: {error}", + "updateEmailTemplateErrMsg": "Під час оновлення шаблонів електронної пошти для цієї форми сталася помилка.", + "updateFormErrMsg": "Під час оновлення налаштувань цієї форми сталася помилка.", + "updateFormConsErrMsg": "Помилка оновлення форми {id}: {error}", + "deleteSubmissionNotifyMsg": "Подання успішно видалено.", + "deleteSubmissionErrMsg": "Під час видалення цього подання сталася помилка.", + "deleteSubmissionConsErrMsg": "Помилка видалення подання {submissionId}: {error}", + "deleteSubmissionsNotifyMsg": "Подання успішно видалено.", + "deleteSubmissionsErrMsg": "Під час видалення вибраних матеріалів сталася помилка.", + "deleteSubmissionsConsErrMsg": "Помилка видалення повідомлень: {error}", + "restoreSubmissionsNotiMsg": "Подання успішно відновлено.", + "restoreSubmissionsErrMsg": "Під час відновлення цього подання сталася помилка.", + "restoreSubmissionsConsErrMsg": "Помилка відновлення подання: {error}", + "restoreSubmissionNotiMsg": "Надсилання успішно відновлено.", + "restoreSubmissionErrMsg": "Під час відновлення цього подання сталася помилка.", + "restoreSubmissionConsErrMsg": "Помилка відновлення подання {submissionId}: {error}", + "fecthSubmissnUsersErrMsg": "Сталася помилка під час отримання електронної пошти одержувача для цього надсилання.", + "fecthSubmissnUsersConsErrMsg": "Помилка отримання електронної пошти одержувача для подання {formSubmissionId}: {error}", + "fetchSubmissnErrMsg": "Під час отримання цього подання сталася помилка.", + "fetchSubmissnConsErrMsg": "Помилка отримання подання {submissionId}: {error}", + "fetchFormCSVExptFieldsErrMsg": "Під час отримання списку полів для цієї форми сталася помилка.", + "fetchFormCSVExptFieldsConsErrMsg": "Помилка отримання форми {formId}: {error}", + "fetchSubmissnsErrMsg": "Сталася помилка під час отримання документів для цієї форми.", + "fetchSubmissnsConsErrMsg": "Помилка отримання документів для {formId}: {error}", + "fetchVersionErrMsg": "Під час отримання цієї форми сталася помилка.", + "fetchVersionConsErrMsg": "Помилка отримання версії {versionId} для форми {formId}: {error}", + "deleteApiKeyNotifyMsg": "Ключ API для цієї форми видалено.", + "deleteApiKeyErrMsg": "Під час спроби видалити ключ API сталася помилка.", + "deleteApiKeyConsErrMsg": "Помилка видалення ключа API для форми {formId}: {error}", + "generateApiKeyNotifyMsg": "Ключ API для цієї форми створено.", + "generateApiKeyErrMsg": "Під час спроби створити ключ API сталася помилка.", + "generateApiKeyConsErrMsg": "Помилка створення ключа API для форми {formId}: {error}", + "readApiKeyErrMsg": "Під час спроби отримати ключ API сталася помилка.", + "readApiKeyConsErrMsg": "Помилка отримання ключа API для форми {formId}: {error}.", + "getFCPHImageUrlErrMsg": "Під час отримання URL-адреси зображення сталася помилка", + "getFCPHImageUrlConsErrMsg": "Помилка отримання URL-адреси зображення: {error}", + "listFCPHErrMsg": "Під час отримання компонентів конструктора форм сталася помилка", + "listFCPHConsErrMsg": "Помилка отримання компонентів конструктора форм: {error}", + "downloadFileErrMsg": "Під час завантаження файлу сталася помилка", + "downloadFileConsErrMsg": "Помилка завантаження файлу: помилка", + "readSubscriptionSettingsErrMsg": "Під час спроби отримати налаштування підписки сталася помилка.", + "readSubscriptionSettingsConsErrMsg": "Помилка отримання налаштувань підписки для форми {formId}: {error}.", + "saveSubscriptionSettingsNotifyMsg": "Налаштування підписки на цю форму збережено.", + "saveSubscriptionSettingsErrMsg": "Під час спроби зберегти налаштування підписки сталася помилка.", + "saveSubscriptionSettingsConsErrMsg": "Помилка збереження налаштувань підписки для форми {formId}: {error}" + } + }, + "admin": { + "root": { + "admin": "адмін" + }, + "form": { + "administerForm": "Форма адміністрування" + }, + "user": { + "administerUser": "Адміністратор користувача" + } + }, + "user": { + "root": { + "myForms": "МОЇ ФОРМИ", + "history": "ІСТОРІЯ", + "user": "Користувач" + } + } +} diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/vi/index.js b/frontend/app/frontend/src/internationalization/trans/chefs/vi/index.js new file mode 100644 index 0000000..0bfbd19 --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/vi/index.js @@ -0,0 +1,4 @@ +import vi from '~/internationalization/trans/chefs/vi/vi.json'; +export default { + trans: vi, +}; diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/vi/vi.json b/frontend/app/frontend/src/internationalization/trans/chefs/vi/vi.json new file mode 100644 index 0000000..beb7c11 --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/vi/vi.json @@ -0,0 +1,993 @@ +{ + "date": { + "date": "yyyy-mm-dd" + }, + "emailManagement": { + "emailManagement": "Quản lý email", + "manageForm": "Quản lý biểu mẫu", + "submissionConfirmation": "Chứng nhận thông tin" + }, + "emailTemplate": { + "body": "Thân hình", + "save": "Cứu", + "saveEmailTemplateConsoleErrMsg": "Lỗi cập nhật mẫu email cho biểu mẫu {formId}: {error}", + "saveEmailTemplateErrMsg": "Đã xảy ra lỗi khi cố gắng cập nhật mẫu email.", + "subject": "Chủ thể", + "title": "Tiêu đề", + "validBodyRequired": "Vui lòng nhập Nội dung cho email", + "validSubjectRequired": "Vui lòng nhập dòng Chủ đề cho email", + "validTitleRequired": "Vui lòng nhập Tiêu đề cho email" + }, + "formsTable": { + "myForms": "biểu mẫu của tôi", + "createNewForm": "Tạo một biểu mẫu mới", + "search": "Tìm kiếm", + "manage": "Quản lý", + "submissions": "đệ trình", + "formTitle": "Tiêu đề mẫu", + "viewForm": "Xem mẫu", + "description": "Sự miêu tả", + "Description": "Sự miêu tả:", + "action": "hành động", + "loadingText": "Tải vui lòng đợi" + }, + "manageLayout": { + "manageForm": "Quản lý biểu mẫu" + }, + "preview": { + "preview": "Xem trước", + "previewToolTip": "Điều này hiển thị bản xem trước của thiết kế và hành vi của phiên bản biểu mẫu khi người gửi của bạn sẽ nhìn thấy nó. Bạn không thể gửi biểu mẫu từ trang này." + }, + "shareForm": { + "shareForm": "chia sẻ biểu mẫu", + "shareLink": "Chia sẻ đường link", + "copyQRCode": "Sao chép liên kết bên dưới hoặc tải xuống mã QR.", + "warningMessage": "Không có phiên bản xuất bản của biểu mẫu tại thời điểm này. Liên kết bên dưới sẽ không thể truy cập được cho đến khi một phiên bản được xuất bản.", + "openThisForm": "Mở biểu mẫu này", + "downloadQRCode": "Tải xuống mã QR", + "close": "Đóng", + "copyURLToClipboard": "Sao chép URL vào khay nhớ tạm" + }, + "manageFormActions": { + "emailManagement": "Quản lý email", + "viewSubmissions": "Xem bài nộp", + "teamManagement": "quản lý nhóm", + "deleteForm": "Xóa biểu mẫu", + "confirmDeletion": "Xác nhận xóa", + "deleteMessageA": "Bạn có chắc chắn muốn xóa", + "deleteMessageB": "Biểu mẫu này sẽ không thể truy cập được nữa.", + "delete": "Xóa bỏ" + }, + "manageForm": { + "formSettings": "Cài đặt biểu mẫu", + "apiKey": "Mã API", + "updated": "cập nhật", + "created": "Tạo", + "formDesignHistory": "Lịch sử thiết kế biểu mẫu", + "totalVersions": "Tổng số phiên bản", + "status": "Trạng thái", + "update": "Cập nhật", + "cancel": "Hủy bỏ", + "eventSubscription": "Đăng ký sự kiện" + }, + "formSettings": { + "pressToAddMultiEmail": "Nhấn enter hoặc , hoặc dấu cách để thêm nhiều địa chỉ email", + "allowMultiDraft": "Cho phép tải lên nhiều bản nháp", + "formTitle": "Tiêu đề mẫu", + "formDescription": "Mô tả biểu mẫu", + "formAccess": "Truy cập biểu mẫu", + "info": "Nếu bạn sẽ sử dụng biểu mẫu này để thu thập thông tin từ công chúng về các chủ đề được công chúng quan tâm, bạn phải liên hệ với GCPE để sự tham gia của bạn có thể được liệt kê trên", + "important": "QUAN TRỌNG", + "idimNotifyA": "Bạn phải thông báo cho nhóm Quản lý thông tin nhận dạng (IDIM) qua email", + "idimNotifyB": "ý định tận dụng BCeID của bạn để xác minh danh tính của những người gửi biểu mẫu của bạn.", + "referenceGuideA": "Vui lòng tham khảo của chúng tôi", + "referenceGuideB": "hướng dẫn sử dụng", + "referenceGuideC": "để biết thêm chi tiết", + "specificTeamMembers": "Thành viên nhóm cụ thể", + "formFunctionality": "Chức năng biểu mẫu", + "formSubmissinScheduleMsg": "Lịch gửi biểu mẫu sẽ có sẵn trong Cài đặt biểu mẫu sau khi biểu mẫu được xuất bản.", + "formSubmissionsSchedule": "Lịch gửi biểu mẫu", + "experimental": "Thực nghiệm", + "learnMore": "Tìm hiểu thêm", + "afterSubmission": "Sau khi gửi", + "submissionConfirmation": "Hiển thị chi tiết xác nhận gửi", + "theConfirmationID": "ID xác nhận", + "infoB": "tùy chọn để người dùng tự gửi email xác nhận gửi", + "loginRequired": "Yêu cầu đăng nhập", + "canSaveAndEditDraftLabel": "Người gửi có thể Lưu và Chỉnh sửa Bản nháp", + "canUpdateStatusAsReviewer": "Người đánh giá có thể Cập nhật Trạng thái của biểu mẫu này (nghĩa là Đã gửi, Đã giao, Đã hoàn thành)", + "submitterCanCopyExistingSubmissn": "Người gửi có thể Sao chép một bài nộp hiện có", + "submissionConfirmationToolTip": "Việc chọn tùy chọn này sẽ kiểm soát những gì người dùng gửi biểu mẫu này sẽ thấy khi gửi thành công.
Nếu được chọn, nó sẽ hiển thị", + "emailNotificatnToTeam": "Gửi cho nhóm của tôi một email thông báo", + "emailNotificatnToTeamToolTip": "Gửi thông báo đến địa chỉ email được chỉ định của bạn khi bất kỳ người dùng nào gửi biểu mẫu này", + "notificationEmailAddrs": "Địa chỉ email thông báo", + "addMoreValidEmailAddrs": "Thêm một hoặc nhiều địa chỉ email hợp lệ", + "formScheduleSettings": "Cài đặt lịch trình biểu mẫu", + "opensubmissions": "mở bài nộp", + "submissionsDeadline": "Bạn muốn nhận bài nộp trong bao lâu?", + "keepSubmissnOpenTilUnplished": "Tiếp tục mở cho đến khi hủy xuất bản theo cách thủ công", + "submissionsClosingDate": "Hẹn ngày kết thúc", + "submissionPeriod": "Thiết lập thời gian gửi", + "closeSubmissions": "Đóng bài nộp", + "keepOpenFor": "Giữ mở cho", + "period": "Giai đoạn", + "allowLateSubmissions": "Cho phép nộp muộn", + "allowLateSubmissionsInfoTip": "Nếu được chọn, người gửi sẽ có thể gửi dữ liệu sau ngày kết thúc.", + "afterCloseDateFor": "Sau ngày đóng cửa cho", + "repeatPeriod": "Thời gian lặp lại", + "every": "Mọi", + "repeatUntil": "Lặp lại cho đến khi", + "summary": "Bản tóm tắt", + "submissionsOpenDateRange": "Biểu mẫu này sẽ được mở để gửi từ", + "to": "ĐẾN", + "scheduleRepetition": "Lịch trình sẽ lặp lại mỗi", + "allowLateSubmissnInterval": "cho phép nộp muộn cho", + "until": "cho đến khi", + "datesOfSubmissnInfo": "Theo các cài đặt, đây là những ngày gửi có sẵn:", + "formOpenInterval": "Biểu mẫu này sẽ được mở để gửi từ", + "allowDateSubmissionDate": "với việc cho phép nộp muộn cho đến khi", + "customClosingMessage": "Đặt thông báo đóng tùy chỉnh", + "customClosingMessageToolTip": "Cho phép bạn thêm thông báo tùy chỉnh cho người dùng của mình khi họ truy cập biểu mẫu đã đóng.", + "closingMessage": "Thông điệp kết thúc", + "sendReminderEmail": "GỬI email nhắc nhở", + "autoReminderNotificatn": "Bật thông báo nhắc nhở tự động", + "autoReminderNotificatnToolTip": "Gửi (các) email nhắc nhở với liên kết biểu mẫu trong thời gian gửi.", + "selectLoginType": "Vui lòng chọn 1 loại đăng nhập", + "formDescriptnMaxChars": "Mô tả biểu mẫu phải từ 255 ký tự trở xuống", + "formTitlemaxChars": "Tiêu đề biểu mẫu phải từ 255 ký tự trở xuống", + "formTitleReq": "Tiêu đề biểu mẫu là bắt buộc", + "atLeastOneEmailReq": "Vui lòng nhập ít nhất 1 địa chỉ email", + "validEmailRequired": "Vui lòng nhập tất cả các địa chỉ email hợp lệ", + "fieldRequired": "Trường này là bắt buộc.", + "correctDateFormat": "Ngày phải ở định dạng chính xác. I E. yyyy-mm-dd", + "dateDiffMsg": "Đóng Ngày gửi phải lớn hơn ngày gửi mở.", + "valueMustBeNumber": "Giá trị phải là một số. I E. 1,2,3,5,99", + "selectAnOptions": "Vui lòng chọn ít nhất 1 tùy chọn", + "validInterval": "Đây phải là một khoảng thời gian hợp lệ.", + "fieldRequiredAndInterval": "Trường này là bắt buộc & phải là một khoảng thời gian.", + "dateGrtOpenSubmissnDate": "Lặp lại cho đến ngày phải lớn hơn ngày gửi mở", + "public": "Công khai (ẩn danh)", + "allowEventSubscription": "Cho phép đăng ký sự kiện", + "eventSubscription": "Đăng ký sự kiện", + "validEndpointRequired": "Vui lòng nhập một điểm cuối hợp lệ bắt đầu bằng https://", + "validBearerTokenRequired": "Nhập ví dụ về mã thông báo mang hợp lệ: 89abddfb-2cff-4fda-83e6-13221f0c3d4f" + }, + "subscribeEvent": { + "eventType": "Loại sự kiện", + "endpointUrl": "URL điểm cuối", + "eventSubmission": "Nộp hồ sơ", + "eventAssignment": "Phân công", + "eventStatusChange": "Thay đổi trạng thái", + "endpointToken": "Mã thông báo điểm cuối", + "urlPlaceholder": "https://endpoint.gov.bc.ca/api/v1/", + "save": "Cứu", + "text": "chữ", + "password": "mật khẩu", + "hideSecret": "Ẩn bí mật", + "showSecret": "Hiển thị bí mật", + "key": "Chìa khóa", + "saveSettingsErrMsg": "Đã xảy ra lỗi khi cố cập nhật cài đặt cho biểu mẫu này.", + "updateSettingsConsoleErrMsg": "Lỗi khi cập nhật cài đặt cho biểu mẫu {formId}: {error}" + }, + "apiKey": { + "disclaimer": "từ chối trách nhiệm", + "infoA": "Đảm bảo rằng khóa bí mật API của bạn được lưu trữ ở một vị trí an toàn (tức là kho khóa).", + "infoB": "Khóa API của bạn cấp quyền truy cập không hạn chế vào biểu mẫu của bạn. Không cung cấp khóa API của bạn cho bất kỳ ai.", + "infoC": "Khóa API CHỈ nên được sử dụng cho các tương tác hệ thống tự động. Không sử dụng khóa API của bạn để truy cập dựa trên người dùng", + "deleteKey": "Phím xoá", + "apiKey": "Mã API", + "hideSecret": "Ẩn bí mật", + "showSecret": "Hiển thị bí mật", + "sCTC": "Đã sao chép bí mật vào khay nhớ tạm", + "cSTC": "Sao chép bí mật vào khay nhớ tạm", + "key": "Chìa khóa", + "confirmDeletion": "Xác nhận xóa", + "deleteMsg": "Bạn có chắc chắn muốn xóa Khóa API của mình không?", + "delete": "Xóa bỏ", + "confirmKeyGen": "Xác nhận tạo khóa", + "createAPIKey": "Tạo Khóa API cho biểu mẫu này?
Đảm bảo bạn tuân theo Tuyên bố miễn trừ trách nhiệm trên trang này.", + "regenerateAPIKey": "Tạo lại khóa API?
Việc tiếp tục sẽ xóa quyền truy cập Khóa API hiện tại của bạn .", + "formOwnerKeyAcess": "Bạn phải là Chủ sở hữu biểu mẫu để quản lý Khóa API.", + "regenerate": "tái tạo", + "generate": "Phát ra", + "secret": "Bí mật" + }, + "manageVersions": { + "important": "QUAN TRỌNG!", + "infoA": "Nếu không có phiên bản đã xuất bản nào, người dùng không thể truy cập biểu mẫu này cho đến khi có một phiên bản đã xuất bản được chỉ định. Sau khi một phiên bản được xuất bản, phiên bản đó không thể chỉnh sửa được nữa. Bạn phải tạo một phiên bản mới dựa trên một trong các phiên bản biểu mẫu trước đó để tiếp tục chỉnh sửa.", + "infoB": "Lưu ý: Chỉ có một phiên bản có thể được xuất bản.", + "version": "Phiên bản", + "draft": "Bản nháp", + "clickToPreview": "Nhấp để xem trước", + "editVersion": "Chỉnh sửa phiên bản", + "exportDesign": "Thiết kế xuất khẩu", + "infoC": "Vui lòng xuất bản hoặc xóa phiên bản nháp mới nhất của bạn trước khi bắt đầu phiên bản mới.", + "deleteVersion": "Xóa phiên bản", + "draftAlreadyExists": "Bản nháp đã tồn tại", + "infoD": "Vui lòng chỉnh sửa, xuất bản hoặc xóa bản nháp hiện có trước khi bắt đầu một bản nháp mới.", + "publishVersion": "Xuất bản phiên bản", + "unpublishVersion": "Phiên bản hủy xuất bản", + "infoE": "Hủy xuất bản biểu mẫu này sẽ khiến biểu mẫu không được lưu hành cho đến khi một phiên bản được xuất bản lại.", + "confirmDeletion": "Xác nhận xóa", + "infoF": "Bạn có chắc chắn muốn xóa Phiên bản này không?", + "delete": "Xóa bỏ", + "status": "Trạng thái", + "dateCreated": "Ngày tạo", + "createdBy": "Được tạo bởi", + "actions": "hành động", + "published": "Được phát hành", + "unpublished": "chưa xuất bản", + "useVersionInfo": "Sử dụng phiên bản {version} làm cơ sở cho phiên bản mới", + "publishingVersionInfo": "Điều này sẽ làm cho Phiên bản {version} của biểu mẫu của bạn hoạt động." + }, + "addOwner": { + "infoA": "Điều này chỉ nên được thực hiện trong trường hợp chủ sở hữu biểu mẫu hiện tại không còn hoạt động hoặc không liên lạc được trong một sự kiện ưu tiên. Nếu không, hãy yêu cầu Chủ sở hữu hiện tại hoặc Quản trị viên nhóm của biểu mẫu tự thực hiện việc này.", + "hint": "Để tìm ID người dùng cần thiết, bạn có thể chuyển đến tab 'NGƯỜI DÙNG' trong cổng Quản trị và tìm kiếm chúng.", + "addowner": "thêm chủ sở hữu", + "label": "ID người dùng (hướng dẫn)" + }, + "adminFormsTable": { + "showDeletedForms": "Hiển thị biểu mẫu đã xóa", + "search": "Tìm kiếm", + "loadingText": "đang tải văn bản", + "noDataText": "Không có biểu mẫu nào trong hệ thống của bạn", + "admin": "Quản trị viên", + "launch": "Phóng", + "formTitle": "Tiêu đề mẫu", + "created": "Tạo", + "deleted": "Đã xóa", + "actions": "hành động", + "delete": "Xóa bỏ" + }, + "administerForm": { + "deleted": "ĐÃ XÓA", + "restoreForm": "Khôi phục biểu mẫu này", + "formDetails": "Chi tiết biểu mẫu", + "apiKeyDetails": "Chi tiết khóa API", + "deleteApiKey": "Xóa khóa API", + "formUsers": "Người dùng biểu mẫu", + "formVersions": "Phiên bản biểu mẫu", + "assignANewOwner": "Chỉ định chủ sở hữu mới", + "restoring": "phục hồi", + "restore": "Khôi phục", + "toActiveState": "sang trạng thái hoạt động", + "confirmDeletion": "Xác nhận xóa", + "confirmDeletionMsg": "Bạn có chắc chắn muốn xóa Khóa API này không?", + "delete": "Xóa bỏ", + "confirmRestore": "Xác nhận khôi phục" + }, + "administerUser": { + "userDetails": "Chi tiết người dùng", + "openSSOConsole": "Mở bảng điều khiển SSO" + }, + "adminPage": { + "forms": "Các hình thức", + "users": "người dùng", + "developer": "nhà phát triển", + "infoLinks": "Liên kết thông tin", + "metrics": "số liệu" + }, + "adminUsersTable": { + "search": "Tìm kiếm", + "loadingText": "Tải vui lòng đợi", + "admin": "Quản trị viên", + "fullName": "Họ và tên", + "userID": "Tên người dùng", + "created": "Tạo", + "actions": "hành động" + }, + "adminVersions": { + "exportDesign": "Thiết kế xuất khẩu", + "versions": "phiên bản", + "status": "Trạng thái", + "created": "Tạo", + "lastUpdated": "Cập nhật mới nhất", + "actions": "hành động", + "published": "Được phát hành", + "unpublished": "chưa xuất bản", + "version": "Phiên bản {versionNo}", + "notificationMsg": "Đã xảy ra lỗi khi tải thiết kế biểu mẫu." + }, + "developer": { + "user": "Người dùng", + "name": "Tên", + "userName": "Tên tài khoản", + "JWTContents": "Nội dung JWT", + "JWTContentsSBTxt": "Nội dung JWT được sao chép vào khay nhớ tạm", + "JWTContentsTTTxt": "Sao chép nội dung JWT vào khay nhớ tạm", + "JWTToken": "Mã thông báo JWT", + "JWTTokenSBTxt": "Mã thông báo JWT được sao chép vào khay nhớ tạm", + "JWTTokenTTTxt": "Sao chép Mã thông báo JWT vào khay nhớ tạm", + "chefsAPI": "API đầu bếp", + "RBACSBTxt": "Phản hồi RBAC được sao chép vào khay nhớ tạm", + "RBACTTTxt": "Sao chép Phản hồi RBAC vào khay nhớ tạm", + "notificationMsg": "Không lấy được người dùng từ RBAC, xem bảng điều khiển", + "notificationConsErr": "Lỗi khi nhận Người dùng từ RBAC" + }, + "baseAuthButton": { + "logout": "Đăng xuất", + "login": "Đăng nhập" + }, + "baseDialog": { + "defaultText": "văn bản mặc định", + "ok": "ĐƯỢC RỒI", + "continue": "Tiếp tục", + "cancel": "Hủy bỏ", + "custom": "Phong tục" + }, + "baseSecure": { + "about": "Về", + "loginInfo": "Bạn phải đăng nhập để sử dụng tính năng này.", + "login": "Đăng nhập", + "401NotAuthorized": "401: không được ủy quyền. :", + "401ErrorMsg": "Tài khoản của bạn không được thiết lập chính xác.
Vui lòng liên hệ", + "403Forbidden": "403: Cấm. :", + "403ErrorMsg": "Trang này yêu cầu xác thực {idp}.", + "401UnAuthorized": "401: Trái phép. :", + "401UnAuthorizedErrMsg": "Bạn không có quyền truy cập trang này." + }, + "formDesigner": { + "formDesign": "thiết kế biểu mẫu", + "exportDesign": "Thiết kế xuất khẩu", + "importDesign": "Thiết kế nhập khẩu", + "important": "QUAN TRỌNG", + "formDesignInfoA": "Sử dụng nút LƯU THIẾT KẾ khi bạn hoàn thành việc xây dựng biểu mẫu này.", + "formDesignInfoB": "Nút GỬI được cung cấp để người dùng của bạn gửi biểu mẫu này và sẽ được kích hoạt sau khi được lưu.", + "formLoadErrMsg": "Đã xảy ra lỗi khi tải thiết kế biểu mẫu.", + "formLoadConsoleErrMsg": "Lỗi khi tải lược đồ biểu mẫu {formId} (phiên bản: {versionId} bản nháp: {draftId}): {error}", + "formSchemaImportErrMsg": "Đã xảy ra lỗi khi nhập lược đồ biểu mẫu.", + "formSchemaImportConsoleErrMsg": "Lỗi khi nhập giản đồ biểu mẫu : {error}", + "formDesignSaveErrMsg": "Đã xảy ra lỗi khi cố gắng lưu thiết kế biểu mẫu này. Nếu bạn cần làm mới hoặc để lại để thử lại sau, bạn có thể Xuất thiết kế hiện có trên trang để lưu lại sau này.", + "formDesignSaveConsoleErrMsg": "Lỗi khi cập nhật hoặc tạo biểu mẫu (FormID: {formId}, versionId: {versionId}, draftId: {draftId}) Lỗi: {error}", + "collapse": "Sụp đổ", + "actions": "hành động", + "version": "Phiên bản", + "save": "Cứu", + "saving": "Tiết kiệm", + "notSaved": "Chưa được lưu", + "fieldnameError": "Bạn KHÔNG THỂ sử dụng từ khóa `form` làm tên trường {label}" + }, + "formViewerMultiUpload": { + "important": "QUAN TRỌNG", + "uploadSucessMsg": "Để đảm bảo tải lên thành công nhiều bản nháp, vui lòng tải xuống và sử dụng mẫu được cung cấp.", + "confirmDownload": "Bạn có muốn tải xuống không?", + "jsonFileUpload": "Chọn tệp JSON để tải lên", + "dragNDrop": "hoặc kéo thả vào đây", + "chooseAFile": "Chọn một tệp", + "downloadDraftSubmns": "Vui lòng tải xuống báo cáo đệ trình dự thảo và đảm bảo rằng dữ liệu được nhập chính xác.", + "downloadReport": "Tải xuống báo cáo", + "doYouWantToDownload": "Bạn có muốn tải xuống không?", + "uploadNewFile": "Tải lên tệp mới", + "uploadMultipleFileErr": "Xin lỗi, bạn chỉ có thể tải lên một tệp", + "dragMultipleFileErr": "Rất tiếc, bạn chỉ có thể kéo một tệp", + "fileFormatErr": "Xin lỗi, chúng tôi chỉ chấp nhận các tệp json", + "fileSizeErr": "Kích thước tệp tối đa cho phép là 5MB", + "parseJsonErr": "Chúng tôi không thể phân tích cú pháp dữ liệu json từ tệp", + "jsonObjNotArray": "Định dạng tệp json sai", + "jsonObjNotArrayConsErr": "Đã xảy ra lỗi không mong muốn.", + "jsonArrayEmpty": "Tệp json này trống.", + "errorWhileValidate": "Có gì đó sai với tập tin này", + "errWhileCheckValidity": "Có gì đó không ổn với tập tin này", + "errAfterValidate": "Đã tìm thấy một số lỗi, xem bên dưới để biết thêm thông tin.", + "fileIsEmpty": "tập tin này là trống rỗng.", + "download": "Tải xuống" + }, + "formDisclaimer": { + "disclaimerAndStatement": "Tuyên bố từ chối trách nhiệm và tuyên bố trách nhiệm đối với Người thiết kế biểu mẫu:", + "privacyLaw": "Bạn có trách nhiệm tuân thủ các luật về Quyền riêng tư điều chỉnh việc thu thập, sử dụng và tiết lộ thông tin nhận dạng cá nhân.", + "disclosure": "Quyền truy cập vào công cụ thiết kế biểu mẫu này vốn không cấp quyền thu thập, sử dụng hoặc tiết lộ bất kỳ thông tin nhận dạng cá nhân nào.", + "consent": "Bạn có trách nhiệm phải có được sự đồng ý để thu thập thông tin theo yêu cầu của pháp luật.", + "formIntention": "Trước khi xuất bản hoặc phân phối biểu mẫu của bạn, bạn được yêu cầu thảo luận về mục đích của biểu mẫu với", + "privacyOfficer": "Cán bộ Bảo mật của Bộ", + "assement": "và hoàn thành các đánh giá theo yêu cầu." + }, + "requestReceipt": { + "emailPriority": "Ưu tiên email", + "emailReceipt": "Gửi email biên nhận của bài nộp này", + "high": "Cao", + "low": "Thấp", + "normal": "Bình thường", + "send": "GỬI", + "sendToEmailAddress": "Gửi đến địa chỉ email", + "emailSent": "Một email đã được gửi tới {to}.", + "sendingEmailErrMsg": "Đã xảy ra lỗi khi cố gắng gửi email của bạn.", + "sendingEmailConsErrMsg": "Xác nhận email tới {to} không thành công: {error}", + "emailRequired": "Email thì cần thiết" + }, + "submissionsTable": { + "noMatchingRecordText": "Không tìm thấy kết quả", + "submissions": "đệ trình", + "submissionsTable": "Đệ trìnhBảng", + "selectColumns": "Chọn cột", + "manageForm": "Quản lý biểu mẫu", + "submissionsToFiles": "Xuất bài nộp vào tệp", + "showDeletedSubmissions": "Hiển thị các bài gửi đã xóa", + "showMySubmissions": "Hiển thị nội dung gửi của tôi", + "search": "Tìm kiếm", + "loadingText": "Tải vui lòng đợi", + "noDataText": "Không có đệ trình cho hình thức này", + "delSelectedSubmissions": "Xóa bài đã chọn", + "resSelectedSubmissions": "Khôi phục các bài nộp đã chọn", + "yes": "ĐÚNG", + "no": "KHÔNG", + "viewSubmission": "Xem bài nộp", + "deleteSubmission": "Xóa bài gửi", + "restore": "Khôi phục", + "confirmDeletion": "Xác nhận xóa", + "delete": "Xóa bỏ", + "confirmRestoration": "Xác nhận khôi phục", + "searchSubmissionFields": "Tìm kiếm các trường gửi", + "save": "Cứu", + "searchTitle": "Tìm kiếm và chọn các cột để hiển thị dưới trang tổng quan của bạn", + "status": "Trạng thái", + "submitter": "người gửi", + "submissionDate": "Ngày nộp hồ sơ", + "event": "sự kiện", + "view": "Xem", + "lateSubmission": "Hồ sơ nộp muộn", + "confirmationID": "ID xác nhận", + "multiDelWarning": "Bạn có chắc chắn muốn xóa các bài gửi đã chọn không?", + "singleDelWarning": "Bạn có chắc chắn muốn xóa nội dung gửi này không?", + "multiRestoreWarning": "Bạn có chắc chắn muốn khôi phục các nội dung gửi này không?", + "singleRestoreWarning": "Bạn có chắc chắn muốn khôi phục nội dung gửi này không?" + }, + "auditHistory": { + "viewEditHistory": "Xem lịch sử chỉnh sửa", + "editHistory": "Chỉnh sửa lịch sử", + "auditLogMsg": "Đây là nhật ký kiểm tra của người đã thực hiện các thay đổi đối với nội dung gửi này sau lần gửi ban đầu.", + "loadingText": "Tải vui lòng đợi", + "close": "Đóng", + "userName": "Tên tài khoản", + "date": "Ngày", + "errorMsg": "Đã xảy ra lỗi khi cố gắng tìm nạp lịch sử.", + "consoleErrMsg": "Lỗi khi nhận lịch sử kiểm tra cho" + }, + "deleteSubmission": { + "deleteThis": "Xóa cái này", + "draft": "Bản nháp", + "submission": "Nộp hồ sơ", + "confirmDeletion": "Xác nhận xóa", + "deleteWarning": "Bạn có chắc chắn muốn xóa cái này", + "drafts": "bản nháp", + "formSubmission": "Nộp mẫu", + "delete": "Xóa bỏ" + }, + "manageSubmissionUsers": { + "manageTeamMembers": "Quản lý thành viên nhóm", + "add": "Thêm vào", + "draftFormInvite": "Bạn chỉ có thể mời và quản lý các thành viên trong nhóm khi biểu mẫu này là bản nháp", + "submissionTeamMembers": "Các thành viên trong nhóm cho bài nộp này", + "actions": "hành động", + "close": "Đóng", + "remove": "Di dời", + "userNotFoundErrMsg": "Không thể tìm thấy một người nào đó? Họ có thể chưa đăng nhập vào CHEFS.
Vui lòng gửi cho họ một liên kết đến CHEFS và yêu cầu họ đăng nhập.", + "name": "Tên", + "username": "tên tài khoản", + "email": "E-mail", + "removeUserWarningMsg1": "Bạn có chắc chắn muốn xóa", + "removeUserWarningMsg2": "Họ sẽ không còn quyền đối với nội dung gửi này.", + "userExistInListMsg": "Người dùng {username} đã có trong danh sách thành viên nhóm.", + "getSubmissionUsersErr": "Đã xảy ra lỗi khi cố gắng tìm nạp người dùng cho nội dung gửi này.", + "getSubmissionUsersConsoleErr": "Lỗi nhận người dùng cho {submissionId} : {error}", + "sentInviteEmailTo": "Đã gửi email mời đến", + "sentUninvitedEmailTo": "Đã gửi email không mời đến", + "updateUserErrMsg": "Đã xảy ra lỗi khi cố gắng cập nhật người dùng cho lần gửi này.", + "updateUserConsoleErrMsg": "Lỗi đặt quyền của người dùng. Phụ: {submissionId} Người dùng: {userId} Lỗi: {error}", + "searchInputLength": "Đầu vào tìm kiếm cho tên người dùng/email BCeID phải lớn hơn 6 ký tự.", + "exactBCEIDSearch": "Tìm kiếm email cho BCeID phải chính xác.", + "getUsersErrMsg": "Lỗi nhận người dùng: {error}", + "exactEmailOrUsername": "Nhập một e-mail hoặc tên người dùng chính xác.", + "requiredFiled": "Nhập tên, e-mail hoặc tên người dùng" + }, + "mySubmissionsActions": { + "viewThisSubmission": "Xem bài nộp này", + "copyThisSubmission": "Sao chép bài nộp này", + "editThisDraft": "Chỉnh sửa bản nháp này" + }, + "mySubmissionsTable": { + "noMatchingRecordText": "Không tìm thấy kết quả", + "previousSubmissions": "Đệ trình trước", + "selectColumns": "Chọn cột", + "createNewSubmission": "Tạo bài nộp mới", + "search": "Tìm kiếm", + "loadingText": "Tải vui lòng đợi", + "noDataText": "Bạn không có bài nộp nào", + "searchSubmissionFields": "Tìm kiếm các trường gửi", + "save": "Cứu", + "filterTitle": "Tìm kiếm và chọn các cột để hiển thị dưới trang tổng quan của bạn", + "confirmationId": "ID xác nhận", + "actions": "hành động", + "createdBy": "Được tạo bởi", + "statusUpdatedBy": "Trạng thái được cập nhật bởi", + "status": "Trạng thái", + "submissionDate": "Ngày nộp hồ sơ", + "draftUpdatedBy": "Dự thảo được cập nhật bởi", + "draftLastEdited": "Bản nháp được chỉnh sửa lần cuối", + "createLateSubmissn": "Tạo bài nộp muộn", + "formLoading": "Vui lòng đợi trong khi biểu mẫu đang tải!!!", + "pleaseConfirm": "Vui lòng xác nhận", + "wantToSaveDraft": "Bạn có muốn lưu bản nháp không?", + "yes": "Đúng", + "no": "KHÔNG", + "multiDraftUploadSuccess": "Tải lên nhiều bản nháp của bạn đã thành công!", + "failedResSubmissn": "Phản hồi không thành công từ điểm cuối gửi. Mã phản hồi: {status}", + "errSubmittingForm": "Đã xảy ra lỗi khi gửi biểu mẫu này", + "errorSavingFile": "Lỗi khi lưu tệp. Tên tệp: {fileName}. Lỗi: {error}", + "submittingDraftErrMsg": "Đã xảy ra lỗi khi lưu bản nháp", + "submittingDraftConsErrMsg": "Lỗi khi lưu bản nháp. Đệ trìnhId: {submissionId}. Lỗi: {error}" + }, + "notesPanel": { + "addNewNote": "Thêm ghi chú mới", + "cancel": "Hủy bỏ", + "addNote": "THÊM GHI CHÚ", + "noResponseErr": "Không có dữ liệu phản hồi từ API trong khi gửi biểu mẫu", + "errorMesg": "Đã xảy ra lỗi khi cố gắng thêm ghi chú.", + "consoleErrMsg": "Lỗi khi thêm ghi chú:", + "fetchErrMsg": "Đã xảy ra lỗi khi cố gắng tìm nạp ghi chú cho nội dung gửi này.", + "fetchConsoleErrMsg": "Lỗi khi thêm ghi chú:", + "notes": "ghi chú", + "note": "Ghi chú", + "maxChars": "Tối đa 4000 ký tự" + }, + "statusPanel": { + "currentStatus": "Tình trạng hiện tại:", + "assignedTo": "Phân công:", + "assignOrUpdateStatus": "Chỉ định hoặc cập nhật trạng thái", + "display": "trưng bày", + "statusIsRequired": "Trạng thái là bắt buộc", + "assignTo": "Giao cho", + "noDataText": "Không tìm thấy Người đánh giá biểu mẫu nào với tìm kiếm. Thêm Người đánh giá biểu mẫu trên trang Quản lý.", + "assigneeIsRequired": "Người được ủy quyền là bắt buộc", + "assignToMe": "GIAO CHO TÔI", + "recipientEmail": "Người nhận E-mail", + "attachCommentToEmail": "Đính kèm Nhận xét vào Email", + "emailComment": "Nhận xét email", + "maxChars": "Tối đa 4000 ký tự", + "viewHistory": "XEM LỊCH SỬ", + "statusHistory": "Lịch sử trạng thái", + "close": "ĐÓNG", + "addNoteNoReponserErr": "Không có dữ liệu phản hồi từ API trong khi gửi ghi chú để cập nhật trạng thái", + "addNoteConsoleErrMsg": "Lỗi khi cập nhật trạng thái: {error}", + "addNoteErrMsg": "Đã xảy ra lỗi khi cố gắng cập nhật trạng thái", + "updtSubmissionsStatusErr": "Không có dữ liệu phản hồi từ API trong khi gửi biểu mẫu cập nhật trạng thái", + "noStatus": "không có trạng thái", + "noStatusesFound": "Không tìm thấy trạng thái nào", + "statusCodesErr": "lỗi tìm mã trạng thái", + "notifyErrorCode": "Đã xảy ra lỗi khi tìm nạp trạng thái cho nội dung gửi này.", + "notifyConsoleErrorCode": "Lỗi nhận trạng thái:", + "fetchSubmissionUsersErr": "Đã xảy ra lỗi khi cố gắng tìm nạp email của người nhận cho nội dung gửi này.", + "fetchSubmissionUsersConsErr": "Lỗi nhận email người nhận cho", + "assignSubmissnToFormReviewer": "Nội dung gửi có thể được chỉ định cho Người đánh giá biểu mẫu.
Để thêm nhiều thành viên nhóm làm Người đánh giá biểu mẫu, hãy chuyển đến trang Quản lý cho biểu mẫu này.", + "update": "CẬP NHẬT", + "revise": "ÔN LẠI", + "complete": "HOÀN THÀNH", + "assign": "GIAO PHÓ" + }, + "statusTable": { + "loadingText": "Tải vui lòng đợi", + "status": "Trạng thái", + "dateStatusChanged": "Tình trạng ngày đã thay đổi", + "assignee": "người được giao", + "updatedBy": "Cập nhật", + "getSubmissionStatusErr": "Đã xảy ra lỗi khi cố gắng tìm nạp trạng thái.", + "getSubmissionStatusConsErr": "Lỗi khi thêm ghi chú:" + }, + "exportSubmissions": { + "exportSubmissionsToFile": "Xuất bài nộp vào tệp", + "viewSubmissions": "Xem bài nộp", + "fileType": "Loại tệp", + "json": "JSON", + "csv": "CSV", + "formVersion": "Phiên bản mẫu", + "versionIsRequired": "Phiên bản là bắt buộc.", + "dataFields": "Trường dữ liệu", + "searchFields": "Trường tìm kiếm", + "selectedForExports": "tuyển chọn để xuất khẩu", + "submissionDate": "Ngày nộp hồ sơ", + "all": "Tất cả", + "selectDateRange": "Chọn Phạm vi ngày", + "SelectdateRange": "Chọn phạm vi ngày", + "from": "Từ", + "to": "ĐẾN", + "CSVFormat": "Định dạng CSV", + "multiRowPerSubmissionA": "1 - Nhiều hàng trên mỗi lần gửi có khoảng cách thụt đầu dòng", + "multiRowPerSubmissionB": "2 - Nhiều hàng cho mỗi lần gửi", + "singleRowPerSubmission": "3 - Một hàng cho mỗi lần gửi", + "unformatted": "4 - Chưa định dạng", + "fileNameAndType": "Tên và loại tệp", + "export": "Xuất khẩu", + "noResponseDataErr": "Không có dữ liệu phản hồi từ lệnh gọi exportSubmissions", + "apiCallErrorMsg": "Đã xảy ra lỗi khi cố gắng xuất nội dung gửi cho biểu mẫu này.", + "apiCallConsErrorMsg": "Lỗi khi xuất nội dung gửi cho", + "selectAllFields": "Chọn tất cả các lĩnh vực", + "emailSentMsg": "Một email sẽ được gửi tới {email} có chứa liên kết để tải xuống dữ liệu của bạn khi sẵn sàng", + "exportInProgress": "Đang xuất", + "of": "của" + }, + "printOptions": { + "submitButtonTxt": "Gửi tới CDOGS và tải xuống", + "templatePrint": "In mẫu", + "uploadTemplateFile": "Tải lên tệp mẫu", + "downloadOptions": "Tùy chọn tải xuống", + "print": "In", + "browserPrint": "In trình duyệt", + "pageFromBrowser": "trang từ trình duyệt của bạn", + "uploadA": "Tải lên một", + "uploadB": "để có một phiên bản có cấu trúc", + "docGrnSucess": "Tài liệu được tạo thành công", + "failedDocGenErrMsg": "Không thể tạo tài liệu", + "failedDocGenConsErrMsg": "Lỗi khi gửi mẫu: {error}", + "cDogsTemplate": "mẫu CDOGS" + }, + "proactiveHelpDialog": { + "componentInfoLink": "Liên kết thông tin thành phần", + "learnMoreLinkTxt": "Tìm hiểu thêm Trường liên kết không được để trống.", + "largeImgTxt": "Hình ảnh lớn. Kích thước hình ảnh không được lớn hơn .5mb", + "componentName": "Tên thành phần:", + "learnMoreLink": "Tìm hiểu thêm Liên kết:", + "clickToEnableLink": "Nhấp để bật liên kết", + "clickToDisableLink": "Nhấp để vô hiệu hóa liên kết", + "imageUpload": "Tải lên hình ảnh:", + "cancel": "Hủy bỏ", + "save": "Cứu", + "description": "Sự miêu tả" + }, + "proactiveHelpPreviewDialog": { + "learnMore": "Tìm hiểu thêm" + }, + "preview": { + "preview": "Xem trước", + "previewToolTip": "Điều này hiển thị bản xem trước của thiết kế và hành vi của phiên bản biểu mẫu khi người gửi của bạn sẽ nhìn thấy nó. Bạn không thể gửi biểu mẫu từ trang này." + }, + "generalLayout": { + "loadingText": "Tải vui lòng đợi", + "preview": "XEM TRƯỚC", + "published": "ĐƯỢC PHÁT HÀNH", + "unpublished": "CHƯA XUẤT BẢN", + "edit": "BIÊN TẬP", + "formTitle": "Tiêu đề mẫu", + "actions": "hành động" + }, + "formSubmission": { + "editThisSubmission": "Chỉnh sửa bài nộp này", + "submission": "Nộp hồ sơ", + "alertInfo": "Sau khi chỉnh sửa, hãy gửi lại biểu mẫu để lưu các thay đổi của bạn.", + "viewAllSubmissions": "Xem tất cả bài dự thi", + "submitted": "Đã gửi:", + "confirmationID": "ID xác nhận:", + "submittedBy": "Gửi bởi:", + "cancel": "HỦY BỎ", + "status": "Trạng thái", + "updatedAt": "đã sửa đổi", + "updatedBy": "sửa đổi bởi" + }, + "teamManagement": { + "noMatchingRecordText": "Không tìm thấy kết quả", + "teamManagement": "quản lý nhóm", + "selectColumns": "Chọn cột", + "manageForm": "Quản lý biểu mẫu", + "search": "Tìm kiếm", + "loadingText": "Tải vui lòng đợi", + "noDataText": "Không thể tải dữ liệu vai trò nhóm", + "removeSelectedUsers": "Xóa người dùng đã chọn", + "removeThisUser": "Xóa người dùng này", + "confirmRemoval": "Xác nhận xóa", + "remove": "Di dời", + "searchTeamManagementFields": "Tìm kiếm lĩnh vực quản lý nhóm", + "save": "Cứu", + "teamMebersTitle": "Tìm kiếm và chọn các cột để hiển thị dưới trang tổng quan của bạn", + "fullName": "Họ và tên", + "username": "tên tài khoản", + "identityProvider": "Nhà cung cấp danh tính", + "delSelectedMembersWarning": "Bạn có chắc chắn muốn xóa các thành viên đã chọn không?", + "delSelectedMemberWarning": "Bạn có chắc chắn muốn xóa thành viên đã chọn không?", + "idpMessage": "đã ở trong đội.", + "formOwnerErrMsg": "Phải luôn có ít nhất một chủ sở hữu biểu mẫu", + "formOwnerConsoleErrMsg": "Không thể xóa {userId} vì họ là chủ sở hữu duy nhất còn lại của biểu mẫu này.", + "insufficientPermissnMsg": "Không đủ quyền để quản lý nhóm", + "getUserErrMsg": "Lỗi nhận người dùng biểu mẫu:", + "getRolesErrMsg": "Lỗi khi nhận danh sách vai trò:", + "formOwnerRemovalWarning": "Không thể xóa vì họ là chủ sở hữu duy nhất còn lại của biểu mẫu này.", + "removeUsersErrMsg": "Đã xảy ra lỗi khi cố xóa người dùng đã chọn", + "removeUserConsoleErrMsg": "Lỗi khi xóa người dùng khỏi biểu mẫu {formId}: {error}", + "updUserRolesErrMsg": "Đã xảy ra lỗi khi cố cập nhật tất cả các vai trò của người dùng", + "updUserRolesConsoleErrMsg": "Lỗi khi đặt tất cả vai trò người dùng cho biểu mẫu {formId}: {error}", + "setUserFormsErrMsg": "Đã xảy ra lỗi khi cố cập nhật vai trò cho người dùng", + "setUserFormsConsoleErrMsg": "Lỗi khi đặt vai trò người dùng cho biểu mẫu {formId}: {error}" + }, + "floatButton": { + "publish": "Công bố", + "manage": "Quản lý", + "redo": "làm lại", + "undo": "Hoàn tác", + "preview": "Xem trước", + "bottom": "Đáy", + "top": "Đứng đầu", + "actions": "hành động", + "collapse": "Sụp đổ", + "saved": "Đã lưu", + "save": "Cứu", + "saving": "Tiết kiệm", + "notSaved": "Chưa được lưu" + }, + "formViewer": { + "lateFormSubmissions": "Thời gian gửi biểu mẫu đã hết hạn! Bạn vẫn có thể tạo một bài nộp muộn bằng cách nhấp vào nút bên dưới.", + "createLateSubmission": "Tạo bài nộp muộn", + "draftSaved": "Bản nháp đã được lưu", + "saving": "Tiết kiệm", + "pleaseConfirm": "Vui lòng xác nhận", + "submitFormWarningMsg": "Bạn có chắc chắn muốn gửi biểu mẫu của mình không?", + "submit": "Nộp", + "wantToSaveDraft": "Bạn có muốn lưu bản nháp không?", + "version": "Phiên bản: {version}", + "formScheduleExpireMessage": "Gửi biểu mẫu không khả dụng vì thời gian gửi theo lịch trình đã hết hạn.", + "getUsersSubmissionsErrMsg": "Đã xảy ra lỗi khi tìm nạp nội dung gửi cho biểu mẫu này", + "getUsersSubmissionsConsoleErrMsg": "Lỗi khi tải dữ liệu gửi biểu mẫu {submissionId}: {error}", + "multiDraftUploadSuccess": "Tải lên nhiều bản nháp của bạn đã thành công!", + "readVersionErrMsg": "Không có lược đồ trong phản hồi. VersionId: {versionId}", + "readDraftErrMsg": "Không có lược đồ trong phản hồi. draftId: {draftId}", + "alertRouteMsg": "Chủ sở hữu biểu mẫu chưa xuất bản biểu mẫu và biểu mẫu không có sẵn để gửi.", + "fecthingFormErrMsg": "Đã xảy ra lỗi khi tìm nạp biểu mẫu này", + "fecthingFormConsoleErrMsg": "Lỗi khi tải lược đồ biểu mẫu {versionId}: {error}", + "savingDraftErrMsg": "Đã xảy ra lỗi khi lưu bản nháp", + "savingDraftConsoleErrMsg": "Lỗi khi lưu bản nháp. Đệ trìnhId: {submissionId}. Lỗi: {error}", + "submissionsPreviewAlert": "Đệ trình bị vô hiệu hóa trong khi xem trước biểu mẫu", + "submissionsSubmitErrMsg": "Lỗi khi gửi biểu mẫu: {errors}", + "sendSubmissionErrMsg": "Phản hồi không thành công từ điểm cuối gửi. Mã phản hồi: {status}", + "errMsg": "Đã xảy ra lỗi khi gửi biểu mẫu này", + "customEventAlert": "Sự kiện nút tùy chỉnh chưa được hỗ trợ. Loại sự kiện: {event}", + "formLoading": "Vui lòng đợi trong khi biểu mẫu đang tải!!!", + "yes": "Đúng", + "no": "KHÔNG", + "failedResSubmissn": "Phản hồi không thành công từ điểm cuối gửi. Mã phản hồi: {status}", + "errSubmittingForm": "Đã xảy ra lỗi khi gửi biểu mẫu này", + "errorSavingFile": "Lỗi khi lưu tệp. Tên tệp: {fileName}. Lỗi: {error}", + "submittingDraftErrMsg": "Đã xảy ra lỗi khi lưu bản nháp", + "submittingDraftConsErrMsg": "Lỗi khi lưu bản nháp. Đệ trìnhId: {submissionId}. Lỗi: {error}", + "formDraftAccessErrMsg": "Yêu cầu gửi đã được gửi, chuyển hướng đến Xem trang" + }, + "bCGovFooter": { + "home": "Trang chủ", + "about": "Về gov.bc.ca", + "disclaimer": "từ chối trách nhiệm", + "privacy": "Sự riêng tư", + "accessibility": "khả năng tiếp cận", + "copyRight": "bản quyền", + "contactUs": "Liên hệ chúng tôi" + }, + "bCGovNavBar": { + "about": "Về", + "myForms": "biểu mẫu của tôi", + "createNewForm": "Tạo một biểu mẫu mới", + "help": "Giúp đỡ", + "feedback": "Nhận xét", + "admin": "Quản trị viên" + }, + "homePage": { + "title": "Tạo, xuất bản biểu mẫu và nhận nội dung gửi bằng Common Hosted Forms Service.", + "subTitle": "Tất cả B.C. Nhân viên chính phủ hoặc nhà thầu có tài khoản IDIR có thể sử dụng phiên bản được lưu trữ của Common Hosted Form Service (CHEFS) của chúng tôi để tạo biểu mẫu.", + "takeATourOfChefs": "Tham quan CHEFS để xem nó hoạt động.", + "logInToGetStarted": "Đăng nhập để bắt đầu", + "loginToStart": "Đăng nhập bằng IDIR để bắt đầu", + "login": "Đăng nhập", + "createFormLabel": "Tạo một biểu mẫu", + "manageAccessTitle": "Quản lý quyền truy cập vào biểu mẫu của bạn", + "manageAccessSub1": "CHEFS cho phép bạn tạo các biểu mẫu công khai hoặc bạn có thể quản lý quyền truy cập thông qua xác thực IDIR hoặc BCeID.", + "manageAccessSub2": "Bạn cũng có thể chỉ định vai trò cho nhóm của mình để quản lý tất cả các nội dung bạn gửi.", + "createCustomFormTitle": "Tạo biểu mẫu tùy chỉnh với trình tạo biểu mẫu CHEFS", + "createCustomFormSub1": "Với CHEFS, bạn có thể tạo các biểu mẫu an toàn bằng giao diện kéo và thả trực quan. Bạn có thể thêm các thành phần biểu mẫu, sắp xếp lại chúng và thả chúng vào các cấu hình bố cục khác nhau.", + "chefsHowToTitle": "Video hướng dẫn của CHEF", + "chefsHowToSub": "Hướng dẫn bắt đầu nhanh của chúng tôi sẽ giới thiệu cho bạn một số chức năng cơ bản của CHEFS.", + "getStartedToChefs": "Bắt đầu sử dụng CHEFS", + "createOnlineTitle": "Tạo biểu mẫu trực tuyến để thu thập thông tin từ khách hàng của bạn và cải thiện quy trình làm việc của bạn.", + "getStarted": "Bắt đầu" + }, + "baseStepper": { + "setUpForm": "Thiết lập biểu mẫu", + "designForm": "mẫu thiết kế", + "manageForm": "Quản lý biểu mẫu" + }, + "create": { + "formSettings": "Cài đặt biểu mẫu", + "disclaimer": "từ chối trách nhiệm", + "disclaimerStmt": "Tôi đồng ý với tuyên bố từ chối trách nhiệm và tuyên bố trách nhiệm đối với Nhà thiết kế biểu mẫu", + "continue": "Tiếp tục", + "back": "Mặt sau", + "confirmPageNav": "Bạn có thực sự muốn rời khỏi trang này? Những thay đổi bạn đã thực hiện sẽ không được lưu.", + "agreementErrMsg": "Bạn phải đồng ý với tuyên bố từ chối trách nhiệm về quyền riêng tư được hiển thị ở trên." + }, + "addTeamMember": { + "cantFindChefsUsers": "Không thể tìm thấy một người nào đó? Họ có thể chưa đăng nhập vào CHEFS.
Vui lòng gửi cho họ một liên kết đến CHEFS và yêu cầu họ đăng nhập.", + "cancel": "Hủy bỏ", + "add": "Thêm vào", + "mustSelectAUser": "Bạn phải chọn ít nhất một vai trò để thêm người dùng này.", + "addNewMember": "Thêm một thành viên mới", + "enterUsername": "Nhập tên, e-mail hoặc tên người dùng", + "enterExactUsername": "Nhập một e-mail hoặc tên người dùng chính xác", + "BCeIDInputSearchMaxLen": "Đầu vào tìm kiếm cho tên người dùng/email BCeID phải lớn hơn 6 ký tự.", + "BCeIDMustBeExact": "Tìm kiếm email cho BCeID phải chính xác.", + "errorGettingUsers": "Lỗi nhận người dùng {error}" + }, + "baseFilter": { + "cancel": "Hủy bỏ", + "columnName": "Tên cột dọc", + "exampleText": "Văn bản mẫu", + "exampleText2": "Văn bản mẫu 2", + "filterPlaceholderTxt": "Lọc văn bản giữ chỗ", + "filter": "Lọc", + "value": "giá trị", + "resetColumns": "Đặt lại cột" + }, + "formViewerActions": { + "viewMyDraftOrSubmissions": "Xem bản nháp/bài nộp của tôi", + "saveAsADraft": "Lưu dưới dạng Bản nháp", + "editThisDraft": "Chỉnh sửa Bản nháp này", + "switchSingleSubmssn": "Chuyển sang gửi một lần", + "switchMultiSubmssn": "Chuyển sang nhiều bài nộp" + }, + "baseCopyToClipboard": { + "linkToClipboard": "Liên kết được sao chép vào khay nhớ tạm", + "copyToClipboard": "Sao chép vào clipboard", + "errCopyToClipboard": "Lỗi khi cố sao chép vào khay nhớ tạm." + }, + "sucess": { + "sucessFormSubmissn": "Biểu mẫu của bạn đã được gửi thành công", + "keepRecord": "Nếu bạn muốn giữ một bản ghi của bài nộp này, bạn có thể giữ như sau", + "confirmationId": "ID xác nhận" + }, + "bcGovAlertBanner": { + "defaultErrMsg": "Lỗi: Đã xảy ra sự cố", + "error": "lỗi" + }, + "permissionUtils": { + "formNotAvailable": "Các hình thức hiện không có sẵn. Điều này có thể là do một liên kết không chính xác hoặc biểu mẫu có thể đã bị xóa bởi chủ sở hữu của nó.", + "missingFormIdAndSubmssId": "Tùy chọn thiếu cả formId và submitId", + "loadingFormErrMsg": "Đã xảy ra lỗi khi tải biểu mẫu này.", + "loadingForm": "Lỗi khi tải {options}: {error}", + "idpHintMsg": "Biểu mẫu này yêu cầu xác thực {idpHint}. Vui lòng đăng nhập lại và thử lại.", + "formIdpMissMatch": "Mẫu IDP không khớp. Biểu mẫu yêu cầu {idpHint} nhưng người dùng có {userIdp}.", + "chefsDataExport": "Xuất dữ liệu CHEFS", + "preparingForDownloading": "Đang chuẩn bị tải xuống...", + "downloadInfoA": "Nếu tệp của bạn không tự động tải xuống", + "downloadInfoB": "Bấm vào đây để thử lại" + }, + "history": { + "submissnHistory": "Lịch sử gửi của bạn (TBD)" + }, + "error": { + "logout": "Đăng xuất", + "somethingWentWrong": "Lỗi: Đã xảy ra sự cố... :(" + }, + "login": { + "authenticateWith": "Xác thực với:", + "alreadyLoggedIn": "đã đăng nhập", + "home": "Trang chủ", + "about": "Về" + }, + "notFound": { + "about": "Về", + "pageNotFound": "Lôi 404 Không Tim Được Trang. :(" + }, + "store": { + "admin": { + "addFormOwnerRole": "Đã thêm vai trò Chủ sở hữu cho biểu mẫu này vào {fullName}", + "addRowError": "Đã xảy ra lỗi khi thêm vai trò.", + "addRowConsoleErr": "Lỗi khi thêm người dùng {userId} vào biểu mẫu {formId}: {error}", + "apiKeyDelMsg": "Khóa API cho biểu mẫu này đã bị xóa.", + "errDeletingApiKey": "Đã xảy ra lỗi khi cố xóa Khóa API.", + "consErrDeletingApiKey": "Lỗi khi xóa Khóa API cho biểu mẫu {formId}: {error}", + "fecthingFormsErrMsg": "Đã xảy ra lỗi khi tìm nạp biểu mẫu.", + "fecthingFormsConsErrMsg": "Lỗi khi nhận dữ liệu biểu mẫu quản trị viên: {error}", + "fecthingFormErrMsg": "Đã xảy ra lỗi khi tìm nạp biểu mẫu này.", + "fecthingFormConsErrMsg": "Lỗi khi nhận dữ liệu biểu mẫu {formId} của quản trị viên: {error}", + "fecthFormUserRolesErrMsg": "Đã xảy ra lỗi khi tìm nạp vai trò người dùng biểu mẫu.", + "fecthFormUserRolesConsErrMsg": "Lỗi khi nhận dữ liệu vai trò quản trị viên: {error}", + "fecthApiDetailsErrMsg": "Đã xảy ra lỗi khi tìm nạp chi tiết API của biểu mẫu này.", + "fecthApiDetailsConsErrMsg": "Lỗi khi nhận chi tiết API của quản trị viên từ dữ liệu biểu mẫu {formId}: {error}", + "restoreFormErrMsg": "Đã xảy ra lỗi khi khôi phục biểu mẫu này.", + "restoreFormConsErrMsg": "Lỗi khôi phục dữ liệu biểu mẫu {formId}: {error}", + "getUsersErrMsg": "Đã xảy ra lỗi khi tìm nạp người dùng.", + "getUsersConsErrMsg": "Lỗi nhận dữ liệu người dùng quản trị: {error}", + "getUserErrMsg": "Đã xảy ra lỗi khi tìm nạp người dùng này.", + "getUserConsErrMsg": "Đã xảy ra lỗi khi nhận dữ liệu {userId} của người dùng quản trị: {error}", + "storingFCHelpInfoErrMsg": "Đã xảy ra lỗi khi lưu trữ thông tin trợ giúp về thành phần biểu mẫu", + "storingFCHelpInfoConsErrMsg": "Lỗi khi lưu trữ thông tin trợ giúp về thành phần biểu mẫu: {error}", + "gettingFCImgUrlErrMsg": "Đã xảy ra lỗi khi nhận url hình ảnh", + "gettingFCImgUrlConsErrMsg": "Lỗi nhận url hình ảnh: {error}", + "updatingFCStatusErrMsg": "Đã xảy ra lỗi khi cập nhật trạng thái xuất bản", + "updatingFCStatusConsErrMsg": "Lỗi khi cập nhật trạng thái xuất bản: {error}", + "fecthingFormBuilderCompsErrMsg": "Đã xảy ra lỗi khi tìm nạp các thành phần của trình tạo biểu mẫu", + "fecthingFormBuilderCompsConsErrMsg": "Lỗi khi nhận các thành phần của trình tạo biểu mẫu: {error}" + }, + "form": { + "fetchEmailTemplatesConsErrMsg": "Lỗi tải mẫu email cho {formId}: {error}", + "fetchEmailTemplatesErrMsg": "Đã xảy ra lỗi khi tìm nạp mẫu email cho biểu mẫu này", + "getCurrUserFormsErrMsg": "Đã xảy ra lỗi khi tìm nạp biểu mẫu của bạn.", + "getCurrUserFormsConsErrMsg": "Lỗi khi lấy dữ liệu người dùng: {error}", + "getUserFormPermErrMsg": "Đã xảy ra lỗi khi tìm nạp dữ liệu người dùng của bạn cho biểu mẫu này.", + "getUserFormPermConsErrMsg": "Lỗi nhận dữ liệu người dùng bằng formID {formId}: {error}", + "getUserFormRolesErrmsg": "Đã xảy ra lỗi khi tìm nạp dữ liệu người dùng của bạn cho biểu mẫu này.", + "getUserFormRolesConsErrmsg": "Lỗi nhận dữ liệu người dùng bằng formID {formId}: {error}", + "updCurrUserFormPrefErrMsg": "Đã xảy ra lỗi khi lưu tùy chọn của bạn cho biểu mẫu này.", + "updCurrUserFormPrefConsErrMsg": "Đã xảy ra lỗi khi cập nhật phần mở đầu biểu mẫu người dùng bằng cách sử dụng formID {formId} và phần mở đầu {preferences}: {error}", + "getCurrUserFormPrefErrMsg": "Đã xảy ra lỗi khi tìm nạp tùy chọn của bạn cho biểu mẫu này.", + "getCurrUserFormPrefConsErrMsg": "Lỗi khi tải trước biểu mẫu người dùng bằng formID {formId}: {error}", + "delCurrformNotiMsg": "Biểu mẫu {name} đã được xóa thành công.", + "delCurrFormConsErMsg": "Lỗi khi xóa biểu mẫu {id}: {error}", + "delDraftErrMsg": "Đã xảy ra lỗi khi xóa bản nháp này.", + "delDraftConsErrMsg": "Đã xảy ra lỗi khi xóa {draftId}: {error}", + "fecthDraftErrMsg": "Đã xảy ra lỗi khi quét bản nháp cho biểu mẫu này.", + "fecthDraftConsErrMsg": "Lỗi khi nhận bản nháp cho biểu mẫu {formId}: {error}", + "fecthFormErrMsg": "Đã xảy ra lỗi khi tìm nạp biểu mẫu này.", + "fecthFormConsErrMsg": "Lỗi khi nhận biểu mẫu {formId}: {error}", + "fetchFormFieldsErrMsg": "Đã xảy ra lỗi khi tìm nạp danh sách các trường cho biểu mẫu này.", + "fetchFormFieldsConsErrMsg": "Lỗi khi nhận biểu mẫu {formId}: {error}", + "publishDraftErrMsg": "Đã xảy ra lỗi khi xuất bản.", + "publishDraftConsErrMsg": "Lỗi xuất bản {draftId}: {error}", + "toggleVersnPublConsErrMsg": "Lỗi trong toggleVersionPublish {versionId} {publish}: {error}", + "updateEmailTemplateConsErrMsg": "Lỗi cập nhật mẫu email cho biểu mẫu {formId}: {error}", + "updateEmailTemplateErrMsg": "Đã xảy ra lỗi khi cập nhật mẫu email cho biểu mẫu này.", + "updateFormErrMsg": "Đã xảy ra lỗi khi cập nhật cài đặt cho biểu mẫu này.", + "updateFormConsErrMsg": "Lỗi khi cập nhật biểu mẫu {id}: {error}", + "deleteSubmissionNotifyMsg": "Đã xóa bài đăng thành công.", + "deleteSubmissionErrMsg": "Đã xảy ra lỗi khi xóa nội dung gửi này.", + "deleteSubmissionConsErrMsg": "Đã xảy ra lỗi khi xóa nội dung gửi {submissionId}: {error}", + "deleteSubmissionsNotifyMsg": "Đã xóa bài đăng thành công.", + "deleteSubmissionsErrMsg": "Đã xảy ra lỗi khi xóa các bài gửi đã chọn.", + "deleteSubmissionsConsErrMsg": "Lỗi khi xóa nội dung gửi: {error}", + "restoreSubmissionsNotiMsg": "Đệ trình được khôi phục thành công.", + "restoreSubmissionsErrMsg": "Đã xảy ra lỗi khi khôi phục nội dung gửi này.", + "restoreSubmissionsConsErrMsg": "Lỗi khi khôi phục nội dung gửi: {error}", + "restoreSubmissionNotiMsg": "Đã khôi phục gửi thành công.", + "restoreSubmissionErrMsg": "Đã xảy ra lỗi khi khôi phục nội dung gửi này.", + "restoreSubmissionConsErrMsg": "Lỗi khi khôi phục nội dung gửi {submissionId}: {error}", + "fecthSubmissnUsersErrMsg": "Đã xảy ra lỗi khi tìm nạp email người nhận cho nội dung gửi này.", + "fecthSubmissnUsersConsErrMsg": "Lỗi khi nhận email người nhận để gửi {formSubmissionId}: {error}", + "fetchSubmissnErrMsg": "Đã xảy ra lỗi khi tìm nạp nội dung gửi này.", + "fetchSubmissnConsErrMsg": "Lỗi khi gửi {submissionId}: {error}", + "fetchFormCSVExptFieldsErrMsg": "Đã xảy ra lỗi khi tìm nạp danh sách các trường cho biểu mẫu này.", + "fetchFormCSVExptFieldsConsErrMsg": "Lỗi khi nhận biểu mẫu {formId}: {error}", + "fetchSubmissnsErrMsg": "Đã xảy ra lỗi khi tìm nạp nội dung gửi cho biểu mẫu này.", + "fetchSubmissnsConsErrMsg": "Lỗi khi gửi {formId}: {error}", + "fetchVersionErrMsg": "Đã xảy ra lỗi khi tìm nạp biểu mẫu này.", + "fetchVersionConsErrMsg": "Lỗi nhận phiên bản {versionId} cho biểu mẫu {formId}: {error}", + "deleteApiKeyNotifyMsg": "Khóa API cho biểu mẫu này đã bị xóa.", + "deleteApiKeyErrMsg": "Đã xảy ra lỗi khi cố xóa Khóa API.", + "deleteApiKeyConsErrMsg": "Lỗi khi xóa Khóa API cho biểu mẫu {formId}: {error}", + "generateApiKeyNotifyMsg": "Khóa API cho biểu mẫu này đã được tạo.", + "generateApiKeyErrMsg": "Đã xảy ra lỗi khi cố gắng tạo Khóa API.", + "generateApiKeyConsErrMsg": "Lỗi khi tạo Khóa API cho biểu mẫu {formId}: {error}", + "readApiKeyErrMsg": "Đã xảy ra lỗi khi cố gắng tìm nạp Khóa API.", + "readApiKeyConsErrMsg": "Lỗi khi nhận Khóa API cho biểu mẫu {formId}: {error}.", + "getFCPHImageUrlErrMsg": "Đã xảy ra lỗi khi nhận url hình ảnh", + "getFCPHImageUrlConsErrMsg": "Lỗi nhận url hình ảnh: {error}", + "listFCPHErrMsg": "Đã xảy ra lỗi khi tìm nạp các thành phần của trình tạo biểu mẫu", + "listFCPHConsErrMsg": "Lỗi khi nhận các thành phần của trình tạo biểu mẫu: {error}", + "downloadFileErrMsg": "Đã xảy ra lỗi khi tải xuống tệp", + "downloadFileConsErrMsg": "Lỗi khi tải xuống tệp: lỗi", + "readSubscriptionSettingsErrMsg": "Đã xảy ra lỗi khi cố tìm nạp cài đặt đăng ký.", + "readSubscriptionSettingsConsErrMsg": "Lỗi nhận cài đặt đăng ký cho biểu mẫu {formId}: {error}.", + "saveSubscriptionSettingsNotifyMsg": "Cài đặt đăng ký cho biểu mẫu này đã được lưu.", + "saveSubscriptionSettingsErrMsg": "Đã xảy ra lỗi khi cố lưu cài đặt đăng ký.", + "saveSubscriptionSettingsConsErrMsg": "Lỗi khi lưu cài đặt đăng ký cho biểu mẫu {formId}: {error}" + } + }, + "admin": { + "root": { + "admin": "Quản trị viên" + }, + "form": { + "administerForm": "quản lý biểu mẫu" + }, + "user": { + "administerUser": "Quản lý người dùng" + } + }, + "user": { + "root": { + "myForms": "MẪU CỦA TÔI", + "history": "LỊCH SỬ", + "user": "Người dùng" + } + } +} diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/zh/index.js b/frontend/app/frontend/src/internationalization/trans/chefs/zh/index.js new file mode 100644 index 0000000..0e7e27c --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/zh/index.js @@ -0,0 +1,4 @@ +import zh from '~/internationalization/trans/chefs/zh/zh.json'; +export default { + trans: zh, +}; diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/zh/zh.json b/frontend/app/frontend/src/internationalization/trans/chefs/zh/zh.json new file mode 100644 index 0000000..c062c71 --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/zh/zh.json @@ -0,0 +1,995 @@ +{ + "date": { + "date": "年-月-日" + }, + "emailManagement": { + "emailManagement": "电子邮件管理", + "manageForm": "管理表格", + "submissionConfirmation": "提交确认" + }, + "emailTemplate": { + "body": "身体", + "save": "节省", + "saveEmailTemplateConsoleErrMsg": "更新表单 {formId} 的电子邮件模板时出错:{error}", + "saveEmailTemplateErrMsg": "尝试更新电子邮件模板时发生错误。", + "subject": "主题", + "title": "标题", + "validBodyRequired": "请输入电子邮件正文", + "validSubjectRequired": "请输入电子邮件的主题行", + "validTitleRequired": "请输入电子邮件的标题" + }, + "formsTable": { + "myForms": "我的表格", + "createNewForm": "创建新表单", + "search": "搜索", + "manage": "管理", + "submissions": "意见书", + "formTitle": "表格标题", + "viewForm": "查看表格", + "description": "描述", + "Description": "描述:", + "action": "行动", + "loadingText": "加载请稍候" + }, + "manageLayout": { + "manageForm": "管理表格" + }, + "preview": { + "preview": "预览", + "previewToolTip": "这显示了提交者将看到的表单版本设计和行为的预览。您无法从此页面提交表格。" + }, + "shareForm": { + "shareForm": "分享表格", + "shareLink": "分享链接", + "copyQRCode": "复制下面的链接或下载二维码。", + "warningMessage": "目前该表格还没有发布版本。在发布版本之前,将无法访问下面的链接。", + "openThisForm": "打开此表格", + "downloadQRCode": "下载二维码", + "close": "关闭", + "copyURLToClipboard": "将 URL 复制到剪贴板" + }, + "manageFormActions": { + "emailManagement": "电子邮件管理", + "viewSubmissions": "查看提交内容", + "teamManagement": "团队管理", + "deleteForm": "删除表格", + "confirmDeletion": "确认删除", + "deleteMessageA": "您确定要删除吗", + "deleteMessageB": "此表格将不再可用。", + "delete": "删除" + }, + "manageForm": { + "formSettings": "表单设置", + "apiKey": "API密钥", + "updated": "更新", + "created": "已创建", + "formDesignHistory": "表单设计历史", + "totalVersions": "总版本", + "status": "地位", + "update": "更新", + "cancel": "取消", + "eventSubscription": "E活动订阅" + }, + "formSettings": { + "pressToAddMultiEmail": "按Enter,空格键添加多个电子邮件地址", + "allowMultiDraft": "允许上传多个草稿", + "formTitle": "表格标题", + "formDescription": "表格说明", + "formAccess": "表格访问", + "info": "如果您将使用此表格向公众收集有关公众普遍感兴趣的主题的信息,您需要联系 GCPE,以便将您的参与情况列在", + "important": "重要的", + "idimNotifyA": "您必须通过电子邮件通知身份信息管理 (IDIM) 团队", + "idimNotifyB": "您打算利用 BCeID 来验证表单提交者的身份。", + "referenceGuideA": "请参考我们的", + "referenceGuideB": "用户指南", + "referenceGuideC": "更多细节", + "specificTeamMembers": "具体团队成员", + "formFunctionality": "表单功能", + "formSubmissinScheduleMsg": "表单发布后,表单提交计划将在表单设置中可用。", + "formSubmissionsSchedule": "表格提交时间表", + "experimental": "实验性的", + "learnMore": "了解更多", + "afterSubmission": "提交后", + "submissionConfirmation": "显示提交确认详细信息", + "theConfirmationID": "确认 ID", + "infoB": "用户可以通过电子邮件向自己发送提交确认的选项", + "loginRequired": "要求登录", + "canSaveAndEditDraftLabel": "提交者可以保存和编辑草稿", + "canUpdateStatusAsReviewer": "审阅者可以更新此表单的状态(即已提交、已分配、已完成)", + "submitterCanCopyExistingSubmissn": "提交者可以复制现有提交", + "submissionConfirmationToolTip": "选择此选项可控制此表单的提交用户在成功提交后将看到的内容。
如果勾选的话会显示", + "emailNotificatnToTeam": "向我的团队发送通知电子邮件", + "emailNotificatnToTeamToolTip": "当任何用户提交此表单时,向您指定的电子邮件地址发送通知", + "notificationEmailAddrs": "通知电子邮件地址", + "addMoreValidEmailAddrs": "添加一个或多个有效电子邮件地址", + "formScheduleSettings": "表格时间表设置", + "opensubmissions": "开放提交", + "submissionsDeadline": "您希望多长时间收到提交的材料?", + "keepSubmissnOpenTilUnplished": "保持打开状态直至手动取消发布", + "submissionsClosingDate": "安排截止日期", + "submissionPeriod": "设置提交期限", + "closeSubmissions": "关闭提交", + "keepOpenFor": "保持开放状态", + "period": "时期", + "allowLateSubmissions": "允许逾期提交", + "allowLateSubmissionsInfoTip": "如果选中,提交者将能够在截止日期之后提交数据。", + "afterCloseDateFor": "截止日期后", + "repeatPeriod": "重复周期", + "every": "每一个", + "repeatUntil": "重复直到", + "summary": "概括", + "submissionsOpenDateRange": "此表格将开放供提交", + "to": "到", + "scheduleRepetition": "该时间表将重复每个", + "allowLateSubmissnInterval": "允许延迟提交", + "until": "直到", + "datesOfSubmissnInfo": "根据设置,这些是可用的提交日期:", + "formOpenInterval": "此表格将开放供提交", + "allowDateSubmissionDate": "允许延迟提交,直到", + "customClosingMessage": "设置自定义结束消息", + "customClosingMessageToolTip": "允许您在用户访问关闭表单时为他们添加自定义消息。", + "closingMessage": "结束语", + "sendReminderEmail": "发送提醒电子邮件", + "autoReminderNotificatn": "启用自动提醒通知", + "autoReminderNotificatnToolTip": "在提交期间发送带有表单链接的提醒电子邮件。", + "selectLoginType": "请选择 1 种登录类型", + "formDescriptnMaxChars": "表单描述不得超过 255 个字符", + "formTitlemaxChars": "表单标题不得超过 255 个字符", + "formTitleReq": "表格标题为必填项", + "atLeastOneEmailReq": "请输入至少 1 个电子邮件地址", + "validEmailRequired": "请输入所有有效的电子邮件地址", + "fieldRequired": "此字段是必需的。", + "correctDateFormat": "日期格式必须正确。 IE。年-月-日", + "dateDiffMsg": "关闭提交日期应晚于开放提交日期。", + "valueMustBeNumber": "值必须是数字。 IE。 1,2,3,5,99", + "selectAnOptions": "请至少选择 1 个选项", + "validInterval": "这应该是一个有效的间隔。", + "fieldRequiredAndInterval": "该字段是必需的并且应该是一个间隔。", + "dateGrtOpenSubmissnDate": "重复直到日期应大于开放提交日期", + "public": "公开(匿名)", + "allowEventSubscription": "允许事件订阅", + "eventSubscription": "E活动订阅", + "validEndpointRequired": "请输入以以下开头的有效端点 https://", + "validBearerTokenRequired": "输入有效的不记名令牌示例: 89abddfb-2cff-4fda-83e6-13221f0c3d4f" + }, + "subscribeEvent": { + "eventType": "事件类型", + "endpointUrl": "端点网址", + "eventSubmission": "提交", + "eventAssignment": "任务", + "eventStatusChange": "状态改变", + "endpointToken": "端点令牌", + "urlPlaceholder": "https://endpoint.gov.bc.ca/api/v1/", + "save": "节省", + "text": "文本", + "password": "密码", + "hideSecret": "隐藏秘密", + "showSecret": "显示秘密", + "key": "钥匙", + "saveSettingsErrMsg": "尝试更新此表单的设置时发生错误。", + "updateSettingsConsoleErrMsg": "更新表单 {formId} 设置时出错:{error}" + }, + "apiKey": { + "disclaimer": "免责声明", + "infoA": "确保您的 API 密钥秘密存储在安全位置(即密钥保管库)。", + "infoB": "您的 API 密钥可以不受限制地访问您的表单。请勿将您的 API 密钥透露给任何人。", + "infoC": "API 密钥只能用于自动化系统交互。请勿使用您的 API 密钥进行基于用户的访问", + "deleteKey": "删除键", + "apiKey": "API密钥", + "hideSecret": "隐藏秘密", + "showSecret": "显示秘密", + "sCTC": "秘密已复制到剪贴板", + "cSTC": "将机密复制到剪贴板", + "key": "钥匙", + "confirmDeletion": "确认删除", + "deleteMsg": "您确定要删除您的 API 密钥吗?", + "delete": "删除", + "confirmKeyGen": "确认密钥生成", + "createAPIKey": "为此表单创建 API 密钥?
确保您遵循本页上的免责声明。", + "regenerateAPIKey": "重新生成 API 密钥?
继续将删除您当前的 API 密钥访问权限。", + "formOwnerKeyAcess": "您必须是表单所有者才能管理 API 密钥。", + "regenerate": "再生", + "generate": "产生", + "secret": "秘密" + }, + "manageVersions": { + "important": "重要的!", + "infoA": "如果没有已发布的版本,则在分配已发布的版本之前,用户无法访问此表单。版本发布后,该版本将不再可编辑。您必须基于以前的表单版本之一创建新版本才能继续编辑。", + "infoB": "注:只能发布一个版本。", + "version": "版本", + "draft": "草稿", + "clickToPreview": "点击预览", + "editVersion": "编辑版本", + "exportDesign": "出口设计", + "infoC": "请在开始新版本之前发布或删除您的最新草稿版本。", + "deleteVersion": "删除版本", + "draftAlreadyExists": "草稿已经存在", + "infoD": "请在开始新草稿之前编辑、发布或删除现有草稿。", + "publishVersion": "发布版本", + "unpublishVersion": "取消发布版本", + "infoE": "取消发布此表格将使该表格停止流通,直到再次发布版本。", + "confirmDeletion": "确认删除", + "infoF": "您确定要删除此版本吗?", + "delete": "删除", + "status": "地位", + "dateCreated": "创建日期", + "createdBy": "由...制作", + "actions": "行动", + "published": "已发表", + "unpublished": "未发表", + "useVersionInfo": "使用版本 {version} 作为新版本的基础", + "publishingVersionInfo": "这将使您的表单的版本 {version} 生效。" + }, + "addOwner": { + "infoA": "仅当当前表单所有者不再活跃或在优先事件中失去联系时才应执行此操作。否则,请让表单的当前所有者或团队管理员自行执行此操作。", + "hint": "要查找所需的用户 ID,您可以转到管理门户中的“用户”选项卡并搜索它们。", + "addowner": "添加所有者", + "label": "用户ID(引导)" + }, + "adminFormsTable": { + "showDeletedForms": "显示已删除的表格", + "search": "搜索", + "loadingText": "加载文本", + "noDataText": "您的系统中没有表格", + "admin": "行政", + "launch": "发射", + "formTitle": "表格标题", + "created": "已创建", + "deleted": "已删除", + "actions": "行动", + "delete": "删除" + }, + "administerForm": { + "deleted": "已删除", + "restoreForm": "恢复此表格", + "formDetails": "表格详情", + "apiKeyDetails": "API 密钥详细信息", + "deleteApiKey": "删除 API 密钥", + "formUsers": "表单用户", + "formVersions": "表单版本", + "assignANewOwner": "指定新所有者", + "restoring": "正在恢复", + "restore": "恢复", + "toActiveState": "到活动状态", + "confirmDeletion": "确认删除", + "confirmDeletionMsg": "您确定要删除此 API 密钥吗?", + "delete": "删除", + "confirmRestore": "确认恢复" + }, + "administerUser": { + "userDetails": "用户详细信息", + "openSSOConsole": "打开 SSO 控制台" + }, + "adminPage": { + "forms": "形式", + "users": "用户", + "developer": "开发商", + "infoLinks": "信息链接", + "metrics": "指标" + }, + "adminUsersTable": { + "search": "搜索", + "loadingText": "加载请稍候", + "admin": "行政", + "fullName": "全名", + "userID": "用户身份", + "created": "已创建", + "actions": "行动" + }, + "adminVersions": { + "exportDesign": "出口设计", + "versions": "版本", + "status": "地位", + "created": "已创建", + "lastUpdated": "最近更新时间", + "actions": "行动", + "published": "已发表", + "unpublished": "未发表", + "version": "版本 {versionNo}", + "notificationMsg": "加载表单设计时出错。" + }, + "developer": { + "user": "用户", + "name": "姓名", + "userName": "用户名", + "JWTContents": "智威汤逊内容", + "JWTContentsSBTxt": "JWT 内容已复制到剪贴板", + "JWTContentsTTTxt": "将 JWT 内容复制到剪贴板", + "JWTToken": "智威汤逊令牌", + "JWTTokenSBTxt": "JWT 令牌已复制到剪贴板", + "JWTTokenTTTxt": "将 JWT 令牌复制到剪贴板", + "chefsAPI": "厨师API", + "RBACSBTxt": "RBAC 响应已复制到剪贴板", + "RBACTTTxt": "将 RBAC 响应复制到剪贴板", + "notificationMsg": "无法从 RBAC 获取用户,请参见控制台", + "notificationConsErr": "从 RBAC 获取用户时出错" + }, + "baseAuthButton": { + "logout": "登出", + "login": "登录" + }, + "baseDialog": { + "defaultText": "默认文本", + "ok": "好的", + "continue": "继续", + "cancel": "取消", + "custom": "风俗" + }, + "baseSecure": { + "about": "关于", + "loginInfo": "您必须先登录才能使用此功能。", + "login": "登录", + "401NotAuthorized": "401:未授权。 :", + "401ErrorMsg": "您的帐户设置不正确。
请联系", + "403Forbidden": "403:禁止。 :", + "403ErrorMsg": "此页面需要 {idp} 身份验证。", + "401UnAuthorized": "401:未经授权。 :", + "401UnAuthorizedErrMsg": "您没有权限访问此页面。" + }, + "formDesigner": { + "formDesign": "表格设计", + "exportDesign": "出口设计", + "importDesign": "导入设计", + "important": "重要的", + "formDesignInfoA": "完成此表单的构建后,请使用“保存设计”按钮。", + "formDesignInfoB": "提交按钮供您的用户提交此表单,并将在保存后激活。", + "formLoadErrMsg": "加载表单设计时出错。", + "formLoadConsoleErrMsg": "加载表单 {formId} 架构时出错(版本:{versionId} 草稿:{draftId}):{error}", + "formSchemaImportErrMsg": "导入表单架构时发生错误。", + "formSchemaImportConsoleErrMsg": "导入表单架构时出错:{error}", + "formDesignSaveErrMsg": "尝试保存此表单设计时发生错误。如果您需要刷新或稍后重试,可以导出页面上的现有设计以保存以供稍后使用。", + "formDesignSaveConsoleErrMsg": "更新或创建表单时出错(FormID:{formId},versionId:{versionId},draftId:{draftId})错误:{error}", + "collapse": "坍塌", + "actions": "行动", + "version": "版本", + "save": "节省", + "saving": "保存", + "notSaved": "未保存", + "fieldnameError": "您不能使用“form”关键字作为 {label} 字段名" + }, + "formViewerMultiUpload": { + "important": "重要的", + "uploadSucessMsg": "为确保成功上传多个草稿,请下载并使用提供的模板。", + "confirmDownload": "您想下载吗?", + "jsonFileUpload": "选择要上传的 JSON 文件", + "dragNDrop": "或将其拖放到此处", + "chooseAFile": "选择一个文件", + "downloadDraftSubmns": "请下载提交报告草稿并确保数据输入正确。", + "downloadReport": "下载报告", + "doYouWantToDownload": "您想下载吗?", + "uploadNewFile": "上传新文件", + "uploadMultipleFileErr": "抱歉,您只能上传一个文件", + "dragMultipleFileErr": "抱歉,您只能拖动一个文件", + "fileFormatErr": "抱歉,我们只接受 json 文件", + "fileSizeErr": "允许的最大文件大小为 5MB", + "parseJsonErr": "我们无法从文件中解析 json 数据", + "jsonObjNotArray": "json 文件格式错误", + "jsonObjNotArrayConsErr": "一个意料之外的问题发生了。", + "jsonArrayEmpty": "这个 json 文件是空的。", + "errorWhileValidate": "这个文件有问题", + "errWhileCheckValidity": "这个文件有问题", + "errAfterValidate": "发现一些错误,请参阅下文了解更多信息。", + "fileIsEmpty": "该文件是空的。", + "download": "下载" + }, + "formDisclaimer": { + "disclaimerAndStatement": "表单设计者的免责声明和责任声明:", + "privacyLaw": "您有责任遵守有关收集、使用和披露个人身份信息的隐私法。", + "disclosure": "访问此表单设计器工具本身并不授予收集、使用或披露任何个人身份信息的权限。", + "consent": "您有责任按照法律要求获得同意收集信息。", + "formIntention": "在发布或分发您的表格之前,您需要与您的同事讨论该表格的意图。", + "privacyOfficer": "部隐私官员", + "assement": "并按要求完成评估。" + }, + "requestReceipt": { + "emailPriority": "电子邮件优先", + "emailReceipt": "通过电子邮件发送此提交的收据", + "high": "高的", + "low": "低的", + "normal": "普通的", + "send": "发送", + "sendToEmailAddress": "发送至电子邮件地址", + "emailSent": "一封电子邮件已发送至 {to}。", + "sendingEmailErrMsg": "尝试发送您的电子邮件时发生错误。", + "sendingEmailConsErrMsg": "向 {to} 发送电子邮件确认失败:{error}", + "emailRequired": "电子邮件为必填项" + }, + "submissionsTable": { + "noMatchingRecordText": "未找到匹配的记录", + "submissions": "意见书", + "submissionsTable": "提交表", + "selectColumns": "选择列", + "manageForm": "管理表格", + "submissionsToFiles": "将提交内容导出到文件", + "showDeletedSubmissions": "显示已删除的提交", + "showMySubmissions": "显示我的提交内容", + "search": "搜索", + "loadingText": "加载请稍候", + "noDataText": "没有提交此表格", + "delSelectedSubmissions": "删除选定的提交内容", + "resSelectedSubmissions": "恢复选定的提交", + "yes": "是的", + "no": "不", + "viewSubmission": "查看提交内容", + "deleteSubmission": "删除提交内容", + "restore": "恢复", + "confirmDeletion": "确认删除", + "delete": "删除", + "confirmRestoration": "确认恢复", + "searchSubmissionFields": "搜索提交字段", + "save": "节省", + "searchTitle": "搜索并选择要在仪表板下显示的列", + "status": "地位", + "submitter": "提交者", + "submissionDate": "提交日期", + "event": "事件", + "view": "看法", + "lateSubmission": "迟交", + "confirmationID": "确认ID", + "multiDelWarning": "您确定要删除选定的提交内容吗?", + "singleDelWarning": "您确定要删除此提交吗?", + "multiRestoreWarning": "您确定要恢复这些提交吗?", + "singleRestoreWarning": "您确定要恢复此提交吗?" + }, + "auditHistory": { + "viewEditHistory": "查看编辑历史记录", + "editHistory": "编辑历史记录", + "auditLogMsg": "这是一份审核日志,记录了在原始提交之后谁对此提交进行了更改。", + "loadingText": "加载请稍候", + "close": "关闭", + "userName": "用户名", + "date": "日期", + "errorMsg": "尝试获取历史记录时发生错误。", + "consoleErrMsg": "获取审核历史记录时出错" + }, + "deleteSubmission": { + "deleteThis": "删除这个", + "draft": "草稿", + "submission": "提交", + "confirmDeletion": "确认删除", + "deleteWarning": "您确定要删除此内容吗", + "drafts": "草稿", + "formSubmission": "表单提交", + "delete": "删除" + }, + "manageSubmissionUsers": { + "manageTeamMembers": "管理团队成员", + "add": "添加", + "draftFormInvite": "当此表单为草稿时,您只能邀请和管理团队成员", + "submissionTeamMembers": "本次提交的团队成员", + "actions": "行动", + "close": "关闭", + "remove": "消除", + "userNotFoundErrMsg": "找不到人吗?他们可能没有登录 CHEFS。
请向他们发送 CHEFS 链接并要求他们登录。", + "name": "姓名", + "username": "用户名", + "email": "电子邮件", + "removeUserWarningMsg1": "您确定要删除吗", + "removeUserWarningMsg2": "他们将不再拥有此提交的权限。", + "userExistInListMsg": "用户 {username} 已在团队成员列表中。", + "getSubmissionUsersErr": "尝试获取此提交的用户时发生错误。", + "getSubmissionUsersConsoleErr": "获取 {submissionId} 的用户时出错:{error}", + "sentInviteEmailTo": "已发送邀请电子邮件至", + "sentUninvitedEmailTo": "发送了未经邀请的电子邮件至", + "updateUserErrMsg": "尝试更新此提交的用户时出错。", + "updateUserConsoleErrMsg": "设置用户权限时出错。子:{submissionId} 用户:{userId} 错误:{error}", + "searchInputLength": "BCeID 用户名/电子邮件的搜索输入必须大于 6 个字符。", + "exactBCEIDSearch": "BCeID 的电子邮件搜索必须准确。", + "getUsersErrMsg": "获取用户时出错:{error}", + "exactEmailOrUsername": "输入准确的电子邮件或用户名。", + "requiredFiled": "输入姓名、电子邮件或用户名" + }, + "mySubmissionsActions": { + "viewThisSubmission": "查看此提交内容", + "copyThisSubmission": "复制此提交内容", + "editThisDraft": "编辑本草稿" + }, + "mySubmissionsTable": { + "noMatchingRecordText": "未找到匹配的记录", + "previousSubmissions": "以前提交的内容", + "selectColumns": "选择列", + "createNewSubmission": "创建新提交", + "search": "搜索", + "loadingText": "加载请稍候", + "noDataText": "您还没有提交内容", + "searchSubmissionFields": "搜索提交字段", + "save": "节省", + "filterTitle": "搜索并选择要在仪表板下显示的列", + "confirmationId": "确认编号", + "actions": "行动", + "createdBy": "由...制作", + "statusUpdatedBy": "状态更新者", + "status": "地位", + "submissionDate": "提交日期", + "draftUpdatedBy": "草稿更新者", + "draftLastEdited": "最后编辑的草稿", + "createLateSubmissn": "创建延迟提交", + "formLoading": "表格正在加载中,请稍候!!!", + "pleaseConfirm": "请确认", + "wantToSaveDraft": "您想保存草稿吗?", + "yes": "是的", + "no": "不", + "multiDraftUploadSuccess": "您的多草稿上传已成功!", + "failedResSubmissn": "提交端点响应失败。响应代码:{status}", + "errSubmittingForm": "提交此表单时出错", + "errorSavingFile": "保存文件时出错。文件名:{fileName}。错误:{error}", + "submittingDraftErrMsg": "保存草稿时出错", + "submittingDraftConsErrMsg": "保存草稿时出错。提交 ID:{submissionId}。错误:{error}" + }, + "notesPanel": { + "addNewNote": "添加新注释", + "cancel": "取消", + "addNote": "添加注释", + "noResponseErr": "提交表单时 API 没有响应数据", + "errorMesg": "尝试添加注释时发生错误。", + "consoleErrMsg": "添加注释时出错:", + "fetchErrMsg": "尝试获取此提交的注释时发生错误。", + "fetchConsoleErrMsg": "添加注释时出错:", + "notes": "笔记", + "note": "笔记", + "maxChars": "最多 4000 个字符" + }, + "statusPanel": { + "currentStatus": "当前状态:", + "assignedTo": "分配给:", + "assignOrUpdateStatus": "分配或更新状态", + "display": "展示", + "statusIsRequired": "状态为必填项", + "assignTo": "分配给", + "noDataText": "通过搜索未找到表单审阅者。在管理页面添加表单审阅者。", + "assigneeIsRequired": "受让人为必填项", + "assignToMe": "分配给我", + "recipientEmail": "收件人电子邮件", + "attachCommentToEmail": "将评论附加到电子邮件", + "emailComment": "电子邮件评论", + "maxChars": "最多 4000 个字符", + "viewHistory": "查看历史记录", + "statusHistory": "状态历史记录", + "close": "关闭", + "addNoteNoReponserErr": "提交状态更新注释时没有来自 API 的响应数据", + "addNoteConsoleErrMsg": "更新状态时出错:{error}", + "addNoteErrMsg": "尝试更新状态时发生错误", + "updtSubmissionsStatusErr": "提交状态更新表单时没有来自 API 的响应数据", + "noStatus": "无状态", + "noStatusesFound": "未找到状态", + "statusCodesErr": "查找状态代码时出错", + "notifyErrorCode": "获取此提交的状态时发生错误。", + "notifyConsoleErrorCode": "获取状态时出错:", + "fetchSubmissionUsersErr": "尝试获取此提交的收件人电子邮件时发生错误。", + "fetchSubmissionUsersConsErr": "获取收件人电子邮件时出错", + "assignSubmissnToFormReviewer": "提交的内容可以分配给表单审阅者。
要将更多团队成员添加为表单审阅者,请转到此表单的管理页面。", + "update": "更新", + "revise": "修订", + "complete": "完全的", + "assign": "分配" + }, + "statusTable": { + "loadingText": "加载请稍候", + "status": "地位", + "dateStatusChanged": "状态更改日期", + "assignee": "受让人", + "updatedBy": "更新者", + "getSubmissionStatusErr": "尝试获取状态时发生错误。", + "getSubmissionStatusConsErr": "添加注释时出错:" + }, + "exportSubmissions": { + "exportSubmissionsToFile": "将提交内容导出到文件", + "viewSubmissions": "查看提交内容", + "fileType": "文件类型", + "json": "JSON", + "csv": "CSV", + "formVersion": "表格版本", + "versionIsRequired": "版本为必填项。", + "dataFields": "数据字段", + "searchFields": "搜索字段", + "selectedForExports": "选定用于出口", + "submissionDate": "提交日期", + "all": "全部", + "selectDateRange": "选择日期范围", + "SelectdateRange": "选择日期范围", + "from": "从", + "to": "到", + "CSVFormat": "CSV 格式", + "multiRowPerSubmissionA": "1 - 每次提交多行,带有缩进空间", + "multiRowPerSubmissionB": "2 - 每次提交多行", + "singleRowPerSubmission": "3 - 每次提交单行", + "unformatted": "4 - 未格式化", + "fileNameAndType": "文件名和类型", + "export": "出口", + "noResponseDataErr": "exportSubmissions 调用没有响应任何数据", + "apiCallErrorMsg": "尝试导出此表单的提交内容时出错。", + "apiCallConsErrorMsg": "导出提交时出错", + "selectAllFields": "选择所有字段", + "emailSentMsg": "准备好后,系统将向 {email} 发送一封电子邮件,其中包含下载数据的链接", + "exportInProgress": "导出正在进行中", + "of": "的" + }, + "printOptions": { + "submitButtonTxt": "提交至 CDOGS 并下载", + "templatePrint": "模板打印", + "uploadTemplateFile": "上传模板文件", + "downloadOptions": "下载选项", + "print": "打印", + "browserPrint": "浏览器打印", + "pageFromBrowser": "您浏览器中的页面", + "uploadA": "上传一个", + "uploadB": "有一个结构化版本", + "docGrnSucess": "文档生成成功", + "failedDocGenErrMsg": "生成文档失败", + "failedDocGenConsErrMsg": "提交模板时出错:{error}", + "cDogsTemplate": "CDOGS 模板" + }, + "proactiveHelpDialog": { + "componentInfoLink": "组件信息链接", + "learnMoreLinkTxt": "了解更多链接字段不能为空。", + "largeImgTxt": "大图像。图片大小不能大于 0.5mb", + "componentName": "组件名称:", + "learnMoreLink": "了解更多链接:", + "clickToEnableLink": "单击以启用链接", + "clickToDisableLink": "单击以禁用链接", + "imageUpload": "图片上传:", + "cancel": "取消", + "save": "节省", + "description": "描述" + }, + "proactiveHelpPreviewDialog": { + "learnMore": "了解更多" + }, + "preview": { + "preview": "预览", + "previewToolTip": "这显示了提交者将看到的表单版本设计和行为的预览。您无法从此页面提交表格。" + }, + "generalLayout": { + "loadingText": "加载请稍候", + "preview": "预览", + "published": "已发表", + "unpublished": "未发表", + "edit": "编辑", + "formTitle": "表格标题", + "actions": "行动" + }, + "formSubmission": { + "editThisSubmission": "编辑本次提交", + "submission": "提交", + "alertInfo": "编辑后,重新提交表单以保存更改。", + "viewAllSubmissions": "查看所有提交内容", + "submitted": "已提交:", + "confirmationID": "确认ID:", + "submittedBy": "由...所提交:", + "cancel": "取消", + "status": "地位", + "updatedAt": "修改的", + "updatedBy": "修改者" + }, + "teamManagement": { + "noMatchingRecordText": "未找到匹配的记录", + "teamManagement": "团队管理", + "selectColumns": "选择列", + "manageForm": "管理表格", + "search": "搜索", + "loadingText": "加载请稍候", + "noDataText": "无法加载团队角色数据", + "removeSelectedUsers": "删除选定的用户", + "removeThisUser": "删除该用户", + "confirmRemoval": "确认删除", + "remove": "消除", + "searchTeamManagementFields": "搜索团队管理领域", + "save": "节省", + "teamMebersTitle": "搜索并选择要在仪表板下显示的列", + "fullName": "全名", + "username": "用户名", + "identityProvider": "身份提供者", + "delSelectedMembersWarning": "您确定要删除选定的成员吗?", + "delSelectedMemberWarning": "您确定要删除所选成员吗?", + "idpMessage": "已经在团队中了。", + "formOwnerErrMsg": "必须始终至少有一个表单所有者", + "formOwnerConsoleErrMsg": "无法删除 {userId},因为他们是此表单的唯一剩余所有者。", + "insufficientPermissnMsg": "没有足够的权限来管理团队", + "getUserErrMsg": "获取表单用户时出错:", + "getRolesErrMsg": "获取角色列表时出错:", + "formOwnerRemovalWarning": "无法删除,因为他们是此表单的唯一剩余所有者。", + "removeUsersErrMsg": "尝试删除所选用户时出错", + "removeUserConsoleErrMsg": "从表单 {formId} 删除用户时出错:{error}", + "updUserRolesErrMsg": "尝试更新所有用户角色时发生错误", + "updUserRolesConsoleErrMsg": "设置表单 {formId} 的所有用户角色时出错:{error}", + "setUserFormsErrMsg": "尝试更新用户的角色时发生错误", + "setUserFormsConsoleErrMsg": "设置表单 {formId} 的用户角色时出错:{error}" + }, + "floatButton": { + "publish": "发布", + "manage": "管理", + "redo": "重做", + "undo": "撤消", + "preview": "预览", + "bottom": "底部", + "top": "顶部", + "actions": "行动", + "collapse": "坍塌", + "saved": "已保存", + "save": "节省", + "saving": "保存", + "notSaved": "未保存" + }, + "formViewer": { + "lateFormSubmissions": "表格提交期限已过!您仍然可以通过单击下面的按钮来创建延迟提交。", + "createLateSubmission": "创建延迟提交", + "draftSaved": "草稿已保存", + "saving": "保存", + "pleaseConfirm": "请确认", + "submitFormWarningMsg": "您确定要提交表格吗?", + "submit": "提交", + "wantToSaveDraft": "您想保存草稿吗?", + "version": "版本:{version}", + "formScheduleExpireMessage": "由于预定的提交期限已过,因此无法提交表格。", + "getUsersSubmissionsErrMsg": "获取此表单的提交内容时发生错误", + "getUsersSubmissionsConsoleErrMsg": "加载表单提交数据 {submissionId} 时出错:{error}", + "multiDraftUploadSuccess": "您的多草稿上传已成功!", + "readVersionErrMsg": "没有响应模式。版本 ID:{versionId}", + "readDraftErrMsg": "没有响应模式。草稿 ID:{draftId}", + "alertRouteMsg": "表单所有者尚未发布该表单,且无法提交。", + "fecthingFormErrMsg": "获取此表单时出错", + "fecthingFormConsoleErrMsg": "加载表单架构 {versionId} 时出错:{error}", + "savingDraftErrMsg": "保存草稿时出错", + "savingDraftConsoleErrMsg": "保存草稿时出错。提交 ID:{submissionId}。错误:{error}", + "submissionsPreviewAlert": "表单预览期间禁用提交", + "submissionsSubmitErrMsg": "提交表单时出错:{errors}", + "sendSubmissionErrMsg": "提交端点响应失败。响应代码:{status}", + "errMsg": "提交此表单时出错", + "customEventAlert": "尚不支持自定义按钮事件。事件类型:{event}", + "formLoading": "表格正在加载中,请稍候!!!", + "yes": "是的", + "no": "不", + "failedResSubmissn": "提交端点响应失败。响应代码:{status}", + "errSubmittingForm": "提交此表单时出错", + "errorSavingFile": "保存文件时出错。文件名:{fileName}。错误:{error}", + "submittingDraftErrMsg": "保存草稿时出错", + "submittingDraftConsErrMsg": "保存草稿时出错。提交 ID:{submissionId}。错误:{error}", + "formDraftAccessErrMsg": "请求的提交已提交,正在重定向到查看页面" + }, + "bCGovFooter": { + "home": "家", + "about": "关于 gov.bc.ca", + "disclaimer": "免责声明", + "privacy": "隐私", + "accessibility": "无障碍", + "copyRight": "版权", + "contactUs": "联系我们" + }, + "bCGovNavBar": { + "about": "关于", + "myForms": "我的表格", + "createNewForm": "创建新表单", + "help": "帮助", + "feedback": "反馈", + "admin": "行政" + }, + "homePage": { + "title": "使用通用托管表单服务创建、发布表单并接收提交内容。", + "subTitle": "所有 BC 省拥有 IDIR 帐户的政府雇员或承包商可以使用我们的托管版本的通用托管表单服务 (CHEFS) 来创建表单。", + "takeATourOfChefs": "参观 CHEFS 以了解其实际情况。", + "logInToGetStarted": "登录以开始使用", + "loginToStart": "使用 IDIR 登录即可开始", + "login": "登录", + "createFormLabel": "创建表格", + "manageAccessTitle": "管理对表单的访问", + "manageAccessSub1": "CHEFS 允许您创建公共表单,或者您可以通过 IDIR 或 BCeID 身份验证管理访问。", + "manageAccessSub2": "您还可以为您的团队分配角色来管理您的所有提交内容。", + "createCustomFormTitle": "使用 CHEFS 表单生成器创建自定义表单", + "createCustomFormSub1": "借助 CHEFS,您可以通过直观的拖放界面创建安全的表单。您可以添加表单组件,重新排列它们,并将它们放入不同的布局配置中。", + "chefsHowToTitle": "厨师操作视频", + "chefsHowToSub": "我们的快速入门指南将向您介绍 CHEFS 的一些基本功能。", + "getStartedToChefs": "开始使用 CHEFS", + "createOnlineTitle": "创建在线表单以收集客户的信息并改进您的工作流程。", + "getStarted": "开始使用" + }, + "baseStepper": { + "setUpForm": "设置表格", + "designForm": "设计形式", + "manageForm": "管理表格" + }, + "create": { + "formSettings": "表单设置", + "disclaimer": "免责声明", + "disclaimerStmt": "我同意表单设计师的免责声明和责任声明", + "continue": "继续", + "back": "后退", + "confirmPageNav": "您真的要离开此页面吗?您所做的更改将不会被保存。", + "agreementErrMsg": "您必须同意上面显示的隐私免责声明。" + }, + "addTeamMember": { + "cantFindChefsUsers": "找不到人吗?他们可能没有登录 CHEFS。
请向他们发送 CHEFS 链接并要求他们登录。", + "cancel": "取消", + "add": "添加", + "mustSelectAUser": "您必须至少选择一个角色才能添加此用户。", + "addNewMember": "添加新成员", + "enterUsername": "输入姓名、电子邮件或用户名", + "enterExactUsername": "输入准确的电子邮件或用户名", + "BCeIDInputSearchMaxLen": "BCeID 用户名/电子邮件的搜索输入必须大于 6 个字符。", + "BCeIDMustBeExact": "BCeID 的电子邮件搜索必须准确。", + "errorGettingUsers": "获取用户时出错 {error}" + }, + "baseFilter": { + "cancel": "取消", + "columnName": "列名", + "exampleText": "示例文本", + "exampleText2": "示例文本2", + "filterPlaceholderTxt": "过滤占位符文本", + "filter": "筛选", + "value": "价值", + "resetColumns": "重置列" + }, + "formViewerActions": { + "viewMyDraftOrSubmissions": "查看我的草稿/提交内容", + "saveAsADraft": "另存为草稿", + "editThisDraft": "编辑本草稿", + "switchSingleSubmssn": "切换到单一提交", + "switchMultiSubmssn": "切换到多次提交" + }, + "baseCopyToClipboard": { + "linkToClipboard": "链接已复制到剪贴板", + "copyToClipboard": "复制到剪贴板", + "errCopyToClipboard": "尝试复制到剪贴板时出错。" + }, + "sucess": { + "sucessFormSubmissn": "您的表格已成功提交", + "keepRecord": "如果您希望保留本次提交的记录,您可以保留以下信息", + "confirmationId": "确认ID" + }, + "bcGovAlertBanner": { + "defaultErrMsg": "错误:出了点问题", + "error": "错误" + }, + "permissionUtils": { + "formNotAvailable": "该表格目前不可用。这可能是由于链接不正确,或者该表单可能已被其所有者删除。", + "missingFormIdAndSubmssId": "缺少 formId 和submissionId 的选项", + "loadingFormErrMsg": "加载此表单时发生错误。", + "loadingForm": "加载{options}时出错:{error}", + "idpHintMsg": "此表单需要 {idpHint} 身份验证。请重新登录并重试。", + "formIdpMissMatch": "表单 IDP 不匹配。表单需要 {idpHint},但用户有 {userIdp}。" + }, + "download": { + "chefsDataExport": "CHEFS 数据导出", + "preparingForDownloading": "正在准备下载...", + "downloadInfoA": "如果您的文件没有自动下载", + "downloadInfoB": "单击此处重试" + }, + "history": { + "submissnHistory": "您的提交历史记录(待定)" + }, + "error": { + "logout": "登出", + "somethingWentWrong": "错误:出了点问题...:(" + }, + "login": { + "authenticateWith": "通过以下方式进行身份验证:", + "alreadyLoggedIn": "已经登录", + "home": "家", + "about": "关于" + }, + "notFound": { + "about": "关于", + "pageNotFound": "404页面不存在。 :(" + }, + "store": { + "admin": { + "addFormOwnerRole": "已将此表单的所有者角色添加到 {fullName}", + "addRowError": "添加角色时出错。", + "addRowConsoleErr": "将用户 {userId} 添加到表单 {formId} 时出错:{error}", + "apiKeyDelMsg": "此表单的 API 密钥已被删除。", + "errDeletingApiKey": "尝试删除 API 密钥时发生错误。", + "consErrDeletingApiKey": "删除表单 {formId} 的 API 密钥时出错:{error}", + "fecthingFormsErrMsg": "获取表单时发生错误。", + "fecthingFormsConsErrMsg": "获取管理表单数据时出错:{error}", + "fecthingFormErrMsg": "获取此表单时发生错误。", + "fecthingFormConsErrMsg": "获取管理表单 {formId} 数据时出错:{error}", + "fecthFormUserRolesErrMsg": "获取表单用户角色时出错。", + "fecthFormUserRolesConsErrMsg": "获取管理员角色数据时出错:{error}", + "fecthApiDetailsErrMsg": "获取此表单的 API 详细信息时发生错误。", + "fecthApiDetailsConsErrMsg": "从表单 {formId} 数据获取管理 API 详细信息时出错:{error}", + "restoreFormErrMsg": "恢复此表单时出错。", + "restoreFormConsErrMsg": "恢复表单 {formId} 数据时出错:{error}", + "getUsersErrMsg": "获取用户时发生错误。", + "getUsersConsErrMsg": "获取管理员用户数据时出错:{error}", + "getUserErrMsg": "获取该用户时发生错误。", + "getUserConsErrMsg": "获取管理员用户 {userId} 数据时出错:{error}", + "storingFCHelpInfoErrMsg": "存储表单组件帮助信息时发生错误", + "storingFCHelpInfoConsErrMsg": "存储表单组件帮助信息时出错:{error}", + "gettingFCImgUrlErrMsg": "获取图片 url 时出错", + "gettingFCImgUrlConsErrMsg": "获取图像 URL 时出错:{error}", + "updatingFCStatusErrMsg": "更新发布状态时出错", + "updatingFCStatusConsErrMsg": "更新发布状态时出错:{error}", + "fecthingFormBuilderCompsErrMsg": "获取表单构建器组件时发生错误", + "fecthingFormBuilderCompsConsErrMsg": "获取表单生成器组件时出错:{error}" + }, + "form": { + "fetchEmailTemplatesConsErrMsg": "加载 {formId} 的电子邮件模板时出错:{error}", + "fetchEmailTemplatesErrMsg": "获取此表单的电子邮件模板时发生错误", + "getCurrUserFormsErrMsg": "获取您的表单时发生错误。", + "getCurrUserFormsConsErrMsg": "获取用户数据时出错:{error}", + "getUserFormPermErrMsg": "获取此表单的用户数据时发生错误。", + "getUserFormPermConsErrMsg": "使用 formID {formId} 获取用户数据时出错:{error}", + "getUserFormRolesErrmsg": "获取此表单的用户数据时发生错误。", + "getUserFormRolesConsErrmsg": "使用 formID {formId} 获取用户数据时出错:{error}", + "updCurrUserFormPrefErrMsg": "保存您对此表单的首选项时出错。", + "updCurrUserFormPrefConsErrMsg": "使用 formID {formId} 和首选项 {preferences} 更新用户表单首选项时出错:{error}", + "getCurrUserFormPrefErrMsg": "获取您对此表单的首选项时发生错误。", + "getCurrUserFormPrefConsErrMsg": "使用 formID {formId} 获取用户表单首选项时出错:{error}", + "delCurrformNotiMsg": "表单 {name} 已成功删除。", + "delCurrFormConsErMsg": "删除表单 {id} 时出错:{error}", + "delDraftErrMsg": "删除此草稿时发生错误。", + "delDraftConsErrMsg": "删除 {draftId} 时出错:{error}", + "fecthDraftErrMsg": "扫描此表单的草稿时出错。", + "fecthDraftConsErrMsg": "获取表单 {formId} 的草稿时出错:{error}", + "fecthFormErrMsg": "获取此表单时发生错误。", + "fecthFormConsErrMsg": "获取表单 {formId} 时出错:{error}", + "fetchFormFieldsErrMsg": "获取此表单的字段列表时出错。", + "fetchFormFieldsConsErrMsg": "获取表单 {formId} 时出错:{error}", + "publishDraftErrMsg": "发布时发生错误。", + "publishDraftConsErrMsg": "发布 {draftId} 时出错:{error}", + "toggleVersnPublConsErrMsg": "切换版本发布 {versionId} {publish} 时出错:{error}", + "updateEmailTemplateConsErrMsg": "更新表单 {formId} 的电子邮件模板时出错:{error}", + "updateEmailTemplateErrMsg": "更新此表单的电子邮件模板时出错。", + "updateFormErrMsg": "更新此表单的设置时出错。", + "updateFormConsErrMsg": "更新表单 {id} 时出错:{error}", + "deleteSubmissionNotifyMsg": "提交删除成功。", + "deleteSubmissionErrMsg": "删除此提交时发生错误。", + "deleteSubmissionConsErrMsg": "删除提交 {submissionId} 时出错:{error}", + "deleteSubmissionsNotifyMsg": "提交内容已成功删除。", + "deleteSubmissionsErrMsg": "删除选定的提交内容时出错。", + "deleteSubmissionsConsErrMsg": "删除提交时出错:{error}", + "restoreSubmissionsNotiMsg": "提交已成功恢复。", + "restoreSubmissionsErrMsg": "恢复此提交时发生错误。", + "restoreSubmissionsConsErrMsg": "恢复提交时出错:{error}", + "restoreSubmissionNotiMsg": "提交已成功恢复。", + "restoreSubmissionErrMsg": "恢复此提交时发生错误。", + "restoreSubmissionConsErrMsg": "恢复提交 {submissionId} 时出错:{error}", + "fecthSubmissnUsersErrMsg": "获取此提交的收件人电子邮件时出错。", + "fecthSubmissnUsersConsErrMsg": "获取提交 {formSubmissionId} 的收件人电子邮件时出错:{error}", + "fetchSubmissnErrMsg": "获取此提交时发生错误。", + "fetchSubmissnConsErrMsg": "获取提交 {submissionId} 时出错:{error}", + "fetchFormCSVExptFieldsErrMsg": "获取此表单的字段列表时出错。", + "fetchFormCSVExptFieldsConsErrMsg": "获取表单 {formId} 时出错:{error}", + "fetchSubmissnsErrMsg": "获取此表单的提交内容时发生错误。", + "fetchSubmissnsConsErrMsg": "获取 {formId} 的提交时出错:{error}", + "fetchVersionErrMsg": "获取此表单时发生错误。", + "fetchVersionConsErrMsg": "获取表单 {formId} 的版本 {versionId} 时出错:{error}", + "deleteApiKeyNotifyMsg": "此表单的 API 密钥已被删除。", + "deleteApiKeyErrMsg": "尝试删除 API 密钥时发生错误。", + "deleteApiKeyConsErrMsg": "删除表单 {formId} 的 API 密钥时出错:{error}", + "generateApiKeyNotifyMsg": "此表单的 API 密钥已创建。", + "generateApiKeyErrMsg": "尝试生成 API 密钥时发生错误。", + "generateApiKeyConsErrMsg": "为表单 {formId} 生成 API 密钥时出错:{error}", + "readApiKeyErrMsg": "尝试获取 API 密钥时发生错误。", + "readApiKeyConsErrMsg": "获取表单 {formId} 的 API 密钥时出错:{error}。", + "getFCPHImageUrlErrMsg": "获取图片 url 时出错", + "getFCPHImageUrlConsErrMsg": "获取图像 URL 时出错:{error}", + "listFCPHErrMsg": "获取表单构建器组件时发生错误", + "listFCPHConsErrMsg": "获取表单生成器组件时出错:{error}", + "downloadFileErrMsg": "下载文件时发生错误", + "downloadFileConsErrMsg": "下载文件时出错:错误", + "readSubscriptionSettingsErrMsg": "尝试获取订阅设置时出错。", + "readSubscriptionSettingsConsErrMsg": "获取表单 {formId} 的订阅设置时出错:{error}。", + "saveSubscriptionSettingsNotifyMsg": "此表单的订阅设置已保存。", + "saveSubscriptionSettingsErrMsg": "尝试保存订阅设置时出错。", + "saveSubscriptionSettingsConsErrMsg": "保存表单 {formId} 的订阅设置时出错:{error}" + } + }, + "admin": { + "root": { + "admin": "行政" + }, + "form": { + "administerForm": "管理表格" + }, + "user": { + "administerUser": "管理用户" + } + }, + "user": { + "root": { + "myForms": "我的表格", + "history": "历史", + "user": "用户" + } + } +} diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/zhTW/index.js b/frontend/app/frontend/src/internationalization/trans/chefs/zhTW/index.js new file mode 100644 index 0000000..65b226f --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/zhTW/index.js @@ -0,0 +1,4 @@ +import zhTW from '~/internationalization/trans/chefs/zhTW/zh-TW.json'; +export default { + trans: zhTW, +}; diff --git a/frontend/app/frontend/src/internationalization/trans/chefs/zhTW/zh-TW.json b/frontend/app/frontend/src/internationalization/trans/chefs/zhTW/zh-TW.json new file mode 100644 index 0000000..b7021bc --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/chefs/zhTW/zh-TW.json @@ -0,0 +1,995 @@ +{ + "date": { + "date": "年-月-日" + }, + "emailManagement": { + "emailManagement": "電子郵件管理", + "manageForm": "管理表格", + "submissionConfirmation": "提交確認" + }, + "emailTemplate": { + "body": "身體", + "save": "節省", + "saveEmailTemplateConsoleErrMsg": "更新表單 {formId} 的電子郵件模板時出錯:{error}", + "saveEmailTemplateErrMsg": "嘗試更新電子郵件模板時發生錯誤。", + "subject": "主題", + "title": "標題", + "validBodyRequired": "請輸入電子郵件正文", + "validSubjectRequired": "請輸入電子郵件的主題行", + "validTitleRequired": "請輸入電子郵件的標題" + }, + "formsTable": { + "myForms": "我的表格", + "createNewForm": "創建新表單", + "search": "搜索", + "manage": "管理", + "submissions": "意見書", + "formTitle": "表格標題", + "viewForm": "查看表格", + "description": "描述", + "Description": "描述:", + "action": "行動", + "loadingText": "加載請稍候" + }, + "manageLayout": { + "manageForm": "管理表格" + }, + "shareForm": { + "shareForm": "分享表格", + "shareLink": "分享鏈接", + "copyQRCode": "複製下面的鏈接或下載二維碼。", + "warningMessage": "目前該表格還沒有發布版本。在發布版本之前,將無法訪問下面的鏈接。", + "openThisForm": "打開此表格", + "downloadQRCode": "下載二維碼", + "close": "關閉", + "copyURLToClipboard": "將 URL 複製到剪貼板" + }, + "preview": { + "preview": "預覽", + "previewToolTip": "這顯示了提交者將看到的表單版本設計和行為的預覽。您無法從此頁面提交表格。" + }, + "manageFormActions": { + "emailManagement": "電子郵件管理", + "viewSubmissions": "查看提交內容", + "teamManagement": "團隊管理", + "deleteForm": "刪除表格", + "confirmDeletion": "確認刪除", + "deleteMessageA": "您確定要刪除嗎", + "deleteMessageB": "此表格將不再可用。", + "delete": "刪除" + }, + "manageForm": { + "formSettings": "表單設置", + "apiKey": "API密鑰", + "updated": "更新", + "created": "已創建", + "formDesignHistory": "表單設計歷史", + "totalVersions": "總版本", + "status": "地位", + "update": "更新", + "cancel": "取消", + "eventSubscription": "活動訂閱" + }, + "formSettings": { + "pressToAddMultiEmail": "按Enter,空格鍵添加多個電子郵件地址", + "allowMultiDraft": "允許上傳多個草稿", + "formTitle": "表格標題", + "formDescription": "表格說明", + "formAccess": "表格訪問", + "info": "如果您將使用此表格向公眾收集有關公眾普遍感興趣的主題的信息,您需要聯繫 GCPE,以便將您的參與情況列在", + "important": "重要的", + "idimNotifyA": "您必須通過電子郵件通知身份信息管理 (IDIM) 團隊", + "idimNotifyB": "您打算利用 BCeID 來驗證表單提交者的身份。", + "referenceGuideA": "請參考我們的", + "referenceGuideB": "用戶指南", + "referenceGuideC": "更多細節", + "specificTeamMembers": "具體團隊成員", + "formFunctionality": "表單功能", + "formSubmissinScheduleMsg": "表單發布後,表單提交計劃將在表單設置中可用。", + "formSubmissionsSchedule": "表格提交時間表", + "experimental": "實驗性的", + "learnMore": "了解更多", + "afterSubmission": "提交後", + "submissionConfirmation": "顯示提交確認詳細信息", + "theConfirmationID": "確認 ID", + "infoB": "用戶可以通過電子郵件向自己發送提交確認的選項", + "loginRequired": "要求登錄", + "canSaveAndEditDraftLabel": "提交者可以保存和編輯草稿", + "canUpdateStatusAsReviewer": "審閱者可以更新此表單的狀態(即已提交、已分配、已完成)", + "submitterCanCopyExistingSubmissn": "提交者可以複製現有提交", + "submissionConfirmationToolTip": "選擇此選項可控制此表單的提交用戶在成功提交後將看到的內容。
如果勾選的話會顯示", + "emailNotificatnToTeam": "向我的團隊發送通知電子郵件", + "emailNotificatnToTeamToolTip": "當任何用戶提交此表單時,向您指定的電子郵件地址發送通知", + "notificationEmailAddrs": "通知電子郵件地址", + "addMoreValidEmailAddrs": "添加一個或多個有效電子郵件地址", + "formScheduleSettings": "表格時間表設置", + "opensubmissions": "開放提交", + "submissionsDeadline": "您希望多長時間收到提交的材料?", + "keepSubmissnOpenTilUnplished": "保持打開狀態直至手動取消發布", + "submissionsClosingDate": "安排截止日期", + "submissionPeriod": "設置提交期限", + "closeSubmissions": "關閉提交", + "keepOpenFor": "保持開放狀態", + "period": "時期", + "allowLateSubmissions": "允許逾期提交", + "allowLateSubmissionsInfoTip": "如果選中,提交者將能夠在截止日期之後提交數據。", + "afterCloseDateFor": "截止日期後", + "repeatPeriod": "重複週期", + "every": "每一個", + "repeatUntil": "重複直到", + "summary": "概括", + "submissionsOpenDateRange": "此表格將開放供提交", + "to": "到", + "scheduleRepetition": "該時間表將重複每個", + "allowLateSubmissnInterval": "允許延遲提交", + "until": "直到", + "datesOfSubmissnInfo": "根據設置,這些是可用的提交日期:", + "formOpenInterval": "此表格將開放供提交", + "allowDateSubmissionDate": "允許延遲提交,直到", + "customClosingMessage": "設置自定義結束消息", + "customClosingMessageToolTip": "允許您在用戶訪問關閉表單時為其添加自定義消息。", + "closingMessage": "結束語", + "sendReminderEmail": "發送提醒電子郵件", + "autoReminderNotificatn": "啟用自動提醒通知", + "autoReminderNotificatnToolTip": "在提交期間發送帶有表單鏈接的提醒電子郵件。", + "selectLoginType": "請選擇 1 種登錄類型", + "formDescriptnMaxChars": "表單描述不得超過 255 個字符", + "formTitlemaxChars": "表單標題不得超過 255 個字符", + "formTitleReq": "表格標題為必填項", + "atLeastOneEmailReq": "請輸入至少 1 個電子郵件地址", + "validEmailRequired": "請輸入所有有效的電子郵件地址", + "fieldRequired": "此字段是必需的。", + "correctDateFormat": "日期格式必須正確。 IE。年-月-日", + "dateDiffMsg": "關閉提交日期應晚於開放提交日期。", + "valueMustBeNumber": "值必須是數字。 IE。 1,2,3,5,99", + "selectAnOptions": "請至少選擇 1 個選項", + "validInterval": "這應該是一個有效的間隔。", + "fieldRequiredAndInterval": "該字段是必需的並且應該是一個間隔。", + "dateGrtOpenSubmissnDate": "重複直到日期應大於開放提交日期", + "public": "公開(匿名)", + "allowEventSubscription": "允許事件訂閱", + "eventSubscription": "活動訂閱", + "validEndpointRequired": "請輸入以以下開頭的有效端點 https://", + "validBearerTokenRequired": "輸入有效的不記名令牌示例: 89abddfb-2cff-4fda-83e6-13221f0c3d4f" + }, + "subscribeEvent": { + "eventType": "事件類型", + "endpointUrl": "端點 URL", + "eventSubmission": "提交", + "eventAssignment": "任務", + "eventStatusChange": "狀態改變", + "endpointToken": "端點令牌", + "urlPlaceholder": "https://endpoint.gov.bc.ca/api/v1/", + "save": "節省", + "text": "文本", + "password": "密碼", + "hideSecret": "隱藏秘密", + "showSecret": "顯示秘密", + "key": "鑰匙", + "saveSettingsErrMsg": "嘗試更新此表單的設置時發生錯誤。", + "updateSettingsConsoleErrMsg": "更新表單 {formId} 的設置時出錯:{error}" + }, + "apiKey": { + "disclaimer": "免責聲明", + "infoA": "確保您的 API 密鑰秘密存儲在安全位置(即密鑰保管庫)。", + "infoB": "您的 API 密鑰可以不受限制地訪問您的表單。請勿將您的 API 密鑰透露給任何人。", + "infoC": "API 密鑰只能用於自動化系統交互。請勿使用您的 API 密鑰進行基於用戶的訪問", + "deleteKey": "刪除鍵", + "apiKey": "API密鑰", + "hideSecret": "隱藏秘密", + "showSecret": "顯示秘密", + "sCTC": "秘密已復製到剪貼板", + "cSTC": "將機密複製到剪貼板", + "key": "鑰匙", + "confirmDeletion": "確認刪除", + "deleteMsg": "您確定要刪除您的 API 密鑰嗎?", + "delete": "刪除", + "confirmKeyGen": "確認密鑰生成", + "createAPIKey": "為此表單創建 API 密鑰?
確保您遵循本頁上的免責聲明。", + "regenerateAPIKey": "重新生成 API 密鑰?
繼續將刪除您當前的 API 密鑰訪問權限。", + "formOwnerKeyAcess": "您必須是表單所有者才能管理 API 密鑰。", + "regenerate": "再生", + "generate": "產生", + "secret": "秘密" + }, + "manageVersions": { + "important": "重要的!", + "infoA": "如果沒有已發布的版本,則在分配已發布的版本之前,用戶無法訪問此表單。版本發布後,該版本將不再可編輯。您必須基於以前的表單版本之一創建新版本才能繼續編輯。", + "infoB": "注:只能發布一個版本。", + "version": "版本", + "draft": "草稿", + "clickToPreview": "點擊預覽", + "editVersion": "編輯版本", + "exportDesign": "出口設計", + "infoC": "請在開始新版本之前發布或刪除您的最新草稿版本。", + "deleteVersion": "刪除版本", + "draftAlreadyExists": "草稿已經存在", + "infoD": "請在開始新草稿之前編輯、發布或刪除現有草稿。", + "publishVersion": "發布版本", + "unpublishVersion": "取消發布版本", + "infoE": "取消發布此表格將使該表格停止流通,直到再次發布版本。", + "confirmDeletion": "確認刪除", + "infoF": "您確定要刪除此版本嗎?", + "delete": "刪除", + "status": "地位", + "dateCreated": "創建日期", + "createdBy": "由...製作", + "actions": "行動", + "published": "已發表", + "unpublished": "未發表", + "useVersionInfo": "使用版本 {version} 作為新版本的基礎", + "publishingVersionInfo": "這將使您的表單的版本 {version} 生效。" + }, + "addOwner": { + "infoA": "僅噹噹前表單所有者不再活躍或在優先事件中失去聯繫時才應執行此操作。否則,請讓表單的當前所有者或團隊管理員自行執行此操作。", + "hint": "要查找所需的用戶 ID,您可以轉到管理門戶中的“用戶”選項卡並蒐索它們。", + "addowner": "添加所有者", + "label": "用戶ID(引導)" + }, + "adminFormsTable": { + "showDeletedForms": "顯示已刪除的表單", + "search": "搜索", + "loadingText": "加載文本", + "noDataText": "您的系統中沒有表格", + "admin": "行政", + "launch": "發射", + "formTitle": "表格標題", + "created": "已創建", + "deleted": "已刪除", + "actions": "行動", + "delete": "刪除" + }, + "administerForm": { + "deleted": "已刪除", + "restoreForm": "恢復此表格", + "formDetails": "表格詳情", + "apiKeyDetails": "API 密鑰詳細信息", + "deleteApiKey": "刪除API密鑰", + "formUsers": "表單用戶", + "formVersions": "表單版本", + "assignANewOwner": "指定新所有者", + "restoring": "正在恢復", + "restore": "恢復", + "toActiveState": "到活動狀態", + "confirmDeletion": "確認刪除", + "confirmDeletionMsg": "您確定要刪除此 API 密鑰嗎?", + "delete": "刪除", + "confirmRestore": "確認恢復" + }, + "administerUser": { + "userDetails": "用戶詳細信息", + "openSSOConsole": "打開 SSO 控制台" + }, + "adminPage": { + "forms": "形式", + "users": "用戶", + "developer": "開發商", + "infoLinks": "信息鏈接", + "metrics": "指標" + }, + "adminUsersTable": { + "search": "搜索", + "loadingText": "加載請稍候", + "admin": "行政", + "fullName": "全名", + "userID": "用戶身份", + "created": "已創建", + "actions": "行動" + }, + "adminVersions": { + "exportDesign": "出口設計", + "versions": "版本", + "status": "地位", + "created": "已創建", + "lastUpdated": "最近更新時間", + "actions": "行動", + "published": "已發表", + "unpublished": "未發表", + "version": "版本 {versionNo}", + "notificationMsg": "加載表單設計時出錯。" + }, + "developer": { + "user": "用戶", + "name": "姓名", + "userName": "用戶名", + "JWTContents": "智威湯遜內容", + "JWTContentsSBTxt": "JWT 內容已復製到剪貼板", + "JWTContentsTTTxt": "將 JWT 內容複製到剪貼板", + "JWTToken": "智威湯遜令牌", + "JWTTokenSBTxt": "JWT 令牌已復製到剪貼板", + "JWTTokenTTTxt": "將 JWT 令牌複製到剪貼板", + "chefsAPI": "廚師API", + "RBACSBTxt": "RBAC 響應已復製到剪貼板", + "RBACTTTxt": "將 RBAC 響應複製到剪貼板", + "notificationMsg": "無法從 RBAC 獲取用戶,請參閱控制台", + "notificationConsErr": "從 RBAC 獲取用戶時出錯" + }, + "baseAuthButton": { + "logout": "登出", + "login": "登錄" + }, + "baseDialog": { + "defaultText": "默認文本", + "ok": "好的", + "continue": "繼續", + "cancel": "取消", + "custom": "風俗" + }, + "baseSecure": { + "about": "關於", + "loginInfo": "您必須先登錄才能使用此功能。", + "login": "登錄", + "401NotAuthorized": "401:未授權。 :", + "401ErrorMsg": "您的帳戶設置不正確。
請聯繫", + "403Forbidden": "403:禁止。 :", + "403ErrorMsg": "此頁面需要 {idp} 身份驗證。", + "401UnAuthorized": "401:未經授權。 :", + "401UnAuthorizedErrMsg": "您沒有權限訪問此頁面。" + }, + "formDesigner": { + "formDesign": "表格設計", + "exportDesign": "出口設計", + "importDesign": "導入設計", + "important": "重要的", + "formDesignInfoA": "完成此表單的構建後,請使用“保存設計”按鈕。", + "formDesignInfoB": "提交按鈕供您的用戶提交此表單,並將在保存後激活。", + "formLoadErrMsg": "加載表單設計時出錯。", + "formLoadConsoleErrMsg": "加載表單 {formId} 架構時出錯(版本:{versionId} 草稿:{draftId}):{error}", + "formSchemaImportErrMsg": "導入表單架構時發生錯誤。", + "formSchemaImportConsoleErrMsg": "導入表單架構時出錯:{error}", + "formDesignSaveErrMsg": "嘗試保存此表單設計時發生錯誤。如果您需要刷新或稍後重試,可以導出頁面上的現有設計以保存供以後使用。", + "formDesignSaveConsoleErrMsg": "更新或創建表單時出錯(FormID:{formId},versionId:{versionId},draftId:{draftId})錯誤:{error}", + "collapse": "坍塌", + "actions": "行動", + "version": "版本", + "save": "節省", + "saving": "保存", + "notSaved": "未保存", + "fieldnameError": "您不能使用“form”關鍵字作為 {label} 字段名" + }, + "formViewerMultiUpload": { + "important": "重要的", + "uploadSucessMsg": "為確保成功上傳多個草稿,請下載並使用提供的模板。", + "confirmDownload": "您想下載嗎?", + "jsonFileUpload": "選擇要上傳的 JSON 文件", + "dragNDrop": "或將其拖放到此處", + "chooseAFile": "選擇一個文件", + "downloadDraftSubmns": "請下載提交報告草稿並確保數據輸入正確。", + "downloadReport": "下載報告", + "doYouWantToDownload": "您想下載嗎?", + "uploadNewFile": "上傳新文件", + "uploadMultipleFileErr": "抱歉,您只能上傳一個文件", + "dragMultipleFileErr": "抱歉,您只能拖動一個文件", + "fileFormatErr": "抱歉,我們只接受 json 文件", + "fileSizeErr": "允許的最大文件大小為 5MB", + "parseJsonErr": "我們無法從文件中解析 json 數據", + "jsonObjNotArray": "json 文件格式錯誤", + "jsonObjNotArrayConsErr": "一個意料之外的問題發生了。", + "jsonArrayEmpty": "該 json 文件是空的。", + "errorWhileValidate": "這個文件有問題", + "errWhileCheckValidity": "這個文件有問題", + "errAfterValidate": "發現一些錯誤,請參閱下文了解更多信息。", + "fileIsEmpty": "該文件是空的。", + "download": "下載" + }, + "formDisclaimer": { + "disclaimerAndStatement": "表單設計者的免責聲明和責任聲明:", + "privacyLaw": "您有責任遵守有關收集、使用和披露個人身份信息的隱私法。", + "disclosure": "訪問此表單設計器工具本身並不授予收集、使用或披露任何個人身份信息的權限。", + "consent": "您有責任按照法律要求獲得同意收集信息。", + "formIntention": "在發布或分發您的表格之前,您需要與您的同事討論該表格的意圖。", + "privacyOfficer": "部隱私官員", + "assement": "並按要求完成評估。" + }, + "requestReceipt": { + "emailPriority": "電子郵件優先", + "emailReceipt": "通過電子郵件發送此提交的收據", + "high": "高的", + "low": "低的", + "normal": "普通的", + "send": "發送", + "sendToEmailAddress": "發送至電子郵件地址", + "emailSent": "一封電子郵件已發送至 {to}。", + "sendingEmailErrMsg": "嘗試發送您的電子郵件時發生錯誤。", + "sendingEmailConsErrMsg": "向 {to} 發送電子郵件確認失敗:{error}", + "emailRequired": "電子郵件為必填項" + }, + "submissionsTable": { + "noMatchingRecordText": "未找到匹配的記錄", + "submissions": "意見書", + "submissionsTable": "提交表", + "selectColumns": "選擇列", + "manageForm": "管理表格", + "submissionsToFiles": "將提交內容導出到文件", + "showDeletedSubmissions": "顯示已刪除的提交", + "showMySubmissions": "顯示我的提交內容", + "search": "搜索", + "loadingText": "加載請稍候", + "noDataText": "沒有提交此表格", + "delSelectedSubmissions": "刪除選定的提交內容", + "resSelectedSubmissions": "恢復選定的提交", + "yes": "是的", + "no": "不", + "viewSubmission": "查看提交內容", + "deleteSubmission": "刪除提交內容", + "restore": "恢復", + "confirmDeletion": "確認刪除", + "delete": "刪除", + "confirmRestoration": "確認恢復", + "searchSubmissionFields": "搜索提交字段", + "save": "節省", + "searchTitle": "搜索並選擇要在儀表板下顯示的列", + "status": "地位", + "submitter": "提交者", + "submissionDate": "提交日期", + "event": "事件", + "view": "看法", + "lateSubmission": "遲交", + "confirmationID": "確認ID", + "multiDelWarning": "您確定要刪除選定的提交內容嗎?", + "singleDelWarning": "您確定要刪除此提交嗎?", + "multiRestoreWarning": "您確定要恢復這些提交嗎?", + "singleRestoreWarning": "您確定要恢復此提交嗎?" + }, + "auditHistory": { + "viewEditHistory": "查看編輯歷史記錄", + "editHistory": "編輯歷史記錄", + "auditLogMsg": "這是一份審核日誌,記錄了在原始提交之後誰對此提交進行了更改。", + "loadingText": "加載請稍候", + "close": "關閉", + "userName": "用戶名", + "date": "日期", + "errorMsg": "嘗試獲取歷史記錄時發生錯誤。", + "consoleErrMsg": "獲取審核歷史記錄時出錯" + }, + "deleteSubmission": { + "deleteThis": "刪除這個", + "draft": "草稿", + "submission": "提交", + "confirmDeletion": "確認刪除", + "deleteWarning": "您確定要刪除此內容嗎", + "drafts": "草稿", + "formSubmission": "表單提交", + "delete": "刪除" + }, + "manageSubmissionUsers": { + "manageTeamMembers": "管理團隊成員", + "add": "添加", + "draftFormInvite": "當此表單為草稿時,您只能邀請和管理團隊成員", + "submissionTeamMembers": "本次提交的團隊成員", + "actions": "行動", + "close": "關閉", + "remove": "消除", + "userNotFoundErrMsg": "找不到人嗎?他們可能沒有登錄 CHEFS。
請向他們發送 CHEFS 鏈接並要求他們登錄。", + "name": "姓名", + "username": "用戶名", + "email": "電子郵件", + "removeUserWarningMsg1": "您確定要刪除嗎", + "removeUserWarningMsg2": "他們將不再擁有此提交的權限。", + "userExistInListMsg": "用戶 {username} 已在團隊成員列表中。", + "getSubmissionUsersErr": "嘗試獲取此提交的用戶時發生錯誤。", + "getSubmissionUsersConsoleErr": "獲取 {submissionId} 的用戶時出錯:{error}", + "sentInviteEmailTo": "已發送邀請電子郵件至", + "sentUninvitedEmailTo": "發送了未經邀請的電子郵件至", + "updateUserErrMsg": "嘗試更新此提交的用戶時出錯。", + "updateUserConsoleErrMsg": "設置用戶權限時出錯。子:{submissionId} 用戶:{userId} 錯誤:{error}", + "searchInputLength": "BCeID 用戶名/電子郵件的搜索輸入必須大於 6 個字符。", + "exactBCEIDSearch": "BCeID 的電子郵件搜索必須準確。", + "getUsersErrMsg": "獲取用戶時出錯:{error}", + "exactEmailOrUsername": "輸入準確的電子郵件或用戶名。", + "requiredFiled": "輸入姓名、電子郵件或用戶名" + }, + "mySubmissionsActions": { + "viewThisSubmission": "查看此提交內容", + "copyThisSubmission": "複製此提交內容", + "editThisDraft": "編輯本草稿" + }, + "mySubmissionsTable": { + "noMatchingRecordText": "未找到匹配的記錄", + "previousSubmissions": "以前提交的內容", + "selectColumns": "選擇列", + "createNewSubmission": "創建新提交", + "search": "搜索", + "loadingText": "加載請稍候", + "noDataText": "您還沒有提交內容", + "searchSubmissionFields": "搜索提交字段", + "save": "節省", + "filterTitle": "搜索並選擇要在儀表板下顯示的列", + "confirmationId": "確認編號", + "actions": "行動", + "createdBy": "由...製作", + "statusUpdatedBy": "狀態更新者", + "status": "地位", + "submissionDate": "提交日期", + "draftUpdatedBy": "草稿更新者", + "draftLastEdited": "最後編輯的草稿", + "createLateSubmissn": "創建延遲提交", + "formLoading": "表格正在加載中,請稍候!!!", + "pleaseConfirm": "請確認", + "wantToSaveDraft": "您想保存草稿嗎?", + "yes": "是的", + "no": "不", + "multiDraftUploadSuccess": "您的多草稿上傳已成功!", + "failedResSubmissn": "提交端點響應失敗。響應代碼:{status}", + "errSubmittingForm": "提交此表單時出錯", + "errorSavingFile": "保存文件時出錯。文件名:{fileName}。錯誤:{error}", + "submittingDraftErrMsg": "保存草稿時出錯", + "submittingDraftConsErrMsg": "保存草稿時出錯。提交 ID:{submissionId}。錯誤:{error}" + }, + "notesPanel": { + "addNewNote": "添加新註釋", + "cancel": "取消", + "addNote": "添加註釋", + "noResponseErr": "提交表單時 API 沒有響應數據", + "errorMesg": "嘗試添加註釋時發生錯誤。", + "consoleErrMsg": "添加註釋時出錯:", + "fetchErrMsg": "嘗試獲取此提交的註釋時發生錯誤。", + "fetchConsoleErrMsg": "添加註釋時出錯:", + "notes": "筆記", + "note": "筆記", + "maxChars": "最多 4000 個字符" + }, + "statusPanel": { + "currentStatus": "當前狀態:", + "assignedTo": "分配給:", + "assignOrUpdateStatus": "分配或更新狀態", + "display": "展示", + "statusIsRequired": "狀態為必填項", + "assignTo": "分配給", + "noDataText": "通過搜索未找到表單審閱者。在管理頁面添加表單審閱者。", + "assigneeIsRequired": "受讓人為必填項", + "assignToMe": "分配給我", + "recipientEmail": "收件人電子郵件", + "attachCommentToEmail": "將評論附加到電子郵件", + "emailComment": "電子郵件評論", + "maxChars": "最多 4000 個字符", + "viewHistory": "查看歷史記錄", + "statusHistory": "狀態歷史記錄", + "close": "關閉", + "addNoteNoReponserErr": "提交狀態更新註釋時沒有來自 API 的響應數據", + "addNoteConsoleErrMsg": "更新狀態時出錯:{error}", + "addNoteErrMsg": "嘗試更新狀態時發生錯誤", + "updtSubmissionsStatusErr": "提交狀態更新表單時沒有來自 API 的響應數據", + "noStatus": "無狀態", + "noStatusesFound": "未找到狀態", + "statusCodesErr": "查找狀態代碼時出錯", + "notifyErrorCode": "獲取此提交的狀態時發生錯誤。", + "notifyConsoleErrorCode": "獲取狀態時出錯:", + "fetchSubmissionUsersErr": "嘗試獲取此提交的收件人電子郵件時發生錯誤。", + "fetchSubmissionUsersConsErr": "獲取收件人電子郵件時出錯", + "assignSubmissnToFormReviewer": "提交的內容可以分配給表單審閱者。
要將更多團隊成員添加為表單審閱者,請轉到此表單的管理頁面。", + "update": "更新", + "revise": "修訂", + "complete": "完全的", + "assign": "分配" + }, + "statusTable": { + "loadingText": "加載請稍候", + "status": "地位", + "dateStatusChanged": "狀態更改日期", + "assignee": "受讓人", + "updatedBy": "更新者", + "getSubmissionStatusErr": "嘗試獲取狀態時發生錯誤。", + "getSubmissionStatusConsErr": "添加註釋時出錯:" + }, + "exportSubmissions": { + "exportSubmissionsToFile": "將提交內容導出到文件", + "viewSubmissions": "查看提交內容", + "fileType": "文件類型", + "json": "JSON", + "csv": "CSV", + "formVersion": "表格版本", + "versionIsRequired": "版本為必填項。", + "dataFields": "數據字段", + "searchFields": "搜索字段", + "selectedForExports": "選定用於出口", + "submissionDate": "提交日期", + "all": "全部", + "selectDateRange": "選擇日期範圍", + "SelectdateRange": "選擇日期範圍", + "from": "從", + "to": "到", + "CSVFormat": "CSV 格式", + "multiRowPerSubmissionA": "1 - 每次提交多行,帶有縮進空間", + "multiRowPerSubmissionB": "2 - 每次提交多行", + "singleRowPerSubmission": "3 - 每次提交單行", + "unformatted": "4 - 未格式化", + "fileNameAndType": "文件名和類型", + "export": "出口", + "noResponseDataErr": "exportSubmissions 調用沒有響應任何數據", + "apiCallErrorMsg": "嘗試導出此表單的提交內容時出錯。", + "apiCallConsErrorMsg": "導出提交時出錯", + "selectAllFields": "選擇所有字段", + "emailSentMsg": "準備好後,系統將向 {email} 發送一封電子郵件,其中包含下載數據的鏈接", + "exportInProgress": "導出正在進行中", + "of": "的" + }, + "printOptions": { + "submitButtonTxt": "提交至 CDOGS 並下載", + "templatePrint": "模板打印", + "uploadTemplateFile": "上傳模板文件", + "downloadOptions": "下載選項", + "print": "打印", + "browserPrint": "瀏覽器打印", + "pageFromBrowser": "您瀏覽器中的頁面", + "uploadA": "上傳一個", + "uploadB": "有一個結構化版本", + "docGrnSucess": "文檔生成成功", + "failedDocGenErrMsg": "生成文檔失敗", + "failedDocGenConsErrMsg": "提交模板時出錯:{error}", + "cDogsTemplate": "CDOGS 模板" + }, + "proactiveHelpDialog": { + "componentInfoLink": "組件信息鏈接", + "learnMoreLinkTxt": "了解更多鏈接字段不能為空。", + "largeImgTxt": "大圖像。圖片大小不能大於 0.5mb", + "componentName": "組件名稱:", + "learnMoreLink": "了解更多鏈接:", + "clickToEnableLink": "單擊以啟用鏈接", + "clickToDisableLink": "單擊以禁用鏈接", + "imageUpload": "圖片上傳:", + "cancel": "取消", + "save": "節省", + "description": "描述" + }, + "proactiveHelpPreviewDialog": { + "learnMore": "了解更多" + }, + "preview": { + "preview": "預覽", + "previewToolTip": "這顯示了提交者將看到的表單版本設計和行為的預覽。您無法從此頁面提交表格。" + }, + "generalLayout": { + "loadingText": "加載請稍候", + "preview": "預覽", + "published": "已發表", + "unpublished": "未發表", + "edit": "編輯", + "formTitle": "表格標題", + "actions": "行動" + }, + "formSubmission": { + "editThisSubmission": "編輯本次提交", + "submission": "提交", + "alertInfo": "編輯後,重新提交表單以保存更改。", + "viewAllSubmissions": "查看所有提交內容", + "submitted": "已提交:", + "confirmationID": "確認ID:", + "submittedBy": "由...所提交:", + "cancel": "取消", + "status": "地位", + "updatedAt": "修改的", + "updatedBy": "修改者" + }, + "teamManagement": { + "noMatchingRecordText": "未找到匹配的記錄", + "teamManagement": "團隊管理", + "selectColumns": "選擇列", + "manageForm": "管理表格", + "search": "搜索", + "loadingText": "加載請稍候", + "noDataText": "無法加載團隊角色數據", + "removeSelectedUsers": "刪除選定的用戶", + "removeThisUser": "刪除該用戶", + "confirmRemoval": "確認刪除", + "remove": "消除", + "searchTeamManagementFields": "搜索團隊管理領域", + "save": "節省", + "teamMebersTitle": "搜索並選擇要在儀表板下顯示的列", + "fullName": "全名", + "username": "用戶名", + "identityProvider": "身份提供者", + "delSelectedMembersWarning": "您確定要刪除選定的成員嗎?", + "delSelectedMemberWarning": "您確定要刪除所選成員嗎?", + "idpMessage": "已經在團隊中了。", + "formOwnerErrMsg": "必須始終至少有一個表單所有者", + "formOwnerConsoleErrMsg": "無法刪除 {userId},因為他們是此表單的唯一剩餘所有者。", + "insufficientPermissnMsg": "沒有足夠的權限來管理團隊", + "getUserErrMsg": "獲取表單用戶時出錯:", + "getRolesErrMsg": "獲取角色列表時出錯:", + "formOwnerRemovalWarning": "無法刪除,因為他們是此表單的唯一剩餘所有者。", + "removeUsersErrMsg": "嘗試刪除所選用戶時出錯", + "removeUserConsoleErrMsg": "從表單 {formId} 刪除用戶時出錯:{error}", + "updUserRolesErrMsg": "嘗試更新所有用戶角色時發生錯誤", + "updUserRolesConsoleErrMsg": "設置表單 {formId} 的所有用戶角色時出錯:{error}", + "setUserFormsErrMsg": "嘗試更新用戶的角色時發生錯誤", + "setUserFormsConsoleErrMsg": "設置表單 {formId} 的用戶角色時出錯:{error}" + }, + "floatButton": { + "publish": "發布", + "manage": "管理", + "redo": "重做", + "undo": "撤消", + "preview": "預覽", + "bottom": "底部", + "top": "頂部", + "actions": "行動", + "collapse": "坍塌", + "saved": "已保存", + "save": "節省", + "saving": "保存", + "notSaved": "未保存" + }, + "formViewer": { + "lateFormSubmissions": "表格提交期限已過!您仍然可以通過單擊下面的按鈕來創建延遲提交。", + "createLateSubmission": "創建延遲提交", + "draftSaved": "草稿已保存", + "saving": "保存", + "pleaseConfirm": "請確認", + "submitFormWarningMsg": "您確定要提交表格嗎?", + "submit": "提交", + "wantToSaveDraft": "您想保存草稿嗎?", + "version": "版本:{version}", + "formScheduleExpireMessage": "由於預定的提交期限已過,因此無法提交表格。", + "getUsersSubmissionsErrMsg": "獲取此表單的提交內容時發生錯誤", + "getUsersSubmissionsConsoleErrMsg": "加載表單提交數據 {submissionId} 時出錯:{error}", + "multiDraftUploadSuccess": "您的多草稿上傳已成功!", + "readVersionErrMsg": "沒有響應架構。版本 ID:{versionId}", + "readDraftErrMsg": "沒有響應架構。草稿 ID:{draftId}", + "alertRouteMsg": "表單所有者尚未發布該表單,且不可提交。", + "fecthingFormErrMsg": "獲取此表單時發生錯誤", + "fecthingFormConsoleErrMsg": "加載表單架構 {versionId} 時出錯:{error}", + "savingDraftErrMsg": "保存草稿時出錯", + "savingDraftConsoleErrMsg": "保存草稿時出錯。提交 ID:{submissionId}。錯誤:{error}", + "submissionsPreviewAlert": "表單預覽期間禁用提交", + "submissionsSubmitErrMsg": "提交表單時出錯:{errors}", + "sendSubmissionErrMsg": "提交端點響應失敗。響應代碼:{status}", + "errMsg": "提交此表單時出錯", + "customEventAlert": "尚不支持自定義按鈕事件。事件類型:{event}", + "formLoading": "表格正在加載中,請稍候!!!", + "yes": "是的", + "no": "不", + "failedResSubmissn": "提交端點響應失敗。響應代碼:{status}", + "errSubmittingForm": "提交此表單時出錯", + "errorSavingFile": "保存文件時出錯。文件名:{fileName}。錯誤:{error}", + "submittingDraftErrMsg": "保存草稿時出錯", + "submittingDraftConsErrMsg": "保存草稿時出錯。提交 ID:{submissionId}。錯誤:{error}", + "formDraftAccessErrMsg": "請求的提交已提交,正在重定向到查看頁面" + }, + "bCGovFooter": { + "home": "家", + "about": "關於 gov.bc.ca", + "disclaimer": "免責聲明", + "privacy": "隱私", + "accessibility": "無障礙", + "copyRight": "版權", + "contactUs": "聯繫我們" + }, + "bCGovNavBar": { + "about": "關於", + "myForms": "我的表格", + "createNewForm": "創建新表單", + "help": "幫助", + "feedback": "反饋", + "admin": "行政" + }, + "homePage": { + "title": "使用通用託管表單服務創建、發布表單並接收提交內容。", + "subTitle": "所有 BC 省擁有 IDIR 帳戶的政府僱員或承包商可以使用我們的託管版本的通用託管表單服務 (CHEFS) 來創建表單。", + "takeATourOfChefs": "參觀 CHEFS 以了解其實際情況。", + "logInToGetStarted": "登錄以開始使用", + "loginToStart": "使用 IDIR 登錄即可開始", + "login": "登錄", + "createFormLabel": "創建表格", + "manageAccessTitle": "管理對錶單的訪問", + "manageAccessSub1": "CHEFS 允許您創建公共表單,或者您可以通過 IDIR 或 BCeID 身份驗證管理訪問。", + "manageAccessSub2": "您還可以為您的團隊分配角色來管理您的所有提交內容。", + "createCustomFormTitle": "使用 CHEFS 表單生成器創建自定義表單", + "createCustomFormSub1": "借助 CHEFS,您可以通過直觀的拖放界面創建安全的表單。您可以添加表單組件,重新排列它們,並將它們放入不同的佈局配置中。", + "chefsHowToTitle": "廚師操作視頻", + "chefsHowToSub": "我們的快速入門指南將向您介紹 CHEFS 的一些基本功能。", + "getStartedToChefs": "開始使用 CHEFS", + "createOnlineTitle": "創建在線表單以收集客戶的信息並改進您的工作流程。", + "getStarted": "開始使用" + }, + "baseStepper": { + "setUpForm": "設置表格", + "designForm": "設計形式", + "manageForm": "管理表格" + }, + "create": { + "formSettings": "表單設置", + "disclaimer": "免責聲明", + "disclaimerStmt": "我同意表單設計師的免責聲明和責任聲明", + "continue": "繼續", + "back": "後退", + "confirmPageNav": "您真的要離開此頁面嗎?您所做的更改將不會被保存。", + "agreementErrMsg": "您必須同意上面顯示的隱私免責聲明。" + }, + "addTeamMember": { + "cantFindChefsUsers": "找不到人嗎?他們可能沒有登錄 CHEFS。
請向他們發送 CHEFS 鏈接並要求他們登錄。", + "cancel": "取消", + "add": "添加", + "mustSelectAUser": "您必須至少選擇一個角色才能添加此用戶。", + "addNewMember": "添加新成員", + "enterUsername": "輸入姓名、電子郵件或用戶名", + "enterExactUsername": "輸入準確的電子郵件或用戶名", + "BCeIDInputSearchMaxLen": "BCeID 用戶名/電子郵件的搜索輸入必須大於 6 個字符。", + "BCeIDMustBeExact": "BCeID 的電子郵件搜索必須準確。", + "errorGettingUsers": "獲取用戶時出錯 {error}" + }, + "baseFilter": { + "cancel": "取消", + "columnName": "列名", + "exampleText": "示例文本", + "exampleText2": "示例文本2", + "filterPlaceholderTxt": "過濾佔位符文本", + "filter": "篩選", + "value": "價值", + "resetColumns": "重置列" + }, + "formViewerActions": { + "viewMyDraftOrSubmissions": "查看我的草稿/投稿內容", + "saveAsADraft": "另存為草稿", + "editThisDraft": "編輯本草稿", + "switchSingleSubmssn": "切換到單一提交", + "switchMultiSubmssn": "切換到多次提交" + }, + "baseCopyToClipboard": { + "linkToClipboard": "鏈接已復製到剪貼板", + "copyToClipboard": "複製到剪貼板", + "errCopyToClipboard": "嘗試複製到剪貼板時出錯。" + }, + "sucess": { + "sucessFormSubmissn": "您的表格已成功提交", + "keepRecord": "如果您希望保留本次提交的記錄,您可以保留以下內容", + "confirmationId": "確認ID" + }, + "bcGovAlertBanner": { + "defaultErrMsg": "錯誤:出了點問題", + "error": "錯誤" + }, + "permissionUtils": { + "formNotAvailable": "該表格目前不可用。這可能是由於鏈接不正確,或者該表單可能已被其所有者刪除。", + "missingFormIdAndSubmssId": "缺少 formId 和submissionId 的選項", + "loadingFormErrMsg": "加載此表單時發生錯誤。", + "loadingForm": "加載 {options} 時出錯:{error}", + "idpHintMsg": "此表單需要 {idpHint} 身份驗證。請重新登錄並重試。", + "formIdpMissMatch": "表單 IDP 不匹配。表單需要 {idpHint},但用戶有 {userIdp}。" + }, + "download": { + "chefsDataExport": "CHEFS 數據導出", + "preparingForDownloading": "正在準備下載...", + "downloadInfoA": "如果您的文件沒有自動下載", + "downloadInfoB": "單擊此處重試" + }, + "history": { + "submissnHistory": "您的提交歷史記錄(待定)" + }, + "error": { + "logout": "登出", + "somethingWentWrong": "錯誤:出了點問題...:(" + }, + "login": { + "authenticateWith": "通過以下方式進行身份驗證:", + "alreadyLoggedIn": "已經登錄", + "home": "家", + "about": "關於" + }, + "notFound": { + "about": "關於", + "pageNotFound": "404頁面不存在。 :(" + }, + "store": { + "admin": { + "addFormOwnerRole": "已將此表單的所有者角色添加到 {fullName}", + "addRowError": "添加角色時出錯。", + "addRowConsoleErr": "將用戶 {userId} 添加到表單 {formId} 時出錯:{error}", + "apiKeyDelMsg": "此表單的 API 密鑰已被刪除。", + "errDeletingApiKey": "嘗試刪除 API 密鑰時發生錯誤。", + "consErrDeletingApiKey": "刪除表單 {formId} 的 API 密鑰時出錯:{error}", + "fecthingFormsErrMsg": "獲取表單時發生錯誤。", + "fecthingFormsConsErrMsg": "獲取管理表單數據時出錯:{error}", + "fecthingFormErrMsg": "獲取此表單時發生錯誤。", + "fecthingFormConsErrMsg": "獲取管理表單 {formId} 數據時出錯:{error}", + "fecthFormUserRolesErrMsg": "獲取表單用戶角色時出錯。", + "fecthFormUserRolesConsErrMsg": "獲取管理員角色數據時出錯:{error}", + "fecthApiDetailsErrMsg": "獲取此表單的 API 詳細信息時發生錯誤。", + "fecthApiDetailsConsErrMsg": "從表單 {formId} 數據獲取管理 API 詳細信息時出錯:{error}", + "restoreFormErrMsg": "恢復此表單時出錯。", + "restoreFormConsErrMsg": "恢復表單 {formId} 數據時出錯:{error}", + "getUsersErrMsg": "獲取用戶時發生錯誤。", + "getUsersConsErrMsg": "獲取管理員用戶數據時出錯:{error}", + "getUserErrMsg": "獲取該用戶時發生錯誤。", + "getUserConsErrMsg": "獲取管理員用戶 {userId} 數據時出錯:{error}", + "storingFCHelpInfoErrMsg": "存儲表單組件幫助信息時發生錯誤", + "storingFCHelpInfoConsErrMsg": "存儲表單組件幫助信息時出錯:{error}", + "gettingFCImgUrlErrMsg": "獲取圖片 url 時出錯", + "gettingFCImgUrlConsErrMsg": "獲取圖像 URL 時出錯:{error}", + "updatingFCStatusErrMsg": "更新發布狀態時出錯", + "updatingFCStatusConsErrMsg": "更新發布狀態時出錯:{error}", + "fecthingFormBuilderCompsErrMsg": "獲取表單構建器組件時發生錯誤", + "fecthingFormBuilderCompsConsErrMsg": "獲取表單生成器組件時出錯:{error}" + }, + "form": { + "fetchEmailTemplatesConsErrMsg": "加載 {formId} 的電子郵件模板時出錯:{error}", + "fetchEmailTemplatesErrMsg": "獲取此表單的電子郵件模板時發生錯誤", + "getCurrUserFormsErrMsg": "獲取您的表單時發生錯誤。", + "getCurrUserFormsConsErrMsg": "獲取用戶數據時出錯:{error}", + "getUserFormPermErrMsg": "獲取此表單的用戶數據時發生錯誤。", + "getUserFormPermConsErrMsg": "使用 formID {formId} 獲取用戶數據時出錯:{error}", + "getUserFormRolesErrmsg": "獲取此表單的用戶數據時發生錯誤。", + "getUserFormRolesConsErrmsg": "使用 formID {formId} 獲取用戶數據時出錯:{error}", + "updCurrUserFormPrefErrMsg": "保存您對此表單的首選項時出錯。", + "updCurrUserFormPrefConsErrMsg": "使用 formID {formId} 和首選項 {preferences} 更新用戶表單首選項時出錯:{error}", + "getCurrUserFormPrefErrMsg": "獲取您對此表單的首選項時發生錯誤。", + "getCurrUserFormPrefConsErrMsg": "使用 formID {formId} 獲取用戶表單首選項時出錯:{error}", + "delCurrformNotiMsg": "表單 {name} 已成功刪除。", + "delCurrFormConsErMsg": "刪除表單 {id} 時出錯:{error}", + "delDraftErrMsg": "刪除此草稿時發生錯誤。", + "delDraftConsErrMsg": "刪除 {draftId} 時出錯:{error}", + "fecthDraftErrMsg": "掃描此表單的草稿時出錯。", + "fecthDraftConsErrMsg": "獲取表單 {formId} 的草稿時出錯:{error}", + "fecthFormErrMsg": "獲取此表單時發生錯誤。", + "fecthFormConsErrMsg": "獲取表單 {formId} 時出錯:{error}", + "fetchFormFieldsErrMsg": "獲取此表單的字段列表時出錯。", + "fetchFormFieldsConsErrMsg": "獲取表單 {formId} 時出錯:{error}", + "publishDraftErrMsg": "發佈時發生錯誤。", + "publishDraftConsErrMsg": "發布 {draftId} 時出錯:{error}", + "toggleVersnPublConsErrMsg": "切換版本發布 {versionId} {publish} 時出錯:{error}", + "updateEmailTemplateConsErrMsg": "更新表單 {formId} 的電子郵件模板時出錯:{error}", + "updateEmailTemplateErrMsg": "更新此表單的電子郵件模板時出錯。", + "updateFormErrMsg": "更新此表單的設置時出錯。", + "updateFormConsErrMsg": "更新表單 {id} 時出錯:{error}", + "deleteSubmissionNotifyMsg": "提交刪除成功。", + "deleteSubmissionErrMsg": "刪除此提交時發生錯誤。", + "deleteSubmissionConsErrMsg": "刪除提交 {submissionId} 時出錯:{error}", + "deleteSubmissionsNotifyMsg": "提交內容已成功刪除。", + "deleteSubmissionsErrMsg": "刪除選定的提交內容時出錯。", + "deleteSubmissionsConsErrMsg": "刪除提交時出錯:{error}", + "restoreSubmissionsNotiMsg": "提交已成功恢復。", + "restoreSubmissionsErrMsg": "恢復此提交時發生錯誤。", + "restoreSubmissionsConsErrMsg": "恢復提交時出錯:{error}", + "restoreSubmissionNotiMsg": "提交已成功恢復。", + "restoreSubmissionErrMsg": "恢復此提交時發生錯誤。", + "restoreSubmissionConsErrMsg": "恢復提交 {submissionId} 時出錯:{error}", + "fecthSubmissnUsersErrMsg": "獲取此提交的收件人電子郵件時出錯。", + "fecthSubmissnUsersConsErrMsg": "獲取提交 {formSubmissionId} 的收件人電子郵件時出錯:{error}", + "fetchSubmissnErrMsg": "獲取此提交時發生錯誤。", + "fetchSubmissnConsErrMsg": "獲取提交 {submissionId} 時出錯:{error}", + "fetchFormCSVExptFieldsErrMsg": "獲取此表單的字段列表時出錯。", + "fetchFormCSVExptFieldsConsErrMsg": "獲取表單 {formId} 時出錯:{error}", + "fetchSubmissnsErrMsg": "獲取此表單的提交內容時發生錯誤。", + "fetchSubmissnsConsErrMsg": "獲取 {formId} 的提交時出錯:{error}", + "fetchVersionErrMsg": "獲取此表單時發生錯誤。", + "fetchVersionConsErrMsg": "獲取表單 {formId} 的版本 {versionId} 時出錯:{error}", + "deleteApiKeyNotifyMsg": "此表單的 API 密鑰已被刪除。", + "deleteApiKeyErrMsg": "嘗試刪除 API 密鑰時發生錯誤。", + "deleteApiKeyConsErrMsg": "刪除表單 {formId} 的 API 密鑰時出錯:{error}", + "generateApiKeyNotifyMsg": "此表單的 API 密鑰已創建。", + "generateApiKeyErrMsg": "嘗試生成 API 密鑰時發生錯誤。", + "generateApiKeyConsErrMsg": "為表單 {formId} 生成 API 密鑰時出錯:{error}", + "readApiKeyErrMsg": "嘗試獲取 API 密鑰時發生錯誤。", + "readApiKeyConsErrMsg": "獲取表單 {formId} 的 API 密鑰時出錯:{error}。", + "getFCPHImageUrlErrMsg": "獲取圖片 url 時出錯", + "getFCPHImageUrlConsErrMsg": "獲取圖像 URL 時出錯:{error}", + "listFCPHErrMsg": "獲取表單構建器組件時發生錯誤", + "listFCPHConsErrMsg": "獲取表單生成器組件時出錯:{error}", + "downloadFileErrMsg": "下載文件時發生錯誤", + "downloadFileConsErrMsg": "下載文件時出錯:錯誤", + "readSubscriptionSettingsErrMsg": "尝试获取订阅设置时出错。", + "readSubscriptionSettingsConsErrMsg": "获取表单 {formId} 的订阅设置时出错:{error}。", + "saveSubscriptionSettingsNotifyMsg": "此表单的订阅设置已保存。", + "saveSubscriptionSettingsErrMsg": "尝试保存订阅设置时出错。", + "saveSubscriptionSettingsConsErrMsg": "保存表单 {formId} 的订阅设置时出错:{error}" + } + }, + "admin": { + "root": { + "admin": "行政" + }, + "form": { + "administerForm": "管理表格" + }, + "user": { + "administerUser": "管理用戶" + } + }, + "user": { + "root": { + "myForms": "我的表格", + "history": "歷史", + "user": "用戶" + } + } +} diff --git a/frontend/app/frontend/src/internationalization/trans/formio/formio.json b/frontend/app/frontend/src/internationalization/trans/formio/formio.json new file mode 100644 index 0000000..77282d1 --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/formio/formio.json @@ -0,0 +1,3546 @@ +{ + "en": { + "Basic Layout": "Basic Layout", + "Text/Images": "Text/Images", + "Columns - 2": "Columns - 2", + "Columns - 3": "Columns - 3", + "Columns - 4": "Columns - 4", + "Tabs": "Tabs", + "Panel": "Panel", + "Basic Fields": "Basic Fields", + "Text Field": "Text Field", + "Multi-line Text": "Multi-line Text", + "Select List": "Select List", + "Checkbox": "Checkbox", + "Checkbox Group": "Checkbox Group", + "Radio Group": "Radio Group", + "Number": "Number", + "Phone Number": "Phone Number", + "Email": "Email", + "Date/Time": "Date/Time", + "Day": "Day", + "Advanced Layout": "Advanced Layout", + "HTML Element": "HTML Element", + "Content": "Content", + "Columns": "Columns", + "Field Set": "Field Set", + "Table": "Table", + "Well": "Well", + "Advanced Fields": "Advanced Fields", + "Text Area": "Text Area", + "Url": "Url", + "Tags": "Tags", + "Address": "Address", + "Password": "Password", + "Time": "Time", + "Select Boxes": "Select Boxes", + "Select": "Select", + "Currency": "Currency", + "Radio": "Radio", + "Button": "Button", + "Survey": "Survey", + "Signature": "Signature", + "Advanced Data": "Advanced Data", + "Hidden": "Hidden", + "Container": "Container", + "Data Map": "Data Map", + "Edit Grid": "Edit Grid", + "Tree": "Tree", + "BC Government": "BC Government", + "File Upload": "File Upload", + "Business Name Search": "Business Name Search", + "BC Address": "BC Address", + "Search field": "Search field", + "Property Name": "Property Name", + "API": "API", + "Conditional": "Conditional", + "Addons": "Addons", + "Paragraph": "Paragraph", + "Save": "Save", + "Cancel": "Cancel", + "Remove": "Remove", + "The following variables are available in all scripts.": "The following variables are available in all scripts.", + "Display": "Display", + "Label": "Label", + "Help": "Help", + "Auto adjust columns": "Auto adjust columns", + "Hide Column when Chidren Hidden": "Hide Column when Chidren Hidden", + "The label for this field that will appear next to it": "The label for this field that will appear next to it", + "Preview": "Preview", + "Columns - 2 Component": "Columns - 2 Component", + "Columns - 3 Component": "Columns - 3 Component", + "Key": "Key", + "Title": "Title", + "Theme": "Theme", + "Collapsible": "Collapsible", + "Label Position": "Label Position", + "Placeholder": "Placeholder", + "Description": "Description", + "Tooltip": "Tooltip", + "Input Mask": "Input Mask", + "Allow Multiple Masks": "Allow Multiple Masks", + "Hide Label": "Hide Label", + "Show Word Counter": "Show Word Counter", + "Show Character Counter": "Show Character Counter", + "Allow Spellcheck": "Allow Spellcheck", + "Disabled": "Disabled", + "Multiple Values": "Multiple Values", + "Default Value": "Default Value", + "Text Case": "Text Case", + "Mixed (Allow upper and lower case)": "Mixed (Allow upper and lower case)", + "Uppercase": "Uppercase", + "Lowercase": "Lowercase", + "Allow value propagation": "Allow value propagation", + "Required": "Required", + "Custom Error Message": "Custom Error Message", + "Minimum Length": "Minimum Length", + "Maximum Length": "Maximum Length", + "This component should Display:": "This component should Display:", + "When the form component:": "When the form component:", + "Has the value:": "Has the value:", + "The decoded JWT token for the authenticated user.": "The decoded JWT token for the authenticated user.", + "The current logged in user": "The current logged in user", + "The complete form JSON object": "The complete form JSON object", + "The complete submission object.": "The complete submission object.", + "The complete submission data object.": "The complete submission data object.", + "Contextual \"row\" data, used within DataGrid, EditGrid, and Container components": "Contextual \"row\" data, used within DataGrid, EditGrid, and Container components", + "The current component JSON": "The current component JSON", + "The current component instance.": "The current component instance.", + "The current value of the component.": "The current value of the component.", + "The moment.js library for date manipulation.": "The moment.js library for date manipulation.", + "An instance of Lodash.": "An instance of Lodash.", + "An instance of the FormioUtils object.": "An instance of the FormioUtils object.", + "An alias for \"utils\".": "An alias for \"utils\".", + "Enter custom javascript code.": "Enter custom javascript code.", + "You must assign the show variable a boolean result.": "You must assign the show variable a boolean result.", + "Note: Advanced Conditional logic will override the results of the Simple Conditional logic.": "Note: Advanced Conditional logic will override the results of the Simple Conditional logic.", + "Example": "Example", + "Click here for an example": "Click here for an example", + "Execute custom logic using JSONLogic.": "Execute custom logic using JSONLogic.", + "token": "token", + "user": "user", + "form": "form", + "submission": "submission", + "data": "data", + "row": "row", + "component": "component", + "instance": "instance", + "value": "value", + "moment": "moment", + "utils": "utils", + "util": "util", + "Error Message": "Error Message", + "Insert": "Insert", + "Name": "Name", + "Selector": "Selector", + "Template": "Template", + "Style": "Style", + "Color": "Color", + "Update On": "Update On", + "Black List": "Black List", + "Auto Expand": "Auto Expand", + "Label Margin": "Label Margin", + "Label Width": "Label Width", + "Inline Layout": "Inline Layout", + "Options Label Position": "Options Label Position", + "Values": "Values", + "Shortcut": "Shortcut", + "Maximum checked error message": "Maximum checked error message", + "Minimum checked error message": "Minimum checked error message", + "Maximum checked number": "Maximum checked number", + "Minimum checked number": "Minimum checked number", + "Decimal Places": "Decimal Places", + "Require Decimal": "Require Decimal", + "Use Thousands Separator": "Use Thousands Separator", + "Maximum Value": "Maximum Value", + "Minimum Value": "Minimum Value", + "Hide Input Labels": "Hide Input Labels", + "Inputs Label Position": "Inputs Label Position", + "Day First": "Day First", + "Type": "Type", + "Month": "Month", + "Year": "Year", + "Data": "Data", + "Validation": "Validation", + "Type of input": "Type of input", + "Minimum Year": "Minimum Year", + "Maximum Year": "Maximum Year", + "Require Year": "Require Year", + "Require Day": "Require Day", + "Require Month": "Require Month", + "Minimum Day": "Minimum Day", + "Maximum Day": "Maximum Day", + "Modal Edit": "Modal Edit", + "Refresh On Change": "Refresh On Change", + "Custom CSS Class": "Custom CSS Class", + "Custom Properties": "Custom Properties", + "Attribute Name": "Attribute Name", + "Attribute Value": "Attribute Value", + "PDF Overlay": "PDF Overlay", + "Page": "Page", + "Left": "Left", + "Top": "Top", + "Width": "Width", + "Height": "Height", + "Database Index": "Database Index", + "Encrypted (Enterprise Only)": "Encrypted (Enterprise Only)", + "Redraw On": "Redraw On", + "Protected": "Protected", + "Persistent": "Persistent", + "None": "None", + "Server": "Server", + "Client": "Client", + "Calculate Value on server": "Calculate Value on server", + "Field Tags": "Field Tags", + "Advanced Logic": "Advanced Logic", + "Table View": "Table View", + "Clear Value When Hidden": "Clear Value When Hidden" + }, + "pa": { + "Basic Layout": "ਮੂਲ ਖਾਕਾ", + "Text/Images": "ਟੈਕਸਟ/ਚਿੱਤਰ", + "Columns - 2": "ਕਾਲਮ - 2", + "Columns - 3": "ਕਾਲਮ - 3", + "Columns - 4": "ਕਾਲਮ - 4", + "Tabs": "ਟੈਬਸ", + "Panel": "ਪੈਨਲ", + "Basic Fields": "ਬੁਨਿਆਦੀ ਖੇਤਰ", + "Text Field": "ਟੈਕਸਟ ਫੀਲਡ", + "Multi-line Text": "ਮਲਟੀ-ਲਾਈਨ ਟੈਕਸਟ", + "Select List": "ਸੂਚੀ ਚੁਣੋ", + "Checkbox": "ਚੈੱਕਬਾਕਸ", + "Checkbox Group": "ਚੈੱਕਬਾਕਸ ਸਮੂਹ", + "Radio Group": "ਰੇਡੀਓ ਸਮੂਹ", + "Number": "ਗਿਣਤੀ", + "Phone Number": "ਫੋਨ ਨੰਬਰ", + "Email": "ਈ - ਮੇਲ", + "Day": "ਦਿਨ", + "Advanced Layout": "ਉੱਨਤ ਖਾਕਾ", + "HTML Element": "HTML ਤੱਤ", + "Content": "ਸਮੱਗਰੀ", + "Columns": "ਕਾਲਮ", + "Field Set": "ਫੀਲਡ ਸੈੱਟ", + "Table": "ਟੇਬਲ", + "Well": "ਖੈਰ", + "Advanced Fields": "ਉੱਨਤ ਖੇਤਰ", + "Text Area": "ਟੈਕਸਟ ਖੇਤਰ", + "Url": "ਯੂਆਰਐਲ", + "Tags": "ਟੈਗਸ", + "Address": "ਪਤਾ", + "Password": "ਪਾਸਵਰਡ", + "Time": "ਸਮਾਂ", + "Select Boxes": "ਬਾਕਸ ਚੁਣੋ", + "Select": "ਚੁਣੋ", + "Currency": "ਮੁਦਰਾ", + "Radio": "ਰੇਡੀਓ", + "Button": "ਬਟਨ", + "Survey": "ਸਰਵੇਖਣ", + "Signature": "ਦਸਤਖਤ", + "Advanced Data": "ਐਡਵਾਂਸਡ ਡੇਟਾ", + "Hidden": "ਲੁਕਿਆ ਹੋਇਆ", + "Container": "ਕੰਟੇਨਰ", + "Data Map": "ਡਾਟਾ ਨਕਸ਼ਾ", + "Edit Grid": "ਗਰਿੱਡ ਦਾ ਸੰਪਾਦਨ ਕਰੋ", + "Tree": "ਰੁੱਖ", + "BC Government": "ਬੀ ਸੀ ਸਰਕਾਰ", + "File Upload": "ਫਾਈਲ ਅਪਲੋਡ ਕਰੋ", + "Business Name Search": "ਕਾਰੋਬਾਰੀ ਨਾਮ ਖੋਜ", + "BC Address": "ਬੀ ਸੀ ਦਾ ਪਤਾ", + "Search field": "ਖੋਜ ਖੇਤਰ", + "Property Name": "ਜਾਇਦਾਦ ਦਾ ਨਾਮ", + "API": "API", + "Conditional": "ਸ਼ਰਤੀਆ", + "Addons": "ਐਡਆਨ", + "Paragraph": "ਪੈਰਾ", + "Save": "ਸੇਵ ਕਰੋ", + "Cancel": "ਰੱਦ ਕਰੋ", + "Remove": "ਹਟਾਓ", + "The following variables are available in all scripts.": "ਹੇਠਾਂ ਦਿੱਤੇ ਵੇਰੀਏਬਲ ਸਾਰੀਆਂ ਸਕ੍ਰਿਪਟਾਂ ਵਿੱਚ ਉਪਲਬਧ ਹਨ।", + "Display": "ਡਿਸਪਲੇ", + "Label": "ਲੇਬਲ", + "Help": "ਮਦਦ ਕਰੋ", + "Auto adjust columns": "ਕਾਲਮਾਂ ਨੂੰ ਆਟੋ ਐਡਜਸਟ ਕਰੋ", + "Hide Column when Chidren Hidden": "ਕਾਲਮ ਨੂੰ ਲੁਕਾਓ ਜਦੋਂ ਬੱਚੇ ਲੁਕੇ ਹੋਏ ਹਨ", + "The label for this field that will appear next to it": "ਇਸ ਖੇਤਰ ਲਈ ਲੇਬਲ ਜੋ ਇਸਦੇ ਅੱਗੇ ਦਿਖਾਈ ਦੇਵੇਗਾ", + "Preview": "ਝਲਕ", + "Columns - 2 Component": "ਕਾਲਮ - 2 ਕੰਪੋਨੈਂਟ", + "Columns - 3 Component": "ਕਾਲਮ - 3 ਕੰਪੋਨੈਂਟ", + "Key": "ਕੁੰਜੀ", + "Title": "ਸਿਰਲੇਖ", + "Theme": "ਥੀਮ", + "Collapsible": "ਸਮੇਟਣਯੋਗ", + "Label Position": "ਲੇਬਲ ਸਥਿਤੀ", + "Placeholder": "ਪਲੇਸਹੋਲਡਰ", + "Description": "ਵਰਣਨ", + "Tooltip": "ਟੂਲਟਿਪ", + "Input Mask": "ਇਨਪੁਟ ਮਾਸਕ", + "Allow Multiple Masks": "ਮਲਟੀਪਲ ਮਾਸਕ ਦੀ ਆਗਿਆ ਦਿਓ", + "Hide Label": "ਲੇਬਲ ਲੁਕਾਓ", + "Show Word Counter": "ਵਰਡ ਕਾਊਂਟਰ ਦਿਖਾਓ", + "Show Character Counter": "ਕਰੈਕਟਰ ਕਾਊਂਟਰ ਦਿਖਾਓ", + "Allow Spellcheck": "ਸ਼ਬਦ-ਜੋੜ ਜਾਂਚ ਦੀ ਇਜਾਜ਼ਤ ਦਿਓ", + "Disabled": "ਅਯੋਗ", + "Multiple Values": "ਕਈ ਮੁੱਲ", + "Default Value": "ਪੂਰਵ-ਨਿਰਧਾਰਤ ਮੁੱਲ", + "Text Case": "ਟੈਕਸਟ ਕੇਸ", + "Mixed (Allow upper and lower case)": "ਮਿਕਸਡ (ਵੱਡੇ ਅਤੇ ਛੋਟੇ ਅੱਖਰਾਂ ਦੀ ਆਗਿਆ ਦਿਓ)", + "Uppercase": "ਅਪਰਕੇਸ", + "Lowercase": "ਲੋਅਰਕੇਸ", + "Allow value propagation": "ਮੁੱਲ ਦੇ ਪ੍ਰਸਾਰ ਦੀ ਆਗਿਆ ਦਿਓ", + "Required": "ਲੋੜੀਂਦਾ ਹੈ", + "Custom Error Message": "ਕਸਟਮ ਅਸ਼ੁੱਧੀ ਸੁਨੇਹਾ", + "Minimum Length": "ਘੱਟੋ-ਘੱਟ ਲੰਬਾਈ", + "Maximum Length": "ਅਧਿਕਤਮ ਲੰਬਾਈ", + "This component should Display:": "ਇਸ ਹਿੱਸੇ ਨੂੰ ਪ੍ਰਦਰਸ਼ਿਤ ਕਰਨਾ ਚਾਹੀਦਾ ਹੈ:", + "When the form component:": "ਜਦੋਂ ਫਾਰਮ ਕੰਪੋਨੈਂਟ:", + "Has the value:": "ਮੁੱਲ ਹੈ:", + "The decoded JWT token for the authenticated user.": "ਪ੍ਰਮਾਣਿਤ ਉਪਭੋਗਤਾ ਲਈ ਡੀਕੋਡ ਕੀਤਾ JWT ਟੋਕਨ।", + "The current logged in user": "ਵਰਤਮਾਨ ਲੌਗਇਨ ਉਪਭੋਗਤਾ", + "The complete form JSON object": "ਪੂਰਾ ਫਾਰਮ JSON ਵਸਤੂ", + "The complete submission object.": "ਪੂਰੀ ਸਪੁਰਦਗੀ ਵਸਤੂ।", + "The complete submission data object.": "ਪੂਰਾ ਸਪੁਰਦਗੀ ਡਾਟਾ ਆਬਜੈਕਟ।", + "Contextual \"row\" data, used within DataGrid, EditGrid, and Container components": "ਸੰਦਰਭੀ \"ਕਤਾਰ\" ਡੇਟਾ, ਡੇਟਾਗ੍ਰਿਡ, ਐਡਿਟਗ੍ਰਿਡ, ਅਤੇ ਕੰਟੇਨਰ ਕੰਪੋਨੈਂਟ ਦੇ ਅੰਦਰ ਵਰਤਿਆ ਜਾਂਦਾ ਹੈ", + "The current component JSON": "ਮੌਜੂਦਾ ਕੰਪੋਨੈਂਟ JSON", + "The current component instance.": "ਮੌਜੂਦਾ ਕੰਪੋਨੈਂਟ ਉਦਾਹਰਨ।", + "The current value of the component.": "ਕੰਪੋਨੈਂਟ ਦਾ ਮੌਜੂਦਾ ਮੁੱਲ।", + "The moment.js library for date manipulation.": "ਮਿਤੀ ਹੇਰਾਫੇਰੀ ਲਈ moment.js ਲਾਇਬ੍ਰੇਰੀ।", + "An instance of Lodash.": "ਲੋਦਾਸ਼ ਦੀ ਇੱਕ ਉਦਾਹਰਣ।", + "An instance of the FormioUtils object.": "FormioUtils ਆਬਜੈਕਟ ਦੀ ਇੱਕ ਉਦਾਹਰਣ।", + "An alias for \"utils\".": "\"ਉਪਯੋਗਤਾਵਾਂ\" ਲਈ ਇੱਕ ਉਪਨਾਮ।", + "Enter custom javascript code.": "ਕਸਟਮ ਜਾਵਾਸਕ੍ਰਿਪਟ ਕੋਡ ਦਰਜ ਕਰੋ।", + "You must assign the show variable a boolean result.": "ਤੁਹਾਨੂੰ ਸ਼ੋਅ ਵੇਰੀਏਬਲ ਨੂੰ ਬੂਲੀਅਨ ਨਤੀਜਾ ਨਿਰਧਾਰਤ ਕਰਨਾ ਚਾਹੀਦਾ ਹੈ।", + "Note: Advanced Conditional logic will override the results of the Simple Conditional logic.": "ਨੋਟ: ਐਡਵਾਂਸਡ ਕੰਡੀਸ਼ਨਲ ਤਰਕ ਸਧਾਰਨ ਸ਼ਰਤੀਆ ਤਰਕ ਦੇ ਨਤੀਜਿਆਂ ਨੂੰ ਓਵਰਰਾਈਡ ਕਰੇਗਾ।", + "Example": "ਉਦਾਹਰਨ", + "Click here for an example": "ਇੱਕ ਉਦਾਹਰਨ ਲਈ ਇੱਥੇ ਕਲਿੱਕ ਕਰੋ", + "Execute custom logic using JSONLogic.": "JSONLogic ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਕਸਟਮ ਤਰਕ ਨੂੰ ਚਲਾਓ।", + "token": "ਟੋਕਨ", + "user": "ਉਪਭੋਗਤਾ", + "form": "ਫਾਰਮ", + "submission": "ਅਧੀਨਗੀ", + "data": "ਡਾਟਾ", + "row": "ਕਤਾਰ", + "component": "ਕੰਪੋਨੈਂਟ", + "instance": "ਉਦਾਹਰਨ", + "value": "ਮੁੱਲ", + "moment": "ਪਲ", + "utils": "ਉਪਯੋਗਤਾਵਾਂ", + "util": "ਉਪਯੋਗ", + "Error Message": "ਗਲਤੀ ਸੁਨੇਹਾ", + "Insert": "ਪਾਓ", + "Name": "ਨਾਮ", + "Selector": "ਚੋਣਕਾਰ", + "Template": "ਟੈਂਪਲੇਟ", + "Style": "ਸ਼ੈਲੀ", + "Color": "ਰੰਗ", + "Update On": "ਅੱਪਡੇਟ ਚਾਲੂ", + "Black List": "ਕਾਲੀ ਸੂਚੀ", + "Auto Expand": "ਆਟੋ ਵਿਸਤਾਰ", + "Label Margin": "ਲੇਬਲ ਮਾਰਜਿਨ", + "Label Width": "ਲੇਬਲ ਦੀ ਚੌੜਾਈ", + "Inline Layout": "ਇਨਲਾਈਨ ਖਾਕਾ", + "Options Label Position": "ਵਿਕਲਪ ਲੇਬਲ ਸਥਿਤੀ", + "Values": "ਮੁੱਲ", + "Shortcut": "ਸ਼ਾਰਟਕੱਟ", + "Maximum checked error message": "ਵੱਧ ਤੋਂ ਵੱਧ ਜਾਂਚਿਆ ਗਲਤੀ ਸੁਨੇਹਾ", + "Minimum checked error message": "ਘੱਟੋ-ਘੱਟ ਜਾਂਚਿਆ ਗਲਤੀ ਸੁਨੇਹਾ", + "Maximum checked number": "ਵੱਧ ਤੋਂ ਵੱਧ ਜਾਂਚਿਆ ਨੰਬਰ", + "Minimum checked number": "ਘੱਟੋ-ਘੱਟ ਜਾਂਚਿਆ ਨੰਬਰ", + "Decimal Places": "ਦਸ਼ਮਲਵ ਸਥਾਨ", + "Require Decimal": "ਦਸ਼ਮਲਵ ਦੀ ਲੋੜ ਹੈ", + "Use Thousands Separator": "ਹਜ਼ਾਰਾਂ ਵਿਭਾਜਕ ਦੀ ਵਰਤੋਂ ਕਰੋ", + "Maximum Value": "ਅਧਿਕਤਮ ਮੁੱਲ", + "Minimum Value": "ਨਿਊਨਤਮ ਮੁੱਲ", + "Hide Input Labels": "ਇਨਪੁਟ ਲੇਬਲ ਲੁਕਾਓ", + "Inputs Label Position": "ਇਨਪੁਟਸ ਲੇਬਲ ਸਥਿਤੀ", + "Day First": "ਪਹਿਲਾ ਦਿਨ", + "Type": "ਟਾਈਪ ਕਰੋ", + "Month": "ਮਹੀਨਾ", + "Year": "ਸਾਲ", + "Data": "ਡਾਟਾ", + "Validation": "ਪ੍ਰਮਾਣਿਕਤਾ", + "Type of input": "ਇੰਪੁੱਟ ਦੀ ਕਿਸਮ", + "Minimum Year": "ਘੱਟੋ-ਘੱਟ ਸਾਲ", + "Maximum Year": "ਵੱਧ ਤੋਂ ਵੱਧ ਸਾਲ", + "Require Year": "ਸਾਲ ਦੀ ਲੋੜ ਹੈ", + "Require Day": "ਦਿਨ ਦੀ ਲੋੜ ਹੈ", + "Require Month": "ਮਹੀਨੇ ਦੀ ਲੋੜ ਹੈ", + "Minimum Day": "ਘੱਟੋ-ਘੱਟ ਦਿਨ", + "Maximum Day": "ਵੱਧ ਤੋਂ ਵੱਧ ਦਿਨ", + "Modal Edit": "ਮਾਡਲ ਸੰਪਾਦਨ", + "Refresh On Change": "ਤਬਦੀਲੀ 'ਤੇ ਤਾਜ਼ਾ ਕਰੋ", + "Custom CSS Class": "ਕਸਟਮ CSS ਕਲਾਸ", + "Custom Properties": "ਕਸਟਮ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ", + "Attribute Name": "ਗੁਣ ਦਾ ਨਾਮ", + "Attribute Value": "ਗੁਣ ਮੁੱਲ", + "PDF Overlay": "PDF ਓਵਰਲੇ", + "Page": "ਪੰਨਾ", + "Left": "ਖੱਬੇ", + "Top": "ਸਿਖਰ", + "Width": "ਚੌੜਾਈ", + "Height": "ਉਚਾਈ", + "Database Index": "ਡਾਟਾਬੇਸ ਇੰਡੈਕਸ", + "Encrypted (Enterprise Only)": "ਐਨਕ੍ਰਿਪਟਡ (ਸਿਰਫ ਐਂਟਰਪ੍ਰਾਈਜ਼)", + "Redraw On": "ਦੁਬਾਰਾ ਖਿੱਚੋ", + "Protected": "ਸੁਰੱਖਿਅਤ ਕੀਤਾ", + "Persistent": "ਸਥਾਈ", + "None": "ਕੋਈ ਨਹੀਂ", + "Server": "ਸਰਵਰ", + "Client": "ਕਲਾਇੰਟ", + "Calculate Value on server": "ਸਰਵਰ 'ਤੇ ਮੁੱਲ ਦੀ ਗਣਨਾ ਕਰੋ", + "Field Tags": "ਫੀਲਡ ਟੈਗਸ", + "Advanced Logic": "ਉੱਨਤ ਤਰਕ", + "Table View": "ਸਾਰਣੀ ਦ੍ਰਿਸ਼", + "Clear Value When Hidden": "ਜਦੋਂ ਲੁਕਿਆ ਹੋਇਆ ਮੁੱਲ ਸਾਫ਼ ਕਰੋ" + }, + "zh": { + "Basic Layout": "基本布局", + "Text/Images": "文字/图片", + "Columns - 2": "专栏 - 2", + "Columns - 3": "专栏 - 3", + "Columns - 4": "专栏 - 4", + "Tabs": "选项卡", + "Panel": "控制板", + "Basic Fields": "基本领域", + "Text Field": "文本域", + "Multi-line Text": "多行文本", + "Select List": "选择列表", + "Checkbox": "复选框", + "Checkbox Group": "复选框组", + "Radio Group": "广播组", + "Number": "数字", + "Phone Number": "电话号码", + "Email": "电子邮件", + "Date/Time": "约会时间", + "Day": "天", + "Advanced Layout": "高级布局", + "HTML Element": "元素", + "Content": "内容", + "Columns": "列", + "Field Set": "字段集", + "Table": "桌子", + "Well": "出色地", + "Advanced Fields": "进阶领域", + "Text Area": "文本区", + "Url": "网址", + "Tags": "标签", + "Address": "地址", + "Password": "密码", + "Time": "时间", + "Select Boxes": "选择框", + "Select": "选择", + "Currency": "货币", + "Radio": "收音机", + "Button": "按钮", + "Survey": "民意调查", + "Signature": "签名", + "Advanced Data": "高级数据", + "Hidden": "隐", + "Container": "容器", + "Data Map": "资料图", + "Edit Grid": "编辑网格", + "Tree": "树", + "BC Government": "卑诗省政府", + "File Upload": "上传文件", + "Business Name Search": "公司名称搜索", + "BC Address": "公元前地址", + "Search field": "搜索字段", + "Property Name": "物业名称", + "API": "应用程序接口", + "Conditional": "有条件的", + "Addons": "插件", + "Paragraph": "段落", + "Save": "节省", + "Cancel": "取消", + "Remove": "消除", + "The following variables are available in all scripts.": "以下变量在所有脚本中都可用。", + "Display": "展示", + "Label": "标签", + "Help": "帮助", + "Auto adjust columns": "自动调整列", + "Hide Column when Chidren Hidden": "隐藏子项时隐藏列", + "The label for this field that will appear next to it": "将显示在其旁边的该字段的标签", + "Preview": "预览", + "Columns - 2 Component": "列 - 2 个分量", + "Columns - 3 Component": "列 - 3 个分量", + "Key": "钥匙", + "Title": "标题", + "Theme": "主题", + "Collapsible": "可折叠", + "Label Position": "标签位置", + "Placeholder": "占位符", + "Description": "描述", + "Tooltip": "工具提示", + "Input Mask": "输入掩码", + "Allow Multiple Masks": "允许多个掩码", + "Hide Label": "隐藏标签", + "Show Word Counter": "显示单词计数器", + "Show Character Counter": "显示字符计数器", + "Allow Spellcheck": "允许拼写检查", + "Disabled": "残疾人", + "Multiple Values": "多个值", + "Default Value": "默认值", + "Text Case": "文本大小写", + "Mixed (Allow upper and lower case)": "混合(允许大写和小写)", + "Uppercase": "大写", + "Lowercase": "小写", + "Allow value propagation": "允许价值传播", + "Required": "必需的", + "Custom Error Message": "自定义错误信息", + "Minimum Length": "最小长度", + "Maximum Length": "最大长度", + "This component should Display:": "该组件应显示:", + "When the form component:": "当表单组件:", + "Has the value:": "具有以下价值:", + "The decoded JWT token for the authenticated user.": "经过身份验证的用户的已解码 JWT 令牌。", + "The current logged in user": "当前登录用户", + "The complete form JSON object": "完整的表单 JSON 对象", + "The complete submission object.": "完整的提交对象。", + "The complete submission data object.": "完整的提交数据对象。", + "Contextual \"row\" data, used within DataGrid, EditGrid, and Container components": "上下文“行”数据,在 DataGrid、EditGrid 和 Container 组件中使用", + "The current component JSON": "当前组件 JSON", + "The current component instance.": "当前组件实例。", + "The current value of the component.": "组件的当前值。", + "The moment.js library for date manipulation.": "用于日期操作的 moment.js 库。", + "An instance of Lodash.": "Lodash 的一个实例。", + "An instance of the FormioUtils object.": "FormioUtils 对象的实例。", + "An alias for \"utils\".": "“utils”的别名。", + "Enter custom javascript code.": "输入自定义 javascript 代码。", + "You must assign the show variable a boolean result.": "您必须为 show 变量分配布尔结果。", + "Note: Advanced Conditional logic will override the results of the Simple Conditional logic.": "注意:高级条件逻辑将覆盖简单条件逻辑的结果。", + "Example": "例子", + "Click here for an example": "单击此处查看示例", + "Execute custom logic using JSONLogic.": "使用 JSONLogic 执行自定义逻辑。", + "token": "令牌", + "user": "用户", + "form": "形式", + "submission": "提交", + "data": "数据", + "row": "排", + "component": "成分", + "instance": "实例", + "value": "价值", + "moment": "片刻", + "utils": "效用", + "util": "效用", + "Error Message": "错误信息", + "Insert": "插入", + "Name": "姓名", + "Selector": "选择器", + "Template": "模板", + "Style": "风格", + "Color": "颜色", + "Update On": "更新时间", + "Black List": "黑名单", + "Auto Expand": "自动展开", + "Label Margin": "标签边距", + "Label Width": "标签宽度", + "Inline Layout": "行内布局", + "Options Label Position": "选项标签位置", + "Values": "价值观", + "Shortcut": "捷径", + "Maximum checked error message": "最大检查错误信息", + "Minimum checked error message": "最小检查错误信息", + "Maximum checked number": "最大勾选数", + "Minimum checked number": "最小勾选数", + "Decimal Places": "小数位", + "Require Decimal": "要求小数", + "Use Thousands Separator": "使用千位分隔符", + "Maximum Value": "最大值", + "Minimum Value": "最小值", + "Hide Input Labels": "隐藏输入标签", + "Inputs Label Position": "输入标签位置", + "Day First": "第一天", + "Type": "类型", + "Month": "月", + "Year": "年", + "Data": "数据", + "Validation": "验证", + "Type of input": "输入类型", + "Minimum Year": "最低年份", + "Maximum Year": "最大年份", + "Require Year": "要求年份", + "Require Day": "需要一天", + "Require Month": "要求月份", + "Minimum Day": "最短天数", + "Maximum Day": "最大天数", + "Modal Edit": "模态编辑", + "Refresh On Change": "更改时刷新", + "Custom CSS Class": "自定义 CSS 类", + "Custom Properties": "自定义属性", + "Attribute Name": "属性名称", + "Attribute Value": "属性值", + "PDF Overlay": "PDF叠加", + "Page": "页", + "Left": "左边", + "Top": "顶部", + "Width": "宽度", + "Height": "高度", + "Database Index": "数据库索引", + "Encrypted (Enterprise Only)": "加密(仅限企业)", + "Redraw On": "重绘于", + "Protected": "受保护", + "Persistent": "执着的", + "None": "没有任何", + "Server": "服务器", + "Client": "客户", + "Calculate Value on server": "在服务器上计算值", + "Field Tags": "字段标签", + "Advanced Logic": "高级逻辑", + "Table View": "表视图", + "Clear Value When Hidden": "隐藏时清除值" + }, + "zhTW": { + "Basic Layout": "基本佈局", + "Text/Images": "文字/圖片", + "Columns - 2": "專欄 - 2", + "Columns - 3": "專欄 - 3", + "Columns - 4": "專欄 - 4", + "Tabs": "選項卡", + "Panel": "控制板", + "Basic Fields": "基本領域", + "Text Field": "文本域", + "Multi-line Text": "多行文本", + "Select List": "選擇列表", + "Checkbox": "複選框", + "Checkbox Group": "複選框組", + "Radio Group": "廣播組", + "Number": "數字", + "Phone Number": "電話號碼", + "Email": "電子郵件", + "Date/Time": "約會時間", + "Day": "天", + "Advanced Layout": "高級佈局", + "HTML Element": "元素", + "Content": "內容", + "Columns": "列", + "Field Set": "字段集", + "Table": "桌子", + "Well": "出色地", + "Advanced Fields": "進階領域", + "Text Area": "文本區", + "Url": "網址", + "Tags": "標籤", + "Address": "地址", + "Password": "密碼", + "Time": "時間", + "Select Boxes": "選擇框", + "Select": "選擇", + "Currency": "貨幣", + "Radio": "收音機", + "Button": "按鈕", + "Survey": "民意調查", + "Signature": "簽名", + "Advanced Data": "高級數據", + "Hidden": "隱", + "Container": "容器", + "Data Map": "資料圖", + "Edit Grid": "編輯網格", + "Tree": "樹", + "BC Government": "卑詩省政府", + "File Upload": "上傳文件", + "Business Name Search": "公司名稱搜索", + "BC Address": "公元前地址", + "Search field": "搜索字段", + "Property Name": "物業名稱", + "API": "應用程序接口", + "Conditional": "有條件的", + "Addons": "插件", + "Paragraph": "段落", + "Save": "節省", + "Cancel": "取消", + "Remove": "消除", + "The following variables are available in all scripts.": "以下變量在所有腳本中都可用。", + "Display": "展示", + "Label": "標籤", + "Help": "幫助", + "Auto adjust columns": "自動調整列", + "Hide Column when Chidren Hidden": "隱藏子項時隱藏列", + "The label for this field that will appear next to it": "將出現在其旁邊的該字段的標籤", + "Preview": "預覽", + "Columns - 2 Component": "列 - 2 個分量", + "Columns - 3 Component": "列 - 3 個分量", + "Key": "鑰匙", + "Title": "標題", + "Theme": "主題", + "Collapsible": "可折疊", + "Label Position": "標籤位置", + "Placeholder": "佔位符", + "Description": "描述", + "Tooltip": "工具提示", + "Input Mask": "輸入掩碼", + "Allow Multiple Masks": "允許多個掩碼", + "Hide Label": "隱藏標籤", + "Show Word Counter": "顯示單詞計數器", + "Show Character Counter": "顯示字符計數器", + "Allow Spellcheck": "允許拼寫檢查", + "Disabled": "殘疾人", + "Multiple Values": "多個值", + "Default Value": "默認值", + "Text Case": "文本大小寫", + "Mixed (Allow upper and lower case)": "混合(允許大寫和小寫)", + "Uppercase": "大寫", + "Lowercase": "小寫", + "Allow value propagation": "允許價值傳播", + "Required": "必需的", + "Custom Error Message": "自定義錯誤信息", + "Minimum Length": "最小長度", + "Maximum Length": "最大長度", + "This component should Display:": "該組件應顯示:", + "When the form component:": "當表單組件:", + "Has the value:": "具有以下價值:", + "The decoded JWT token for the authenticated user.": "經過身份驗證的用戶的已解碼 JWT 令牌。", + "The current logged in user": "當前登錄用戶", + "The complete form JSON object": "完整的表單 JSON 對象", + "The complete submission object.": "完整的提交對象。", + "The complete submission data object.": "完整的提交數據對象。", + "Contextual \"row\" data, used within DataGrid, EditGrid, and Container components": "上下文“行”數據,在 DataGrid、EditGrid 和 Container 組件中使用", + "The current component JSON": "當前組件 JSON", + "The current component instance.": "當前組件實例。", + "The current value of the component.": "組件的當前值。", + "The moment.js library for date manipulation.": "用於日期操作的 moment.js 庫。", + "An instance of Lodash.": "Lodash 的一個實例。", + "An instance of the FormioUtils object.": "FormioUtils 對象的實例。", + "An alias for \"utils\".": "“utils”的別名。", + "Enter custom javascript code.": "輸入自定義 javascript 代碼。", + "You must assign the show variable a boolean result.": "您必須為 show 變量分配布爾結果。", + "Note: Advanced Conditional logic will override the results of the Simple Conditional logic.": "注意:高級條件邏輯將覆蓋簡單條件邏輯的結果。", + "Example": "例子", + "Click here for an example": "單擊此處查看示例", + "Execute custom logic using JSONLogic.": "使用 JSONLogic 執行自定義邏輯。", + "token": "令牌", + "user": "用戶", + "form": "形式", + "submission": "提交", + "data": "數據", + "row": "排", + "component": "成分", + "instance": "實例", + "value": "價值", + "moment": "片刻", + "utils": "效用", + "util": "效用", + "Error Message": "錯誤信息", + "Insert": "插入", + "Name": "姓名", + "Selector": "選擇器", + "Template": "模板", + "Style": "風格", + "Color": "顏色", + "Update On": "更新時間", + "Black List": "黑名單", + "Auto Expand": "自動展開", + "Label Margin": "標籤邊距", + "Label Width": "標籤寬度", + "Inline Layout": "行內佈局", + "Options Label Position": "選項標籤位置", + "Values": "價值觀", + "Shortcut": "捷徑", + "Maximum checked error message": "最大檢查錯誤信息", + "Minimum checked error message": "最小檢查錯誤信息", + "Maximum checked number": "最大勾選數", + "Minimum checked number": "最小勾選數", + "Decimal Places": "小數位", + "Require Decimal": "要求小數", + "Use Thousands Separator": "使用千位分隔符", + "Maximum Value": "最大值", + "Minimum Value": "最小值", + "Hide Input Labels": "隱藏輸入標籤", + "Inputs Label Position": "輸入標籤位置", + "Day First": "第一天", + "Type": "類型", + "Month": "月", + "Year": "年", + "Data": "數據", + "Validation": "驗證", + "Type of input": "輸入類型", + "Minimum Year": "最低年份", + "Maximum Year": "最大年份", + "Require Year": "要求年份", + "Require Day": "需要一天", + "Require Month": "要求月份", + "Minimum Day": "最短天數", + "Maximum Day": "最大天數", + "Modal Edit": "模態編輯", + "Refresh On Change": "更改時刷新", + "Custom CSS Class": "自定義 CSS 類", + "Custom Properties": "自定義屬性", + "Attribute Name": "屬性名稱", + "Attribute Value": "屬性值", + "PDF Overlay": "PDF疊加", + "Page": "頁", + "Left": "左邊", + "Top": "頂部", + "Width": "寬度", + "Height": "高度", + "Database Index": "數據庫索引", + "Encrypted (Enterprise Only)": "加密(僅限企業)", + "Redraw On": "重繪於", + "Protected": "受保護", + "Persistent": "執著的", + "None": "沒有任何", + "Server": "服務器", + "Client": "客戶", + "Calculate Value on server": "在服務器上計算值", + "Field Tags": "字段標籤", + "Advanced Logic": "高級邏輯", + "Table View": "表視圖", + "Clear Value When Hidden": "隱藏時清除值" + }, + "fr": { + "Basic Layout": "Disposition de base", + "Text/Images": "Texte/Images", + "Columns - 2": "Colonnes - 2", + "Columns - 3": "Colonnes - 3", + "Columns - 4": "Colonnes - 4", + "Tabs": "Onglets", + "Panel": "Panneau", + "Basic Fields": "Champs de base", + "Text Field": "Champ de texte", + "Multi-line Text": "Texte multiligne", + "Select List": "Sélectionner la liste", + "Checkbox": "Case à cocher", + "Checkbox Group": "Groupe de cases à cocher", + "Radio Group": "Groupe Radio", + "Number": "Nombre", + "Phone Number": "Numéro de téléphone", + "Email": "E-mail", + "Date/Time": "Date/Heure", + "Day": "Jour", + "Advanced Layout": "Mise en page avancée", + "HTML Element": "Élément HTML", + "Content": "Contenu", + "Columns": "Colonnes", + "Field Set": "Ensemble de champs", + "Table": "Tableau", + "Well": "Bien", + "Advanced Fields": "Champs avancés", + "Text Area": "Zone de texte", + "Url": "URL", + "Tags": "Mots clés", + "Address": "Adresse", + "Password": "Mot de passe", + "Time": "Temps", + "Select Boxes": "Sélectionnez les boîtes", + "Select": "Sélectionner", + "Currency": "Monnaie", + "Radio": "Radio", + "Button": "Bouton", + "Survey": "Enquête", + "Signature": "Signature", + "Advanced Data": "Données avancées", + "Hidden": "Cachée", + "Container": "Récipient", + "Data Map": "Carte de données", + "Edit Grid": "Modifier la grille", + "Tree": "Arbre", + "BC Government": "Gouvernement de la Colombie-Britannique", + "File Upload": "Téléchargement de fichiers", + "Business Name Search": "Recherche de nom d`entreprise", + "BC Address": "Adresse de la C.-B.", + "Search field": "Champ de recherche", + "Property Name": "Nom de la propriété", + "API": "API", + "Conditional": "Conditionnelle", + "Addons": "Compléments", + "Paragraph": "Paragraphe", + "Save": "Sauvegarder", + "Cancel": "Annuler", + "Remove": "Retirer", + "The following variables are available in all scripts.": "Les variables suivantes sont disponibles dans tous les scripts.", + "Display": "Afficher", + "Label": "Étiqueter", + "Help": "Aider", + "Auto adjust columns": "Ajuster automatiquement les colonnes", + "Hide Column when Chidren Hidden": "Masquer la colonne lorsque les enfants sont masqués", + "The label for this field that will appear next to it": "Le libellé de ce champ qui apparaîtra à côté", + "Preview": "Aperçu", + "Columns - 2 Component": "Colonnes - 2 composants", + "Columns - 3 Component": "Colonnes - 3 composants", + "Key": "Clé", + "Title": "Titre", + "Theme": "Thème", + "Collapsible": "Pliant", + "Label Position": "Emplacement de l'étiquette", + "Placeholder": "Espace réservé", + "Description": "Description", + "Tooltip": "Info-bulle", + "Input Mask": "Masque de saisie", + "Allow Multiple Masks": "Autoriser plusieurs masques", + "Hide Label": "Masquer l'étiquette", + "Show Word Counter": "Afficher le compteur de mots", + "Show Character Counter": "Afficher le compteur de caractères", + "Allow Spellcheck": "Autoriser la vérification orthographique", + "Disabled": "Désactivé", + "Multiple Values": "Valeurs multiples", + "Default Value": "Valeur par défaut", + "Text Case": "Casse du texte", + "Mixed (Allow upper and lower case)": "Mixte (Autoriser majuscules et minuscules)", + "Uppercase": "Majuscule", + "Lowercase": "Minuscule", + "Allow value propagation": "Autoriser la propagation de la valeur", + "Required": "Requis", + "Custom Error Message": "Message d'erreur personnalisé", + "Minimum Length": "Longueur minimale", + "Maximum Length": "Longueur maximale", + "This component should Display:": "Ce composant doit afficher :", + "When the form component:": "Lorsque le composant de formulaire :", + "Has the value:": "A la valeur :", + "The decoded JWT token for the authenticated user.": "Jeton JWT décodé pour l'utilisateur authentifié.", + "The current logged in user": "L'utilisateur actuellement connecté", + "The complete form JSON object": "L'objet JSON complet du formulaire", + "The complete submission object.": "L'objet de soumission complet.", + "The complete submission data object.": "L'objet de données de soumission complet.", + "Contextual \"row\" data, used within DataGrid, EditGrid, and Container components": "Données de \"ligne\" contextuelles, utilisées dans les composants DataGrid, EditGrid et Container", + "The current component JSON": "Le composant actuel JSON", + "The current component instance.": "L'instance de composant actuelle.", + "The current value of the component.": "La valeur actuelle du composant.", + "The moment.js library for date manipulation.": "La bibliothèque moment.js pour la manipulation de date.", + "An instance of Lodash.": "Une instance de Lodash.", + "An instance of the FormioUtils object.": "Une instance de l'objet FormioUtils.", + "An alias for \"utils\".": "Un alias pour \"utils\".", + "Enter custom javascript code.": "Entrez le code javascript personnalisé.", + "You must assign the show variable a boolean result.": "Vous devez attribuer à la variable show un résultat booléen.", + "Note: Advanced Conditional logic will override the results of the Simple Conditional logic.": "Remarque : La logique conditionnelle avancée remplacera les résultats de la logique conditionnelle simple.", + "Example": "Exemple", + "Click here for an example": "Cliquez ici pour un exemple", + "Execute custom logic using JSONLogic.": "Exécutez une logique personnalisée à l'aide de JSONLogic.", + "token": "jeton", + "user": "utilisateur", + "form": "former", + "submission": "soumission", + "data": "données", + "row": "ligne", + "component": "composant", + "value": "valeur", + "moment": "moment", + "utils": "utilitaires", + "util": "utile", + "Error Message": "Message d'erreur", + "Insert": "Insérer", + "Name": "Nom", + "Selector": "Sélecteur", + "Template": "Modèle", + "Style": "Style", + "Color": "Couleur", + "Update On": "Mettre à jour le", + "Black List": "Liste noire", + "Auto Expand": "Déplier automatiquement", + "Label Margin": "Marge de l'étiquette", + "Label Width": "Largeur de l'étiquette", + "Inline Layout": "Disposition en ligne", + "Options Label Position": "Options Position de l'étiquette", + "Values": "Valeurs", + "Shortcut": "Raccourci", + "Maximum checked error message": "Message d'erreur vérifié maximum", + "Minimum checked error message": "Message d'erreur vérifié minimum", + "Maximum checked number": "Nombre maximal de vérifications", + "Minimum checked number": "Nombre minimal de vérifications", + "Decimal Places": "Décimales", + "Require Decimal": "Exiger une décimale", + "Use Thousands Separator": "Utiliser le séparateur de milliers", + "Maximum Value": "Valeur maximum", + "Minimum Value": "Valeur minimum", + "Hide Input Labels": "Masquer les étiquettes d'entrée", + "Inputs Label Position": "Position de l'étiquette des entrées", + "Day First": "Premier jour", + "Type": "Taper", + "Month": "Mois", + "Year": "Année", + "Data": "Données", + "Validation": "Validation", + "Type of input": "Type d'entrée", + "Minimum Year": "Année minimale", + "Maximum Year": "Année maximale", + "Require Year": "Année requise", + "Require Day": "Jour requis", + "Require Month": "Mois requis", + "Minimum Day": "Journée minimale", + "Maximum Day": "Journée maximale", + "Modal Edit": "Modification modale", + "Refresh On Change": "Actualiser en cas de modification", + "Custom CSS Class": "Classe CSS personnalisée", + "Custom Properties": "Propriétés personnalisées", + "Attribute Name": "Nom d'attribut", + "Attribute Value": "Valeur d'attribut", + "PDF Overlay": "Superposition PDF", + "Page": "Page", + "Left": "Gauche", + "Top": "Haut", + "Width": "Largeur", + "Height": "Hauteur", + "Database Index": "Index de la base de données", + "Encrypted (Enterprise Only)": "Crypté (Entreprise uniquement)", + "Redraw On": "Redessiner sur", + "Protected": "Protégé", + "Persistent": "Persistant", + "None": "Aucun", + "Server": "Serveur", + "Client": "Client", + "Calculate Value on server": "Calculer la valeur sur le serveur", + "Field Tags": "Balises de champ", + "Advanced Logic": "Logique avancée", + "Table View": "Vue de tableau", + "Clear Value When Hidden": "Effacer la valeur lorsqu'elle est masquée" + }, + "es": { + "Basic Layout": "Diseño básico", + "Text/Images": "Texto/Imágenes", + "Columns - 2": "columnas - 2", + "Columns - 3": "columnas - 3", + "Columns - 4": "Columnas - 4", + "Tabs": "Pestañas", + "Panel": "Panel", + "Basic Fields": "Campos básicos", + "Text Field": "Campo de texto", + "Multi-line Text": "Texto de varias líneas", + "Select List": "Seleccionar lista", + "Checkbox": "Caja", + "Checkbox Group": "Grupo de casillas de verificación", + "Radio Group": "grupo radial", + "Number": "Número", + "Phone Number": "Número de teléfono", + "Email": "Correo electrónico", + "Date/Time": "Fecha y hora", + "Day": "Día", + "Advanced Layout": "Diseño avanzado", + "HTML Element": "Elemento HTML", + "Content": "Contenido", + "Columns": "columnas", + "Field Set": "Conjunto de campos", + "Table": "Mesa", + "Well": "Bien", + "Advanced Fields": "Campos Avanzados", + "Text Area": "Área de texto", + "Url": "URL", + "Tags": "Etiquetas", + "Address": "DIRECCIÓN", + "Password": "Contraseña", + "Time": "Tiempo", + "Select Boxes": "Seleccionar cajas", + "Select": "Seleccionar", + "Currency": "Divisa", + "Radio": "Radio", + "Button": "Botón", + "Survey": "Encuesta", + "Signature": "Firma", + "Advanced Data": "Datos avanzados", + "Hidden": "Oculto", + "Container": "Envase", + "Data Map": "Mapa de datos", + "Edit Grid": "Editar cuadrícula", + "Tree": "Árbol", + "BC Government": "Gobierno de BC", + "File Upload": "Subir archivo", + "Business Name Search": "Búsqueda de nombre comercial", + "BC Address": "Dirección BC", + "Search field": "Campo de búsqueda", + "Property Name": "Nombre de la propiedad", + "API": "API", + "Conditional": "Condicional", + "Addons": "Complementos", + "Paragraph": "Párrafo", + "Save": "Ahorrar", + "Cancel": "Cancelar", + "Remove": "Eliminar", + "The following variables are available in all scripts.": "Las siguientes variables están disponibles en todos los scripts.", + "Display": "Mostrar", + "Label": "Etiqueta", + "Help": "Ayuda", + "Auto adjust columns": "Columnas de ajuste automático", + "Hide Column when Chidren Hidden": "Ocultar columna cuando los niños están ocultos", + "The label for this field that will appear next to it": "La etiqueta de este campo que aparecerá junto a él", + "Preview": "Avance", + "Columns - 2 Component": "Columnas - 2 Componente", + "Columns - 3 Component": "Columnas - 3 Componente", + "Key": "Llave", + "Title": "Título", + "Theme": "Tema", + "Collapsible": "Plegable", + "Label Position": "Posición de la etiqueta", + "Placeholder": "Marcador de posición", + "Description": "Descripción", + "Tooltip": "Información sobre herramientas", + "Input Mask": "Máscara de entrada", + "Allow Multiple Masks": "Permitir máscaras múltiples", + "Hide Label": "Ocultar etiqueta", + "Show Word Counter": "Mostrar contador de palabras", + "Show Character Counter": "Mostrar contador de caracteres", + "Allow Spellcheck": "Permitir corrector ortográfico", + "Disabled": "Desactivado", + "Multiple Values": "Valores múltiples", + "Default Value": "Valor por defecto", + "Text Case": "Caso de texto", + "Mixed (Allow upper and lower case)": "Mixto (Permitir mayúsculas y minúsculas)", + "Uppercase": "Mayúsculas", + "Lowercase": "Minúsculas", + "Allow value propagation": "Permitir propagación de valor", + "Required": "Requerido", + "Custom Error Message": "Mensaje de error personalizado", + "Minimum Length": "Longitud mínima", + "Maximum Length": "Longitud máxima", + "This component should Display:": "Este componente debe mostrar:", + "When the form component:": "Cuando el componente de formulario:", + "Has the value:": "Tiene el valor:", + "The decoded JWT token for the authenticated user.": "El token JWT decodificado para el usuario autenticado.", + "The current logged in user": "El usuario conectado actual", + "The complete form JSON object": "El objeto JSON de formulario completo", + "The complete submission object.": "El objeto de envío completo.", + "The complete submission data object.": "El objeto de datos de envío completo.", + "Contextual \"row\" data, used within DataGrid, EditGrid, and Container components": "Datos de \"fila\" contextuales, utilizados en los componentes DataGrid, EditGrid y Container", + "The current component JSON": "El componente actual JSON", + "The current component instance.": "La instancia del componente actual.", + "The current value of the component.": "El valor actual del componente.", + "The moment.js library for date manipulation.": "La biblioteca moment.js para la manipulación de fechas.", + "An instance of Lodash.": "Una instancia de Lodash.", + "An instance of the FormioUtils object.": "Una instancia del objeto FormioUtils.", + "An alias for \"utils\".": "Un alias para \"utils\".", + "Enter custom javascript code.": "Ingrese el código javascript personalizado.", + "You must assign the show variable a boolean result.": "Debe asignar a la variable show un resultado booleano.", + "Note: Advanced Conditional logic will override the results of the Simple Conditional logic.": "Nota: La lógica condicional avanzada anulará los resultados de la lógica condicional simple.", + "Example": "Ejemplo", + "Click here for an example": "Haga clic aquí para ver un ejemplo", + "Execute custom logic using JSONLogic.": "Ejecute lógica personalizada usando JSONLogic.", + "token": "simbólico", + "user": "usuario", + "form": "forma", + "submission": "envío", + "data": "datos", + "row": "fila", + "component": "componente", + "instance": "instancia", + "value": "valor", + "moment": "momento", + "utils": "útiles", + "util": "útil", + "Error Message": "Mensaje de error", + "Insert": "Insertar", + "Name": "Nombre", + "Selector": "Selector", + "Template": "Plantilla", + "Style": "Estilo", + "Color": "Color", + "Update On": "Actualizar en", + "Black List": "Lista negra", + "Auto Expand": "Expansión automática", + "Label Margin": "Margen de etiqueta", + "Label Width": "Ancho de etiqueta", + "Inline Layout": "Diseño en línea", + "Options Label Position": "Posición de la etiqueta de opciones", + "Values": "Valores", + "Shortcut": "Atajo", + "Maximum checked error message": "Mensaje de error máximo verificado", + "Minimum checked error message": "Mensaje de error mínimo comprobado", + "Maximum checked number": "Número máximo facturado", + "Minimum checked number": "Número mínimo facturado", + "Decimal Places": "Lugares decimales", + "Require Decimal": "Requerir decimales", + "Use Thousands Separator": "Usar separador de miles", + "Maximum Value": "Valor máximo", + "Minimum Value": "Valor mínimo", + "Hide Input Labels": "Ocultar etiquetas de entrada", + "Inputs Label Position": "Posición de la etiqueta de entradas", + "Day First": "día primero", + "Type": "Tipo", + "Month": "Mes", + "Year": "Año", + "Data": "Datos", + "Validation": "Validación", + "Type of input": "Tipo de entrada", + "Minimum Year": "Año Mínimo", + "Maximum Year": "Año Máximo", + "Require Year": "Requerir Año", + "Require Day": "Requerir día", + "Require Month": "Requerir Mes", + "Minimum Day": "Día Mínimo", + "Maximum Day": "Día Máximo", + "Modal Edit": "Edición modal", + "Refresh On Change": "Actualizar al cambiar", + "Custom CSS Class": "Clase CSS personalizada", + "Custom Properties": "Propiedades personalizadas", + "Attribute Name": "Nombre del Atributo", + "Attribute Value": "Valor de atributo", + "PDF Overlay": "Superposición de PDF", + "Page": "Página", + "Left": "Izquierda", + "Top": "Arriba", + "Width": "Ancho", + "Height": "Altura", + "Database Index": "Índice de base de datos", + "Encrypted (Enterprise Only)": "Cifrado (Solo Enterprise)", + "Redraw On": "Redibujar en", + "Protected": "Protegido", + "Persistent": "Persistente", + "None": "Ninguno", + "Server": "Servidor", + "Client": "Cliente", + "Calculate Value on server": "Calcular valor en el servidor", + "Field Tags": "Etiquetas de campo", + "Advanced Logic": "Lógica avanzada", + "Table View": "Vista de tabla", + "Clear Value When Hidden": "Borrar valor cuando está oculto" + }, + "ar": { + "Basic Layout": "التخطيط الأساسي", + "Text/Images": "نص / صور", + "Columns - 2": "الأعمدة - 2", + "Columns - 3": "الأعمدة - 3", + "Columns - 4": "الأعمدة - 4", + "Tabs": "نوافذ التبويب", + "Panel": "لوحة", + "Basic Fields": "الحقول الأساسية", + "Text Field": "حقل النص", + "Multi-line Text": "نص متعدد الأسطر", + "Select List": "حدد قائمة", + "Checkbox": "خانة اختيار", + "Checkbox Group": "مجموعة خانة الاختيار", + "Radio Group": "مجموعة راديو", + "Number": "رقم", + "Phone Number": "رقم التليفون", + "Email": "بريد إلكتروني", + "Date/Time": "التاريخ / الوقت", + "Day": "يوم", + "Advanced Layout": "تخطيط متقدم", + "HTML Element": "عنصر HTML", + "Content": "محتوى", + "Columns": "الأعمدة", + "Field Set": "مجموعة الميدان", + "Table": "طاولة", + "Well": "حسنًا", + "Advanced Fields": "المجالات المتقدمة", + "Text Area": "منطقة النص", + "Url": "عنوان Url", + "Tags": "العلامات", + "Address": "عنوان", + "Password": "كلمة المرور", + "Time": "وقت", + "Select Boxes": "حدد المربعات", + "Select": "يختار", + "Currency": "عملة", + "Radio": "مذياع", + "Button": "زر", + "Survey": "استطلاع", + "Signature": "إمضاء", + "Advanced Data": "البيانات المتقدمة", + "Hidden": "مختفي", + "Container": "حاوية", + "Data Map": "خريطة البيانات", + "Edit Grid": "تحرير الشبكة", + "Tree": "شجرة", + "BC Government": "حكومة BC", + "File Upload": "تحميل الملف", + "Business Name Search": "البحث عن اسم الشركة", + "BC Address": "عنوان BC", + "Search field": "مجال البحث", + "Property Name": "اسم الخاصية", + "API": "API", + "Conditional": "الشرط", + "Addons": "الإضافات", + "Paragraph": "فقرة", + "Save": "يحفظ", + "Cancel": "يلغي", + "Remove": "يزيل", + "The following variables are available in all scripts.": "المتغيرات التالية متوفرة في جميع البرامج النصية.", + "Display": "عرض", + "Label": "ملصق", + "Help": "يساعد", + "Auto adjust columns": "أعمدة الضبط التلقائي", + "Hide Column when Chidren Hidden": "إخفاء العمود عندما يكون الأطفال مختبئين", + "The label for this field that will appear next to it": "تسمية هذا الحقل الذي سيظهر بجانبه", + "Preview": "معاينة", + "Columns - 2 Component": "الأعمدة - 2 مكون", + "Columns - 3 Component": "الأعمدة - 3 مكونات", + "Key": "مفتاح", + "Title": "عنوان", + "Theme": "سمة", + "Collapsible": "انهيار", + "Label Position": "موقف التسمية", + "Placeholder": "عنصر نائب", + "Description": "وصف", + "Tooltip": "تلميح", + "Input Mask": "قناع الإدخال", + "Allow Multiple Masks": "السماح بأقنعة متعددة", + "Hide Label": "إخفاء التسمية", + "Show Word Counter": "إظهار عداد الكلمات", + "Show Character Counter": "إظهار عداد الأحرف", + "Allow Spellcheck": "السماح بالتدقيق الإملائي", + "Disabled": "عاجز", + "Multiple Values": "قيم متعددة", + "Default Value": "القيمة الافتراضية", + "Text Case": "حالة النص", + "Mixed (Allow upper and lower case)": "مختلط (السماح بالأحرف الكبيرة والصغيرة)", + "Uppercase": "الأحرف الكبيرة", + "Lowercase": "أحرف صغيرة", + "Allow value propagation": "السماح بانتشار القيمة", + "Required": "مطلوب", + "Custom Error Message": "رسالة خطأ مخصصة", + "Minimum Length": "الطول الأدنى", + "Maximum Length": "الحد الأقصى لطول", + "This component should Display:": "يجب أن يعرض هذا المكون:", + "When the form component:": "عندما يكون مكون النموذج:", + "Has the value:": "له القيمة:", + "The decoded JWT token for the authenticated user.": "رمز JWT الذي تم فك ترميزه للمستخدم المصادق عليه.", + "The current logged in user": "المستخدم الحالي الذي قام بتسجيل الدخول", + "The complete form JSON object": "شكل كائن JSON الكامل", + "The complete submission object.": "كائن التقديم الكامل.", + "The complete submission data object.": "كائن بيانات الإرسال الكامل.", + "Contextual \"row\" data, used within DataGrid, EditGrid, and Container components": "بيانات \"الصف\" السياقية , المستخدمة داخل مكونات DataGrid و EditGrid والحاوية", + "The current component JSON": "المكون الحالي JSON", + "The current component instance.": "مثيل المكون الحالي.", + "The current value of the component.": "القيمة الحالية للمكون.", + "The moment.js library for date manipulation.": "مكتبة moment.js لمعالجة التاريخ.", + "An instance of Lodash.": "مثال على لوداش.", + "An instance of the FormioUtils object.": "مثيل لكائن FormioUtils.", + "An alias for \"utils\".": "اسم مستعار لـ \"utils\".", + "Enter custom javascript code.": "أدخل كود جافا سكريبت المخصص.", + "You must assign the show variable a boolean result.": "يجب تعيين نتيجة منطقية لمتغير العرض.", + "Note: Advanced Conditional logic will override the results of the Simple Conditional logic.": "ملاحظة: سيتجاوز المنطق الشرطي المتقدم نتائج المنطق الشرطي البسيط.", + "Example": "مثال", + "Click here for an example": "انقر هنا للحصول على مثال", + "Execute custom logic using JSONLogic.": "تنفيذ منطق مخصص باستخدام JSONLogic.", + "token": "رمز", + "user": "مستخدم", + "form": "استمارة", + "submission": "استسلام", + "data": "بيانات", + "row": "صف", + "component": "عنصر", + "instance": "مثال", + "value": "قيمة", + "moment": "لحظة", + "utils": "المرافق", + "util": "الاستفادة", + "Error Message": "رسالة خطأ", + "Insert": "إدراج", + "Name": "اسم", + "Selector": "محدد", + "Template": "نموذج", + "Style": "أسلوب", + "Color": "لون", + "Update On": "تحديث على", + "Black List": "القائمة السوداء", + "Auto Expand": "توسيع تلقائي", + "Label Margin": "هامش التسمية", + "Label Width": "عرض التسمية", + "Inline Layout": "تخطيط مضمن", + "Options Label Position": "وضع تسمية الخيارات", + "Values": "قيم", + "Shortcut": "الاختصار", + "Maximum checked error message": "تم فحص الحد الأقصى لرسالة الخطأ", + "Minimum checked error message": "الحد الأدنى من رسالة الخطأ المحددة", + "Maximum checked number": "أقصى عدد تم التحقق منه", + "Minimum checked number": "الحد الأدنى للرقم المدقق", + "Decimal Places": "منازل عشرية", + "Require Decimal": "مطلوب عشري", + "Use Thousands Separator": "استخدم فاصل الآلاف", + "Maximum Value": "القيمة القصوى", + "Minimum Value": "الحد الأدنى للقيمة", + "Hide Input Labels": "إخفاء عناوين الإدخال", + "Inputs Label Position": "موضع تسمية المدخلات", + "Day First": "اليوم الأول", + "Type": "يكتب", + "Month": "شهر", + "Year": "سنة", + "Data": "بيانات", + "Validation": "تصديق", + "Type of input": "نوع الإدخال", + "Minimum Year": "الحد الأدنى للسنة", + "Maximum Year": "الحد الأقصى للسنة", + "Require Year": "تتطلب السنة", + "Require Day": "تتطلب اليوم", + "Require Month": "يتطلب الشهر", + "Minimum Day": "يوم الحد الأدنى", + "Maximum Day": "أقصى يوم", + "Modal Edit": "تعديل مشروط", + "Refresh On Change": "التحديث عند التغيير", + "Custom CSS Class": "فئة CSS مخصصة", + "Custom Properties": "خصائص مخصصة", + "Attribute Name": "اسم السمة", + "Attribute Value": "قيمة السمة", + "PDF Overlay": "تراكب PDF", + "Page": "صفحة", + "Left": "غادر", + "Top": "قمة", + "Width": "عرض", + "Height": "ارتفاع", + "Database Index": "فهرس قاعدة البيانات", + "Encrypted (Enterprise Only)": "مشفر (مؤسسي فقط)", + "Redraw On": "إعادة رسم", + "Protected": "محمي", + "Persistent": "مثابر", + "None": "لا أحد", + "Server": "الخادم", + "Client": "عميل", + "Calculate Value on server": "حساب القيمة على الخادم", + "Field Tags": "العلامات الميدانية", + "Advanced Logic": "المنطق المتقدم", + "Table View": "عرض جدول", + "Clear Value When Hidden": "قيمة واضحة عند إخفاءها" + }, + "vi": { + "Basic Layout": "Bố cục cơ bản", + "Text/Images": "Văn bản/Hình ảnh", + "Columns - 2": "Cột - 2", + "Columns - 3": "Cột - 3", + "Columns - 4": "Cột - 4", + "Tabs": "tab", + "Panel": "bảng điều khiển", + "Basic Fields": "Các trường cơ bản", + "Text Field": "Trương Văn bản", + "Multi-line Text": "Văn bản nhiều dòng", + "Select List": "Chọn danh sách", + "Checkbox": "hộp kiểm", + "Checkbox Group": "Nhóm hộp kiểm", + "Radio Group": "Nhóm đài phát thanh", + "Number": "Con số", + "Phone Number": "Số điện thoại", + "Email": "E-mail", + "Date/Time": "Ngày giờ", + "Day": "Ngày", + "Advanced Layout": "Bố cục nâng cao", + "HTML Element": "Phần tử HTML", + "Content": "Nội dung", + "Columns": "Cột", + "Field Set": "Bộ trường", + "Table": "Bàn", + "Well": "Tốt", + "Advanced Fields": "Trường nâng cao", + "Text Area": "Khu vực văn bản", + "Url": "url", + "Tags": "thẻ", + "Address": "Địa chỉ", + "Password": "Mật khẩu", + "Time": "Thời gian", + "Select Boxes": "Chọn hộp", + "Select": "Lựa chọn", + "Currency": "Tiền tệ", + "Radio": "Đài", + "Button": "Cái nút", + "Survey": "Sự khảo sát", + "Signature": "Chữ ký", + "Advanced Data": "Dữ liệu nâng cao", + "Hidden": "Ẩn giấu", + "Container": "Thùng đựng hàng", + "Data Map": "Bản đồ dữ liệu", + "Edit Grid": "Chỉnh sửa lưới", + "Tree": "Cây", + "BC Government": "Chính phủ BC", + "File Upload": "Tải lên tệp", + "Business Name Search": "Tìm kiếm tên doanh nghiệp", + "BC Address": "Địa chỉ BC", + "Search field": "trường tìm kiếm", + "Property Name": "Tên tài sản", + "API": "API", + "Conditional": "có điều kiện", + "Addons": "bổ trợ", + "Paragraph": "Đoạn văn", + "Save": "Cứu", + "Cancel": "Hủy bỏ", + "Remove": "Di dời", + "The following variables are available in all scripts.": "Các biến sau đây có sẵn trong tất cả các tập lệnh.", + "Display": "Trưng bày", + "Label": "Nhãn", + "Help": "Giúp đỡ", + "Auto adjust columns": "Tự động điều chỉnh cột", + "Hide Column when Chidren Hidden": "Ẩn cột khi trẻ em ẩn", + "The label for this field that will appear next to it": "Nhãn cho trường này sẽ xuất hiện bên cạnh nó", + "Preview": "Xem trước", + "Columns - 2 Component": "Cột - 2 Thành phần", + "Columns - 3 Component": "Cột - 3 Thành phần", + "Key": "Chìa khóa", + "Title": "Tiêu đề", + "Theme": "chủ đề", + "Collapsible": "có thể thu gọn", + "Label Position": "Vị trí nhãn", + "Placeholder": "Trình giữ chỗ", + "Description": "Sự miêu tả", + "Tooltip": "Chú giải công cụ", + "Input Mask": "Mặt nạ", + "Allow Multiple Masks": "Cho phép nhiều mặt nạ", + "Hide Label": "Ẩn nhãn", + "Show Word Counter": "Hiển thị bộ đếm từ", + "Show Character Counter": "Hiển thị bộ đếm ký tự", + "Allow Spellcheck": "Cho phép kiểm tra chính tả", + "Disabled": "Tàn tật", + "Multiple Values": "Nhiều giá trị", + "Default Value": "Giá trị mặc định", + "Text Case": "trường hợp văn bản", + "Mixed (Allow upper and lower case)": "Hỗn hợp (Cho phép chữ hoa và chữ thường)", + "Uppercase": "chữ hoa", + "Lowercase": "chữ thường", + "Allow value propagation": "Cho phép lan truyền giá trị", + "Required": "Yêu cầu", + "Custom Error Message": "Thông báo lỗi tùy chỉnh", + "Minimum Length": "Chiều dài tối thiểu", + "Maximum Length": "Chiều dài tối đa", + "This component should Display:": "Thành phần này sẽ hiển thị:", + "When the form component:": "Khi thành phần biểu mẫu:", + "Has the value:": "Có giá trị:", + "The decoded JWT token for the authenticated user.": "Mã thông báo JWT đã giải mã cho người dùng được xác thực.", + "The current logged in user": "Người dùng đăng nhập hiện tại", + "The complete form JSON object": "Đối tượng JSON dạng hoàn chỉnh", + "The complete submission object.": "Các đối tượng đệ trình hoàn chỉnh.", + "The complete submission data object.": "Đối tượng dữ liệu đệ trình hoàn chỉnh.", + "Contextual \"row\" data, used within DataGrid, EditGrid, and Container components": "Dữ liệu \"hàng\" theo ngữ cảnh, được sử dụng trong các thành phần DataGrid, EditGrid và Vùng chứa", + "The current component JSON": "JSON thành phần hiện tại", + "The current component instance.": "Ví dụ thành phần hiện tại.", + "The current value of the component.": "Giá trị hiện tại của thành phần.", + "The moment.js library for date manipulation.": "Thư viện moment.js để thao tác ngày tháng.", + "An instance of Lodash.": "Một ví dụ của Lodash.", + "An instance of the FormioUtils object.": "Một thể hiện của đối tượng FormioUtils.", + "An alias for \"utils\".": "Một bí danh cho \"utils\".", + "Enter custom javascript code.": "Nhập mã javascript tùy chỉnh.", + "You must assign the show variable a boolean result.": "Bạn phải gán biến show một kết quả boolean.", + "Note: Advanced Conditional logic will override the results of the Simple Conditional logic.": "Lưu ý: Logic Điều kiện Nâng cao sẽ ghi đè kết quả của logic Điều kiện Đơn giản.", + "Example": "Ví dụ", + "Click here for an example": "Nhấn vào đây để xem ví dụ", + "Execute custom logic using JSONLogic.": "Thực thi logic tùy chỉnh bằng JSONLogic.", + "token": "mã thông báo", + "user": "người dùng", + "form": "hình thức", + "submission": "nộp hồ sơ", + "data": "dữ liệu", + "row": "hàng ngang", + "component": "thành phần", + "instance": "ví dụ", + "value": "giá trị", + "moment": "chốc lát", + "utils": "đồ dùng", + "util": "sử dụng", + "Error Message": "Thông báo lỗi", + "Insert": "Chèn", + "Name": "Tên", + "Selector": "Bộ chọn", + "Template": "Bản mẫu", + "Style": "Phong cách", + "Color": "Màu sắc", + "Update On": "Cập nhật lên", + "Black List": "Danh sách đen", + "Auto Expand": "Tự động mở rộng", + "Label Margin": "Lề nhãn", + "Label Width": "Chiều rộng nhãn", + "Inline Layout": "Bố cục nội tuyến", + "Options Label Position": "Tùy chọn Vị trí Nhãn", + "Values": "giá trị", + "Shortcut": "Đường tắt", + "Maximum checked error message": "Thông báo lỗi được kiểm tra tối đa", + "Minimum checked error message": "Thông báo lỗi được kiểm tra tối thiểu", + "Maximum checked number": "Số lượng kiểm tra tối đa", + "Minimum checked number": "Số kiểm tra tối thiểu", + "Decimal Places": "Số thập phân", + "Require Decimal": "Yêu cầu số thập phân", + "Use Thousands Separator": "Sử dụng dấu tách hàng nghìn", + "Maximum Value": "Gia trị lơn nhât", + "Minimum Value": "Giá trị tối thiểu", + "Hide Input Labels": "Ẩn nhãn đầu vào", + "Inputs Label Position": "Vị trí nhãn đầu vào", + "Day First": "Ngày đầu tiên", + "Type": "Kiểu", + "Month": "Tháng", + "Year": "Năm", + "Data": "Dữ liệu", + "Validation": "Thẩm định", + "Type of input": "Loại đầu vào", + "Minimum Year": "Năm tối thiểu", + "Maximum Year": "Năm tối đa", + "Require Year": "yêu cầu năm", + "Require Day": "ngày yêu cầu", + "Require Month": "Yêu cầu tháng", + "Minimum Day": "Ngày tối thiểu", + "Maximum Day": "Ngày tối đa", + "Modal Edit": "Sửa đổi phương thức", + "Refresh On Change": "Làm mới khi thay đổi", + "Custom CSS Class": "Lớp CSS tùy chỉnh", + "Custom Properties": "Thuộc tính tùy chỉnh", + "Attribute Name": "Tên thuộc tính", + "Attribute Value": "Giá trị thuộc tính", + "PDF Overlay": "Lớp phủ PDF", + "Page": "Trang", + "Left": "Bên trái", + "Top": "Đứng đầu", + "Width": "Chiều rộng", + "Height": "Chiều cao", + "Database Index": "chỉ mục cơ sở dữ liệu", + "Encrypted (Enterprise Only)": "Đã mã hóa (Chỉ dành cho doanh nghiệp)", + "Redraw On": "Bật vẽ lại", + "Protected": "được bảo vệ", + "Persistent": "Kiên trì", + "None": "Không có", + "Server": "Máy chủ", + "Client": "Khách hàng", + "Calculate Value on server": "Tính giá trị trên máy chủ", + "Field Tags": "Thẻ trường", + "Advanced Logic": "Logic nâng cao", + "Table View": "Xem bảng", + "Clear Value When Hidden": "Xóa giá trị khi ẩn" + }, + "tl": { + "Basic Layout": "Pangunahing Layout", + "Text/Images": "Teksto/Mga Larawan", + "Columns - 2": "Mga Hanay - 2", + "Columns - 3": "Mga Hanay - 3", + "Columns - 4": "Mga Hanay - 4", + "Tabs": "Mga tab", + "Panel": "Panel", + "Basic Fields": "Mga Pangunahing Patlang", + "Text Field": "Patlang ng Teksto", + "Multi-line Text": "Multi-line na Teksto", + "Select List": "Piliin ang Listahan", + "Checkbox": "Checkbox", + "Checkbox Group": "Pangkat ng Checkbox", + "Radio Group": "Grupo ng Radyo", + "Number": "Numero", + "Phone Number": "Numero ng telepono", + "Email": "Email", + "Date/Time": "Petsa/Oras", + "Day": "Araw", + "Advanced Layout": "Advanced na Layout", + "HTML Element": "HTML Element", + "Content": "Nilalaman", + "Columns": "Mga hanay", + "Field Set": "Field Set", + "Table": "mesa", + "Well": "Well", + "Advanced Fields": "Mga Advanced na Field", + "Text Area": "Lugar ng Teksto", + "Url": "Url", + "Tags": "Mga tag", + "Address": "Address", + "Password": "Password", + "Time": "Oras", + "Select Boxes": "Pumili ng Mga Kahon", + "Select": "Pumili", + "Currency": "Pera", + "Radio": "Radyo", + "Button": "Pindutan", + "Survey": "Survey", + "Signature": "Lagda", + "Advanced Data": "Advanced na Data", + "Hidden": "Nakatago", + "Container": "Lalagyan", + "Data Map": "Mapa ng Data", + "Edit Grid": "I-edit ang Grid", + "Tree": "Puno", + "BC Government": "Pamahalaan ng BC", + "File Upload": "Pag-upload ng File", + "Business Name Search": "Paghahanap ng Pangalan ng Negosyo", + "BC Address": "BC Address", + "Search field": "Field ng paghahanap", + "Property Name": "Pangalan ng Ari-arian", + "API": "API", + "Conditional": "May kundisyon", + "Addons": "Mga addon", + "Paragraph": "Talata", + "Save": "I-save", + "Cancel": "Kanselahin", + "Remove": "Alisin", + "The following variables are available in all scripts.": "Ang mga sumusunod na variable ay magagamit sa lahat ng mga script.", + "Display": "Display", + "Label": "Label", + "Help": "Tulong", + "Auto adjust columns": "Awtomatikong ayusin ang mga column", + "Hide Column when Chidren Hidden": "Itago ang Column kapag Nakatago ang mga Chidren", + "The label for this field that will appear next to it": "Ang label para sa field na ito na lalabas sa tabi nito", + "Preview": "Silipin", + "Columns - 2 Component": "Mga Column - 2 Component", + "Columns - 3 Component": "Mga Column - 3 Component", + "Key": "Susi", + "Title": "Pamagat", + "Theme": "Tema", + "Collapsible": "Collapsible", + "Label Position": "Posisyon ng Label", + "Placeholder": "Placeholder", + "Description": "Paglalarawan", + "Tooltip": "Tooltip", + "Input Mask": "Input Mask", + "Allow Multiple Masks": "Payagan ang Maramihang Maskara", + "Hide Label": "Itago ang Label", + "Show Word Counter": "Ipakita ang Word Counter", + "Show Character Counter": "Ipakita ang Character Counter", + "Allow Spellcheck": "Payagan ang Spellcheck", + "Disabled": "Hindi pinagana", + "Multiple Values": "Maramihang Halaga", + "Default Value": "Default na Halaga", + "Text Case": "Text Case", + "Mixed (Allow upper and lower case)": "Mixed (Pahintulutan ang upper at lower case)", + "Uppercase": "Malaking titik", + "Lowercase": "Maliit na titik", + "Allow value propagation": "Payagan ang pagpapalaganap ng halaga", + "Required": "Kailangan", + "Custom Error Message": "Custom na Mensahe ng Error", + "Minimum Length": "Pinakamababang Haba", + "Maximum Length": "Pinakamataas na Haba", + "This component should Display:": "Dapat Ipakita ang bahaging ito:", + "When the form component:": "Kapag ang bahagi ng form:", + "Has the value:": "May halaga:", + "The decoded JWT token for the authenticated user.": "Ang na-decode na JWT token para sa na-authenticate na user.", + "The current logged in user": "Ang kasalukuyang naka-log in na user", + "The complete form JSON object": "Ang kumpletong form na JSON object", + "The complete submission object.": "Ang kumpletong bagay sa pagsusumite.", + "The complete submission data object.": "Ang kumpletong object ng pagsusumite ng data.", + "Contextual \"row\" data, used within DataGrid, EditGrid, and Container components": "Data ng \"row\" sa konteksto, na ginagamit sa loob ng mga bahagi ng DataGrid, EditGrid, at Container", + "The current component JSON": "Ang kasalukuyang component na JSON", + "The current component instance.": "Ang kasalukuyang component instance.", + "The current value of the component.": "Ang kasalukuyang halaga ng bahagi.", + "The moment.js library for date manipulation.": "The moment.js library para sa pagmamanipula ng petsa.", + "An instance of Lodash.": "Isang halimbawa ng Lodash.", + "An instance of the FormioUtils object.": "Isang halimbawa ng bagay na FormioUtils.", + "An alias for \"utils\".": "Isang alias para sa \"utils\".", + "Enter custom javascript code.": "Maglagay ng custom na javascript code.", + "You must assign the show variable a boolean result.": "Dapat mong italaga ang show variable ng boolean na resulta.", + "Note: Advanced Conditional logic will override the results of the Simple Conditional logic.": "Tandaan: I-override ng Advanced na Conditional logic ang mga resulta ng Simple Conditional logic.", + "Example": "Halimbawa", + "Click here for an example": "Mag-click dito para sa isang halimbawa", + "Execute custom logic using JSONLogic.": "Magsagawa ng custom na logic gamit ang JSONLogic.", + "token": "token", + "user": "gumagamit", + "form": "anyo", + "submission": "pagsusumite", + "data": "datos", + "row": "hilera", + "component": "sangkap", + "instance": "halimbawa", + "value": "halaga", + "moment": "sandali", + "utils": "mga gamit", + "util": "gamitin", + "Error Message": "Maling mensahe", + "Insert": "Ipasok", + "Name": "Pangalan", + "Selector": "Tagapili", + "Template": "Template", + "Style": "Estilo", + "Color": "Kulay", + "Update On": "Naka-on ang Update", + "Black List": "Black List", + "Auto Expand": "Auto Expand", + "Label Margin": "Label Margin", + "Label Width": "Lapad ng Label", + "Inline Layout": "Inline na Layout", + "Options Label Position": "Posisyon ng Label ng Opsyon", + "Values": "Mga halaga", + "Shortcut": "Shortcut", + "Maximum checked error message": "Pinakamataas na nasuri na mensahe ng error", + "Minimum checked error message": "Minimum na nasuri na mensahe ng error", + "Maximum checked number": "Pinakamataas na naka-check na numero", + "Minimum checked number": "Minimum na naka-check na numero", + "Decimal Places": "Mga Desimal na Lugar", + "Require Decimal": "Nangangailangan ng Decimal", + "Use Thousands Separator": "Gumamit ng Thousands Separator", + "Maximum Value": "Pinakamataas na Halaga", + "Minimum Value": "Pinakamababang Halaga", + "Hide Input Labels": "Itago ang Mga Label ng Input", + "Inputs Label Position": "Posisyon ng Label ng Mga Input", + "Day First": "Unang Araw", + "Type": "Uri", + "Month": "buwan", + "Year": "taon", + "Data": "Data", + "Validation": "Pagpapatunay", + "Type of input": "Uri ng input", + "Minimum Year": "Minimum na Taon", + "Maximum Year": "Pinakamataas na Taon", + "Require Year": "Nangangailangan ng Taon", + "Require Day": "Kinakailangan ang Araw", + "Require Month": "Kinakailangan ang Buwan", + "Minimum Day": "Minimum na Araw", + "Maximum Day": "Pinakamataas na Araw", + "Modal Edit": "Modal Edit", + "Refresh On Change": "I-refresh Sa Pagbabago", + "Custom CSS Class": "Custom na CSS Class", + "Custom Properties": "Mga Custom na Property", + "Attribute Name": "Pangalan ng Katangian", + "Attribute Value": "Halaga ng Katangian", + "PDF Overlay": "PDF Overlay", + "Page": "Pahina", + "Left": "Kaliwa", + "Top": "Nangunguna", + "Width": "Lapad", + "Height": "taas", + "Database Index": "Index ng Database", + "Encrypted (Enterprise Only)": "Naka-encrypt (Enterprise Lang)", + "Redraw On": "I-redraw Sa", + "Protected": "Pinoprotektahan", + "Persistent": "Nagpupursige", + "None": "wala", + "Server": "server", + "Client": "Kliyente", + "Calculate Value on server": "Kalkulahin ang Halaga sa server", + "Field Tags": "Mga Field Tag", + "Advanced Logic": "Advanced na Logic", + "Table View": "Table View", + "Clear Value When Hidden": "I-clear ang Halaga Kapag Nakatago" + }, + "hi": { + "Basic Layout": "मूल लेआउट", + "Text/Images": "पाठ/छवियां", + "Columns - 2": "कॉलम - 2", + "Columns - 3": "कॉलम - 3", + "Columns - 4": "कॉलम - 4", + "Tabs": "टैब", + "Panel": "पैनल", + "Basic Fields": "बुनियादी क्षेत्र", + "Text Field": "पाठ्य से भरा", + "Multi-line Text": "बहु-पंक्ति पाठ", + "Select List": "सूची का चयन करें", + "Checkbox": "चेक बॉक्स", + "Checkbox Group": "चेकबॉक्स समूह", + "Radio Group": "रेडियो समूह", + "Number": "संख्या", + "Phone Number": "फ़ोन नंबर", + "Email": "ईमेल", + "Date/Time": "दिनांक समय", + "Day": "दिन", + "Advanced Layout": "उन्नत लेआउट", + "HTML Element": "एचटीएमएल तत्व", + "Content": "संतुष्ट", + "Columns": "कॉलम", + "Field Set": "फील्ड सेट", + "Table": "मेज", + "Well": "कुंआ", + "Advanced Fields": "उन्नत क्षेत्र", + "Text Area": "पाठ क्षेत्र", + "Url": "यूआरएल", + "Tags": "टैग", + "Address": "पता", + "Password": "पासवर्ड", + "Time": "समय", + "Select Boxes": "बक्सों का चयन करें", + "Select": "चुनना", + "Currency": "मुद्रा", + "Radio": "रेडियो", + "Button": "बटन", + "Survey": "सर्वे", + "Signature": "हस्ताक्षर", + "Advanced Data": "उन्नत डेटा", + "Hidden": "छिपा हुआ", + "Container": "पात्र", + "Data Map": "डेटा मानचित्र", + "Edit Grid": "ग्रिड संपादित करें", + "Tree": "पेड़", + "BC Government": "ईसा पूर्व सरकार", + "File Upload": "फाइल अपलोड", + "Business Name Search": "व्यवसाय का नाम खोज", + "BC Address": "बीसी पता", + "Search field": "खोज क्षेत्र", + "Property Name": "संपत्ति का नाम", + "API": "एपीआई", + "Conditional": "सशर्त", + "Addons": "ऐड-ऑन", + "Paragraph": "अनुच्छेद", + "Save": "बचाना", + "Cancel": "रद्द करना", + "Remove": "निकालना", + "The following variables are available in all scripts.": "निम्नलिखित चर सभी लिपियों में उपलब्ध हैं।", + "Display": "दिखाना", + "Label": "लेबल", + "Help": "मदद", + "Auto adjust columns": "स्वत: कॉलम समायोजित करें", + "Hide Column when Chidren Hidden": "बच्चों के छिपे होने पर कॉलम छुपाएं", + "The label for this field that will appear next to it": "इस फ़ील्ड का वह लेबल जो इसके आगे दिखाई देगा", + "Preview": "पूर्व दर्शन", + "Columns - 2 Component": "कॉलम - 2 घटक", + "Columns - 3 Component": "कॉलम - 3 घटक", + "Key": "चाबी", + "Title": "शीर्षक", + "Theme": "थीम", + "Collapsible": "खुलने और बंधनेवाला", + "Label Position": "लेबल स्थिति", + "Placeholder": "प्लेसहोल्डर", + "Description": "विवरण", + "Tooltip": "टूलटिप", + "Input Mask": "मुखौटा डालें", + "Allow Multiple Masks": "एकाधिक मास्क की अनुमति दें", + "Hide Label": "लेबल छुपाएं", + "Show Word Counter": "वर्ड काउंटर दिखाएं", + "Show Character Counter": "कैरेक्टर काउंटर दिखाएं", + "Allow Spellcheck": "वर्तनी जाँच की अनुमति दें", + "Disabled": "अक्षम", + "Multiple Values": "एकाधिक मान", + "Default Value": "डिफ़ॉल्ट मान", + "Text Case": "टेक्स्ट केस", + "Mixed (Allow upper and lower case)": "मिश्रित (ऊपरी और निचले मामले की अनुमति दें)", + "Uppercase": "अपरकेस", + "Lowercase": "छोटे", + "Allow value propagation": "मूल्य प्रसार की अनुमति दें", + "Required": "आवश्यक", + "Custom Error Message": "कस्टम त्रुटि संदेश", + "Minimum Length": "न्यूनतम लंबाई", + "Maximum Length": "ज्यादा से ज्यादा लंबाई", + "This component should Display:": "इस घटक को प्रदर्शित करना चाहिए:", + "When the form component:": "जब प्रपत्र घटक:", + "Has the value:": "मूल्य है:", + "The decoded JWT token for the authenticated user.": "प्रमाणित उपयोगकर्ता के लिए डीकोडेड जेडब्ल्यूटी टोकन।", + "The current logged in user": "वर्तमान लॉग इन उपयोगकर्ता", + "The complete form JSON object": "पूरा फॉर्म JSON ऑब्जेक्ट", + "The complete submission object.": "पूरा सबमिशन ऑब्जेक्ट।", + "The complete submission data object.": "पूरा सबमिशन डेटा ऑब्जेक्ट।", + "Contextual \"row\" data, used within DataGrid, EditGrid, and Container components": "प्रासंगिक \"पंक्ति\" डेटा, डेटाग्रिड, एडिटग्रिड और कंटेनर घटकों के भीतर उपयोग किया जाता है", + "The current component JSON": "वर्तमान घटक JSON", + "The current component instance.": "वर्तमान घटक उदाहरण।", + "The current value of the component.": "घटक का वर्तमान मूल्य।", + "The moment.js library for date manipulation.": "तारीख में हेरफेर के लिए पल.जेएस पुस्तकालय।", + "An instance of Lodash.": "लोदश का उदाहरण।", + "An instance of the FormioUtils object.": "FormioUtils ऑब्जेक्ट का एक उदाहरण।", + "An alias for \"utils\".": "\"बर्तन\" के लिए एक उपनाम।", + "Enter custom javascript code.": "कस्टम जावास्क्रिप्ट कोड दर्ज करें।", + "You must assign the show variable a boolean result.": "आपको शो वेरिएबल को एक बूलियन परिणाम निर्दिष्ट करना होगा।", + "Note: Advanced Conditional logic will override the results of the Simple Conditional logic.": "नोट: उन्नत सशर्त तर्क सरल सशर्त तर्क के परिणामों को ओवरराइड करेगा।", + "Example": "उदाहरण", + "Click here for an example": "एक उदाहरण के लिए यहां क्लिक करें", + "Execute custom logic using JSONLogic.": "JSONLogic का उपयोग करके कस्टम लॉजिक निष्पादित करें।", + "token": "टोकन", + "user": "उपयोगकर्ता", + "form": "प्रपत्र", + "submission": "जमा करना", + "data": "आंकड़े", + "row": "पंक्ति", + "component": "अवयव", + "instance": "उदाहरण", + "value": "कीमत", + "moment": "पल", + "utils": "बर्तन", + "util": "उपयोग", + "Error Message": "त्रुटि संदेश", + "Insert": "डालना", + "Name": "नाम", + "Selector": "चयनकर्ता", + "Template": "खाका", + "Style": "शैली", + "Color": "रंग", + "Update On": "अपर अद्यतन", + "Black List": "काली सूची", + "Auto Expand": "ऑटो विस्तार", + "Label Margin": "लेबल मार्जिन", + "Label Width": "लेबल की चौड़ाई", + "Inline Layout": "इनलाइन लेआउट", + "Options Label Position": "विकल्प लेबल स्थिति", + "Values": "मान", + "Shortcut": "छोटा रास्ता", + "Maximum checked error message": "अधिकतम जाँच त्रुटि संदेश", + "Minimum checked error message": "न्यूनतम जाँच त्रुटि संदेश", + "Maximum checked number": "अधिकतम जाँच संख्या", + "Minimum checked number": "न्यूनतम जाँच संख्या", + "Decimal Places": "दशमलव स्थानों", + "Require Decimal": "दशमलव की आवश्यकता है", + "Use Thousands Separator": "हजार विभाजक का प्रयोग करें", + "Maximum Value": "अधिकतम मूल्य", + "Minimum Value": "न्यूनतम मूल्य", + "Hide Input Labels": "इनपुट लेबल छुपाएं", + "Inputs Label Position": "इनपुट लेबल स्थिति", + "Day First": "पहला दिन", + "Type": "प्रकार", + "Month": "महीना", + "Year": "वर्ष", + "Data": "आंकड़े", + "Validation": "मान्यकरण", + "Type of input": "इनपुट का प्रकार", + "Minimum Year": "न्यूनतम वर्ष", + "Maximum Year": "अधिकतम वर्ष", + "Require Year": "वर्ष की आवश्यकता है", + "Require Day": "दिन की आवश्यकता है", + "Require Month": "माह चाहिए", + "Minimum Day": "न्यूनतम दिन", + "Maximum Day": "अधिकतम दिन", + "Modal Edit": "मॉडल संपादित करें", + "Refresh On Change": "परिवर्तन पर ताज़ा करें", + "Custom CSS Class": "कस्टम सीएसएस वर्ग", + "Custom Properties": "कस्टम गुण", + "Attribute Name": "उत्तरदायी ठहराने के लिए नाम", + "Attribute Value": "मान बताइए", + "PDF Overlay": "पीडीएफ ओवरले", + "Page": "पृष्ठ", + "Left": "बाएं", + "Top": "ऊपर", + "Width": "चौड़ाई", + "Height": "ऊंचाई", + "Database Index": "डाटाबेस इंडेक्स", + "Encrypted (Enterprise Only)": "एन्क्रिप्ट किया गया (केवल एंटरप्राइज़)", + "Redraw On": "फिर से ड्रा करें", + "Protected": "संरक्षित", + "Persistent": "ज़िद्दी", + "None": "कोई नहीं", + "Server": "सर्वर", + "Client": "ग्राहक", + "Calculate Value on server": "सर्वर पर मूल्य की गणना करें", + "Field Tags": "फील्ड टैग", + "Advanced Logic": "उन्नत तर्क", + "Table View": "तालिका दृश्य", + "Clear Value When Hidden": "छुपाए जाने पर स्पष्ट मूल्य" + }, + "uk": { + "Basic Layout": "Базовий макет", + "Text/Images": "Текст/Зображення", + "Columns - 2": "Колонки - 2", + "Columns - 3": "Колонки - 3", + "Columns - 4": "Колонки - 4", + "Tabs": "Вкладки", + "Panel": "Панель", + "Basic Fields": "Основні поля", + "Text Field": "Текстове поле", + "Multi-line Text": "Багаторядковий текст", + "Select List": "Виберіть Список", + "Checkbox": "Прапорець", + "Checkbox Group": "Група прапорців", + "Radio Group": "Радіогрупа", + "Number": "Номер", + "Phone Number": "Номер телефону", + "Email": "Електронна пошта", + "Date/Time": "Дата, час", + "Day": "День", + "Advanced Layout": "Розширений макет", + "HTML Element": "Елемент HTML", + "Content": "Зміст", + "Columns": "Стовпці", + "Field Set": "Набір полів", + "Table": "Таблиця", + "Well": "Добре", + "Advanced Fields": "Розширені поля", + "Text Area": "Текстова область", + "Url": "Url", + "Tags": "Теги", + "Address": "Адреса", + "Password": "Пароль", + "Time": "час", + "Select Boxes": "Виберіть Коробки", + "Select": "Виберіть", + "Currency": "Валюта", + "Radio": "радіо", + "Button": "Кнопка", + "Survey": "Опитування", + "Signature": "Підпис", + "Advanced Data": "Розширені дані", + "Hidden": "Прихований", + "Container": "Контейнер", + "Data Map": "Карта даних", + "Edit Grid": "Редагувати сітку", + "Tree": "дерево", + "BC Government": "Уряд БК", + "File Upload": "Завантаження файлу", + "Business Name Search": "Пошук назв компанії", + "BC Address": "БК Адреса", + "Search field": "Поле пошуку", + "Property Name": "Назва власності", + "API": "API", + "Conditional": "Умовний", + "Addons": "Аддони", + "Paragraph": "Абзац", + "Save": "зберегти", + "Cancel": "Скасувати", + "Remove": "видалити", + "The following variables are available in all scripts.": "Наступні змінні доступні в усіх сценаріях.", + "Display": "Дисплей", + "Label": "Мітка", + "Help": "Довідка", + "Auto adjust columns": "Автоматичне налаштування стовпців", + "Hide Column when Chidren Hidden": "Сховати стовпець, коли діти приховані", + "The label for this field that will appear next to it": "Мітка для цього поля, яка з’явиться поруч", + "Preview": "Попередній перегляд", + "Columns - 2 Component": "Стовпці - 2 компоненти", + "Columns - 3 Component": "Стовпці - 3 компоненти", + "Key": "ключ", + "Title": "Назва", + "Theme": "Тема", + "Collapsible": "розбірні", + "Label Position": "Позиція етикетки", + "Placeholder": "Заповнювач", + "Description": "опис", + "Tooltip": "Підказка", + "Input Mask": "Маска введення", + "Allow Multiple Masks": "Дозволити кілька масок", + "Hide Label": "Приховати мітку", + "Show Word Counter": "Показати лічильник слів", + "Show Character Counter": "Показати лічильник символів", + "Allow Spellcheck": "Дозволити перевірку правопису", + "Disabled": "Вимкнено", + "Multiple Values": "Кілька значень", + "Default Value": "Значення за замовчуванням", + "Text Case": "Регістр тексту", + "Mixed (Allow upper and lower case)": "Змішаний (дозволити верхній і нижній регістри)", + "Uppercase": "Великі літери", + "Lowercase": "Малі літери", + "Allow value propagation": "Дозволити поширення значення", + "Required": "вимагається", + "Custom Error Message": "Спеціальне повідомлення про помилку", + "Minimum Length": "Мінімальна довжина", + "Maximum Length": "Максимальна довжина", + "This component should Display:": "Цей компонент повинен відображати:", + "When the form component:": "Коли компонент форми:", + "Has the value:": "Має значення:", + "The decoded JWT token for the authenticated user.": "Декодований маркер JWT для автентифікованого користувача.", + "The current logged in user": "Поточний авторизований користувач", + "The complete form JSON object": "Об’єкт повної форми JSON", + "The complete submission object.": "Повний об’єкт подання.", + "The complete submission data object.": "Повний об’єкт даних подання.", + "Contextual \"row\" data, used within DataGrid, EditGrid, and Container components": "Контекстні «рядкові» дані, що використовуються в компонентах DataGrid, EditGrid і Container", + "The current component JSON": "Поточний компонент JSON", + "The current component instance.": "Поточний екземпляр компонента.", + "The current value of the component.": "Поточне значення компонента.", + "The moment.js library for date manipulation.": "Бібліотека moment.js для обробки дат.", + "An instance of Lodash.": "Примірник Лодаша.", + "An instance of the FormioUtils object.": "Екземпляр об’єкта FormioUtils.", + "An alias for \"utils\".": "Псевдонім для \"utils\".", + "Enter custom javascript code.": "Введіть спеціальний код JavaScript.", + "You must assign the show variable a boolean result.": "Ви повинні призначити змінній show логічний результат.", + "Note: Advanced Conditional logic will override the results of the Simple Conditional logic.": "Примітка. Розширена умовна логіка замінить результати простої умовної логіки.", + "Example": "приклад", + "Click here for an example": "Натисніть тут для прикладу", + "Execute custom logic using JSONLogic.": "Виконайте спеціальну логіку за допомогою JSONLogic.", + "token": "жетон", + "user": "користувача", + "form": "форму", + "submission": "подання", + "data": "даних", + "row": "рядок", + "component": "компонент", + "instance": "екземпляр", + "value": "значення", + "moment": "момент", + "utils": "утиліти", + "util": "util", + "Error Message": "Повідомлення про помилку", + "Insert": "Вставка", + "Name": "Ім'я", + "Selector": "Селектор", + "Template": "Шаблон", + "Style": "Стиль", + "Color": "колір", + "Update On": "Оновлення ввімкнено", + "Black List": "Чорний список", + "Auto Expand": "Автоматичне розширення", + "Label Margin": "Поле етикетки", + "Label Width": "Ширина етикетки", + "Inline Layout": "Вбудований макет", + "Options Label Position": "Позиція мітки параметрів", + "Values": "Цінності", + "Shortcut": "Ярлик", + "Maximum checked error message": "Максимально перевірене повідомлення про помилку", + "Minimum checked error message": "Мінімальне перевірене повідомлення про помилку", + "Maximum checked number": "Максимальна перевірена кількість", + "Minimum checked number": "Мінімальна перевірена кількість", + "Decimal Places": "Десяткові знаки", + "Require Decimal": "Вимагати Decimal", + "Use Thousands Separator": "Використовуйте роздільник тисяч", + "Maximum Value": "Максимальне значення", + "Minimum Value": "Мінімальна вартість", + "Hide Input Labels": "Приховати мітки введення", + "Inputs Label Position": "Вхідне положення мітки", + "Day First": "День перший", + "Type": "Тип", + "Month": "місяць", + "Year": "рік", + "Data": "Дані", + "Validation": "Перевірка", + "Type of input": "Тип введення", + "Minimum Year": "Мінімальний рік", + "Maximum Year": "Максимальний рік", + "Require Year": "Вимагати Рік", + "Require Day": "Потрібен день", + "Require Month": "Вимагати місяць", + "Minimum Day": "Мінімальний день", + "Maximum Day": "Максимальний день", + "Modal Edit": "Модальне редагування", + "Refresh On Change": "Оновити після зміни", + "Custom CSS Class": "Спеціальний клас CSS", + "Custom Properties": "Спеціальні властивості", + "Attribute Name": "Назва атрибута", + "Attribute Value": "Значення атрибута", + "PDF Overlay": "PDF Overlay", + "Page": "Сторінка", + "Left": "Ліворуч", + "Top": "Топ", + "Width": "Ширина", + "Height": "Висота", + "Database Index": "Індекс бази даних", + "Encrypted (Enterprise Only)": "Зашифровано (тільки для підприємств)", + "Redraw On": "Перемалювати вкл", + "Protected": "Захищений", + "Persistent": "Наполегливий", + "None": "Жодного", + "Server": "Сервер", + "Client": "Клієнт", + "Calculate Value on server": "Розрахувати вартість на сервері", + "Field Tags": "Теги полів", + "Advanced Logic": "Розширена логіка", + "Table View": "Перегляд таблиці", + "Clear Value When Hidden": "Очистити значення, коли воно приховане" + }, + "ru": { + "Basic Layout": "Базовая компоновка", + "Text/Images": "Текст/изображения", + "Columns - 2": "Колонны - 2", + "Columns - 3": "Колонны - 3", + "Columns - 4": "Колонны - 4", + "Tabs": "Вкладки", + "Panel": "Панель", + "Basic Fields": "Основные поля", + "Text Field": "Текстовое поле", + "Multi-line Text": "Многострочный текст", + "Select List": "Выберите список", + "Checkbox": "Флажок", + "Checkbox Group": "Группа флажков", + "Radio Group": "Радио Группа", + "Number": "Число", + "Phone Number": "Номер телефона", + "Email": "Электронная почта", + "Date/Time": "Дата/время", + "Day": "День", + "Advanced Layout": "Расширенный макет", + "HTML Element": "HTML-элемент", + "Content": "Содержание", + "Columns": "Столбцы", + "Field Set": "Набор полей", + "Table": "Стол", + "Well": "Хорошо", + "Advanced Fields": "Расширенные поля", + "Text Area": "Текстовая область", + "Url": "URL", + "Tags": "Теги", + "Address": "Адрес", + "Password": "Пароль", + "Time": "Время", + "Select Boxes": "Выберите коробки", + "Select": "Выбирать", + "Currency": "Валюта", + "Radio": "Радио", + "Button": "Кнопка", + "Survey": "Опрос", + "Signature": "Подпись", + "Advanced Data": "Расширенные данные", + "Hidden": "Скрытый", + "Container": "Контейнер", + "Data Map": "Карта данных", + "Edit Grid": "Редактировать сетку", + "Tree": "Дерево", + "BC Government": "Правительство Британской Колумбии", + "File Upload": "Файл загружен", + "Business Name Search": "Поиск названия компании", + "BC Address": "Адрес БК", + "Search field": "Поле поиска", + "Property Name": "Имя свойства", + "API": "API", + "Conditional": "Условный", + "Addons": "Аддоны", + "Paragraph": "Параграф", + "Save": "Сохранять", + "Cancel": "Отмена", + "Remove": "Удалять", + "The following variables are available in all scripts.": "Следующие переменные доступны во всех скриптах.", + "Display": "Отображать", + "Label": "Этикетка", + "Help": "Помощь", + "Auto adjust columns": "Автоматическая настройка столбцов", + "Hide Column when Chidren Hidden": "Скрыть столбец, когда дети скрыты", + "The label for this field that will appear next to it": "Метка для этого поля, которая будет отображаться рядом с ним", + "Preview": "Предварительный просмотр", + "Columns - 2 Component": "Колонны - 2 компонента", + "Columns - 3 Component": "Колонны - 3 компонента", + "Key": "Ключ", + "Title": "Заголовок", + "Theme": "Тема", + "Collapsible": "Складной", + "Label Position": "Позиция метки", + "Placeholder": "Заполнитель", + "Description": "Описание", + "Tooltip": "Подсказка", + "Input Mask": "Маска ввода", + "Allow Multiple Masks": "Разрешить несколько масок", + "Hide Label": "Скрыть ярлык", + "Show Word Counter": "Показать счетчик слов", + "Show Character Counter": "Показать счетчик символов", + "Allow Spellcheck": "Разрешить проверку орфографии", + "Disabled": "Неполноценный", + "Multiple Values": "Несколько значений", + "Default Value": "Значение по умолчанию", + "Text Case": "Текстовый регистр", + "Mixed (Allow upper and lower case)": "Смешанный (разрешить верхний и нижний регистр)", + "Uppercase": "Верхний регистр", + "Lowercase": "Нижний регистр", + "Allow value propagation": "Разрешить распространение значения", + "Required": "Необходимый", + "Custom Error Message": "Пользовательское сообщение об ошибке", + "Minimum Length": "Минимальная длина", + "Maximum Length": "Максимальная длина", + "This component should Display:": "Этот компонент должен отображать:", + "When the form component:": "Когда компонент формы:", + "Has the value:": "Имеет значение:", + "The decoded JWT token for the authenticated user.": "Расшифрованный токен JWT для аутентифицированного пользователя.", + "The current logged in user": "Текущий авторизованный пользователь", + "The complete form JSON object": "Полный объект формы JSON", + "The complete submission object.": "Полный объект отправки.", + "The complete submission data object.": "Полный объект данных отправки.", + "Contextual \"row\" data, used within DataGrid, EditGrid, and Container components": "Контекстные данные «строки», используемые в компонентах DataGrid, EditGrid и Container.", + "The current component JSON": "Текущий компонент JSON", + "The current component instance.": "Текущий экземпляр компонента.", + "The current value of the component.": "Текущее значение компонента.", + "The moment.js library for date manipulation.": "Библиотека moment.js для работы с датами.", + "An instance of Lodash.": "Экземпляр Lodash.", + "An instance of the FormioUtils object.": "Экземпляр объекта FormioUtils.", + "An alias for \"utils\".": "Псевдоним для «utils».", + "Enter custom javascript code.": "Введите пользовательский код JavaScript.", + "You must assign the show variable a boolean result.": "Вы должны присвоить переменной show логический результат.", + "Note: Advanced Conditional logic will override the results of the Simple Conditional logic.": "Примечание. Расширенная логика условий переопределяет результаты логики простых условий.", + "Example": "Пример", + "Click here for an example": "Нажмите здесь для примера", + "Execute custom logic using JSONLogic.": "Выполнение пользовательской логики с помощью JSONLogic.", + "token": "жетон", + "user": "пользователь", + "form": "форма", + "submission": "подчинение", + "data": "данные", + "row": "ряд", + "component": "компонент", + "instance": "пример", + "value": "ценить", + "moment": "момент", + "utils": "утилиты", + "util": "использовать", + "Error Message": "Сообщение об ошибке", + "Insert": "Вставлять", + "Name": "Имя", + "Selector": "Селектор", + "Template": "Шаблон", + "Style": "Стиль", + "Color": "Цвет", + "Update On": "Обновление включено", + "Black List": "Черный список", + "Auto Expand": "Автоматическое расширение", + "Label Margin": "Поле этикетки", + "Label Width": "Ширина этикетки", + "Inline Layout": "Встроенный макет", + "Options Label Position": "Положение ярлыка параметров", + "Values": "Ценности", + "Shortcut": "Ярлык", + "Maximum checked error message": "Максимальное проверенное сообщение об ошибке", + "Minimum checked error message": "Минимальное проверенное сообщение об ошибке", + "Maximum checked number": "Максимальное проверенное количество", + "Minimum checked number": "Минимальное проверенное число", + "Decimal Places": "Десятичные разряды", + "Require Decimal": "Требовать десятичной дроби", + "Use Thousands Separator": "Использовать разделитель тысяч", + "Maximum Value": "Максимальное значение", + "Minimum Value": "Минимальное значение", + "Hide Input Labels": "Скрыть метки ввода", + "Inputs Label Position": "Позиция метки входов", + "Day First": "День первый", + "Type": "Тип", + "Month": "Месяц", + "Year": "Год", + "Data": "Данные", + "Validation": "Проверка", + "Type of input": "Тип ввода", + "Minimum Year": "Минимальный год", + "Maximum Year": "Максимальный год", + "Require Year": "Требовать год", + "Require Day": "Требовать день", + "Require Month": "Требовать месяц", + "Minimum Day": "Минимальный день", + "Maximum Day": "Максимальный день", + "Modal Edit": "Модальное редактирование", + "Refresh On Change": "Обновить при изменении", + "Custom CSS Class": "Пользовательский класс CSS", + "Custom Properties": "Пользовательские свойства", + "Attribute Name": "имя атрибута", + "Attribute Value": "Значение атрибута", + "PDF Overlay": "Наложение PDF", + "Page": "Страница", + "Left": "Левый", + "Top": "Вершина", + "Width": "Ширина", + "Height": "Высота", + "Database Index": "Индекс базы данных", + "Encrypted (Enterprise Only)": "Зашифровано (только для предприятий)", + "Redraw On": "Перерисовать", + "Protected": "Защищено", + "Persistent": "Настойчивый", + "None": "Никто", + "Server": "Сервер", + "Client": "Клиент", + "Calculate Value on server": "Рассчитать стоимость на сервере", + "Field Tags": "Теги поля", + "Advanced Logic": "Расширенная логика", + "Table View": "Табличный вид", + "Clear Value When Hidden": "Очистить значение, если оно скрыто" + }, + "ja": { + "Basic Layout": "基本レイアウト", + "Text/Images": "テキスト/画像", + "Columns - 2": "列 - 2", + "Columns - 3": "列 - 3", + "Columns - 4": "列 - 4", + "Tabs": "タブ", + "Panel": "パネル", + "Basic Fields": "基本フィールド", + "Text Field": "テキストフィールド", + "Multi-line Text": "複数行テキスト", + "Select List": "リストを選択", + "Checkbox": "チェックボックス", + "Checkbox Group": "チェックボックス グループ", + "Radio Group": "ラジオグループ", + "Number": "番号", + "Phone Number": "電話番号", + "Email": "Eメール", + "Date/Time": "日付時刻", + "Day": "日", + "Advanced Layout": "高度なレイアウト", + "HTML Element": "HTML 要素", + "Content": "コンテンツ", + "Columns": "コラム", + "Field Set": "フィールドセット", + "Table": "テーブル", + "Well": "良い", + "Advanced Fields": "高度なフィールド", + "Text Area": "テキストエリア", + "Url": "URL", + "Tags": "タグ", + "Address": "住所", + "Password": "パスワード", + "Time": "時間", + "Select Boxes": "ボックスを選択", + "Select": "選択する", + "Currency": "通貨", + "Radio": "無線", + "Button": "ボタン", + "Survey": "調査", + "Signature": "サイン", + "Advanced Data": "高度なデータ", + "Hidden": "隠れた", + "Container": "容器", + "Data Map": "データマップ", + "Edit Grid": "グリッドを編集", + "Tree": "木", + "BC Government": "BC政府", + "File Upload": "ファイルのアップロード", + "Business Name Search": "商号検索", + "BC Address": "BC住所", + "Search field": "検索フィールド", + "Property Name": "プロパティ名", + "API": "API", + "Conditional": "条件付き", + "Addons": "アドオン", + "Paragraph": "段落", + "Save": "保存", + "Cancel": "キャンセル", + "Remove": "削除", + "The following variables are available in all scripts.": "次の変数は、すべてのスクリプトで使用できます。", + "Display": "画面", + "Label": "ラベル", + "Help": "ヘルプ", + "Auto adjust columns": "列の自動調整", + "Hide Column when Chidren Hidden": "子供が非表示のときに列を非表示", + "The label for this field that will appear next to it": "横に表示されるこのフィールドのラベル", + "Preview": "プレビュー", + "Columns - 2 Component": "列 - 2 コンポーネント", + "Columns - 3 Component": "列 - 3 コンポーネント", + "Key": "鍵", + "Title": "タイトル", + "Theme": "テーマ", + "Collapsible": "折りたたみ可能", + "Label Position": "ラベルの位置", + "Placeholder": "プレースホルダー", + "Description": "説明", + "Tooltip": "ツールチップ", + "Input Mask": "入力マスク", + "Allow Multiple Masks": "複数のマスクを許可", + "Hide Label": "ラベルを非表示", + "Show Word Counter": "単語カウンターを表示", + "Show Character Counter": "文字カウンターを表示", + "Allow Spellcheck": "スペルチェックを許可", + "Disabled": "無効", + "Multiple Values": "複数の値", + "Default Value": "デフォルト値", + "Text Case": "テキストケース", + "Mixed (Allow upper and lower case)": "混合 (大文字と小文字を許可)", + "Uppercase": "大文字", + "Lowercase": "小文字", + "Allow value propagation": "値の伝播を許可する", + "Required": "必要", + "Custom Error Message": "カスタム エラー メッセージ", + "Minimum Length": "最小長", + "Maximum Length": "最大長", + "This component should Display:": "このコンポーネントは次を表示する必要があります。", + "When the form component:": "フォーム コンポーネントの場合:", + "Has the value:": "次の値があります。", + "The decoded JWT token for the authenticated user.": "認証済みユーザーのデコードされた JWT トークン。", + "The current logged in user": "現在ログインしているユーザー", + "The complete form JSON object": "完全なフォーム JSON オブジェクト", + "The complete submission object.": "完全な送信オブジェクト。", + "The complete submission data object.": "完全な送信データ オブジェクト。", + "Contextual \"row\" data, used within DataGrid, EditGrid, and Container components": "DataGrid、EditGrid、および Container コンポーネント内で使用されるコンテキスト「行」データ", + "The current component JSON": "現在のコンポーネント JSON", + "The current component instance.": "現在のコンポーネント インスタンス。", + "The current value of the component.": "コンポーネントの現在の値。", + "The moment.js library for date manipulation.": "日付操作用の moment.js ライブラリ。", + "An instance of Lodash.": "Lodash のインスタンス。", + "An instance of the FormioUtils object.": "FormioUtils オブジェクトのインスタンス。", + "An alias for \"utils\".": "「utils」の別名。", + "Enter custom javascript code.": "カスタム JavaScript コードを入力します。", + "You must assign the show variable a boolean result.": "show 変数にブール値の結果を割り当てる必要があります。", + "Note: Advanced Conditional logic will override the results of the Simple Conditional logic.": "注: 高度な条件付きロジックは、単純な条件付きロジックの結果を上書きします。", + "Example": "例", + "Click here for an example": "例については、ここをクリックしてください", + "Execute custom logic using JSONLogic.": "JSONLogic を使用してカスタム ロジックを実行します。", + "token": "トークン", + "user": "ユーザー", + "form": "形状", + "submission": "提出", + "data": "データ", + "row": "行", + "component": "成分", + "instance": "実例", + "value": "価値", + "moment": "一瞬", + "utils": "ユーティリティ", + "util": "ユーティリティ", + "Error Message": "エラーメッセージ", + "Insert": "入れる", + "Name": "名前", + "Selector": "セレクタ", + "Template": "レンプレート", + "Style": "スタイル", + "Color": "色", + "Update On": "アップデートオン", + "Black List": "ブラックリスト", + "Auto Expand": "自動拡張", + "Label Margin": "ラベル余白", + "Label Width": "ラベル幅", + "Inline Layout": "インライン レイアウト", + "Options Label Position": "オプション ラベルの位置", + "Values": "値", + "Shortcut": "ショートカット", + "Maximum checked error message": "最大チェック エラー メッセージ", + "Minimum checked error message": "最小限のチェック済みエラー メッセージ", + "Maximum checked number": "最大チェック数", + "Minimum checked number": "最小チェック数", + "Decimal Places": "小数位", + "Require Decimal": "小数が必要", + "Use Thousands Separator": "桁区切り記号を使用する", + "Maximum Value": "最大値", + "Minimum Value": "最小値", + "Hide Input Labels": "入力ラベルを非表示", + "Inputs Label Position": "入力ラベルの位置", + "Day First": "初日", + "Type": "タイプ", + "Month": "月", + "Year": "年", + "Data": "データ", + "Validation": "検証", + "Type of input": "入力の種類", + "Minimum Year": "最低年", + "Maximum Year": "最大年", + "Require Year": "年が必要", + "Require Day": "必須日", + "Require Month": "月が必要", + "Minimum Day": "最小日", + "Maximum Day": "最大日", + "Modal Edit": "モーダル編集", + "Refresh On Change": "変更時にリフレッシュ", + "Custom CSS Class": "カスタム CSS クラス", + "Custom Properties": "カスタム プロパティ", + "Attribute Name": "属性名", + "Attribute Value": "属性値", + "PDF Overlay": "PDFオーバーレイ", + "Page": "ページ", + "Left": "左", + "Top": "上", + "Width": "幅", + "Height": "身長", + "Database Index": "データベース インデックス", + "Encrypted (Enterprise Only)": "暗号化 (エンタープライズのみ)", + "Redraw On": "再描画オン", + "Protected": "保護された", + "Persistent": "持続的に", + "None": "なし", + "Server": "サーバ", + "Client": "クライアント", + "Calculate Value on server": "サーバーで値を計算する", + "Field Tags": "フィールドタグ", + "Advanced Logic": "高度なロジック", + "Table View": "テーブル ビュー", + "Clear Value When Hidden": "非表示の場合は値をクリア" + }, + "ko": { + "Basic Layout": "기본 레이아웃", + "Text/Images": "텍스트/이미지", + "Columns - 2": "열 - 2", + "Columns - 3": "열 - 3", + "Columns - 4": "열 - 4", + "Tabs": "탭", + "Panel": "패널", + "Basic Fields": "기본 필드", + "Text Field": "텍스트 필드", + "Multi-line Text": "여러 줄 텍스트", + "Select List": "목록 선택", + "Checkbox": "체크박스", + "Checkbox Group": "확인란 그룹", + "Radio Group": "라디오 그룹", + "Number": "숫자", + "Phone Number": "전화 번호", + "Email": "이메일", + "Date/Time": "날짜 시간", + "Day": "낮", + "Advanced Layout": "고급 레이아웃", + "HTML Element": "HTML 요소", + "Content": "콘텐츠", + "Columns": "열", + "Field Set": "필드 세트", + "Table": "테이블", + "Well": "잘", + "Advanced Fields": "고급 필드", + "Text Area": "텍스트 영역", + "Url": "URL", + "Tags": "태그", + "Address": "주소", + "Password": "비밀번호", + "Time": "시간", + "Select Boxes": "상자 선택", + "Select": "선택하다", + "Currency": "통화", + "Radio": "라디오", + "Button": "단추", + "Survey": "조사", + "Signature": "서명", + "Advanced Data": "고급 데이터", + "Hidden": "숨겨진", + "Container": "컨테이너", + "Data Map": "데이터 맵", + "Edit Grid": "그리드 편집", + "Tree": "나무", + "BC Government": "BC 정부", + "File Upload": "파일 업로드", + "Business Name Search": "업체명 검색", + "BC Address": "기원전 주소", + "Search field": "검색 필드", + "Property Name": "속성 이름", + "API": "API", + "Conditional": "가정 어구", + "Addons": "애드온", + "Paragraph": "절", + "Save": "구하다", + "Cancel": "취소", + "Remove": "제거하다", + "The following variables are available in all scripts.": "다음 변수는 모든 스크립트에서 사용할 수 있습니다.", + "Display": "표시하다", + "Label": "상표", + "Help": "돕다", + "Auto adjust columns": "열 자동 조정", + "Hide Column when Chidren Hidden": "Chidren Hidden 시 열 숨기기", + "The label for this field that will appear next to it": "옆에 표시될 이 필드의 레이블", + "Preview": "시사", + "Columns - 2 Component": "열 - 2 구성 요소", + "Columns - 3 Component": "열 - 3개 구성 요소", + "Key": "열쇠", + "Title": "제목", + "Theme": "주제", + "Collapsible": "접을 수 있는", + "Label Position": "라벨 위치", + "Placeholder": "자리 표시자", + "Description": "설명", + "Tooltip": "툴팁", + "Input Mask": "입력 마스크", + "Allow Multiple Masks": "여러 마스크 허용", + "Hide Label": "라벨 숨기기", + "Show Word Counter": "단어 카운터 표시", + "Show Character Counter": "문자 카운터 표시", + "Allow Spellcheck": "맞춤법 검사 허용", + "Disabled": "장애가 있는", + "Multiple Values": "여러 값", + "Default Value": "기본값", + "Text Case": "텍스트 케이스", + "Mixed (Allow upper and lower case)": "혼합(대소문자 허용)", + "Uppercase": "대문자", + "Lowercase": "소문자", + "Allow value propagation": "가치 전파 허용", + "Required": "필수의", + "Custom Error Message": "사용자 지정 오류 메시지", + "Minimum Length": "최소 길이", + "Maximum Length": "최대 길이", + "This component should Display:": "이 구성 요소는 다음을 표시해야 합니다.", + "When the form component:": "양식 구성요소가 다음과 같은 경우:", + "Has the value:": "값:", + "The decoded JWT token for the authenticated user.": "인증된 사용자의 디코딩된 JWT 토큰입니다.", + "The current logged in user": "현재 로그인한 사용자", + "The complete form JSON object": "완전한 양식 JSON 객체", + "The complete submission object.": "완전한 제출 객체.", + "The complete submission data object.": "완전한 제출 데이터 개체입니다.", + "Contextual \"row\" data, used within DataGrid, EditGrid, and Container components": "DataGrid, EditGrid 및 컨테이너 구성 요소 내에서 사용되는 컨텍스트 \"행\" 데이터", + "The current component JSON": "현재 구성 요소 JSON", + "The current component instance.": "현재 구성 요소 인스턴스입니다.", + "The current value of the component.": "구성 요소의 현재 값입니다.", + "The moment.js library for date manipulation.": "날짜 조작을 위한 moment.js 라이브러리.", + "An instance of Lodash.": "Lodash의 인스턴스.", + "An instance of the FormioUtils object.": "FormioUtils 개체의 인스턴스입니다.", + "An alias for \"utils\".": "\"utils\"의 별칭입니다.", + "Enter custom javascript code.": "맞춤 자바스크립트 코드를 입력하세요.", + "You must assign the show variable a boolean result.": "show 변수에 부울 결과를 지정해야 합니다.", + "Note: Advanced Conditional logic will override the results of the Simple Conditional logic.": "참고: 고급 조건 논리는 단순 조건 논리의 결과를 재정의합니다.", + "Example": "예", + "Click here for an example": "예를 보려면 여기를 클릭하십시오.", + "Execute custom logic using JSONLogic.": "JSONLogic을 사용하여 사용자 지정 논리를 실행합니다.", + "token": "토큰", + "user": "사용자", + "form": "형태", + "submission": "제출", + "data": "데이터", + "row": "열", + "component": "요소", + "instance": "사례", + "value": "값", + "moment": "순간", + "utils": "유틸리티", + "util": "유틸리티", + "Error Message": "에러 메시지", + "Insert": "끼워 넣다", + "Name": "이름", + "Selector": "선택자", + "Template": "주형", + "Style": "스타일", + "Color": "색상", + "Update On": "업데이트 켜기", + "Black List": "블랙리스트", + "Auto Expand": "자동 확장", + "Label Margin": "라벨 여백", + "Label Width": "라벨 폭", + "Inline Layout": "인라인 레이아웃", + "Options Label Position": "옵션 라벨 위치", + "Values": "가치", + "Shortcut": "지름길", + "Maximum checked error message": "최대 확인 오류 메시지", + "Minimum checked error message": "최소 확인 오류 메시지", + "Maximum checked number": "최대 확인 수", + "Minimum checked number": "최소 확인 수", + "Decimal Places": "소수 자릿수", + "Require Decimal": "십진수 필요", + "Use Thousands Separator": "천 단위 구분 기호 사용", + "Maximum Value": "최대값", + "Minimum Value": "최소값", + "Hide Input Labels": "입력 레이블 숨기기", + "Inputs Label Position": "레이블 위치 입력", + "Day First": "첫날", + "Type": "유형", + "Month": "월", + "Year": "년도", + "Data": "데이터", + "Validation": "확인", + "Type of input": "입력 유형", + "Minimum Year": "최소 연도", + "Maximum Year": "최대 연도", + "Require Year": "연도 필요", + "Require Day": "요일 필요", + "Require Month": "월 필요", + "Minimum Day": "최소 요일", + "Maximum Day": "최대 일", + "Modal Edit": "모달 편집", + "Refresh On Change": "변경 시 새로 고침", + "Custom CSS Class": "사용자 정의 CSS 클래스", + "Custom Properties": "사용자 지정 속성", + "Attribute Name": "속성 이름", + "Attribute Value": "속성 값", + "PDF Overlay": "PDF 오버레이", + "Page": "페이지", + "Left": "왼쪽", + "Top": "맨 위", + "Width": "너비", + "Height": "키", + "Database Index": "데이터베이스 색인", + "Encrypted (Enterprise Only)": "암호화됨(기업 전용)", + "Redraw On": "다시 그리기 켜기", + "Protected": "보호", + "Persistent": "지속성 있는", + "None": "없음", + "Server": "섬기는 사람", + "Client": "고객", + "Calculate Value on server": "서버에서 값 계산", + "Field Tags": "필드 태그", + "Advanced Logic": "고급 로직", + "Table View": "테이블 보기", + "Clear Value When Hidden": "숨겨진 값 지우기" + }, + "pt": { + "Basic Layout": "Layout básico", + "Text/Images": "Texto/Imagens", + "Columns - 2": "Colunas - 2", + "Columns - 3": "Colunas - 3", + "Columns - 4": "Colunas - 4", + "Tabs": "Guias", + "Panel": "Painel", + "Basic Fields": "Campos Básicos", + "Text Field": "Campo de texto", + "Multi-line Text": "Texto de várias linhas", + "Select List": "Selecione a lista", + "Checkbox": "Caixa de seleção", + "Checkbox Group": "Grupo de caixas de seleção", + "Radio Group": "Grupo de rádio", + "Number": "Número", + "Phone Number": "Número de telefone", + "Email": "E-mail", + "Date/Time": "Data hora", + "Day": "Dia", + "Advanced Layout": "Esquema Avançado", + "HTML Element": "Elemento HTML", + "Content": "Contente", + "Columns": "colunas", + "Field Set": "Conjunto de campos", + "Table": "Mesa", + "Well": "Bem", + "Advanced Fields": "Campos Avançados", + "Text Area": "Área de texto", + "Url": "url", + "Tags": "Tag", + "Address": "Endereço", + "Password": "Senha", + "Time": "Tempo", + "Select Boxes": "Selecionar caixas", + "Select": "Selecione", + "Currency": "Moeda", + "Radio": "Rádio", + "Button": "Botão", + "Survey": "Enquete", + "Signature": "Assinatura", + "Advanced Data": "Dados Avançados", + "Hidden": "Escondido", + "Container": "Recipiente", + "Data Map": "Mapa de Dados", + "Edit Grid": "Editar grade", + "Tree": "Árvore", + "BC Government": "Governo BC", + "File Upload": "Carregar arquivo", + "Business Name Search": "Pesquisa de nomes comerciais", + "BC Address": "Endereço BC", + "Search field": "Campo de pesquisa", + "Property Name": "Nome da propriedade", + "API": "API", + "Conditional": "Condicional", + "Addons": "Complementos", + "Paragraph": "Parágrafo", + "Save": "Salvar", + "Cancel": "Cancelar", + "Remove": "Remover", + "The following variables are available in all scripts.": "As seguintes variáveis estão disponíveis em todos os scripts.", + "Display": "Mostrar", + "Label": "Rótulo", + "Help": "Ajuda", + "Auto adjust columns": "Colunas de ajuste automático", + "Hide Column when Chidren Hidden": "Ocultar coluna quando os filhos estão ocultos", + "The label for this field that will appear next to it": "O rótulo para este campo que aparecerá próximo a ele", + "Preview": "Visualização", + "Columns - 2 Component": "Colunas - 2 componentes", + "Columns - 3 Component": "Colunas - 3 componentes", + "Key": "Chave", + "Title": "Título", + "Theme": "Tema", + "Collapsible": "Dobrável", + "Label Position": "Posição da Etiqueta", + "Placeholder": "espaço reservado", + "Description": "Descrição", + "Tooltip": "Dica de ferramenta", + "Input Mask": "Máscara de entrada", + "Allow Multiple Masks": "Permitir várias máscaras", + "Hide Label": "Ocultar etiqueta", + "Show Word Counter": "Mostrar contador de palavras", + "Show Character Counter": "Mostrar contador de caracteres", + "Allow Spellcheck": "Permitir verificação ortográfica", + "Disabled": "Desabilitado", + "Multiple Values": "Valores Múltiplos", + "Default Value": "Valor padrão", + "Text Case": "maiúsculas e minúsculas", + "Mixed (Allow upper and lower case)": "Misto (permite maiúsculas e minúsculas)", + "Uppercase": "Maiúsculas", + "Lowercase": "Minúsculas", + "Allow value propagation": "Permitir propagação de valor", + "Required": "Obrigatório", + "Custom Error Message": "Mensagem de erro personalizada", + "Minimum Length": "Comprimento mínimo", + "Maximum Length": "Comprimento máximo", + "This component should Display:": "Este componente deve exibir:", + "When the form component:": "Quando o componente de formulário:", + "Has the value:": "Tem o valor:", + "The decoded JWT token for the authenticated user.": "O token JWT decodificado para o usuário autenticado.", + "The current logged in user": "O usuário conectado atual", + "The complete form JSON object": "O objeto JSON de formulário completo", + "The complete submission object.": "O objeto de envio completo.", + "The complete submission data object.": "O objeto de dados de envio completo.", + "Contextual \"row\" data, used within DataGrid, EditGrid, and Container components": "Dados contextuais de \"linha\", usados nos componentes DataGrid, EditGrid e Container", + "The current component JSON": "O componente atual JSON", + "The current component instance.": "A instância do componente atual.", + "The current value of the component.": "O valor atual do componente.", + "The moment.js library for date manipulation.": "A biblioteca moment.js para manipulação de data.", + "An instance of Lodash.": "Uma instância de Lodash.", + "An instance of the FormioUtils object.": "Uma instância do objeto FormioUtils.", + "An alias for \"utils\".": "Um apelido para \"utils\".", + "Enter custom javascript code.": "Digite o código javascript personalizado.", + "You must assign the show variable a boolean result.": "Você deve atribuir à variável show um resultado booleano.", + "Note: Advanced Conditional logic will override the results of the Simple Conditional logic.": "Observação: a lógica condicional avançada substituirá os resultados da lógica condicional simples.", + "Example": "Exemplo", + "Click here for an example": "Clique aqui para um exemplo", + "Execute custom logic using JSONLogic.": "Execute a lógica personalizada usando JSONLogic.", + "token": "símbolo", + "user": "do utilizador", + "form": "forma", + "submission": "submissão", + "data": "dados", + "row": "linha", + "component": "componente", + "instance": "instância", + "value": "valor", + "moment": "momento", + "utils": "útil", + "util": "útil", + "Error Message": "Mensagem de erro", + "Insert": "Inserir", + "Name": "Nome", + "Selector": "Seletor", + "Template": "Modelo", + "Style": "Estilo", + "Color": "Cor", + "Update On": "Atualizar em", + "Black List": "Lista negra", + "Auto Expand": "Expansão Automática", + "Label Margin": "Margem da etiqueta", + "Label Width": "Largura da etiqueta", + "Inline Layout": "Layout embutido", + "Options Label Position": "Posição do Rótulo de Opções", + "Values": "valores", + "Shortcut": "Atalho", + "Maximum checked error message": "Máximo verificado mensagem de erro", + "Minimum checked error message": "Mensagem de erro mínima verificada", + "Maximum checked number": "Número máximo verificado", + "Minimum checked number": "número mínimo verificado", + "Decimal Places": "Casas decimais", + "Require Decimal": "Exigir Decimais", + "Use Thousands Separator": "Usar separador de milhar", + "Maximum Value": "Valor máximo", + "Minimum Value": "Valor Mínimo", + "Hide Input Labels": "Ocultar rótulos de entrada", + "Inputs Label Position": "Posição do Rótulo de Entradas", + "Day First": "primeiro dia", + "Type": "Tipo", + "Month": "Mês", + "Year": "Ano", + "Data": "Dados", + "Validation": "Validação", + "Type of input": "Tipo de entrada", + "Minimum Year": "Ano Mínimo", + "Maximum Year": "Ano Máximo", + "Require Year": "Exigir ano", + "Require Day": "Exigir dia", + "Require Month": "Exigir Mês", + "Minimum Day": "Dia Mínimo", + "Maximum Day": "Dia Máximo", + "Modal Edit": "Edição modal", + "Refresh On Change": "Atualizar ao alterar", + "Custom CSS Class": "Classe CSS personalizada", + "Custom Properties": "Propriedades personalizadas", + "Attribute Name": "Nome do Atributo", + "Attribute Value": "Valor do atributo", + "PDF Overlay": "Sobreposição de PDF", + "Page": "Página", + "Left": "Esquerda", + "Top": "Principal", + "Width": "Largura", + "Height": "Altura", + "Database Index": "Índice de banco de dados", + "Encrypted (Enterprise Only)": "Criptografado (Somente Enterprise)", + "Redraw On": "Redesenhar", + "Protected": "Protegido", + "Persistent": "Persistente", + "None": "Nenhum", + "Server": "Servidor", + "Client": "Cliente", + "Calculate Value on server": "Calcular valor no servidor", + "Field Tags": "Marcas de campo", + "Advanced Logic": "Lógica Avançada", + "Table View": "Vista de mesa", + "Clear Value When Hidden": "Limpar valor quando oculto" + }, + "de": { + "Basic Layout": "Grundlayout", + "Text/Images": "Text/Bilder", + "Columns - 2": "Spalten - 2", + "Columns - 3": "Spalten - 3", + "Columns - 4": "Spalten - 4", + "Tabs": "Tabs", + "Panel": "Panel", + "Basic Fields": "Grundfelder", + "Text Field": "Textfeld", + "Multi-line Text": "Mehrzeiliger Text", + "Select List": "Wählen Sie Liste aus", + "Checkbox": "Kontrollkästchen", + "Checkbox Group": "Kontrollkästchengruppe", + "Radio Group": "Radiogruppe", + "Number": "Nummer", + "Phone Number": "Telefonnummer", + "Email": "Email", + "Date/Time": "Terminzeit", + "Day": "Tag", + "Advanced Layout": "Erweitertes Layout", + "HTML Element": "HTML-Element", + "Content": "Inhalt", + "Columns": "Säulen", + "Field Set": "Feldsatz", + "Table": "Tisch", + "Well": "Also", + "Advanced Fields": "Erweiterte Felder", + "Text Area": "Textbereich", + "Url": "URL", + "Tags": "Stichworte", + "Address": "Adresse", + "Password": "Passwort", + "Time": "Zeit", + "Select Boxes": "Wählen Sie Boxen aus", + "Select": "Wählen", + "Currency": "Währung", + "Radio": "Radio", + "Button": "Taste", + "Survey": "Umfrage", + "Signature": "Unterschrift", + "Advanced Data": "Erweiterte Daten", + "Hidden": "Versteckt", + "Container": "Container", + "Data Map": "Datenkarte", + "Edit Grid": "Raster bearbeiten", + "Tree": "Baum", + "BC Government": "Regierung von British Columbia", + "File Upload": "Datei-Upload", + "Business Name Search": "Suche nach Firmennamen", + "BC Address": "BC-Adresse", + "Search field": "Suchfeld", + "Property Name": "Name des Anwesens", + "API": "API", + "Conditional": "Bedingt", + "Addons": "Add-ons", + "Paragraph": "Absatz", + "Save": "Speichern", + "Cancel": "Stornieren", + "Remove": "Entfernen", + "The following variables are available in all scripts.": "Die folgenden Variablen sind in allen Skripten verfügbar.", + "Display": "Anzeige", + "Label": "Etikett", + "Help": "Hilfe", + "Auto adjust columns": "Spalten automatisch anpassen", + "Hide Column when Chidren Hidden": "Spalte ausblenden, wenn Kinder ausgeblendet sind", + "The label for this field that will appear next to it": "Die Beschriftung für dieses Feld, die daneben angezeigt wird", + "Preview": "Vorschau", + "Columns - 2 Component": "Säulen – 2 Komponenten", + "Columns - 3 Component": "Säulen – 3 Komponenten", + "Key": "Taste", + "Title": "Titel", + "Theme": "Thema", + "Collapsible": "Zusammenklappbar", + "Label Position": "Etikettenposition", + "Placeholder": "Platzhalter", + "Description": "Beschreibung", + "Tooltip": "Tooltip", + "Input Mask": "Eingabemaske", + "Allow Multiple Masks": "Mehrere Masken zulassen", + "Hide Label": "Beschriftung ausblenden", + "Show Word Counter": "Wortzähler anzeigen", + "Show Character Counter": "Zeichenzähler anzeigen", + "Allow Spellcheck": "Rechtschreibprüfung zulassen", + "Disabled": "Behinderte", + "Multiple Values": "Mehrere Werte", + "Default Value": "Standardwert", + "Text Case": "Textfall", + "Mixed (Allow upper and lower case)": "Gemischt (Groß- und Kleinschreibung zulassen)", + "Uppercase": "Großbuchstaben", + "Lowercase": "Kleinbuchstaben", + "Allow value propagation": "Wertweitergabe zulassen", + "Required": "Erforderlich", + "Custom Error Message": "Benutzerdefinierte Fehlermeldung", + "Minimum Length": "Minimale Länge", + "Maximum Length": "Maximale Länge", + "This component should Display:": "Diese Komponente sollte Folgendes anzeigen:", + "When the form component:": "Wenn die Formularkomponente:", + "Has the value:": "Hat den Wert:", + "The decoded JWT token for the authenticated user.": "Das entschlüsselte JWT-Token für den authentifizierten Benutzer.", + "The current logged in user": "Der aktuell angemeldete Benutzer", + "The complete form JSON object": "Das vollständige Formular-JSON-Objekt", + "The complete submission object.": "Das vollständige Einreichungsobjekt.", + "The complete submission data object.": "Das vollständige Übermittlungsdatenobjekt.", + "Contextual \"row\" data, used within DataGrid, EditGrid, and Container components": "Kontextbezogene „Zeilen“-Daten, die in DataGrid-, EditGrid- und Container-Komponenten verwendet werden", + "The current component JSON": "Der aktuelle Komponenten-JSON", + "The current component instance.": "Die aktuelle Komponenteninstanz.", + "The current value of the component.": "Der aktuelle Wert der Komponente.", + "The moment.js library for date manipulation.": "Die moment.js-Bibliothek zur Datumsmanipulation.", + "An instance of Lodash.": "Eine Instanz von Lodash.", + "An instance of the FormioUtils object.": "Eine Instanz des FormioUtils-Objekts.", + "An alias for \"utils\".": "Ein Alias für „utils“.", + "Enter custom javascript code.": "Geben Sie benutzerdefinierten Javascript-Code ein.", + "You must assign the show variable a boolean result.": "Sie müssen der Show-Variablen ein boolesches Ergebnis zuweisen.", + "Note: Advanced Conditional logic will override the results of the Simple Conditional logic.": "Hinweis: Die erweiterte bedingte Logik überschreibt die Ergebnisse der einfachen bedingten Logik.", + "Example": "Beispiel", + "Click here for an example": "Klicken Sie hier für ein Beispiel", + "Execute custom logic using JSONLogic.": "Führen Sie benutzerdefinierte Logik mit JSONLogic aus.", + "token": "Zeichen", + "user": "Benutzer", + "form": "form", + "submission": "Vorlage", + "data": "Daten", + "row": "Reihe", + "component": "Komponente", + "instance": "Beispiel", + "value": "Wert", + "moment": "Moment", + "utils": "Dienstprogramme", + "util": "util", + "Error Message": "Fehlermeldung", + "Insert": "Einfügung", + "Name": "Name", + "Selector": "Wähler", + "Template": "Vorlage", + "Style": "Stil", + "Color": "Farbe", + "Update On": "Update auf", + "Black List": "Schwarze Liste", + "Auto Expand": "Automatisch erweitern", + "Label Margin": "Etikettenrand", + "Label Width": "Etikettenbreite", + "Inline Layout": "Inline-Layout", + "Options Label Position": "Optionen Beschriftungsposition", + "Values": "Werte", + "Shortcut": "Abkürzung", + "Maximum checked error message": "Maximal überprüfte Fehlermeldung", + "Minimum checked error message": "Mindestens geprüfte Fehlermeldung", + "Maximum checked number": "Maximale überprüfte Anzahl", + "Minimum checked number": "Geprüfte Mindestanzahl", + "Decimal Places": "Nachkommastellen", + "Require Decimal": "Dezimalzahl erforderlich", + "Use Thousands Separator": "Verwenden Sie das Tausendertrennzeichen", + "Maximum Value": "Höchster Wert", + "Minimum Value": "Mindestwert", + "Hide Input Labels": "Eingabebeschriftungen ausblenden", + "Inputs Label Position": "Gibt die Etikettenposition ein", + "Day First": "Der erste Tag", + "Type": "Typ", + "Month": "Monat", + "Year": "Jahr", + "Data": "Daten", + "Validation": "Validierung", + "Type of input": "Art der Eingabe", + "Minimum Year": "Mindestjahr", + "Maximum Year": "Maximales Jahr", + "Require Year": "Jahr erforderlich", + "Require Day": "Tag erforderlich", + "Require Month": "Monat erforderlich", + "Minimum Day": "Mindesttag", + "Maximum Day": "Maximaler Tag", + "Modal Edit": "Modale Bearbeitung", + "Refresh On Change": "Bei Änderung aktualisieren", + "Custom CSS Class": "Benutzerdefinierte CSS-Klasse", + "Custom Properties": "Benutzerdefinierte Eigenschaften", + "Attribute Name": "Attributname", + "Attribute Value": "Attributwert", + "PDF Overlay": "PDF-Overlay", + "Page": "Buchseite", + "Left": "Links", + "Top": "Spitze", + "Width": "Breite", + "Height": "Höhe", + "Database Index": "Datenbankindex", + "Encrypted (Enterprise Only)": "Verschlüsselt (nur Enterprise)", + "Redraw On": "Neu zeichnen", + "Protected": "Geschützt", + "Persistent": "Hartnäckig", + "None": "Keiner", + "Server": "Server", + "Client": "Klient", + "Calculate Value on server": "Berechnen Sie den Wert auf dem Server", + "Field Tags": "Feld-Tags", + "Advanced Logic": "Erweiterte Logik", + "Table View": "Tabellenansicht", + "Clear Value When Hidden": "Wert löschen, wenn ausgeblendet" + }, + "it": { + "Basic Layout": "Disposizione di base", + "Text/Images": "Testo/Immagini", + "Columns - 2": "Colonne - 2", + "Columns - 3": "Colonne - 3", + "Columns - 4": "Colonne - 4", + "Tabs": "Schede", + "Panel": "Pannello", + "Basic Fields": "Campi di base", + "Text Field": "Campo di testo", + "Multi-line Text": "Testo multilinea", + "Select List": "Seleziona Elenco", + "Checkbox": "Casella di controllo", + "Checkbox Group": "Gruppo di caselle di controllo", + "Radio Group": "Gruppo radiofonico", + "Number": "Numero", + "Phone Number": "Numero di telefono", + "Email": "E-mail", + "Date/Time": "Appuntamento", + "Day": "Giorno", + "Advanced Layout": "Layout avanzato", + "HTML Element": "Elemento HTML", + "Content": "Contenuto", + "Columns": "Colonne", + "Field Set": "Insieme del campo", + "Table": "Tavolo", + "Well": "BENE", + "Advanced Fields": "Campi avanzati", + "Text Area": "Area di testo", + "Url": "Url", + "Tags": "Tag", + "Address": "Indirizzo", + "Password": "Parola d'ordine", + "Time": "Tempo", + "Select Boxes": "Seleziona Scatole", + "Select": "Selezionare", + "Currency": "Valuta", + "Radio": "Radio", + "Button": "Pulsante", + "Survey": "Sondaggio", + "Signature": "Firma", + "Advanced Data": "Dati avanzati", + "Hidden": "Nascosto", + "Container": "Contenitore", + "Data Map": "Mappa dati", + "Edit Grid": "Modifica griglia", + "Tree": "Albero", + "BC Government": "Governo a.C", + "File Upload": "Upload di file", + "Business Name Search": "Ricerca del nome dell'azienda", + "BC Address": "Indirizzo BC", + "Search field": "Campo di ricerca", + "Property Name": "Nome della proprietà", + "API": "API", + "Conditional": "Condizionale", + "Addons": "Componenti aggiuntivi", + "Paragraph": "Paragrafo", + "Save": "Salva", + "Cancel": "Annulla", + "Remove": "Rimuovere", + "The following variables are available in all scripts.": "Le seguenti variabili sono disponibili in tutti gli script.", + "Display": "Schermo", + "Label": "Etichetta", + "Help": "Aiuto", + "Auto adjust columns": "Regola automaticamente le colonne", + "Hide Column when Chidren Hidden": "Nascondi colonna quando i bambini sono nascosti", + "The label for this field that will appear next to it": "L'etichetta per questo campo che apparirà accanto ad esso", + "Preview": "Anteprima", + "Columns - 2 Component": "Colonne - 2 Componenti", + "Columns - 3 Component": "Colonne - 3 componenti", + "Key": "Chiave", + "Title": "Titolo", + "Theme": "Tema", + "Collapsible": "Collassabile", + "Label Position": "Posizione etichetta", + "Placeholder": "Segnaposto", + "Description": "Descrizione", + "Tooltip": "Descrizione comando", + "Input Mask": "Maschera di input", + "Allow Multiple Masks": "Consenti più maschere", + "Hide Label": "Nascondi etichetta", + "Show Word Counter": "Mostra contatore di parole", + "Show Character Counter": "Mostra contatore caratteri", + "Allow Spellcheck": "Consenti il controllo ortografico", + "Disabled": "Disabilitato", + "Multiple Values": "Valori multipli", + "Default Value": "Valore di default", + "Text Case": "Caso di testo", + "Mixed (Allow upper and lower case)": "Misto (Consenti lettere maiuscole e minuscole)", + "Uppercase": "Maiuscolo", + "Lowercase": "Minuscolo", + "Allow value propagation": "Consenti la propagazione del valore", + "Required": "Necessario", + "Custom Error Message": "Messaggio di errore personalizzato", + "Minimum Length": "Lunghezza minima", + "Maximum Length": "Lunghezza massima", + "This component should Display:": "Questo componente dovrebbe visualizzare:", + "When the form component:": "Quando il componente del modulo:", + "Has the value:": "Ha il valore:", + "The decoded JWT token for the authenticated user.": "Il token JWT decodificato per l'utente autenticato.", + "The current logged in user": "L'utente attualmente connesso", + "The complete form JSON object": "L'oggetto JSON del modulo completo", + "The complete submission object.": "L'oggetto di invio completo.", + "The complete submission data object.": "L'oggetto dati di invio completo.", + "Contextual \"row\" data, used within DataGrid, EditGrid, and Container components": "Dati di \"riga\" contestuali, utilizzati all'interno dei componenti DataGrid, EditGrid e Container", + "The current component JSON": "Il componente corrente JSON", + "The current component instance.": "L'istanza del componente corrente.", + "The current value of the component.": "Il valore corrente del componente.", + "The moment.js library for date manipulation.": "La libreria moment.js per la manipolazione della data.", + "An instance of Lodash.": "Un'istanza di Lodash.", + "An instance of the FormioUtils object.": "Un'istanza dell'oggetto FormioUtils.", + "An alias for \"utils\".": "Un alias per \"utils\".", + "Enter custom javascript code.": "Inserisci il codice JavaScript personalizzato.", + "You must assign the show variable a boolean result.": "Devi assegnare alla variabile show un risultato booleano.", + "Note: Advanced Conditional logic will override the results of the Simple Conditional logic.": "Nota: la logica condizionale avanzata sostituirà i risultati della logica condizionale semplice.", + "Example": "Esempio", + "Click here for an example": "Clicca qui per un esempio", + "Execute custom logic using JSONLogic.": "Esegui la logica personalizzata utilizzando JSONLogic.", + "token": "gettone", + "user": "utente", + "form": "modulo", + "submission": "sottomissione", + "data": "dati", + "row": "riga", + "component": "componente", + "instance": "esempio", + "value": "valore", + "moment": "momento", + "utils": "utils", + "util": "utile", + "Error Message": "Messaggio di errore", + "Insert": "Inserire", + "Name": "Nome", + "Selector": "Selettore", + "Template": "Modello", + "Style": "Stile", + "Color": "Colore", + "Update On": "Aggiornamento su", + "Black List": "Lista nera", + "Auto Expand": "Espandi automaticamente", + "Label Margin": "Margine etichetta", + "Label Width": "Larghezza etichetta", + "Inline Layout": "Disposizione in linea", + "Options Label Position": "Opzioni Etichetta Posizione", + "Values": "Valori", + "Shortcut": "Scorciatoia", + "Maximum checked error message": "Messaggio di errore massimo verificato", + "Minimum checked error message": "Messaggio di errore minimo verificato", + "Maximum checked number": "Numero massimo controllato", + "Minimum checked number": "Numero minimo controllato", + "Decimal Places": "Decimali", + "Require Decimal": "Richiedi decimale", + "Use Thousands Separator": "Usa il separatore delle migliaia", + "Maximum Value": "Valore massimo", + "Minimum Value": "Valore minimo", + "Hide Input Labels": "Nascondi etichette di input", + "Inputs Label Position": "Posizione etichetta ingressi", + "Day First": "Primo giorno", + "Type": "Tipo", + "Month": "Mese", + "Year": "Anno", + "Data": "Dati", + "Validation": "Convalida", + "Type of input": "Tipo di ingresso", + "Minimum Year": "Anno minimo", + "Maximum Year": "Anno massimo", + "Require Year": "Richiedi Anno", + "Require Day": "Richiedi Giorno", + "Require Month": "Richiedi mese", + "Minimum Day": "Giorno minimo", + "Maximum Day": "Giorno Massimo", + "Modal Edit": "Modifica modale", + "Refresh On Change": "Aggiorna al cambiamento", + "Custom CSS Class": "Classe CSS personalizzata", + "Custom Properties": "Proprietà personalizzate", + "Attribute Name": "nome attributo", + "Attribute Value": "Valore dell'attributo", + "PDF Overlay": "Sovrapposizione PDF", + "Page": "Pagina", + "Left": "Sinistra", + "Top": "Superiore", + "Width": "Larghezza", + "Height": "Altezza", + "Database Index": "Indice della banca dati", + "Encrypted (Enterprise Only)": "Crittografato (solo Enterprise)", + "Redraw On": "Ridisegna su", + "Protected": "Protetto", + "Persistent": "Persistente", + "None": "Nessuno", + "Server": "server", + "Client": "Cliente", + "Calculate Value on server": "Calcola valore sul server", + "Field Tags": "Tag di campo", + "Advanced Logic": "Logica avanzata", + "Table View": "Vista tabella", + "Clear Value When Hidden": "Cancella valore quando nascosto" + }, + "fa": { + "Basic Layout": "چیدمان اولیه", + "Text/Images": "متن/تصاویر", + "Columns - 2": "ستون ها - 2", + "Columns - 3": "ستون ها - 3", + "Columns - 4": "ستون ها - 4", + "Tabs": "زبانه ها", + "Panel": "پانل", + "Basic Fields": "زمینه های پایه", + "Text Field": "فیلد متن", + "Multi-line Text": "متن چند خطی", + "Select List": "فهرست را انتخاب کنید", + "Checkbox": "چک باکس", + "Checkbox Group": "گروه چک باکس", + "Radio Group": "گروه رادیویی", + "Number": "عدد", + "Phone Number": "شماره تلفن", + "Email": "پست الکترونیک", + "Date/Time": "زمان قرار", + "Day": "روز", + "Advanced Layout": "طرح بندی پیشرفته", + "HTML Element": "عنصر HTML", + "Content": "محتوا", + "Columns": "ستون ها", + "Field Set": "مجموعه فیلد", + "Table": "جدول", + "Well": "خوب", + "Advanced Fields": "زمینه های پیشرفته", + "Text Area": "ناحیه متن", + "Url": "آدرس اینترنتی", + "Tags": "برچسب ها", + "Address": "نشانی", + "Password": "کلمه عبور", + "Time": "زمان", + "Select Boxes": "جعبه ها را انتخاب کنید", + "Select": "انتخاب کنید", + "Currency": "واحد پول", + "Radio": "رادیو", + "Button": "دکمه", + "Survey": "نظر سنجی", + "Signature": "امضا", + "Advanced Data": "داده های پیشرفته", + "Hidden": "پنهان شده است", + "Container": "ظرف", + "Data Map": "نقشه داده ها", + "Edit Grid": "ویرایش گرید", + "Tree": "درخت", + "BC Government": "دولت قبل از میلاد", + "File Upload": "آپلود فایل", + "Business Name Search": "جستجوی نام کسب و کار", + "BC Address": "آدرس BC", + "Search field": "فیلد جستجو", + "Property Name": "نام ملک", + "API": "API", + "Conditional": "مشروط", + "Addons": "افزونه ها", + "Paragraph": "پاراگراف", + "Save": "صرفه جویی", + "Cancel": "لغو کنید", + "Remove": "برداشتن", + "The following variables are available in all scripts.": "متغیرهای زیر در همه اسکریپت ها موجود هستند.", + "Display": "نمایش دادن", + "Label": "برچسب", + "Help": "کمک", + "Auto adjust columns": "تنظیم خودکار ستون ها", + "Hide Column when Chidren Hidden": "پنهان کردن ستون هنگامی که کودکان پنهان می شوند", + "The label for this field that will appear next to it": "برچسب این فیلد که در کنار آن ظاهر می شود", + "Preview": "پیش نمایش", + "Columns - 2 Component": "ستون ها - 2 جزء", + "Columns - 3 Component": "ستون ها - 3 جزء", + "Key": "کلید", + "Title": "عنوان", + "Theme": "موضوع", + "Collapsible": "تاشو", + "Label Position": "موقعیت برچسب", + "Placeholder": "مکان نگهدار", + "Description": "شرح", + "Tooltip": "راهنمای ابزار", + "Input Mask": "ماسک ورودی", + "Allow Multiple Masks": "اجازه دادن به ماسک های متعدد", + "Hide Label": "پنهان کردن برچسب", + "Show Word Counter": "نمایش کلمه شمار", + "Show Character Counter": "نمایش شمارنده کاراکتر", + "Allow Spellcheck": "اجازه بررسی املا", + "Disabled": "معلول", + "Multiple Values": "ارزش های چندگانه", + "Default Value": "مقدار پیش فرض", + "Text Case": "مورد متن", + "Mixed (Allow upper and lower case)": "مخلوط (اجازه حروف بزرگ و کوچک)", + "Uppercase": "حروف بزرگ", + "Lowercase": "حروف کوچک", + "Allow value propagation": "اجازه انتشار ارزش را بدهید", + "Required": "ضروری", + "Custom Error Message": "پیام خطای سفارشی", + "Minimum Length": "حداقل طول", + "Maximum Length": "حداکثر طول", + "This component should Display:": "این کامپوننت باید نمایش دهد:", + "When the form component:": "هنگامی که جزء فرم:", + "Has the value:": "دارای ارزش:", + "The decoded JWT token for the authenticated user.": "رمز JWT رمزگشایی شده برای کاربر احراز هویت شده.", + "The current logged in user": "کاربر فعلی وارد شده", + "The complete form JSON object": "فرم کامل شی JSON", + "The complete submission object.": "شی ارسال کامل.", + "The complete submission data object.": "شی داده ارسال کامل.", + "Contextual \"row\" data, used within DataGrid, EditGrid, and Container components": "داده های متنی \"ردیف\", مورد استفاده در اجزای DataGrid, EditGrid و Container", + "The current component JSON": "جزء فعلی JSON", + "The current component instance.": "نمونه جزء فعلی.", + "The current value of the component.": "مقدار فعلی جزء", + "The moment.js library for date manipulation.": "کتابخانه moment.js برای دستکاری تاریخ.", + "An instance of Lodash.": "یک نمونه از لوداش.", + "An instance of the FormioUtils object.": "نمونه ای از شی FormioUtils.", + "An alias for \"utils\".": "نام مستعار \"Utils\".", + "Enter custom javascript code.": "کد جاوا اسکریپت سفارشی را وارد کنید.", + "You must assign the show variable a boolean result.": "شما باید به متغیر show یک نتیجه بولی اختصاص دهید.", + "Note: Advanced Conditional logic will override the results of the Simple Conditional logic.": "توجه: منطق شرطی پیشرفته نتایج منطق شرطی ساده را لغو می کند.", + "Example": "مثال", + "Click here for an example": "برای یک مثال اینجا کلیک کنید", + "Execute custom logic using JSONLogic.": "منطق سفارشی را با استفاده از JSONLogic اجرا کنید.", + "token": "نشانه", + "user": "کاربر", + "form": "فرم", + "submission": "ارسال", + "data": "داده ها", + "row": "ردیف", + "component": "جزء", + "instance": "نمونه, مثال", + "value": "ارزش", + "moment": "لحظه", + "utils": "کاربردها", + "util": "استفاده کنید", + "Error Message": "پیغام خطا", + "Insert": "درج کنید", + "Name": "نام", + "Selector": "انتخابگر", + "Template": "قالب", + "Style": "سبک", + "Color": "رنگ", + "Update On": "به روز رسانی روشن است", + "Black List": "لیست سیاه", + "Auto Expand": "گسترش خودکار", + "Label Margin": "حاشیه برچسب", + "Label Width": "عرض برچسب", + "Inline Layout": "طرح بندی درون خطی", + "Options Label Position": "موقعیت برچسب گزینه ها", + "Values": "ارزش های", + "Shortcut": "میانبر", + "Maximum checked error message": "حداکثر پیام خطای بررسی شده", + "Minimum checked error message": "حداقل پیام خطای بررسی شده", + "Maximum checked number": "حداکثر تعداد بررسی شده", + "Minimum checked number": "حداقل تعداد بررسی شده", + "Decimal Places": "مکان های اعشاری", + "Require Decimal": "نیاز به اعشار", + "Use Thousands Separator": "از جداکننده هزاران استفاده کنید", + "Maximum Value": "حداکثر مقدار", + "Minimum Value": "حداقل ارزش", + "Hide Input Labels": "پنهان کردن برچسب های ورودی", + "Inputs Label Position": "موقعیت برچسب ورودی ها", + "Day First": "روز اول", + "Type": "تایپ کنید", + "Month": "ماه", + "Year": "سال", + "Data": "داده ها", + "Validation": "اعتبار سنجی", + "Type of input": "نوع ورودی", + "Minimum Year": "حداقل سال", + "Maximum Year": "حداکثر سال", + "Require Year": "نیاز به سال", + "Require Day": "نیاز به روز", + "Require Month": "نیاز به ماه", + "Minimum Day": "حداقل روز", + "Maximum Day": "حداکثر روز", + "Modal Edit": "ویرایش مودال", + "Refresh On Change": "Refresh On Change", + "Custom CSS Class": "کلاس CSS سفارشی", + "Custom Properties": "ویژگی های سفارشی", + "Attribute Name": "نام مشخصه", + "Attribute Value": "ارزش صفت", + "PDF Overlay": "پوشش PDF", + "Page": "صفحه", + "Left": "ترک کرد", + "Top": "بالا", + "Width": "عرض", + "Height": "ارتفاع", + "Database Index": "فهرست پایگاه داده", + "Encrypted (Enterprise Only)": "رمزگذاری شده (فقط سازمانی)", + "Redraw On": "دوباره ترسیم کنید", + "Protected": "حفاظت شده", + "Persistent": "مداوم", + "None": "هیچ یک", + "Server": "سرور", + "Client": "مشتری", + "Calculate Value on server": "محاسبه مقدار روی سرور", + "Field Tags": "تگ های فیلد", + "Advanced Logic": "منطق پیشرفته", + "Table View": "نمای جدول", + "Clear Value When Hidden": "پاک کردن مقدار هنگام پنهان" + } +} \ No newline at end of file diff --git a/frontend/app/frontend/src/internationalization/trans/vuetify/locale/README.md b/frontend/app/frontend/src/internationalization/trans/vuetify/locale/README.md new file mode 100644 index 0000000..047600a --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/vuetify/locale/README.md @@ -0,0 +1,2 @@ +This directory contains the translation files for languages that are supported +by CHEFS, but not supported by Vuetify. diff --git a/frontend/app/frontend/src/internationalization/trans/vuetify/locale/hi.js b/frontend/app/frontend/src/internationalization/trans/vuetify/locale/hi.js new file mode 100644 index 0000000..46e6e3d --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/vuetify/locale/hi.js @@ -0,0 +1,69 @@ +export default { + badge: 'बिल्ला', + close: 'बंद करना', + dataIterator: { + noResultsText: 'कोई मिलान रिकॉर्ड पाया', + loadingText: 'आइटम लोड हो रहे हैं...', + }, + dataTable: { + itemsPerPageText: 'पंक्तियाँ प्रति पृष्ठ:', + ariaLabel: { + sortDescending: 'अवरोही क्रमबद्ध करें।', + sortAscending: 'आरोही क्रमबद्ध करें।', + sortNone: 'क्रमबद्ध नहीं।', + activateNone: 'छँटाई हटाने के लिए सक्रिय करें।', + activateDescending: 'अवरोही क्रमबद्ध करने के लिए सक्रिय करें।', + activateAscending: 'आरोही क्रमबद्ध करने के लिए सक्रिय करें।', + }, + sortBy: 'इसके अनुसार क्रमबद्ध करें', + }, + dataFooter: { + itemsPerPageText: 'आइटम प्रति पेज:', + itemsPerPageAll: 'सभी', + nextPage: 'अगला पृष्ठ', + prevPage: 'पिछला पृष्ठ', + firstPage: 'पहला पन्ना', + lastPage: 'अंतिम पृष्ठ', + pageText: '{2} में से {0}-{1}', + }, + datePicker: { + itemsSelected: '{0} चयनित', + nextMonthAriaLabel: 'अगले महीने', + nextYearAriaLabel: 'अगले वर्ष', + prevMonthAriaLabel: 'पिछला महीना', + prevYearAriaLabel: 'Previous year', + }, + noDataText: 'No data available', + carousel: { + prev: 'पिछला दृश्य', + next: 'अगला दृश्य', + ariaLabel: { + delimiter: '{1} में से हिंडोला स्लाइड {0}', + }, + }, + calendar: { + moreEvents: '{0} और', + }, + fileInput: { + counter: '{0} फ़ाइलें', + counterSize: '{0} फ़ाइलें (कुल {1})', + }, + timePicker: { + am: 'पूर्वाह्न', + pm: 'बजे', + }, + pagination: { + ariaLabel: { + wrapper: 'पेजिनेशन नेविगेशन', + next: 'अगला पृष्ठ', + previous: 'पिछला पृष्ठ', + page: 'गोटो पृष्ठ {0}', + currentPage: 'वर्तमान पृष्ठ, पृष्ठ {0}', + }, + }, + rating: { + ariaLabel: { + icon: '{1} में से {0} रेटिंग', + }, + }, +}; diff --git a/frontend/app/frontend/src/internationalization/trans/vuetify/locale/pa.js b/frontend/app/frontend/src/internationalization/trans/vuetify/locale/pa.js new file mode 100644 index 0000000..48bbd08 --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/vuetify/locale/pa.js @@ -0,0 +1,69 @@ +export default { + badge: 'ਬੈਜ', + close: 'ਬੰਦ ਕਰੋ', + dataIterator: { + noResultsText: 'ਕੋਈ ਮੇਲ ਖਾਂਦਾ ਰਿਕਾਰਡ ਨਹੀਂ ਮਿਲਿਆ', + loadingText: 'ਆਈਟਮਾਂ ਲੋਡ ਕੀਤੀਆਂ ਜਾ ਰਹੀਆਂ ਹਨ...', + }, + dataTable: { + itemsPerPageText: 'ਪ੍ਰਤੀ ਪੰਨਾ ਕਤਾਰਾਂ:', + ariaLabel: { + sortDescending: 'ਘਟਦੇ ਕ੍ਰਮ ਵਿੱਚ ਕ੍ਰਮਬੱਧ।', + sortAscending: 'ਵੱਧਦੇ ਕ੍ਰਮ ਵਿੱਚ ਕ੍ਰਮਬੱਧ।', + sortNone: 'ਕ੍ਰਮਬੱਧ ਨਹੀਂ।', + activateNone: 'ਛਾਂਟੀ ਨੂੰ ਹਟਾਉਣ ਲਈ ਕਿਰਿਆਸ਼ੀਲ ਕਰੋ।', + activateDescending: 'ਘਟਦੇ ਕ੍ਰਮ ਨੂੰ ਕ੍ਰਮਬੱਧ ਕਰਨ ਲਈ ਕਿਰਿਆਸ਼ੀਲ ਕਰੋ।', + activateAscending: 'ਵਧਦੇ ਕ੍ਰਮ ਨੂੰ ਕ੍ਰਮਬੱਧ ਕਰਨ ਲਈ ਕਿਰਿਆਸ਼ੀਲ ਕਰੋ।', + }, + sortBy: 'ਦੇ ਨਾਲ ਕ੍ਰਮਬੱਧ', + }, + dataFooter: { + itemsPerPageText: 'ਆਈਟਮਾਂ ਪ੍ਰਤੀ ਪੰਨਾ:', + itemsPerPageAll: 'ਸਾਰੇ', + nextPage: 'ਅਗਲਾ ਪੰਨਾ', + prevPage: 'ਪਿਛਲੇ ਸਫ਼ੇ', + firstPage: 'ਪਹਿਲਾ ਪੰਨਾ', + lastPage: 'ਆਖਰੀ ਪੰਨਾ', + pageText: '{2} ਵਿੱਚੋਂ {0}-{1}', + }, + datePicker: { + itemsSelected: '{0} ਚੁਣਿਆ ਗਿਆ', + nextMonthAriaLabel: 'ਅਗਲਾ ਮਹੀਨਾ', + nextYearAriaLabel: 'ਅਗਲੇ ਸਾਲ', + prevMonthAriaLabel: 'ਪਿਛਲਾ ਮਹੀਨਾ', + prevYearAriaLabel: 'ਪਿਛਲੇ ਸਾਲ', + }, + noDataText: 'ਕੋਈ ਡਾਟਾ ਉਪਲਬਧ ਨਹੀਂ ਹੈ', + carousel: { + prev: 'ਪਿਛਲਾ ਵਿਜ਼ੂਅਲ', + next: 'ਅਗਲਾ ਵਿਜ਼ੁਅਲ', + ariaLabel: { + delimiter: 'ਕੈਰੋਸੇਲ ਸਲਾਈਡ {1} ਵਿੱਚੋਂ {0}', + }, + }, + calendar: { + moreEvents: '{0} ਹੋਰ', + }, + fileInput: { + counter: '{0} ਫ਼ਾਈਲਾਂ', + counterSize: '{0} ਫ਼ਾਈਲਾਂ (ਕੁੱਲ {1})', + }, + timePicker: { + am: 'ਏ.ਐੱਮ', + pm: 'ਪੀ.ਐੱਮ', + }, + pagination: { + ariaLabel: { + wrapper: 'ਪੰਨਾ ਨੈਵੀਗੇਸ਼ਨ', + next: 'ਅਗਲਾ ਪੰਨਾ', + previous: 'ਪਿਛਲੇ ਸਫ਼ੇ', + page: `ਪੰਨਾ {0} 'ਤੇ ਜਾਓ`, + currentPage: 'ਮੌਜੂਦਾ ਪੰਨਾ, ਪੰਨਾ {0}', + }, + }, + rating: { + ariaLabel: { + icon: '{1} ਵਿੱਚੋਂ {0} ਰੇਟਿੰਗ', + }, + }, +}; diff --git a/frontend/app/frontend/src/internationalization/trans/vuetify/locale/tl.js b/frontend/app/frontend/src/internationalization/trans/vuetify/locale/tl.js new file mode 100644 index 0000000..e61045e --- /dev/null +++ b/frontend/app/frontend/src/internationalization/trans/vuetify/locale/tl.js @@ -0,0 +1,69 @@ +export default { + badge: 'Badge', + close: 'Isara', + dataIterator: { + noResultsText: 'Walang nakitang katugmang mga tala', + loadingText: 'Naglo-load ng mga item...', + }, + dataTable: { + itemsPerPageText: 'Mga hilera bawat pahina:', + ariaLabel: { + sortDescending: 'Pinagsunod-sunod pababa.', + sortAscending: 'Pinagsunod-sunod pataas.', + sortNone: 'Hindi inayos.', + activateNone: 'I-activate para alisin ang pag-uuri.', + activateDescending: 'I-activate para pagbukud-bukurin pababa.', + activateAscending: 'I-activate para pagbukud-bukurin ang pataas.', + }, + sortBy: 'Pagbukud-bukurin ayon sa', + }, + dataFooter: { + itemsPerPageText: 'Mga item sa bawat pahina:', + itemsPerPageAll: 'Lahat', + nextPage: 'Susunod na pahina', + prevPage: 'Nakaraang pahina', + firstPage: 'Unang pahina', + lastPage: 'Huling pahina', + pageText: '{0}-{1} ng {2}', + }, + datePicker: { + itemsSelected: '{0} ang napili', + nextMonthAriaLabel: 'Susunod na buwan', + nextYearAriaLabel: 'Sa susunod na taon', + prevMonthAriaLabel: 'Nakaraang buwan', + prevYearAriaLabel: 'Nakaraang taon', + }, + noDataText: 'Walang available na data', + carousel: { + prev: 'Nakaraang visual', + next: 'Susunod na visual', + ariaLabel: { + delimiter: 'Carousel slide {0} ng {1}', + }, + }, + calendar: { + moreEvents: '{0} pa', + }, + fileInput: { + counter: '{0} mga file', + counterSize: '{0} mga file ({1} sa kabuuan)', + }, + timePicker: { + am: 'AM', + pm: 'PM', + }, + pagination: { + ariaLabel: { + wrapper: 'Pag-navigate sa Pagbilang ng pahina', + next: 'Susunod na pahina', + previous: 'Nakaraang pahina', + page: 'Pumunta sa Pahina {0}', + currentPage: 'Kasalukuyang Pahina, Pahina {0}', + }, + }, + rating: { + ariaLabel: { + icon: 'Rating {0} ng {1}', + }, + }, +}; diff --git a/frontend/app/frontend/src/main.js b/frontend/app/frontend/src/main.js new file mode 100644 index 0000000..fd75a26 --- /dev/null +++ b/frontend/app/frontend/src/main.js @@ -0,0 +1,202 @@ +import 'nprogress/nprogress.css'; +import '@bcgov/bc-sans/css/BCSans.css'; +import '~/assets/scss/style.scss'; + +import axios from 'axios'; +import Keycloak from 'keycloak-js'; +import NProgress from 'nprogress'; +import { createPinia } from 'pinia'; +import { createApp, h } from 'vue'; + +import App from '~/App.vue'; + +import { formatDate, formatDateLong } from '~/filters'; +import i18n from '~/internationalization'; +import vuetify from '~/plugins/vuetify'; +import getRouter from '~/router'; +import { useAuthStore } from '~/store/auth'; +import { useAppStore } from '~/store/app'; +import { assertOptions, getConfig, sanitizeConfig } from '~/utils/keycloak'; + +let keycloak = null; +const pinia = createPinia(); + +const app = createApp({ + render: () => h(App), +}); + +app.config.globalProperties.$filters = { + formatDate, + formatDateLong, +}; + +// Add our custom components to the formio instance +// importing the main formio dependency (whether through vue-formio or directly) +// has to be done BEFORE the keycloak adapter for some reason or it breaks the keycloak library on non-Chromium MS Edge (or IE11). +// No idea why, probably a polyfill clash +import BcGovFormioComponents from '~/formio/lib'; +import { Formio } from '@formio/vue'; +Formio.use(BcGovFormioComponents); + +/* import clipboard */ +import Clipboard from 'vue3-clipboard'; +app.use(Clipboard, { + autoSetContainer: true, + appendToBody: true, +}); + +app.use(pinia); +app.use(vuetify); + +NProgress.configure({ showSpinner: false }); +NProgress.start(); + +// IE11 Detection (https://stackoverflow.com/a/21825207) +if (!!window.MSInputMethodContext && !!document.documentMode) { + document.write(`
+

We're sorry but ${ + import.meta.env.VITE_TITLE + } is not supported in Internet Explorer.

+

Please use a modern browser instead (Chrome, Firefox, etc).

+
`); + NProgress.done(); +} else { + loadConfig(); +} + +/** + * @function initializeApp + * Initializes and mounts the Vue instance + * @param {boolean} [kcSuccess=false] is Keycloak initialized successfully? + * @param {string} [basepath='/'] base server path + */ +function initializeApp(kcSuccess = false, basePath = '/') { + if (!kcSuccess) return; + + app.use(i18n); + + const router = getRouter(basePath); + app.use(router); + router.app = app; + + app.mount('#app'); + + axios.defaults.baseURL = import.meta.env.BASE_URL; + + NProgress.done(); +} + +/** + * @function loadConfig + * Acquires the configuration state from the backend server + */ +async function loadConfig() { + // App publicPath is ./ - so use relative path here, will hit the backend server using relative path to root. + const configUrl = + import.meta.env.MODE === 'production' + ? 'config' + : `${import.meta.env.BASE_URL}/config`; + const storageKey = 'config'; + try { + // Get configuration if it isn't already in session storage + if (sessionStorage.getItem(storageKey) === null) { + const { data } = await axios.get(configUrl); + sessionStorage.setItem(storageKey, JSON.stringify(data)); + } + + // Mount the configuration as a prototype for easier access from Vue + const config = JSON.parse(sessionStorage.getItem(storageKey)); + const appStore = useAppStore(); + appStore.config = Object.freeze(config); + + if ( + !config || + !config.keycloak || + !config.keycloak.clientId || + !config.keycloak.realm || + !config.keycloak.serverUrl + ) { + throw new Error('Keycloak is misconfigured'); + } + + loadKeycloak(config); + } catch (err) { + sessionStorage.removeItem(storageKey); + initializeApp(false); // Attempt to gracefully fail + throw new Error(`Failed to acquire configuration: ${err.message}`); + } +} + +/** + * @function loadKeycloak + * Applies Keycloak authentication capabilities + * @param {object} config A config object + */ +function loadKeycloak(config) { + const defaultParams = { + config: window.__BASEURL__ ? `${window.__BASEURL__}/config` : '/config', + init: { onLoad: 'login-required' }, + }; + + const options = Object.assign({}, defaultParams, { + init: { onLoad: 'check-sso' }, + config: { + clientId: config.keycloak.clientId, + realm: config.keycloak.realm, + url: config.keycloak.serverUrl, + }, + onReady: () => { + initializeApp(true, config.basePath); + }, + onInitError: (error) => { + console.error('Keycloak failed to initialize'); // eslint-disable-line no-console + console.error(error); // eslint-disable-line no-console + }, + }); + + if (assertOptions(options).hasError) + throw new Error(`Invalid options given: ${assertOptions(options).error}`); + + getConfig(options.config) + .then((cfg) => { + const ctor = sanitizeConfig(cfg); + + const authStore = useAuthStore(); + + keycloak = new Keycloak(ctor); + keycloak.onReady = (authenticated) => { + authStore.updateKeycloak(keycloak, authenticated); + authStore.ready = true; + typeof options.onReady === 'function' && options.onReady(); + }; + keycloak.onAuthSuccess = () => { + // Check token validity every 10 seconds (10 000 ms) and, if necessary, update the token. + // Refresh token if it's valid for less then 60 seconds + const updateTokenInterval = setInterval( + () => + keycloak.updateToken(60).catch(() => { + keycloak.clearToken(); + }), + 10000 + ); + authStore.logoutFn = () => { + clearInterval(updateTokenInterval); + keycloak.logout( + options.logout || { redirectUri: config['logoutRedirectUri'] } + ); + }; + }; + keycloak.onAuthRefreshSuccess = () => { + authStore.updateKeycloak(keycloak, true); + }; + keycloak.onAuthLogout = () => { + authStore.updateKeycloak(keycloak, false); + }; + keycloak.init(options.init).catch((err) => { + typeof options.onInitError === 'function' && options.onInitError(err); + }); + }) + .catch((err) => { + console.log(err); // eslint-disable-line no-console + }); +} diff --git a/frontend/app/frontend/src/plugins/templateExtensions.js b/frontend/app/frontend/src/plugins/templateExtensions.js new file mode 100644 index 0000000..4e40fce --- /dev/null +++ b/frontend/app/frontend/src/plugins/templateExtensions.js @@ -0,0 +1,53 @@ +import { Templates } from '@formio/vue'; + +/** + * Extend an existing template by first getting the current template function and then call that function in addition to your own + * see: https://help.form.io/developers/form-templates#overriding-templates + */ +const currentTemplate = Templates.current; + +export default Templates.current = { + // template + input: { + // render mode + form: (ctx) => { + // add accessibility attributes for required fields + if (ctx.component.validate.required) { + ctx.input.attr['aria-required'] = 'true'; + ctx.input.attr['required'] = 'required'; + } + return currentTemplate.input.form(ctx); + }, + }, + checkbox: { + form: (ctx) => { + // add accessibility attributes for required fields + if (ctx.component.validate.required) { + ctx.input.attr['aria-required'] = 'true'; + ctx.input.attr['required'] = 'required'; + } + return currentTemplate.checkbox.form(ctx); + }, + }, + select: { + form: (ctx) => { + // add accessibility attributes for required fields + if (ctx.component.validate.required) { + ctx.input.attr['aria-required'] = 'true'; + ctx.input.attr['required'] = 'required'; + } + return currentTemplate.select.form(ctx); + }, + }, + radio: { + form: (ctx) => { + // add accessibility attributes for required fields + if (ctx.component.validate.required) { + ctx.input.attr['required'] = 'required'; + } + return `
${currentTemplate.radio.form( + ctx + )}
`; + }, + }, +}; diff --git a/frontend/app/frontend/src/plugins/vuetify.js b/frontend/app/frontend/src/plugins/vuetify.js new file mode 100644 index 0000000..9c8fbc4 --- /dev/null +++ b/frontend/app/frontend/src/plugins/vuetify.js @@ -0,0 +1,107 @@ +import 'vuetify/styles'; +import { createVuetify } from 'vuetify'; +import * as components from 'vuetify/components'; +import * as directives from 'vuetify/directives'; +import { fa as FONTAWESOME } from 'vuetify/iconsets/fa'; +import { aliases, mdi } from 'vuetify/iconsets/mdi'; +import { VDataTable, VDataTableServer } from 'vuetify/labs/VDataTable'; +import { VSkeletonLoader } from 'vuetify/labs/VSkeletonLoader'; +import { + VStepper, + VStepperHeader, + VStepperItem, + VStepperWindow, + VStepperWindowItem, +} from 'vuetify/labs/VStepper'; +import hi from '~/internationalization/trans/vuetify/locale/hi'; +import pa from '~/internationalization/trans/vuetify/locale/pa'; +import tl from '~/internationalization/trans/vuetify/locale/tl'; +import zhHans from 'vuetify/lib/locale/zh-Hans'; +import zhHant from 'vuetify/lib/locale/zh-Hant'; +import vi from 'vuetify/lib/locale/vi'; +import uk from 'vuetify/lib/locale/uk'; +import ru from 'vuetify/lib/locale/ru'; +import pt from 'vuetify/lib/locale/pt'; +import ko from 'vuetify/lib/locale/ko'; +import ja from 'vuetify/lib/locale/ja'; +import it from 'vuetify/lib/locale/it'; +import fr from 'vuetify/lib/locale/fr'; +import fa from 'vuetify/lib/locale/fa'; +import de from 'vuetify/lib/locale/de'; +import en from 'vuetify/lib/locale/en'; +import es from 'vuetify/lib/locale/es'; +import ar from 'vuetify/lib/locale/ar'; + +const chefsTheme = { + dark: false, + colors: { + primary: '#003366', + 'surface-variant': '#003366', + secondary: '#FCBA19', + anchor: '#1A5A96', + accent: '#82B1FF', + error: '#D8292F', + info: '#2196F3', + success: '#2E8540', + warning: '#FFC107', + }, +}; + +export default createVuetify({ + defaultAssets: { + font: true, + icons: 'mdi', + }, + locale: { + locale: 'en', + messages: { + zhHans, + zhHant, + pt, + vi, + uk, + ru, + ko, + ja, + it, + fr, + fa, + de, + en, + es, + ar, + hi, + pa, + tl, + }, + }, + icons: { + defaultSet: 'mdi', + aliases, + sets: { + mdi, + FONTAWESOME, + }, + }, + theme: { + defaultTheme: 'chefsTheme', + options: { + customProperties: true, + }, + themes: { + chefsTheme, + }, + }, + components: { + ...components, + VDataTable, + VDataTableServer, + VSkeletonLoader, + VStepper, + VStepperHeader, + VStepperItem, + VStepperWindow, + VStepperWindowItem, + }, + directives, +}); diff --git a/frontend/app/frontend/src/router.js b/frontend/app/frontend/src/router.js new file mode 100644 index 0000000..ff28501 --- /dev/null +++ b/frontend/app/frontend/src/router.js @@ -0,0 +1,446 @@ +import NProgress from 'nprogress'; +import { createRouter, createWebHistory } from 'vue-router'; + +import { useAuthStore } from '~/store/auth'; +import { useFormStore } from '~/store/form'; +import { IdentityProviders } from '~/utils/constants'; +import { preFlightAuth } from '~/utils/permissionUtils'; + +let isFirstTransition = true; +let router = undefined; + +/** + * @function createProps + * Parses the route query and params to generate vue props + * @param {object} route The route object + * @returns {object} a Vue props object + */ +const createProps = (route) => ({ ...route.query, ...route.params }); + +/** + * @function getRouter + * Constructs and returns a Vue Router object + * @param {string} [basePath='/'] the base server path + * @returns {object} a Vue Router object + */ +export default function getRouter(basePath = '/') { + // Return existing router object if already instantiated + if (router) return router; + + // Create new router definition + router = createRouter({ + history: createWebHistory(basePath), + routes: [ + { + path: '/', + name: 'Home', + redirect: { name: 'About' }, + }, + { + path: '/', + name: 'About', + component: () => import('~/views/About.vue'), + meta: { + hasLogin: true, + }, + }, + { + path: '/admin', + component: () => import('~/views/Admin.vue'), + children: [ + { + path: '', + name: 'Admin', + component: () => import('~/views/admin/Root.vue'), + }, + { + path: 'form', + name: 'AdministerForm', + component: () => import('~/views/admin/Form.vue'), + props: createProps, + }, + { + path: 'user', + name: 'AdministerUser', + component: () => import('~/views/admin/User.vue'), + props: createProps, + }, + ], + meta: { + requiresAuth: true, + hasLogin: true, + }, + }, + { + path: '/form', + component: () => import('~/views/Form.vue'), + children: [ + { + path: 'create', + name: 'FormCreate', + component: () => import('~/views/form/Create.vue'), + meta: { + breadcrumbTitle: 'Form Designer', + requiresAuth: IdentityProviders.IDIR, + hasLogin: true, + }, + }, + { + path: 'publish', + name: 'PublishForm', + component: () => import('~/views/form/PublishForm.vue'), + meta: { + breadcrumbTitle: 'Publish Form', + requiresAuth: IdentityProviders.IDIR, + hasLogin: true, + }, + props: (route) => { + return { + ...route.query, + ...route.params, + fd: + String(route.query.fd).toLowerCase() === 'true' || + route.query.fd === true, + }; + }, + }, + { + path: 'design', + name: 'FormDesigner', + component: () => import('~/views/form/Design.vue'), + meta: { + breadcrumbTitle: 'Form Designer', + requiresAuth: IdentityProviders.IDIR, + hasLogin: true, + }, + props: (route) => { + return { + ...route.query, + ...route.params, + nv: + String(route.query.nv).toLowerCase() === 'true' || + route.query.nv === true, + sv: + String(route.query.sv).toLowerCase() === 'true' || + route.query.sv === true, + }; + }, + }, + { + path: 'export', + name: 'SubmissionsExport', + component: () => import('~/views/form/Export.vue'), + meta: { + breadcrumbTitle: 'Submissions Export', + requiresAuth: true, + hasLogin: true, + }, + props: createProps, + }, + { + path: 'manage', + name: 'FormManage', + component: () => import('~/views/form/Manage.vue'), + meta: { + breadcrumbTitle: 'Manage Form', + requiresAuth: IdentityProviders.IDIR, + hasLogin: true, + }, + props: createProps, + }, + { + path: 'preview', + name: 'FormPreview', + component: () => import('~/views/form/Preview.vue'), + meta: { + breadcrumbTitle: 'Preview Form', + formSubmitMode: true, + requiresAuth: IdentityProviders.IDIR, + hasLogin: true, + }, + props: createProps, + }, + { + path: 'submissions', + name: 'FormSubmissions', + component: () => import('~/views/form/Submissions.vue'), + meta: { + breadcrumbTitle: 'Submissions', + requiresAuth: IdentityProviders.IDIR, + hasLogin: true, + }, + props: createProps, + }, + { + path: 'submit', + name: 'FormSubmit', + component: () => import('~/views/form/Submit.vue'), + meta: { + breadcrumbTitle: 'Submit Form', + formSubmitMode: true, + }, + props: createProps, + beforeEnter(to, _from, next) { + preFlightAuth({ formId: to.query.f }, next); + }, + }, + { + path: 'success', + name: 'FormSuccess', + component: () => import('~/views/form/Success.vue'), + meta: { + breadcrumbTitle: 'Submit Success', + formSubmitMode: true, + }, + props: createProps, + beforeEnter(to, _from, next) { + preFlightAuth({ submissionId: to.query.s }, next); + }, + }, + { + path: 'emails', + name: 'FormEmails', + component: () => import('~/views/form/Emails.vue'), + meta: { + breadcrumbTitle: 'Email Management', + requiresAuth: IdentityProviders.IDIR, + hasLogin: true, + }, + props: createProps, + }, + { + path: 'teams', + name: 'FormTeams', + component: () => import('~/views/form/Teams.vue'), + meta: { + breadcrumbTitle: 'Team Management', + requiresAuth: IdentityProviders.IDIR, + hasLogin: true, + }, + props: createProps, + }, + { + path: 'view', + name: 'FormView', + component: () => import('~/views/form/View.vue'), + meta: { + breadcrumbTitle: 'View Submission', + requiresAuth: true, + hasLogin: true, + formSubmitMode: true, + }, + props: createProps, + }, + ], + }, + { + path: '/user', + component: () => import('~/views/User.vue'), + children: [ + { + path: '', + name: 'User', + component: () => import('~/views/user/Root.vue'), + meta: { + requiresAuth: true, + }, + }, + { + path: 'draft', + name: 'UserFormDraftEdit', + component: () => import('~/views/user/SubmissionDraftEdit.vue'), + meta: { + breadcrumbTitle: 'Edit Draft', + formSubmitMode: true, + }, + props: (route) => { + return { + ...route.query, + ...route.params, + sv: + String(route.query.sv).toLowerCase() === 'true' || + route.query.sv === true, + }; + }, + beforeEnter(to, _from, next) { + preFlightAuth({ submissionId: to.query.s }, next); + }, + }, + { + path: 'duplicate', + name: 'UserFormDuplicate', + component: () => import('~/views/user/SubmissionDuplicate.vue'), + meta: { + breadcrumbTitle: 'Create from existing', + formSubmitMode: true, + }, + props: createProps, + beforeEnter(to, _from, next) { + preFlightAuth( + { submissionId: to.query.s, formId: to.query.f, sv: true }, + next + ); + }, + }, + { + path: 'forms', + name: 'UserForms', + component: () => import('~/views/user/Forms.vue'), + meta: { + breadcrumbTitle: 'My Forms', + requiresAuth: IdentityProviders.IDIR, + }, + }, + { + path: 'history', + name: 'UserHistory', + component: () => import('~/views/user/History.vue'), + meta: { + breadcrumbTitle: 'History', + requiresAuth: true, + }, + }, + { + path: 'submissions', + name: 'UserSubmissions', + component: () => import('~/views/user/Submissions.vue'), + meta: { + breadcrumbTitle: 'Previous Submissions', + formSubmitMode: true, + }, + props: createProps, + beforeEnter(to, _from, next) { + preFlightAuth({ formId: to.query.f }, next); + }, + }, + { + path: 'view', + name: 'UserFormView', + component: () => import('~/views/user/SubmissionView.vue'), + meta: { + breadcrumbTitle: 'Submission', + formSubmitMode: true, + }, + props: createProps, + beforeEnter(to, _from, next) { + preFlightAuth({ submissionId: to.query.s }, next); + }, + }, + ], + }, + { + path: '/alert', + name: 'Alert', + component: () => import('~/components/bcgov/BCGovAlertBanner.vue'), + meta: { + formSubmitMode: true, + hasLogin: true, + }, + props: createProps, + }, + { + path: '/error', + name: 'Error', + component: () => import('~/views/Error.vue'), + meta: { + formSubmitMode: true, + hasLogin: true, + }, + props: createProps, + }, + { + path: '/file', + component: () => import('~/views/File.vue'), + children: [ + { + path: 'download', + name: 'Download', + component: () => import('~/views/file/Download.vue'), + meta: { + requiresAuth: true, + hasLogin: true, + }, + props: createProps, + }, + ], + }, + { + path: '/login', + name: 'Login', + component: () => import('~/views/Login.vue'), + props: true, + beforeEnter(to, from, next) { + // Block navigation to login page if already authenticated + NProgress.done(); + const authStore = useAuthStore(); + if (authStore.authenticated) next('/'); + else next(); + }, + }, + { + path: '/:pathMatch(.*)*', + name: 'NotFound', + component: () => import('~/views/NotFound.vue'), + meta: { + hasLogin: true, + }, + }, + ], + scrollBehavior(_to, _from, savedPosition) { + return savedPosition ? savedPosition : { top: 0 }; + }, + }); + + router.beforeEach((to, from, next) => { + NProgress.start(); + + const authStore = useAuthStore(); + + if (isFirstTransition) { + // Always call rbac/current if authenticated and on first page load + if (authStore?.ready && authStore?.authenticated) { + const formStore = useFormStore(); + formStore.getFormsForCurrentUser(); + } + + // Handle proper redirections on first page load + if (to.query.r) { + router.replace({ + path: to.query.r.replace(basePath, ''), + query: (({ r, ...q }) => q)(to.query), // eslint-disable-line no-unused-vars + }); + } + } + + // Force login redirect if not authenticated + // Note some pages (Submit and Success) only require auth if the form being loaded is secured + // in those cases, see the beforeEnter navigation guards for auth loop determination + if ( + to.matched.some((route) => route.meta.requiresAuth) && + authStore.ready && + !authStore.authenticated + ) { + const redirectUri = + location.origin + basePath + to.path + location.search; + authStore.redirectUri = redirectUri; + + // Determine what kind of redirect behavior is needed + let idpHint = undefined; + if (typeof to.meta.requiresAuth === 'string') { + idpHint = to.meta.requiresAuth; + } + authStore.login(idpHint); + } + + // Update document title if applicable + document.title = to.meta.title ? to.meta.title : import.meta.env.VITE_TITLE; + next(); + }); + + router.afterEach(() => { + isFirstTransition = false; + NProgress.done(); + }); + + return router; +} diff --git a/frontend/app/frontend/src/services/adminService.js b/frontend/app/frontend/src/services/adminService.js new file mode 100644 index 0000000..b4cae57 --- /dev/null +++ b/frontend/app/frontend/src/services/adminService.js @@ -0,0 +1,185 @@ +import { appAxios } from '~/services/interceptors'; +import { ApiRoutes } from '~/utils/constants'; + +export default { + // + // Form calls + // + + /** + * @function addFormUser + * Add a form user role (specific administrative task, for real form/user/role management see rbac service) + * @param {formId} formId The request body for the relationships + * @param {userId} userId The request body for the relationships + * @param {String[]} [roles] The list of roles to add + * @returns {Promise} An axios response + */ + addFormUser(userId, formId, roles) { + return appAxios().put( + `${ApiRoutes.ADMIN}${ApiRoutes.FORMS}/${formId}/addUser`, + roles.map((role) => ({ + userId: userId, + formId: formId, + role: role, + })), + { params: { userId: userId } } + ); + }, + + /** + * @function deleteApiKey + * Hard delete an API Key + * @param {string} formId The form uuid + * @returns {Promise} An axios response + */ + deleteApiKey(formId) { + return appAxios().delete( + `${ApiRoutes.ADMIN}${ApiRoutes.FORMS}/${formId}${ApiRoutes.APIKEY}` + ); + }, + + /** + * @function listForms + * Read all the forms in the DB + * @param {Boolean} active Don't show deleted forms + * @returns {Promise} An axios response + */ + listForms(active = true) { + return appAxios().get(`${ApiRoutes.ADMIN}${ApiRoutes.FORMS}`, { + params: { active: active }, + }); + }, + + /** + * @function readForm + * Get a form + * @param {string} formId The GUID + * @returns {Promise} An axios response + */ + readForm(formId) { + return appAxios().get(`${ApiRoutes.ADMIN}${ApiRoutes.FORMS}/${formId}`); + }, + + /** + * @function readRoles + * Get roles for form user + * @param {string} formId The GUID + * @returns {Promise} An axios response + */ + readRoles(formId) { + return appAxios().get( + `${ApiRoutes.ADMIN}${ApiRoutes.FORMS}/${formId}/formUsers` + ); + }, + + /** + * @function readApiDetails + * Gets the form's API Key details + * @param {string} formId The GUID + * @returns {Promise} An axios response + */ + readApiDetails(formId) { + return appAxios().get( + `${ApiRoutes.ADMIN}${ApiRoutes.FORMS}/${formId}${ApiRoutes.APIKEY}` + ); + }, + + /** + * @function restoreForm + * Restore a deleted form + * @param {string} formId The GUID + * @returns {Promise} An axios response + */ + restoreForm(formId) { + return appAxios().put( + `${ApiRoutes.ADMIN}${ApiRoutes.FORMS}/${formId}/restore` + ); + }, + + /** + * @function readVersion + * Get a specific form version schema + * @param {string} formId The form uuid + * @param {string} formVersionId The form version uuid + * @returns {Promise} An axios response + */ + readVersion(formId, formVersionId) { + return appAxios().get( + `${ApiRoutes.ADMIN}${ApiRoutes.FORMS}/${formId}/versions/${formVersionId}` + ); + }, + + // + // User calls + // + /** + * @function listUsers + * Read all the users in the DB + * @returns {Promise} An axios response + */ + listUsers() { + return appAxios().get(`${ApiRoutes.ADMIN}${ApiRoutes.USERS}`); + }, + + /** + * @function readUser + * Read a user in the DB + * @param {string} userId The GUID + * @returns {Promise} An axios response + */ + readUser(userId) { + return appAxios().get(`${ApiRoutes.ADMIN}${ApiRoutes.USERS}/${userId}`); + }, + + /** + * addFormComponentsProactiveHelp + * @function addFCProactiveHelp + * Create a new Form + * @param {Object} data An Object containing each form component help information + * @returns {Promise} An axios response + */ + addFCProactiveHelp(data) { + return appAxios().post( + `${ApiRoutes.ADMIN}/formcomponents/proactivehelp/object`, + data + ); + }, + + /** + * updateFormComponentsProactiveHelpStatus + * @function updateFCProactiveHelpStatus + * Update publish status of each Form Components Help Link Information + * @param {boolean} publishStatus This is used to determine if the help link information is published or not + * @param {string} componentId component id + * @returns {Promise} An axios response + */ + updateFCProactiveHelpStatus(componentId, publishStatus) { + return appAxios().put( + `${ApiRoutes.ADMIN}/formcomponents/proactivehelp/${publishStatus}/${componentId}` + ); + }, + + /** + * @function getPresignedUrl + * get signed image upload url + * @param {Object} imageName component name and component image encoded into base64 + * @returns {Promise} An axios response + */ + async getFCProactiveHelpImageUrl(componentId) { + return appAxios().get( + `${ApiRoutes.ADMIN}/formcomponents/proactivehelp/imageUrl/${componentId}` + ); + }, + + /** + * listFormComponentsProactiveHelp + * @function listFCProactiveHelp + * Reads all form components help information + * @returns {Promise} An axios response + */ + async listFCProactiveHelp() { + return await appAxios().get( + `${ApiRoutes.ADMIN}/formcomponents/proactivehelp/list` + ); + }, +}; diff --git a/frontend/app/frontend/src/services/apiKeyService.js b/frontend/app/frontend/src/services/apiKeyService.js new file mode 100644 index 0000000..175a288 --- /dev/null +++ b/frontend/app/frontend/src/services/apiKeyService.js @@ -0,0 +1,34 @@ +import { appAxios } from '~/services/interceptors'; +import { ApiRoutes } from '~/utils/constants'; + +export default { + /** + * @function readApiKey + * Get the current api key for the form + * @param {string} formId The form uuid + * @returns {Promise} An axios response + */ + readApiKey(formId) { + return appAxios().get(`${ApiRoutes.FORMS}/${formId}${ApiRoutes.APIKEY}`); + }, + + /** + * @function generateApiKey + * Create a new API key for a form, will overwrite any existing key + * @param {string} formId The form uuid + * @returns {Promise} An axios response + */ + generateApiKey(formId) { + return appAxios().put(`${ApiRoutes.FORMS}/${formId}${ApiRoutes.APIKEY}`); + }, + + /** + * @function deleteApiKey + * Hard delete an API Key + * @param {string} formId The form uuid + * @returns {Promise} An axios response + */ + deleteApiKey(formId) { + return appAxios().delete(`${ApiRoutes.FORMS}/${formId}${ApiRoutes.APIKEY}`); + }, +}; diff --git a/frontend/app/frontend/src/services/fileService.js b/frontend/app/frontend/src/services/fileService.js new file mode 100644 index 0000000..e383836 --- /dev/null +++ b/frontend/app/frontend/src/services/fileService.js @@ -0,0 +1,8 @@ +import { appAxios } from '~/services/interceptors'; +import { ApiRoutes } from '~/utils/constants'; + +export default { + async getFile(fileId) { + return appAxios().get(`${ApiRoutes.FILES}/${fileId}`); + }, +}; diff --git a/frontend/app/frontend/src/services/formService.js b/frontend/app/frontend/src/services/formService.js new file mode 100644 index 0000000..abe7e4e --- /dev/null +++ b/frontend/app/frontend/src/services/formService.js @@ -0,0 +1,586 @@ +import { appAxios } from '~/services/interceptors'; +import { ApiRoutes } from '~/utils/constants'; + +export default { + // + // Form calls + // + + /** + * @function readForm + * Get the baseline form metadata + * @param {string} formId The form uuid + * @returns {Promise} An axios response + */ + readForm(formId) { + return appAxios().get(`${ApiRoutes.FORMS}/${formId}`); + }, + + /** + * @function createForm + * Create a new Form + * @param {Object} formData An object containing the form details + * @returns {Promise} An axios response + */ + createForm(formData) { + return appAxios().post(`${ApiRoutes.FORMS}`, formData); + }, + + /** + * @function updateForm + * Update a Form + * @param {string} formId The form uuid + * @param {Object} formData An object containing the form details + * @returns {Promise} An axios response + */ + updateForm(formId, formData) { + return appAxios().put(`${ApiRoutes.FORMS}/${formId}`, formData); + }, + + /** + * @function deleteForm + * Soft delete a Form + * @param {string} formId The form uuid + * @returns {Promise} An axios response + */ + deleteForm(formId) { + return appAxios().delete(`${ApiRoutes.FORMS}/${formId}`); + }, + + /** + * @function readFormOptions + * Get pre-flight details for a form + * @param {string} formId The form uuid + * @returns {Promise} An axios response + */ + readFormOptions(formId) { + return appAxios().get(`${ApiRoutes.FORMS}/${formId}/options`); + }, + + /** + * @function getStatusCodes + * Get the statuses that are available to a form + * @param {string} formId The form identifier + * @returns {Promise} An axios response + */ + getStatusCodes(formId) { + return appAxios().get(`/forms/${formId}/statusCodes`); + }, + + // + // Form draft calls + // + + /** + * @function createDraft + * Create a new Form draft + * @param {string} formId The form uuid + * @param {Object} data An object containing an updated schema object attribute + * @returns {Promise} An axios response + */ + createDraft(formId, data) { + return appAxios().post(`${ApiRoutes.FORMS}/${formId}/drafts`, data); + }, + + /** + * @function deleteDraft + * Delete a Form draft + * @param {string} formId The form uuid + * @param {string} formVersionDraftId The form version draft uuid + * @returns {Promise} An axios response + */ + deleteDraft(formId, formVersionDraftId) { + return appAxios().delete( + `${ApiRoutes.FORMS}/${formId}/drafts/${formVersionDraftId}` + ); + }, + + /** + * @function listDrafts + * Get any drafts for a form + * @param {string} formId The form uuid + * @returns {Promise} An axios response + */ + listDrafts(formId) { + return appAxios().get(`${ApiRoutes.FORMS}/${formId}/drafts`); + }, + + /** + * @function publishDraft + * Publishes a specific form draft + * @param {string} formId The form uuid + * @param {string} formVersionDraftId The form version draft uuid + * @returns {Promise} An axios response + */ + publishDraft(formId, formVersionDraftId) { + return appAxios().post( + `${ApiRoutes.FORMS}/${formId}/drafts/${formVersionDraftId}/publish` + ); + }, + + /** + * @function readDraft + * Get a specific draft for a form + * @param {string} formId The form uuid + * @param {string} formVersionDraftId The draft uuid + * @returns {Promise} An axios response + */ + readDraft(formId, formVersionDraftId) { + return appAxios().get( + `${ApiRoutes.FORMS}/${formId}/drafts/${formVersionDraftId}` + ); + }, + + /** + * @function updateDraft + * Update a draft with a new schema + * @param {string} formId The form uuid + * @param {string} formVersionDraftId The draft uuid + * @param {Object} data The request body + * @returns {Promise} An axios response + */ + updateDraft(formId, formVersionDraftId, data) { + return appAxios().put( + `${ApiRoutes.FORMS}/${formId}/drafts/${formVersionDraftId}`, + data + ); + }, + + // + // Form email template calls + // + + /** + * @function listEmailTemplates + * Get all the email templates for a form + * @param {string} formId The form uuid + * @returns {Promise} An axios response + */ + listEmailTemplates(formId) { + return appAxios().get(`${ApiRoutes.FORMS}/${formId}/emailTemplates`); + }, + + /** + * @function updateEmailTemplate + * Update a form's email template + * @param {Object} data The request body (containing formId) + * @returns {Promise} An axios response + */ + updateEmailTemplate(data) { + return appAxios().put( + `${ApiRoutes.FORMS}/${data.formId}/emailTemplate`, + data + ); + }, + + // + // Form version calls + // + + /** + * @function readPublished + * Get the most recently published form version schema + * @param {string} formId The form uuid + * @returns {Promise} An axios response + */ + readPublished(formId) { + return appAxios().get(`${ApiRoutes.FORMS}/${formId}/version`); + }, + + /** + * @function readVersion + * Get a specific form version schema + * @param {string} formId The form uuid + * @param {string} formVersionId The form version uuid + * @returns {Promise} An axios response + */ + readVersion(formId, formVersionId) { + return appAxios().get( + `${ApiRoutes.FORMS}/${formId}/versions/${formVersionId}` + ); + }, + + /** + * @function readVersionFields + * Get a list of valid form fields in this form version + * @param {string} formId The form uuid + * @param {string} formVersionId The form version uuid + * @returns {Promise} An axios response + */ + readVersionFields(formId, formVersionId) { + return appAxios().get( + `${ApiRoutes.FORMS}/${formId}/versions/${formVersionId}/fields` + ); + }, + + /** + * @function publishVersion + * Publish or unpublish a specific form version. Publishing a verison will unpublish all others. + * @param {string} formId The form uuid + * @param {string} formVersionId The form version uuid + * @param {Boolean} publish True to publish, false to unpublish + * @returns {Promise} An axios response + */ + publishVersion(formId, formVersionId, publish) { + return appAxios().post( + `${ApiRoutes.FORMS}/${formId}/versions/${formVersionId}/publish`, + null, + { + params: { + unpublish: !publish, + }, + } + ); + }, + + /** + * @function updateVersion + * Updates a specific form version schema + * @param {string} formId The form uuid + * @param {string} formVersionId The form version uuid + * @param {Object} data An object containing an updated schema object attribute + * @returns {Promise} An axios response + */ + updateVersion(formId, formVersionId, data) { + return appAxios().put( + `${ApiRoutes.FORMS}/${formId}/versions/${formVersionId}`, + data + ); + }, + + // + // Form submission calls + // + + /** + * @function createSubmission + * Submit the form data + * @param {string} formId The form uuid + * @param {string} versionId The form uuid + * @param {Object} requestBody The form data for the submission + * @returns {Promise} An axios response + */ + createSubmission(formId, versionId, requestBody) { + return appAxios().post( + `${ApiRoutes.FORMS}/${formId}/versions/${versionId}/submissions`, + requestBody + ); + }, + + /** + * @function createBulkSubmission + * Submit the form data + * @param {string} formId The form uuid + * @param {string} versionId The form uuid + * @param {Object} requestBody The files data for multi submission + * @returns {Promise} An axios response + */ + createMultiSubmission(formId, versionId, requestBody) { + return appAxios().post( + `${ApiRoutes.FORMS}/${formId}/versions/${versionId}/multiSubmission`, + requestBody + ); + }, + + /** + * @function deleteSubmission + * Soft delete a specific submission + * @param {string} submissionId The form submission identifier + * @returns {Promise} An axios response + */ + deleteSubmission(submissionId) { + return appAxios().delete(`${ApiRoutes.SUBMISSION}/${submissionId}`); + }, + + /** + * @function deleteMultipleSubmissions + * Soft delete a specific submission + * @param {array} submissionIds The form submission identifier + * @returns {Promise} An axios response + */ + deleteMultipleSubmissions(submissionId, formId, requestBody) { + return appAxios().delete( + `${ApiRoutes.SUBMISSION}/${submissionId}/${formId}/submissions`, + requestBody + ); + }, + + /** + * @function restoreSubmission + * Restores an existing submission + * @param {string} submissionId The form uuid + * @param {Object} requestBody The form data for the submission + * @returns {Promise} An axios response + */ + restoreSubmission(submissionId, requestBody) { + return appAxios().put( + `${ApiRoutes.SUBMISSION}/${submissionId}/restore`, + requestBody + ); + }, + + /** + * @function restoreMutipleSubmissions + * Restores an existing submission + * @param {string} submissionId The form uuid + * @returns {Promise} An axios response + */ + restoreMutipleSubmissions(submissionId, formId, requestBody) { + return appAxios().put( + `${ApiRoutes.SUBMISSION}/${submissionId}/${formId}/submissions/restore`, + requestBody + ); + }, + + /** + * @function updateSubmission + * Update an existing submission + * @param {string} submissionId The form uuid + * @param {Object} requestBody The form data for the submission + * @returns {Promise} An axios response + */ + updateSubmission(submissionId, requestBody) { + return appAxios().put( + `${ApiRoutes.SUBMISSION}/${submissionId}`, + requestBody + ); + }, + + /** + * @function getSubmission + * Get the form data + version + submission data + * @param {string} submissionId The form submission identifier + * @returns {Promise} An axios response + */ + getSubmission(submissionId) { + return appAxios().get(`${ApiRoutes.SUBMISSION}/${submissionId}`); + }, + + /** + * @function getSubmissionOptions + * Get pre-flight details for a form submission + * @param {string} submissionId The form submission identifier + * @returns {Promise} An axios response + */ + getSubmissionOptions(submissionId) { + return appAxios().get(`${ApiRoutes.SUBMISSION}/${submissionId}/options`); + }, + + /** + * @function listSubmissions + * Get the submissions for a form + * @param {string} formId The form uuid + * @param {Object} params the query parameters + * @returns {Promise} An axios response + */ + listSubmissions(formId, params = {}) { + return appAxios().get(`${ApiRoutes.FORMS}/${formId}/submissions`, { + params, + }); + }, + + /** + * @function listSubmissionEdits + * Get the audit history for edits of a submission + * @param {string} submissionId The submission uuid + * @returns {Promise} An axios response + */ + listSubmissionEdits(submissionId) { + return appAxios().get(`${ApiRoutes.SUBMISSION}/${submissionId}/edits`); + }, + + /** + * @function readCSVExportFields + * Get a list of valid form fields in this form version + * @param {string} formId The form uuid + * @param {string} type The export type and it is defaulted to submissions + * @param {string} draft The default value is false + * @param {string} deleted The default value is false + * @param {string} version The form version + * @returns {Promise} An axios response + */ + readCSVExportFields(formId, type, draft, deleted, version, singleRow) { + return appAxios().get(`${ApiRoutes.FORMS}/${formId}/csvexport/fields`, { + params: { + type: type, + draft: draft, + deleted: deleted, + version: version, + singleRow: singleRow, + }, + }); + }, + + /** + * @function exportSubmissions + * Get the export file for a range of form submittions + * @param {string} formId The form uuid + * @param {Array} preference selected fields by the user + * @param {string} format The export file format csv or json + * @param {object} options options for the export (eg: minDate, maxDate, deleted, drafts) + * @returns {Promise} An axios response + */ + exportSubmissions( + formId, + format, + template, + versionSelected, + preference, + fields, + emailExport = false, + options = {} + ) { + return appAxios().post( + `${ApiRoutes.FORMS}/${formId}/export/fields`, + { + format: format, + template: template, + version: versionSelected, + type: 'submissions', + preference: preference, + fields: fields, + emailExport, + ...options, + }, + { + responseType: 'blob', + } + ); + }, + + // + // Notes and Status + // + + /** + * @function getSubmissionNotes + * Get the notes associated with the submission + * @param {string} submissionId The form submission identifier + * @returns {Promise} An axios response + */ + getSubmissionNotes(submissionId) { + return appAxios().get(`${ApiRoutes.SUBMISSION}/${submissionId}/notes`); + }, + + /** + * @function addNote + * Add a new notes to the submission + * @param {string} submissionId The form submission identifier + * @param {Object} data The request body + * @returns {Promise} An axios response + */ + addNote(submissionId, data) { + return appAxios().post( + `${ApiRoutes.SUBMISSION}/${submissionId}/notes`, + data + ); + }, + + /** + * @function getSubmissionStatuses + * Get the current status history associated with the submission + * @param {string} submissionId The form submission identifier + * @returns {Promise} An axios response + */ + getSubmissionStatuses(submissionId) { + return appAxios().get(`${ApiRoutes.SUBMISSION}/${submissionId}/status`); + }, + + /** + * @function docGen + * Upload a template to generate PDF from CDOGS API + * @param {string} submissionId The form submission identifier + * @param {Object} body The request body + * @returns {Promise} An axios response + */ + docGen(submissionId, body) { + return appAxios().post( + `${ApiRoutes.SUBMISSION}/${submissionId}/template/render`, + body, + { + responseType: 'arraybuffer', // Needed for binaries unless you want pain + timeout: 30000, // Override default timeout as this call could take a while + } + ); + }, + + /** + * @function updateSubmissionStatus + * Add a new status entry to the submission + * @param {string} submissionId The form submission identifier + * @param {Object} data The request body + * @returns {Promise} An axios response + */ + updateSubmissionStatus(submissionId, data) { + return appAxios().post( + `${ApiRoutes.SUBMISSION}/${submissionId}/status`, + data + ); + }, + + // + // Email + // + + /** + * @function requestReceiptEmail + * Send a receipt email + * @param {string} submissionId The submission uuid + * @param {Object} requestBody The body for the api call: { priority, to } + * @returns {Promise} An axios response + */ + requestReceiptEmail(submissionId, requestBody) { + return appAxios().post( + `${ApiRoutes.SUBMISSION}/${submissionId}/email`, + requestBody + ); + }, + + /** + * listFormComponentsProactiveHelp + * @function listFCProactiveHelp + * Reads all form components help information + * @returns {Promise} An axios response + */ + async listFCProactiveHelp() { + return await appAxios().get( + `${ApiRoutes.FORMS}/formcomponents/proactivehelp/list` + ); + }, + + /** + * @function getPresignedUrl + * get signed image upload url + * @param {Object} imageName component name and component image encoded into base64 + * @returns {Promise} An axios response + */ + async getFCProactiveHelpImageUrl(componentId) { + return appAxios().get( + `${ApiRoutes.FORMS}/formcomponents/proactivehelp/imageUrl/${componentId}` + ); + }, + + /** + * @function readFormSubscriptionData + * Get the current subscription for the form + * @param {string} formId The form uuid + * @returns {Promise} An axios response + */ + readFormSubscriptionData(formId) { + return appAxios().get(`${ApiRoutes.FORMS}/${formId}/subscriptions`); + }, + + /** + * @function updateSubscription + * Update a subscription settings of a Form + * @param {string} formId The form uuid + * @param {Object} subscriptionData An object containing the form subscription details + * @returns {Promise} An axios response + */ + updateSubscription(formId, subscriptionData) { + return appAxios().put( + `${ApiRoutes.FORMS}/${formId}/subscriptions`, + subscriptionData + ); + }, +}; diff --git a/frontend/app/frontend/src/services/index.js b/frontend/app/frontend/src/services/index.js new file mode 100644 index 0000000..a0f2990 --- /dev/null +++ b/frontend/app/frontend/src/services/index.js @@ -0,0 +1,8 @@ +export { default as adminService } from './adminService'; +export { default as apiKeyService } from './apiKeyService'; +export { default as formService } from './formService'; +export { default as rbacService } from './rbacService'; +export { default as roleService } from './roleService'; +export { default as userService } from './userService'; +export { default as fileService } from './fileService'; +export { default as utilsService } from './utilsService'; diff --git a/frontend/app/frontend/src/services/interceptors.js b/frontend/app/frontend/src/services/interceptors.js new file mode 100644 index 0000000..e690cc4 --- /dev/null +++ b/frontend/app/frontend/src/services/interceptors.js @@ -0,0 +1,35 @@ +import axios from 'axios'; +import { useAuthStore } from '~/store/auth'; +import { useAppStore } from '~/store/app'; + +/** + * @function appAxios + * Returns an Axios instance with auth header and preconfiguration + * @param {integer} [timeout=10000] Number of milliseconds before timing out the request + * @returns {object} An axios instance + */ +export function appAxios(timeout = 10000) { + const appStore = useAppStore(); + const axiosOptions = { timeout: timeout }; + if (appStore.config) { + axiosOptions.baseURL = `${appStore.config.basePath}/${appStore.config.apiPath}`; + } + + const instance = axios.create(axiosOptions); + + const authStore = useAuthStore(); + + instance.interceptors.request.use( + (cfg) => { + if (authStore?.ready && authStore?.authenticated) { + cfg.headers.Authorization = `Bearer ${authStore.keycloak.token}`; + } + return Promise.resolve(cfg); + }, + (error) => { + return Promise.reject(error); + } + ); + + return instance; +} diff --git a/frontend/app/frontend/src/services/rbacService.js b/frontend/app/frontend/src/services/rbacService.js new file mode 100644 index 0000000..1c886d0 --- /dev/null +++ b/frontend/app/frontend/src/services/rbacService.js @@ -0,0 +1,114 @@ +import { appAxios } from '~/services/interceptors'; +import { ApiRoutes } from '~/utils/constants'; + +export default { + /** + * @function getCurrentUser + * Get the current user details from the rbac endpoint + * @returns {Promise} An axios response + */ + getCurrentUser(params = {}) { + return appAxios().get(`${ApiRoutes.RBAC}/current`, { params }); + }, + + /** + * @function getUserSubmissions + * Get the submissions for a form that the current user has permissions on + * @param {Object} [params={}] The query parameters + * @returns {Promise} An axios response + */ + getUserSubmissions(params = {}) { + return appAxios().get(`${ApiRoutes.RBAC}/current/submissions`, { params }); + }, + + // + // Form Management calls + // + + /** + * @function getFormUsers + * Get the list of form and associated users + * @param {Object} [params={}] The query parameters + * @returns {Promise} An axios response + */ + getFormUsers(params = {}) { + return appAxios().get(`${ApiRoutes.RBAC}/forms`, { params }); + }, + + /** + * @function setFormUsers + * Set relationships between forms, roles, users + * @param {Object} requestBody The request body for the relationships + * @param {Object} [params={}] The query parameters + * @returns {Promise} An axios response + */ + setFormUsers(requestBody, params = {}) { + return appAxios().put(`${ApiRoutes.RBAC}/forms`, requestBody, { params }); + }, + + // + // User Management calls + // + + /** + * @function getUserForms + * Get the list of forms for associated user (admin use only at this point if needed, use /current for an actual user) + * @param {Object} [params={}] The query parameters + * @returns {Promise} An axios response + */ + getUserForms(params = {}) { + return appAxios().get(`${ApiRoutes.RBAC}/users`, { params }); + }, + + /** + * @function setUserForms + * Set relationships between users, roles, forms + * @param {Object} requestBody The request body for the relationships + * @param {Object} [params={}] The query parameters + * @returns {Promise} An axios response + */ + setUserForms(requestBody, params = {}) { + return appAxios().put(`${ApiRoutes.RBAC}/users`, requestBody, { params }); + }, + + /** + * @function removeMultiUsers + * removes selected users from the from + * @param {Object} requestBody The request body for the relationships + * @returns {Promise} An axios response + */ + removeMultiUsers(requestBody, params = {}) { + return appAxios().delete( + `${ApiRoutes.RBAC}/users?formId=${params.formId}`, + { data: requestBody }, + { params } + ); + }, + + // + // Submission Management calls + // + + /** + * @function getSubmissionUsers + * Get the list of associated users for a submission + * @param {Object} [params={}] The query parameters + * @returns {Promise} An axios response + */ + getSubmissionUsers(params = {}) { + return appAxios().get(`${ApiRoutes.RBAC}/submissions`, { params }); + }, + + /** + * @function setFormUsers + * Set permissions for a user on the form + * @param {Object} requestBody The request body containing the permissions list + * @param {Object} [params={}] The query parameters + * @returns {Promise} An axios response + */ + setSubmissionUserPermissions(requestBody, params = {}) { + return appAxios().put(`${ApiRoutes.RBAC}/submissions`, requestBody, { + params, + }); + }, +}; diff --git a/frontend/app/frontend/src/services/roleService.js b/frontend/app/frontend/src/services/roleService.js new file mode 100644 index 0000000..affdc38 --- /dev/null +++ b/frontend/app/frontend/src/services/roleService.js @@ -0,0 +1,17 @@ +import { appAxios } from '~/services/interceptors'; +import { ApiRoutes } from '~/utils/constants'; + +export default { + // + // Role Management calls + // + + /** + * @function list + * List roles in the system + * @returns {Promise} An axios response + */ + list() { + return appAxios().get(`${ApiRoutes.ROLES}`); + }, +}; diff --git a/frontend/app/frontend/src/services/userService.js b/frontend/app/frontend/src/services/userService.js new file mode 100644 index 0000000..a9ce4be --- /dev/null +++ b/frontend/app/frontend/src/services/userService.js @@ -0,0 +1,48 @@ +import { appAxios } from '~/services/interceptors'; +import { ApiRoutes } from '~/utils/constants'; + +export default { + /** + * @function getUsers + * Get users (used for searching or filtering users by params) + * @param {Object} [params={}] The query parameters + * @returns {Promise} An axios response + */ + getUsers(params = {}) { + return appAxios().get(`${ApiRoutes.USERS}/`, { params }); + }, + + /** + * @function getUser + * Get user information + * @param {String} userId The user id to read + * @returns {Promise} An axios response + */ + getUser(userId) { + return appAxios().get(`${ApiRoutes.USERS}/${userId}`); + }, + + /** + * @function getUserFormPreferences + * Get the preferences for a the current user for a specific form + * @param {String} formId The form + * @returns {Promise} An axios response + */ + getUserFormPreferences(formId) { + return appAxios().get(`${ApiRoutes.USERS}/preferences/forms/${formId}`); + }, + + /** + * @function updateUserFormPreferences + * Set the preferences for a the current user for a specific form + * @param {String} formId The form + * @param {Object} body The user form preferences + * @returns {Promise} An axios response + */ + updateUserFormPreferences(formId, body) { + return appAxios().put( + `${ApiRoutes.USERS}/preferences/forms/${formId}`, + body + ); + }, +}; diff --git a/frontend/app/frontend/src/services/utilsService.js b/frontend/app/frontend/src/services/utilsService.js new file mode 100644 index 0000000..3d405fb --- /dev/null +++ b/frontend/app/frontend/src/services/utilsService.js @@ -0,0 +1,21 @@ +import { appAxios } from '~/services/interceptors'; +import { ApiRoutes } from '~/utils/constants'; + +export default { + // + // Util calls + // + + /** + * @function draftDocGen + * Upload a template and submission data to generate PDF from CDOGS API + * @param {Object} body The request body containing the template and submission data + * @returns {Promise} An axios response + */ + draftDocGen(body) { + return appAxios().post(`${ApiRoutes.UTILS}/template/render`, body, { + responseType: 'arraybuffer', // Needed for binaries unless you want pain + timeout: 30000, // Override default timeout as this call could take a while + }); + }, +}; diff --git a/frontend/app/frontend/src/store/admin.js b/frontend/app/frontend/src/store/admin.js new file mode 100644 index 0000000..229d360 --- /dev/null +++ b/frontend/app/frontend/src/store/admin.js @@ -0,0 +1,272 @@ +import { defineStore } from 'pinia'; +import { i18n } from '~/internationalization'; + +import { adminService } from '~/services'; +import { useNotificationStore } from '~/store/notification'; +import { NotificationTypes } from '~/utils/constants'; + +export const useAdminStore = defineStore('admin', { + state: () => ({ + apiKey: undefined, + form: {}, + formList: [], + roles: [], + user: {}, + userList: [], + fcProactiveHelp: {}, // Form Component Proactive Help + fcProactiveHelpImageUrl: '', + fcProactiveHelpGroupList: [], + }), + getters: {}, + actions: { + // + // Forms + // + async addFormUser(formUser) { + const notificationStore = useNotificationStore(); + try { + const response = await adminService.addFormUser( + formUser.userId, + formUser.formId, + formUser.roles + ); + // Re-get the form users + this.readRoles(formUser.formId); + notificationStore.addNotification({ + text: i18n.t('trans.store.admin.addFormOwnerRole', { + fullName: response.data[0].fullName, + }), + ...NotificationTypes.SUCCESS, + }); + } catch (error) { + notificationStore.addNotification({ + text: i18n.t('trans.store.admin.addRowError'), + consoleError: i18n.t('trans.store.admin.addRowError', { + userId: formUser.userId, + formId: formUser.formId, + error: error, + }), + }); + } + }, + async deleteApiKey(formId) { + try { + await adminService.deleteApiKey(formId); + this.apiKey = undefined; + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.admin.apiKeyDelMsg'), + ...NotificationTypes.SUCCESS, + }); + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.admin.errDeletingApiKey'), + consoleError: i18n.t('trans.store.admin.apiKeyDelMsg', { + formId: formId, + error: error, + }), + }); + } + }, + async getForms(activeOnly) { + try { + this.formList = []; + // Get all forms + const response = await adminService.listForms(activeOnly); + this.formList = response.data; + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.admin.fecthingFormsErrMsg'), + consoleError: i18n.t('trans.store.admin.fecthingFormsErrMsg', { + error: error, + }), + }); + } + }, + async readForm(formId) { + try { + this.form = {}; + // Get specific form + const response = await adminService.readForm(formId); + this.form = response.data; + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.admin.fecthingFormErrMsg'), + consoleError: i18n.t('trans.store.admin.fecthingFormsErrMsg', { + formId: formId, + error: error, + }), + }); + } + }, + async readRoles(formId) { + try { + // Get specific roles + const response = await adminService.readRoles(formId); + this.roles = response.data; + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.admin.fecthFormUserRolesErrMsg'), + consoleError: i18n.t( + 'trans.store.admin.fecthFormUserRolesConsErrMsg', + { + error: error, + } + ), + }); + } + }, + async readApiDetails(formId) { + try { + // Get form's api details + const response = await adminService.readApiDetails(formId); + this.apiKey = response.data; + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.admin.fecthApiDetailsErrMsg'), + consoleError: i18n.t('trans.store.admin.fecthApiDetailsConsErrMsg', { + formId: formId, + error: error, + }), + }); + } + }, + async restoreForm(formId) { + try { + // Get specific form + const response = await adminService.restoreForm(formId); + this.form = response.data; + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.admin.restoreFormErrMsg'), + consoleError: i18n.t('trans.store.admin.restoreFormConsErrMsg', { + formId: formId, + error: error, + }), + }); + } + }, + + // + // Users + // + async getUsers() { + try { + // Get all users + this.userList = []; + const response = await adminService.listUsers(); + this.userList = response.data; + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.admin.getUsersErrMsg'), + consoleError: i18n.t('trans.store.admin.getUsersConsErrMsg', { + error: error, + }), + }); + } + }, + async readUser(userId) { + try { + // Get a users + this.user = {}; + const response = await adminService.readUser(userId); + this.user = response.data; + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.admin.getUserErrMsg'), + consoleError: i18n.t('trans.store.admin.getUserConsErrMsg', { + userId: userId, + error: error, + }), + }); + } + }, + + //addFormComponentsProactiveHelp + async addFCProactiveHelp(data) { + try { + // Get Common Components Help Information + this.fcProactiveHelp = {}; + const response = await adminService.addFCProactiveHelp(data); + this.fcProactiveHelp = response.data; + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.admin.storingFCHelpInfoErrMsg'), + consoleError: i18n.t( + 'trans.store.admin.storingFCHelpInfoConsErrMsg', + { + error: error, + } + ), + }); + } + }, + + async getFCProactiveHelpImageUrl(componentId) { + try { + // Get Common Components Help Information + this.fcProactiveHelpImageUrl = ''; + const response = await adminService.getFCProactiveHelpImageUrl( + componentId + ); + this.fcProactiveHelpImageUrl = response.data.url; + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.admin.gettingFCImgUrlErrMsg'), + consoleError: i18n.t('trans.store.admin.gettingFCImgUrlConsErrMsg', { + error: error, + }), + }); + } + }, + + //updateFormComponentsProactiveHelpStatus + async updateFCProactiveHelpStatus({ componentId, publishStatus }) { + try { + // Get Common Components Help Information + const response = await adminService.updateFCProactiveHelpStatus( + componentId, + publishStatus + ); + this.fcProactiveHelp = response.data; + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.admin.updatingFCStatusErrMsg'), + consoleError: i18n.t('trans.store.admin.updatingFCStatusConsErrMsg', { + error: error, + }), + }); + } + }, + + //listFormComponentsProactiveHelp + async listFCProactiveHelp() { + try { + // Get Form Components Proactive Help Group Object + this.fcProactiveHelpGroupList = []; + const response = await adminService.listFCProactiveHelp(); + this.fcProactiveHelpGroupList = response.data; + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.admin.fecthingFormBuilderCompsErrMsg'), + consoleError: i18n.t( + 'trans.store.admin.fecthingFormBuilderCompsConsErrMsg', + { error: error } + ), + }); + } + }, + }, +}); diff --git a/frontend/app/frontend/src/store/app.js b/frontend/app/frontend/src/store/app.js new file mode 100644 index 0000000..ecc0fa5 --- /dev/null +++ b/frontend/app/frontend/src/store/app.js @@ -0,0 +1,9 @@ +import { defineStore } from 'pinia'; + +export const useAppStore = defineStore('app', { + state: () => ({ + config: null, + }), + getters: {}, + actions: {}, +}); diff --git a/frontend/app/frontend/src/store/auth.js b/frontend/app/frontend/src/store/auth.js new file mode 100644 index 0000000..ca2d1b2 --- /dev/null +++ b/frontend/app/frontend/src/store/auth.js @@ -0,0 +1,126 @@ +import { defineStore } from 'pinia'; +import getRouter from '~/router'; + +/** + * @function hasRoles + * Checks if all elements in `roles` array exists in `tokenRoles` array + * @param {string[]} tokenRoles An array of roles that exist in the token + * @param {string[]} roles An array of roles to check + * @returns {boolean} True if all `roles` exist in `tokenRoles`; false otherwise + */ +function hasRoles(tokenRoles, roles = []) { + return roles + .map((r) => tokenRoles.some((t) => t === r)) + .every((x) => x === true); +} + +export const useAuthStore = defineStore('auth', { + state: () => ({ + keycloak: undefined, + redirectUri: undefined, + ready: false, + authenticated: false, + }), + getters: { + createLoginUrl: (state) => (options) => + state.keycloak.createLoginUrl(options), + createLogoutUrl: (state) => (options) => + state.keycloak.createLogoutUrl(options), + email: (state) => + state.keycloak.tokenParsed ? state.keycloak.tokenParsed.email : '', + fullName: (state) => state.keycloak.tokenParsed.name, + /** + * Checks if the state has the required resource roles + * @returns (T/F) Whether the state has the required roles + */ + hasResourceRoles: (state) => { + return (resource, roles) => { + if (!state.authenticated) return false; + if (!roles.length) return true; // No roles to check against + + if (state.resourceAccess && state.resourceAccess[resource]) { + return hasRoles(state.resourceAccess[resource].roles, roles); + } + return false; // There are roles to check, but nothing in token to check against + }; + }, + identityProvider: (state) => + state.keycloak.tokenParsed + ? state.keycloak.tokenParsed.identity_provider + : null, + isAdmin: (state) => state.hasResourceRoles('chefs', ['admin']), + isUser: (state) => state.hasResourceRoles('chefs', ['user']), + keycloakSubject: (state) => state.keycloak.subject, + identityProviderIdentity: (state) => state.keycloak.tokenParsed.idp_userid, + moduleLoaded: (state) => !!state.keycloak, + realmAccess: (state) => state.keycloak.tokenParsed.realm_access, + resourceAccess: (state) => state.keycloak.tokenParsed.resource_access, + token: (state) => state.keycloak.token, + tokenParsed: (state) => state.keycloak.tokenParsed, + userName: (state) => state.keycloak.tokenParsed.preferred_username, + user: (state) => { + const user = { + username: '', + firstName: '', + lastName: '', + fullName: '', + email: '', + idp: 'public', + public: !state.authenticated, + }; + if (state.authenticated) { + if (state.tokenParsed.idp_username) { + user.username = state.tokenParsed.idp_username; + } else { + user.username = state.tokenParsed.preferred_username; + } + user.firstName = state.tokenParsed.given_name; + user.lastName = state.tokenParsed.family_name; + user.fullName = state.tokenParsed.name; + user.email = state.tokenParsed.email; + user.idp = state.tokenParsed.identity_provider; + } + + return user; + }, + }, + actions: { + updateKeycloak(keycloak, isAuthenticated) { + this.keycloak = keycloak; + this.authenticated = isAuthenticated; + }, + login(idpHint) { + if (this.ready) { + if (!this.redirectUri) this.redirectUri = location.toString(); + + const options = { + redirectUri: this.redirectUri, + }; + + // Determine idpHint based on input or form + if (idpHint && typeof idpHint === 'string') options.idpHint = idpHint; + + if (options.idpHint) { + // Redirect to Keycloak if idpHint is available + window.location.replace(this.createLoginUrl(options)); + } else { + // Navigate to internal login page if no idpHint specified + const router = getRouter(); + router.replace({ + name: 'Login', + query: { idpHint: ['idir', 'bceid-business', 'bceid-basic'] }, + }); + } + } + }, + logout() { + if (this.ready) { + window.location.replace( + this.createLogoutUrl({ + redirectUri: location.origin, + }) + ); + } + }, + }, +}); diff --git a/frontend/app/frontend/src/store/form.js b/frontend/app/frontend/src/store/form.js new file mode 100644 index 0000000..b40a224 --- /dev/null +++ b/frontend/app/frontend/src/store/form.js @@ -0,0 +1,853 @@ +import { defineStore } from 'pinia'; +import { i18n } from '~/internationalization'; +import { + apiKeyService, + formService, + fileService, + rbacService, + userService, +} from '~/services'; +import { useNotificationStore } from '~/store/notification'; +import { IdentityMode, NotificationTypes } from '~/utils/constants'; +import { generateIdps, parseIdps } from '~/utils/transformUtils'; + +const genInitialSchedule = () => ({ + enabled: null, + scheduleType: null, + openSubmissionDateTime: null, + keepOpenForTerm: null, + keepOpenForInterval: null, + closingMessageEnabled: null, + closingMessage: null, + closeSubmissionDateTime: null, + repeatSubmission: { + enabled: null, + repeatUntil: null, + everyTerm: null, + everyIntervalType: null, + }, + allowLateSubmissions: { + enabled: null, + forNext: { + term: null, + intervalType: null, + }, + }, +}); + +const genInitialSubscribe = () => ({ + enabled: null, +}); +const genInitialSubscribeDetails = () => ({ + subscribeEvent: '', + endpointUrl: null, + endpointToken: null, + key: '', +}); + +const genInitialForm = () => ({ + description: '', + enableSubmitterDraft: false, + enableStatusUpdates: false, + allowSubmitterToUploadFile: false, + id: '', + idps: [], + isDirty: false, + name: '', + sendSubReceivedEmail: false, + showSubmissionConfirmation: true, + snake: '', + submissionReceivedEmails: [], + reminder_enabled: false, + schedule: genInitialSchedule(), + subscribe: genInitialSubscribe(), + userType: IdentityMode.TEAM, + versions: [], + enableCopyExistingSubmission: false, +}); + +export const useFormStore = defineStore('form', { + state: () => ({ + apiKey: undefined, + downloadedFile: { + data: null, + headers: null, + }, + drafts: [], + emailTemplates: [], + fcProactiveHelpGroupList: {}, + fcProactiveHelpImageUrl: '', + form: genInitialForm(), + formFields: [], + formSubmission: { + confirmationId: '', + originalName: '', + submission: { + data: {}, + }, + }, + formList: [], + imageList: new Map(), + lang: 'en', + isRTL: false, + permissions: [], + roles: [], + submissionList: [], + submissionUsers: [], + subscriptionData: genInitialSubscribeDetails(), + totalSubmissions: 0, + userFormPreferences: {}, + version: {}, + }), + getters: { + isFormPublished: (state) => + state?.form?.versions?.length && + state.form.versions.some((v) => v.published), + }, + actions: { + // + // Current User + // + // + async getFormsForCurrentUser() { + try { + // Get the forms based on the user's permissions + const response = await rbacService.getCurrentUser(); + const data = response.data; + // Build up the list of forms for the table + const forms = data.forms.map((f) => ({ + currentVersionId: f.formVersionId, + id: f.formId, + idps: f.idps, + name: f.formName, + description: f.formDescription, + permissions: f.permissions, + published: f.published, + })); + this.formList = forms; + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.form.getCurrUserFormsErrMsg'), + consoleError: i18n.t('trans.store.form.getCurrUserFormsErrMsg', { + error: error, + }), + }); + } + }, + async getFormPermissionsForUser(formId) { + try { + this.permissions = []; + // Get the forms based on the user's permissions + const response = await rbacService.getCurrentUser({ formId: formId }); + const data = response.data; + if (data.forms[0]) { + this.permissions = data.forms[0].permissions; + } else { + throw new Error('No form found'); + } + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.form.getUserFormPermErrMsg'), + consoleError: i18n.t('trans.store.form.getUserFormPermConsErrMsg', { + formId: formId, + error: error, + }), + }); + } + }, + async getFormRolesForUser(formId) { + try { + this.roles = []; + // Get the forms based on the user's permissions + const response = await rbacService.getCurrentUser({ formId: formId }); + const data = response.data; + if (data.forms[0]) { + this.roles = data.forms[0].roles; + } else { + throw new Error('No form found'); + } + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.form.getUserFormRolesErrmsg'), + consoleError: i18n.t('trans.store.form.getUserFormRolesConsErrmsg', { + formId: formId, + error: error, + }), + }); + } + }, + async getFormPreferencesForCurrentUser(formId) { + try { + const response = await userService.getUserFormPreferences(formId); + this.userFormPreferences = response.data; + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.form.getCurrUserFormPrefErrMsg'), + consoleError: i18n.t('trans.store.form.getCurrUserFormPrefErrMsg', { + formId: formId, + error: error, + }), + }); + } + }, + async updateFormPreferencesForCurrentUser({ formId, preferences }) { + try { + const response = await userService.updateUserFormPreferences( + formId, + preferences + ); + this.userFormPreferences = response.data; + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.form.updCurrUserFormPrefErrMsg'), + consoleError: i18n.t( + 'trans.store.form.updCurrUserFormPrefConsErrMsg', + { + formId: formId, + preferences: preferences, + error: error, + } + ), + }); + } + }, + // + // Form + // + async deleteCurrentForm() { + const notificationStore = useNotificationStore(); + try { + await formService.deleteForm(this.form.id); + notificationStore.addNotification({ + text: i18n.t('trans.store.form.delCurrformNotiMsg', { + name: this.form.name, + }), + ...NotificationTypes.SUCCESS, + }); + } catch (error) { + notificationStore.addNotification({ + text: i18n.t('trans.store.form.delCurrformNotiMsg', { + name: this.form.name, + }), + consoleError: i18n.t('trans.store.form.delCurrFormConsErMsg', { + id: this.form.id, + error: error, + }), + }); + } + }, + async deleteDraft({ formId, draftId }) { + try { + await formService.deleteDraft(formId, draftId); + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.form.delDraftErrMsg'), + consoleError: i18n.t('trans.store.form.delDraftConsErrMsg', { + draftId: draftId, + error: error, + }), + }); + } + }, + async fetchDrafts(formId) { + try { + // Get any drafts for this form from the api + const { data } = await formService.listDrafts(formId); + this.drafts = data; + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.form.fecthDraftErrMsg'), + consoleError: i18n.t('trans.store.form.fecthDraftConsErrMsg', { + formId: formId, + error: error, + }), + }); + } + }, + async fetchEmailTemplates(formId) { + try { + // Get the email templates for this form from the api + const { data } = await formService.listEmailTemplates(formId); + this.emailTemplates = data; + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.form.fetchEmailTemplatesErrMsg'), + consoleError: i18n.t( + 'trans.store.form.fetchEmailTemplatesConsErrMsg', + { + formId, + error, + } + ), + }); + } + }, + async fetchForm(formId) { + try { + this.apiKey = null; + // Get the form definition from the api + const { data } = await formService.readForm(formId); + const identityProviders = parseIdps(data.identityProviders); + data.idps = identityProviders.idps; + data.userType = identityProviders.userType; + data.sendSubRecieviedEmail = + data.submissionReceivedEmails && data.submissionReceivedEmails.length; + data.schedule = { + ...genInitialSchedule(), + ...data.schedule, + }; + data.subscribe = { + ...genInitialSubscribe(), + ...data.subscribe, + }; + + this.form = data; + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.form.fecthFormErrMsg'), + consoleError: i18n.t('trans.store.form.fecthFormErrMsg', { + formId: formId, + error: error, + }), + }); + } + }, + async fetchFormFields({ formId, formVersionId }) { + try { + this.formFields = []; + const { data } = await formService.readVersionFields( + formId, + formVersionId + ); + this.formFields = data; + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.form.fetchFormFieldsErrMsg'), + consoleError: i18n.t('trans.store.form.fetchFormFieldsConsErrMsg', { + formId: formId, + error: error, + }), + }); + } + }, + async publishDraft({ formId, draftId }) { + try { + await formService.publishDraft(formId, draftId); + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.form.publishDraftErrMsg'), + consoleError: i18n.t('trans.store.form.publishDraftConsErrMsg', { + draftId: draftId, + error: error, + }), + }); + } + }, + async toggleVersionPublish({ formId, versionId, publish }) { + try { + await formService.publishVersion(formId, versionId, publish); + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: `An error occurred while ${ + publish ? 'publishing' : 'unpublishing' + }.`, + consoleError: i18n.t('trans.store.form.toggleVersnPublConsErrMsg', { + versionId: versionId, + publish: publish, + error: error, + }), + }); + } + }, + resetForm() { + this.form = genInitialForm(); + }, + async updateEmailTemplate(emailTemplate) { + try { + await formService.updateEmailTemplate(emailTemplate); + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.form.updateEmailTemplateErrMsg'), + consoleError: i18n.t( + 'trans.store.form.updateEmailTemplateConsErrMsg', + { + formId: emailTemplate.formId, + error: error, + } + ), + }); + } + }, + async updateForm() { + try { + const emailList = + this.form.sendSubRecieviedEmail && + this.form.submissionReceivedEmails && + Array.isArray(this.form.submissionReceivedEmails) + ? this.form.submissionReceivedEmails + : []; + + const schedule = this.form.schedule.enabled ? this.form.schedule : {}; + const subscribe = this.form.subscribe.enabled + ? this.form.subscribe + : {}; + + await formService.updateForm(this.form.id, { + name: this.form.name, + description: this.form.description, + enableSubmitterDraft: this.form.enableSubmitterDraft, + enableStatusUpdates: this.form.enableStatusUpdates, + identityProviders: generateIdps({ + idps: this.form.idps, + userType: this.form.userType, + }), + showSubmissionConfirmation: this.form.showSubmissionConfirmation, + submissionReceivedEmails: emailList, + schedule: schedule, + subscribe: subscribe, + allowSubmitterToUploadFile: this.form.allowSubmitterToUploadFile, + reminder_enabled: this.form.reminder_enabled + ? this.form.reminder_enabled + : false, + enableCopyExistingSubmission: this.form.enableCopyExistingSubmission + ? this.form.enableCopyExistingSubmission + : false, + }); + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.form.updateFormErrMsg'), + consoleError: i18n.t('trans.store.form.updateFormConsErrMsg', { + id: this.form.id, + error: error, + }), + }); + } + }, + // + // Submission + // + async deleteSubmission(submissionId) { + try { + // Get this submission + await formService.deleteSubmission(submissionId); + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.form.deleteSubmissionNotifyMsg'), + ...NotificationTypes.SUCCESS, + }); + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.form.deleteSubmissionErrMsg'), + consoleError: i18n.t('trans.store.form.deleteSubmissionConsErrMsg', { + submissionId: submissionId, + error: error, + }), + }); + } + }, + + async deleteMultiSubmissions({ formId, submissionIds }) { + const notificationStore = useNotificationStore(); + try { + await formService.deleteMultipleSubmissions(submissionIds[0], formId, { + data: { submissionIds: submissionIds }, + }); + notificationStore.addNotification({ + text: i18n.t('trans.store.form.deleteSubmissionsNotifyMsg'), + ...NotificationTypes.SUCCESS, + }); + } catch (error) { + notificationStore.addNotification({ + text: i18n.t('trans.store.form.deleteSubmissionsErrMsg'), + consoleError: i18n.t('trans.store.form.deleteSubmissionsConsErrMsg', { + error: error, + }), + }); + } + }, + + async restoreMultiSubmissions({ formId, submissionIds }) { + const notificationStore = useNotificationStore(); + try { + // Get this submission + await formService.restoreMutipleSubmissions(submissionIds[0], formId, { + submissionIds: submissionIds, + }); + notificationStore.addNotification({ + text: i18n.t('trans.store.form.restoreSubmissionsNotiMsg'), + ...NotificationTypes.SUCCESS, + }); + } catch (error) { + notificationStore.addNotification({ + text: i18n.t('trans.store.form.restoreSubmissionsErrMsg'), + consoleError: i18n.t( + 'trans.store.form.restoreSubmissionsConsErrMsg', + { + error: error, + } + ), + }); + } + }, + + async restoreSubmission({ submissionId, deleted }) { + const notificationStore = useNotificationStore(); + try { + // Get this submission + await formService.restoreSubmission(submissionId, { deleted }); + notificationStore.addNotification({ + text: i18n.t('trans.store.form.deleteSubmissionsNotifyMsg'), + ...NotificationTypes.SUCCESS, + }); + } catch (error) { + notificationStore.addNotification({ + text: i18n.t('trans.store.form.restoreSubmissionsErrMsg'), + consoleError: i18n.t( + 'trans.store.form.restoreSubmissionsConsErrMsg', + { + error: error, + submissionId: submissionId, + } + ), + }); + } + }, + async fetchSubmissionUsers(formSubmissionId) { + try { + // Get user list for this submission + const response = await rbacService.getSubmissionUsers({ + formSubmissionId, + }); + this.submissionUsers = response; + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.form.fecthSubmissnUsersErrMsg'), + consoleError: i18n.t( + 'trans.store.form.fecthSubmissnUsersConsErrMsg', + { formSubmissionId: formSubmissionId, error: error } + ), + }); + } + }, + async fetchSubmission({ submissionId }) { + try { + // Get this submission + const response = await formService.getSubmission(submissionId); + this.formSubmission = response.data.submission; + this.form = response.data.form; + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.form.fetchSubmissnErrMsg'), + consoleError: i18n.t('trans.store.form.fetchSubmissnConsErrMsg', { + submissionId: submissionId, + error: error, + }), + }); + } + }, + async fetchFormCSVExportFields({ + formId, + type, + draft, + deleted, + version, + singleRow, + }) { + try { + this.formFields = []; + const { data } = await formService.readCSVExportFields( + formId, + type, + draft, + deleted, + version, + singleRow + ); + this.formFields = data; + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.form.fetchFormCSVExptFieldsErrMsg'), + consoleError: i18n.t( + 'trans.store.form.fetchFormCSVExptFieldsErrMsg', + { + formId: formId, + error: error, + } + ), + }); + } + }, + async fetchSubmissions({ + formId, + userView, + deletedOnly = false, + createdBy = '', + createdAt, + page, + paginationEnabled, + itemsPerPage, + filterformSubmissionStatusCode, + sortBy: sortBy, + search: search, + searchEnabled: searchEnabled, + }) { + try { + this.submissionList = []; + // Get list of active submissions for this form (for either all submissions, or just single user) + const fields = + this.userFormPreferences && this.userFormPreferences.preferences + ? this.userFormPreferences.preferences.columns + : undefined; + const response = userView + ? await rbacService.getUserSubmissions({ + formId: formId, + }) + : await formService.listSubmissions(formId, { + deleted: deletedOnly, + fields: fields, + createdBy: createdBy, + createdAt: createdAt, + page: page, + paginationEnabled: paginationEnabled, + filterformSubmissionStatusCode: filterformSubmissionStatusCode, + itemsPerPage: itemsPerPage, + totalSubmissions: this.totalSubmissions, + sortBy: sortBy, + search: search, + searchEnabled: searchEnabled, + }); + if (paginationEnabled) { + this.submissionList = response.data.results; + this.totalSubmissions = response.data.total; + } else { + this.submissionList = response.data; + } + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.form.fetchSubmissnsErrMsg'), + consoleError: i18n.t('trans.store.form.fetchSubmissnsConsErrMsg', { + formId: formId, + error: error, + }), + }); + } + }, + async fetchVersion({ formId, versionId }) { + try { + // TODO: need a better 'set back to initial state' ability + this.formSubmission = { + submission: { + data: {}, + }, + }; + // Get details about the sepecific form version + const response = await formService.readVersion(formId, versionId); + this.version = response.data; + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.form.fetchVersionErrMsg'), + consoleError: i18n.t('trans.store.form.fetchVersionConsErrMsg', { + versionId: versionId, + formId: formId, + error: error, + }), + }); + } + }, + + // + // API Keys + // + async deleteApiKey(formId) { + const notificationStore = useNotificationStore(); + try { + await apiKeyService.deleteApiKey(formId); + this.apiKey = null; + notificationStore.addNotification({ + text: i18n.t('trans.store.form.deleteApiKeyNotifyMsg'), + ...NotificationTypes.SUCCESS, + }); + } catch (error) { + notificationStore.addNotification({ + text: i18n.t('trans.store.form.deleteApiKeyErrMsg'), + consoleError: i18n.t('trans.store.form.deleteApiKeyConsErrMsg', { + formId: formId, + error: error, + }), + }); + } + }, + async generateApiKey(formId) { + const notificationStore = useNotificationStore(); + try { + const { data } = await apiKeyService.generateApiKey(formId); + this.apiKey = data; + notificationStore.addNotification({ + text: i18n.t('trans.store.form.generateApiKeyNotifyMsg'), + ...NotificationTypes.SUCCESS, + }); + } catch (error) { + notificationStore.addNotification({ + text: 'An error occurred while trying to generate an API Key.', + consoleError: `Error generating API Key for form ${formId}: ${error}`, + }); + } + }, + async readApiKey(formId) { + try { + const { data } = await apiKeyService.readApiKey(formId); + this.apiKey = data; + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.form.generateApiKeyErrMsg'), + consoleError: i18n.t('trans.store.form.generateApiKeyConsErrMsg', { + formId: formId, + error: error, + }), + }); + } + }, + + async getFCProactiveHelpImageUrl(componentId) { + try { + this.fcProactiveHelpImageUrl = {}; + const response = this.imageList.get(componentId); + if (response) { + this.fcProactiveHelpImageUrl = response.data.url; + } else { + const response = await formService.getFCProactiveHelpImageUrl( + componentId + ); + this.imageList.set(componentId, response); + this.fcProactiveHelpImageUrl = response.data.url; + } + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.form.getFCPHImageUrlErrMsg'), + consoleError: i18n.t('trans.store.form.getFCPHImageUrlConsErrMsg', { + error: error, + }), + }); + } + }, + //listFormComponentsProactiveHelp + async listFCProactiveHelp() { + try { + // Get Form Components Proactive Help Group Object + this.fcProactiveHelpGroupList = {}; + const response = await formService.listFCProactiveHelp(); + this.fcProactiveHelpGroupList = response.data; + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.form.listFCPHErrMsg'), + consoleError: i18n.t('trans.store.form.listFCPHConsErrMsg', { + error: error, + }), + }); + } + }, + async setDirtyFlag(isDirty) { + // When the form is detected to be dirty set the browser guards for closing the tab etc + // There are also Vue route-specific guards so that we can ask before navigating away with the links + // Look for those in the Views for the relevant pages, look for "beforeRouteLeave" lifecycle + if (!this.form || this.form.isDirty === isDirty) return; // don't do anything if not changing the val (or if form is blank for some reason) + this.form.isDirty = isDirty; + }, + async setMultiLanguage(lang) { + this.lang = lang; + if (lang === 'ar' || lang === 'fa') { + this.isRTL = true; + } else { + this.isRTL = false; + } + }, + async downloadFile(fileId) { + try { + this.downloadedFile.data = null; + this.downloadedFile.headers = null; + const response = await fileService.getFile(fileId); + this.downloadedFile.data = response.data; + this.downloadedFile.headers = response.headers; + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.form.downloadFileErrMsg'), + consoleError: i18n.t('trans.store.form.downloadFileConsErrMsg', { + error: error, + }), + }); + } + }, + async readFormSubscriptionData(formId) { + try { + const { data } = await formService.readFormSubscriptionData(formId); + if (data) { + this.subscriptionData = data; + } + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.form.readSubscriptionSettingsErrMsg'), + consoleError: i18n.t( + 'trans.store.form.readSubscriptionSettingsConsErrMsg', + { + formId: formId, + error: error, + } + ), + }); + } + }, + async updateSubscription({ formId, subscriptionData }) { + try { + const { data } = await formService.updateSubscription( + formId, + subscriptionData + ); + if (data) { + this.subscriptionData = data; + } + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.form.saveSubscriptionSettingsNotifyMsg'), + ...NotificationTypes.SUCCESS, + }); + } catch (error) { + const notificationStore = useNotificationStore(); + notificationStore.addNotification({ + text: i18n.t('trans.store.form.saveSubscriptionSettingsErrMsg'), + consoleError: i18n.t( + 'trans.store.form.saveSubscriptionSettingsConsErrMsg', + { + formId: formId, + error: error, + } + ), + }); + } + }, + }, +}); diff --git a/frontend/app/frontend/src/store/index.js b/frontend/app/frontend/src/store/index.js new file mode 100644 index 0000000..ed7db63 --- /dev/null +++ b/frontend/app/frontend/src/store/index.js @@ -0,0 +1,3 @@ +import { createPinia } from 'pinia'; + +export default createPinia(); diff --git a/frontend/app/frontend/src/store/notification.js b/frontend/app/frontend/src/store/notification.js new file mode 100644 index 0000000..0ead34f --- /dev/null +++ b/frontend/app/frontend/src/store/notification.js @@ -0,0 +1,58 @@ +import { defineStore } from 'pinia'; +import getRouter from '~/router'; + +import { NotificationTypes } from '~/utils/constants'; + +export const useNotificationStore = defineStore('notification', { + state: () => ({ + notifications: [], + notificationId: 1, + }), + getters: {}, + actions: { + /* + * Navigates to the error view + * @param msg The locale message + */ + errorNavigate(msg) { + const router = getRouter(); + router.replace({ + name: 'Error', + query: { text: typeof msg === 'object' ? JSON.stringify(msg) : msg }, + }); + }, + /* + * Navigates to the alert banner view + * @param msg The locale message + */ + alertNavigate(type, msg) { + const router = getRouter(); + router.replace({ + name: 'Alert', + params: { + text: msg, + type: type, + }, + }); + }, + /* + * We add notifications here that aren't translated. When calling + * this function, you need to send in the locale message. We translate + * it in the final component. + */ + addNotification(notification) { + if (!notification.type) + notification = { ...notification, ...NotificationTypes.ERROR }; + + this.notifications.push({ + ...notification, + id: this.notificationId++, + }); + }, + deleteNotification(notification) { + this.notifications = this.notifications.filter( + (n) => n.id !== notification.id + ); + }, + }, +}); diff --git a/frontend/app/frontend/src/utils/constants.js b/frontend/app/frontend/src/utils/constants.js new file mode 100644 index 0000000..ea6fc5c --- /dev/null +++ b/frontend/app/frontend/src/utils/constants.js @@ -0,0 +1,120 @@ +// +// Constants +// + +/** API Route paths */ +export const ApiRoutes = Object.freeze({ + ADMIN: '/admin', + APIKEY: '/apiKey', + FORMS: '/forms', + RBAC: '/rbac', + ROLES: '/roles', + SUBMISSION: '/submissions', + USERS: '/users', + FILES: '/files', + UTILS: '/utils', +}); + +/** Roles a user can have on a form. These are defined in the DB and sent from the API */ +// Note: values are sorted in descending order for accessibility +export const FormRoleCodes = Object.freeze({ + OWNER: 'owner', + TEAM_MANAGER: 'team_manager', + FORM_DESIGNER: 'form_designer', + SUBMISSION_REVIEWER: 'submission_reviewer', + FORM_SUBMITTER: 'form_submitter', +}); + +/** Permissions a user can have on a form. These are defined in the DB and sent from the API */ +export const FormPermissions = Object.freeze({ + EMAIL_TEMPLATE_READ: 'email_template_read', + EMAIL_TEMPLATE_UPDATE: 'email_template_update', + + FORM_API_CREATE: 'form_api_create', + FORM_API_READ: 'form_api_read', + FORM_API_UPDATE: 'form_api_update', + FORM_API_DELETE: 'form_api_delete', + + FORM_READ: 'form_read', + FORM_UPDATE: 'form_update', + FORM_DELETE: 'form_delete', + + SUBMISSION_CREATE: 'submission_create', + SUBMISSION_READ: 'submission_read', + SUBMISSION_UPDATE: 'submission_update', + SUBMISSION_DELETE: 'submission_delete', + + DESIGN_CREATE: 'design_create', + DESIGN_READ: 'design_read', + DESIGN_UPDATE: 'design_update', + DESIGN_DELETE: 'design_delete', + + TEAM_READ: 'team_read', + TEAM_UPDATE: 'team_update', +}); + +/** Permissions a user needs to Manage a Form */ +export const FormManagePermissions = Object.freeze([ + FormPermissions.FORM_UPDATE, + FormPermissions.FORM_DELETE, + FormPermissions.DESIGN_UPDATE, + FormPermissions.DESIGN_DELETE, + FormPermissions.TEAM_UPDATE, +]); + +/** Identity modes that a form can operate in regards to user identification */ +export const IdentityMode = Object.freeze({ + LOGIN: 'login', // Requires Login + PUBLIC: 'public', // Anonymous + TEAM: 'team', // Specific People +}); + +/** Identitiy Providers a user can log in as and a form can be allowed for */ +export const IdentityProviders = Object.freeze({ + BCEIDBASIC: 'bceid-basic', // Basic BCeID + BCEIDBUSINESS: 'bceid-business', // Business BCeID + IDIR: 'idir', // IDIR +}); + +/** Corresponds to vuetify alert classes for notification types */ +export const NotificationTypes = Object.freeze({ + ERROR: { + color: 'error', + type: 'error', + icon: '$error', + }, + SUCCESS: { + color: 'success', + type: 'success', + icon: 'mdi:mdi-check-circle', + }, + INFO: { + color: 'info', + type: 'info', + icon: '$info', + }, + WARNING: { + color: 'warning', + type: 'warning', + icon: '$warning', + }, +}); + +export const Regex = Object.freeze({ + // From ajv-format + EMAIL: + "^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$", +}); + +/** Identity modes that a form can operate in regards to user identification */ +export const ScheduleType = Object.freeze({ + MANUAL: 'manual', // Requires Login + CLOSINGDATE: 'closingDate', // Anonymous + PERIOD: 'period', // Specific People +}); + +/** Constants for Export large data submission feature */ +export const ExportLargeData = Object.freeze({ + MAX_RECORDS: 300, // Maximum number of submissions after that we gonna upload the export to Cloud and send user a download link via email + MAX_FIELDS: 30, // Maximum number of fields in a form after that we gonna upload the export to Cloud and send user a download link via email +}); diff --git a/frontend/app/frontend/src/utils/keycloak.js b/frontend/app/frontend/src/utils/keycloak.js new file mode 100644 index 0000000..6a1804f --- /dev/null +++ b/frontend/app/frontend/src/utils/keycloak.js @@ -0,0 +1,75 @@ +export function sanitizeConfig(config) { + const renameProp = (oldProp, newProp, { [oldProp]: old, ...others }) => { + return { + [newProp]: old, + ...others, + }; + }; + return Object.keys(config).reduce(function (previous, key) { + if (['authRealm', 'authUrl', 'authClientId'].includes(key)) { + const cleaned = key.replace('auth', ''); + const newKey = cleaned.charAt(0).toLowerCase() + cleaned.slice(1); + return renameProp(key, newKey, previous); + } + return previous; + }, config); +} + +function _isObject(obj) { + return ( + obj !== null && + typeof obj === 'object' && + Object.prototype.toString.call(obj) !== '[object Array]' + ); +} + +export function getConfig(config) { + if (_isObject(config)) return Promise.resolve(config); + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest(); + xhr.open('GET', config); + xhr.setRequestHeader('Accept', 'application/json'); + xhr.onreadystatechange = () => { + if (xhr.readyState === 4) { + if (xhr.status === 200) { + resolve(JSON.parse(xhr.responseText)); + } else { + reject(Error(xhr.statusText)); + } + } + }; + xhr.send(); + }); +} + +export function assertOptions(options) { + const { config, init, onReady, onInitError } = options; + if (typeof config !== 'string' && !_isObject(config)) { + return { + hasError: true, + error: `'config' option must be a string or an object. Found: '${config}'`, + }; + } + if (!_isObject(init) || typeof init.onLoad !== 'string') { + return { + hasError: true, + error: `'init' option must be an object with an 'onLoad' property. Found: '${init}'`, + }; + } + if (onReady && typeof onReady !== 'function') { + return { + hasError: true, + error: `'onReady' option must be a function. Found: '${onReady}'`, + }; + } + if (onInitError && typeof onInitError !== 'function') { + return { + hasError: true, + error: `'onInitError' option must be a function. Found: '${onInitError}'`, + }; + } + return { + hasError: false, + error: null, + }; +} diff --git a/frontend/app/frontend/src/utils/permissionUtils.js b/frontend/app/frontend/src/utils/permissionUtils.js new file mode 100644 index 0000000..83035d6 --- /dev/null +++ b/frontend/app/frontend/src/utils/permissionUtils.js @@ -0,0 +1,178 @@ +import { formService } from '~/services'; +import { useAuthStore } from '~/store/auth'; +import { useNotificationStore } from '~/store/notification'; +import { + FormPermissions, + FormManagePermissions, + IdentityMode, + IdentityProviders, + NotificationTypes, +} from '~/utils/constants'; + +// +// Utility Functions for determining permissions +// + +/** + * @function checkFormSubmit + * Returns true or false if the user can submit this form + * @param {Object} userForm The form object for the rbac user + * @returns {boolean} TRUE if they can + */ +export function checkFormSubmit(userForm) { + return ( + userForm && + ((userForm.idps && userForm.idps.includes(IdentityProviders.PUBLIC)) || + (userForm.permissions && + userForm.permissions.includes(FormPermissions.SUBMISSION_CREATE))) + ); +} + +/** + * @function checkFormManage + * Returns true if the user can manage a form, false otherwise + * @param {Array} userForm A form's permissions array for the rbac user + * @returns {boolean} TRUE if they can + */ +export function checkFormManage(permissions) { + return ( + permissions && permissions.some((p) => FormManagePermissions.includes(p)) + ); +} + +/** + * @function checkSubmissionView + * Returns true if the user can view submissions of a form, false otherwise + * @param {Array} permissions A form's permissions array for the rbac user + * @returns {boolean} TRUE if they can + */ +export function checkSubmissionView(permissions) { + const perms = [ + FormPermissions.SUBMISSION_READ, + FormPermissions.SUBMISSION_UPDATE, + ]; + + return permissions && permissions.some((p) => perms.includes(p)); +} + +/** + * @function getErrorMessage + * Gets the message to display for preflight errors. Expand this to add + * friendlier messages for other errors. + * @param {Object} options - The Object containing preflight request details. + * @param {Error} error - The error that was produced. + * @returns {string|undefined} - The error message to display, or undefined to + * use the default message. + */ +function getErrorMessage(options, error) { + let errorMessage = undefined; + if (options.formId) { + const status = error?.response?.status; + if (status === 404 || status === 422) { + errorMessage = 'trans.permissionUtils.formNotAvailable'; + } + } + return errorMessage; +} + +/** + * @function preFlightAuth + * Determines whether to enter a route based on user authentication state and idpHint + * @param {Object} options Object containing either a formId or submissionId attribute + * @param {Object} next The callback function + */ +export async function preFlightAuth(options = {}, next) { + const notificationStore = useNotificationStore(); + // Support lambda functions (Consider making them util functions?) + const getIdpHint = (values) => { + return Array.isArray(values) && values.length ? values[0] : undefined; + }; + const isValidIdp = (value) => + Object.values(IdentityProviders).includes(value); + + // Determine current form or submission idpHint if available + let idpHint = undefined; + try { + if (options.formId) { + const { data } = await formService.readFormOptions(options.formId); + idpHint = getIdpHint(data.idpHints); + } else if (options.submissionId) { + const { data } = await formService.getSubmissionOptions( + options.submissionId + ); + idpHint = getIdpHint(data.form.idpHints); + } else { + throw new Error('trans.permissionUtils.missingFormIdAndSubmssId'); + } + } catch (error) { + // Halt user with error page, use alertNavigate for "friendly" messages. + const message = getErrorMessage(options, error); + if (message) { + // Don't display the 'An error has occurred...' popup notification. + notificationStore.alertNavigate( + NotificationTypes.ERROR.type, + 'trans.permissionUtils.formNotAvailable' + ); + } else { + notificationStore.addNotification({ + text: 'trans.permissionUtils.loadingFormErrMsg', + consoleError: { + text: 'trans.permissionUtils.loadingForm', + options: { + options, + error, + }, + }, + }); + notificationStore.errorNavigate(); + } + + return; // Short circuit this function - no point executing further logic + } + + const authStore = useAuthStore(); + + if (authStore.authenticated) { + const userIdp = authStore.identityProvider; + + if (idpHint === IdentityMode.PUBLIC || !idpHint) { + next(); // Permit navigation if public or team form + } else if (isValidIdp(idpHint) && userIdp === idpHint) { + next(); // Permit navigation if idps match + } else { + const msg = { + text: 'trans.permissionUtils.idpHintMsg', + options: { + idpHint: idpHint.toUpperCase(), + }, + }; + notificationStore.addNotification({ + ...msg, + consoleError: msg, + }); + notificationStore.errorNavigate(msg); + } + } else { + if (idpHint === IdentityMode.PUBLIC) { + next(); // Permit navigation if public form + } else if (isValidIdp(idpHint)) { + authStore.login(idpHint); // Force login flow with specified idpHint + } else { + authStore.login(); // Force login flow with user choice + } + } +} + +/** + * @function isFormPublic + * Returns true for a form object if this form can be viewed by public users + * @param {Object} form The form object fr + * @returns {boolean} TRUE if public + */ +export function isFormPublic(form) { + return ( + form && + form.identityProviders && + form.identityProviders.some((i) => i.code === IdentityMode.PUBLIC) + ); +} diff --git a/frontend/app/frontend/src/utils/transformUtils.js b/frontend/app/frontend/src/utils/transformUtils.js new file mode 100644 index 0000000..6e2d22e --- /dev/null +++ b/frontend/app/frontend/src/utils/transformUtils.js @@ -0,0 +1,254 @@ +import formioUtils from 'formiojs/utils'; +import moment from 'moment'; +import { IdentityMode } from '~/utils/constants'; + +// +// Transformation Functions for converting form objects +// + +/** + * @function generateIdps + * Converts idps and userType to identity provider objects + * @param {String[]} idps A string array of identity providers + * @param {String} userType The type of users + * @returns {Object[]} An object array of identity providers + */ +export function generateIdps({ idps, userType }) { + let identityProviders = []; + if (userType === IdentityMode.LOGIN && idps && idps.length) { + identityProviders = identityProviders.concat( + idps.map((i) => ({ code: i })) + ); + } else if (userType === IdentityMode.PUBLIC) { + identityProviders.push({ code: IdentityMode.PUBLIC }); + } + return identityProviders; +} + +/** + * @function parseIdps + * Converts identity provider objects to idps and userType + * @param {Object[]} identityProviders An object array of identity providers + * @returns {Object} An object containing idps and userType + */ +export function parseIdps(identityProviders) { + const result = { + idps: [], + userType: IdentityMode.TEAM, + }; + if (identityProviders && identityProviders.length) { + if (identityProviders[0].code === IdentityMode.PUBLIC) { + result.userType = IdentityMode.PUBLIC; + } else { + result.userType = IdentityMode.LOGIN; + result.idps = identityProviders.map((ip) => ip.code); + } + } + return result; +} + +/** + * @function attachAttributesToLinks + * Attaches attributes to Link tags to open in a new tab + * @param {Object[]} formSchemaComponents An array of Components + */ +export function attachAttributesToLinks(formSchemaComponents) { + const simpleContentComponents = formioUtils.searchComponents( + formSchemaComponents, + { + type: 'simplecontent', + } + ); + const advancedContent = formioUtils.searchComponents(formSchemaComponents, { + type: 'content', + }); + const combinedLinks = [...simpleContentComponents, ...advancedContent]; + + combinedLinks.forEach((component) => { + if (component.html && component.html.includes(']+target=)/g, + ' +import { mapState } from 'pinia'; +import BaseImagePopout from '../components/base/BaseImagePopout.vue'; +import { useAuthStore } from '~/store/auth'; +import { useFormStore } from '~/store/form'; + +export default { + components: { + BaseImagePopout, + }, + computed: { + ...mapState(useAuthStore, ['authenticated']), + ...mapState(useFormStore, ['isRTL', 'lang']), + howToVideoUrl() { + return import.meta.env.VITE_HOWTOURL; + }, + chefsTourVideoUrl() { + return import.meta.env.VITE_CHEFSTOURURL; + }, + }, +}; + + + + + diff --git a/frontend/app/frontend/src/views/Admin.vue b/frontend/app/frontend/src/views/Admin.vue new file mode 100644 index 0000000..c73f78f --- /dev/null +++ b/frontend/app/frontend/src/views/Admin.vue @@ -0,0 +1,28 @@ + + + diff --git a/frontend/app/frontend/src/views/Error.vue b/frontend/app/frontend/src/views/Error.vue new file mode 100644 index 0000000..567fb11 --- /dev/null +++ b/frontend/app/frontend/src/views/Error.vue @@ -0,0 +1,56 @@ + + + + + diff --git a/frontend/app/frontend/src/views/File.vue b/frontend/app/frontend/src/views/File.vue new file mode 100644 index 0000000..c9d1985 --- /dev/null +++ b/frontend/app/frontend/src/views/File.vue @@ -0,0 +1,13 @@ + + + diff --git a/frontend/app/frontend/src/views/Form.vue b/frontend/app/frontend/src/views/Form.vue new file mode 100644 index 0000000..5cff596 --- /dev/null +++ b/frontend/app/frontend/src/views/Form.vue @@ -0,0 +1,9 @@ + diff --git a/frontend/app/frontend/src/views/Login.vue b/frontend/app/frontend/src/views/Login.vue new file mode 100644 index 0000000..701c157 --- /dev/null +++ b/frontend/app/frontend/src/views/Login.vue @@ -0,0 +1,97 @@ + + + + + diff --git a/frontend/app/frontend/src/views/NotFound.vue b/frontend/app/frontend/src/views/NotFound.vue new file mode 100644 index 0000000..592558a --- /dev/null +++ b/frontend/app/frontend/src/views/NotFound.vue @@ -0,0 +1,23 @@ + + + diff --git a/frontend/app/frontend/src/views/User.vue b/frontend/app/frontend/src/views/User.vue new file mode 100644 index 0000000..5cff596 --- /dev/null +++ b/frontend/app/frontend/src/views/User.vue @@ -0,0 +1,9 @@ + diff --git a/frontend/app/frontend/src/views/admin/Form.vue b/frontend/app/frontend/src/views/admin/Form.vue new file mode 100644 index 0000000..f9de0bb --- /dev/null +++ b/frontend/app/frontend/src/views/admin/Form.vue @@ -0,0 +1,30 @@ + + + diff --git a/frontend/app/frontend/src/views/admin/Root.vue b/frontend/app/frontend/src/views/admin/Root.vue new file mode 100644 index 0000000..2e41510 --- /dev/null +++ b/frontend/app/frontend/src/views/admin/Root.vue @@ -0,0 +1,24 @@ + + + diff --git a/frontend/app/frontend/src/views/admin/User.vue b/frontend/app/frontend/src/views/admin/User.vue new file mode 100644 index 0000000..4b7281f --- /dev/null +++ b/frontend/app/frontend/src/views/admin/User.vue @@ -0,0 +1,30 @@ + + + diff --git a/frontend/app/frontend/src/views/file/Download.vue b/frontend/app/frontend/src/views/file/Download.vue new file mode 100644 index 0000000..bf61b91 --- /dev/null +++ b/frontend/app/frontend/src/views/file/Download.vue @@ -0,0 +1,105 @@ + + + diff --git a/frontend/app/frontend/src/views/form/Create.vue b/frontend/app/frontend/src/views/form/Create.vue new file mode 100644 index 0000000..284ef49 --- /dev/null +++ b/frontend/app/frontend/src/views/form/Create.vue @@ -0,0 +1,115 @@ + + + diff --git a/frontend/app/frontend/src/views/form/Design.vue b/frontend/app/frontend/src/views/form/Design.vue new file mode 100644 index 0000000..233c8f8 --- /dev/null +++ b/frontend/app/frontend/src/views/form/Design.vue @@ -0,0 +1,79 @@ + + + diff --git a/frontend/app/frontend/src/views/form/Emails.vue b/frontend/app/frontend/src/views/form/Emails.vue new file mode 100644 index 0000000..783b659 --- /dev/null +++ b/frontend/app/frontend/src/views/form/Emails.vue @@ -0,0 +1,31 @@ + + + diff --git a/frontend/app/frontend/src/views/form/Export.vue b/frontend/app/frontend/src/views/form/Export.vue new file mode 100644 index 0000000..f9111de --- /dev/null +++ b/frontend/app/frontend/src/views/form/Export.vue @@ -0,0 +1,27 @@ + + + diff --git a/frontend/app/frontend/src/views/form/Manage.vue b/frontend/app/frontend/src/views/form/Manage.vue new file mode 100644 index 0000000..3b1562d --- /dev/null +++ b/frontend/app/frontend/src/views/form/Manage.vue @@ -0,0 +1,39 @@ + + + diff --git a/frontend/app/frontend/src/views/form/Preview.vue b/frontend/app/frontend/src/views/form/Preview.vue new file mode 100644 index 0000000..bdf04ab --- /dev/null +++ b/frontend/app/frontend/src/views/form/Preview.vue @@ -0,0 +1,59 @@ + + + diff --git a/frontend/app/frontend/src/views/form/PublishForm.vue b/frontend/app/frontend/src/views/form/PublishForm.vue new file mode 100644 index 0000000..d17518a --- /dev/null +++ b/frontend/app/frontend/src/views/form/PublishForm.vue @@ -0,0 +1,94 @@ + + + diff --git a/frontend/app/frontend/src/views/form/Submissions.vue b/frontend/app/frontend/src/views/form/Submissions.vue new file mode 100644 index 0000000..451147b --- /dev/null +++ b/frontend/app/frontend/src/views/form/Submissions.vue @@ -0,0 +1,27 @@ + + + diff --git a/frontend/app/frontend/src/views/form/Submit.vue b/frontend/app/frontend/src/views/form/Submit.vue new file mode 100644 index 0000000..afba90e --- /dev/null +++ b/frontend/app/frontend/src/views/form/Submit.vue @@ -0,0 +1,19 @@ + + + diff --git a/frontend/app/frontend/src/views/form/Success.vue b/frontend/app/frontend/src/views/form/Success.vue new file mode 100644 index 0000000..3b35fa0 --- /dev/null +++ b/frontend/app/frontend/src/views/form/Success.vue @@ -0,0 +1,62 @@ + + + diff --git a/frontend/app/frontend/src/views/form/Teams.vue b/frontend/app/frontend/src/views/form/Teams.vue new file mode 100644 index 0000000..b35d933 --- /dev/null +++ b/frontend/app/frontend/src/views/form/Teams.vue @@ -0,0 +1,27 @@ + + + diff --git a/frontend/app/frontend/src/views/form/View.vue b/frontend/app/frontend/src/views/form/View.vue new file mode 100644 index 0000000..90b738c --- /dev/null +++ b/frontend/app/frontend/src/views/form/View.vue @@ -0,0 +1,27 @@ + + + diff --git a/frontend/app/frontend/src/views/user/Forms.vue b/frontend/app/frontend/src/views/user/Forms.vue new file mode 100644 index 0000000..d18ce4a --- /dev/null +++ b/frontend/app/frontend/src/views/user/Forms.vue @@ -0,0 +1,15 @@ + + + diff --git a/frontend/app/frontend/src/views/user/History.vue b/frontend/app/frontend/src/views/user/History.vue new file mode 100644 index 0000000..b3fae40 --- /dev/null +++ b/frontend/app/frontend/src/views/user/History.vue @@ -0,0 +1,22 @@ + + + diff --git a/frontend/app/frontend/src/views/user/Root.vue b/frontend/app/frontend/src/views/user/Root.vue new file mode 100644 index 0000000..3c05e48 --- /dev/null +++ b/frontend/app/frontend/src/views/user/Root.vue @@ -0,0 +1,32 @@ + + + diff --git a/frontend/app/frontend/src/views/user/SubmissionDraftEdit.vue b/frontend/app/frontend/src/views/user/SubmissionDraftEdit.vue new file mode 100644 index 0000000..122e332 --- /dev/null +++ b/frontend/app/frontend/src/views/user/SubmissionDraftEdit.vue @@ -0,0 +1,20 @@ + + + diff --git a/frontend/app/frontend/src/views/user/SubmissionDuplicate.vue b/frontend/app/frontend/src/views/user/SubmissionDuplicate.vue new file mode 100644 index 0000000..a7955f9 --- /dev/null +++ b/frontend/app/frontend/src/views/user/SubmissionDuplicate.vue @@ -0,0 +1,29 @@ + + + diff --git a/frontend/app/frontend/src/views/user/SubmissionView.vue b/frontend/app/frontend/src/views/user/SubmissionView.vue new file mode 100644 index 0000000..50ef270 --- /dev/null +++ b/frontend/app/frontend/src/views/user/SubmissionView.vue @@ -0,0 +1,19 @@ + + + diff --git a/frontend/app/frontend/src/views/user/Submissions.vue b/frontend/app/frontend/src/views/user/Submissions.vue new file mode 100644 index 0000000..bb0177c --- /dev/null +++ b/frontend/app/frontend/src/views/user/Submissions.vue @@ -0,0 +1,27 @@ + + + diff --git a/frontend/app/frontend/tests/unit/App.spec.js b/frontend/app/frontend/tests/unit/App.spec.js new file mode 100644 index 0000000..84c3906 --- /dev/null +++ b/frontend/app/frontend/tests/unit/App.spec.js @@ -0,0 +1,24 @@ +import { shallowMount } from '@vue/test-utils'; +import { describe, expect, it } from 'vitest'; +import { createRouter, createWebHistory } from 'vue-router'; + +import App from '~/App.vue'; +import getRouter from '~/router'; + +describe('App.vue', () => { + const router = createRouter({ + history: createWebHistory(), + routes: getRouter().getRoutes(), + }); + + it('renders', () => { + const wrapper = shallowMount(App, { + global: { + plugins: [router], + }, + }); + + expect(wrapper.find('v-layout-stub').exists()).toBeTruthy(); + expect(wrapper.text()).toMatch(''); + }); +}); diff --git a/frontend/app/frontend/tests/unit/components/admin/AddOwner.spec.js b/frontend/app/frontend/tests/unit/components/admin/AddOwner.spec.js new file mode 100644 index 0000000..4258c24 --- /dev/null +++ b/frontend/app/frontend/tests/unit/components/admin/AddOwner.spec.js @@ -0,0 +1,24 @@ +import { mount } from '@vue/test-utils'; +import { expect } from 'vitest'; +import { nextTick } from 'vue'; + +import AddOwner from '~/components/admin/AddOwner.vue'; + +describe('AddOwner.vue', () => { + it('renders', async () => { + const wrapper = mount(AddOwner, { + props: { + formId: 'f', + }, + global: { + plugins: [], + }, + }); + + await nextTick(); + + expect(wrapper.text()) + .toContain('trans.addOwner.infoA') + .toContain('trans.addOwner.label'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/components/admin/AdminPage.spec.js b/frontend/app/frontend/tests/unit/components/admin/AdminPage.spec.js new file mode 100644 index 0000000..e1cbfb1 --- /dev/null +++ b/frontend/app/frontend/tests/unit/components/admin/AdminPage.spec.js @@ -0,0 +1,77 @@ +import { mount } from '@vue/test-utils'; +import { createTestingPinia } from '@pinia/testing'; +import { setActivePinia } from 'pinia'; +import { beforeEach, expect } from 'vitest'; + +import AdminPage from '~/components/admin/AdminPage.vue'; +import { useAppStore } from '~/store/app'; + +describe('AdminPage.vue', () => { + const pinia = createTestingPinia(); + + setActivePinia(pinia); + const appStore = useAppStore(pinia); + + beforeEach(() => { + appStore.$reset(); + }); + + it('renders', async () => { + appStore.config = {}; + const wrapper = mount(AdminPage, { + global: { + plugins: [pinia], + stubs: { + AdminFormsTable: true, + AdminUsersTable: true, + Developer: true, + FormComponentsProactiveHelp: true, + Metrics: true, + }, + }, + }); + + expect(wrapper.text()).toContain('trans.adminPage.forms'); + expect(wrapper.text()).not.toContain('trans.adminPage.metrics'); + }); + + it('renders without metrics', async () => { + appStore.config = { + adminDashboardUrl: '', + }; + const wrapper = mount(AdminPage, { + global: { + plugins: [pinia], + stubs: { + AdminFormsTable: true, + AdminUsersTable: true, + Developer: true, + FormComponentsProactiveHelp: true, + Metrics: true, + }, + }, + }); + + expect(wrapper.text()).not.toContain('trans.adminPage.metrics'); + }); + + it('renders with metrics', async () => { + appStore.config = { + adminDashboardUrl: 'x', + }; + const wrapper = mount(AdminPage, { + global: { + plugins: [pinia], + stubs: { + AdminFormsTable: true, + AdminUsersTable: true, + Developer: true, + FormComponentsProactiveHelp: true, + Metrics: true, + }, + }, + }); + + expect(wrapper.text()).toContain('trans.adminPage.metrics'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/components/admin/AdministerForm.spec.js b/frontend/app/frontend/tests/unit/components/admin/AdministerForm.spec.js new file mode 100644 index 0000000..522e16b --- /dev/null +++ b/frontend/app/frontend/tests/unit/components/admin/AdministerForm.spec.js @@ -0,0 +1,46 @@ +import { flushPromises, mount } from '@vue/test-utils'; +import { createTestingPinia } from '@pinia/testing'; +import { setActivePinia } from 'pinia'; +import { beforeEach, expect } from 'vitest'; + +import AdministerForm from '~/components/admin/AdministerForm.vue'; +import { useAdminStore } from '~/store/admin'; + +describe('AdministerForm.vue', () => { + const pinia = createTestingPinia(); + + setActivePinia(pinia); + const adminStore = useAdminStore(pinia); + + beforeEach(() => { + adminStore.$reset(); + }); + + it('renders', async () => { + adminStore.readForm.mockImplementation(() => { + return {}; + }); + adminStore.readApiDetails.mockImplementation(() => { + return {}; + }); + adminStore.readRoles.mockImplementation(() => { + return []; + }); + adminStore.form = { + name: 'tehForm', + versions: [], + }; + const wrapper = mount(AdministerForm, { + props: { + formId: 'f', + }, + global: { + plugins: [pinia], + stubs: {}, + }, + }); + + await flushPromises(); + expect(wrapper.text()).toContain('tehForm'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/components/admin/AdministerUser.spec.js b/frontend/app/frontend/tests/unit/components/admin/AdministerUser.spec.js new file mode 100644 index 0000000..65ca028 --- /dev/null +++ b/frontend/app/frontend/tests/unit/components/admin/AdministerUser.spec.js @@ -0,0 +1,50 @@ +import { flushPromises, mount } from '@vue/test-utils'; +import { createTestingPinia } from '@pinia/testing'; +import { setActivePinia } from 'pinia'; +import { beforeEach, expect } from 'vitest'; + +import AdministerUser from '~/components/admin/AdministerUser.vue'; +import { useAppStore } from '~/store/app'; +import { useAdminStore } from '~/store/admin'; + +describe('AdministerUser.vue', () => { + const pinia = createTestingPinia(); + + setActivePinia(pinia); + const appStore = useAppStore(pinia); + const adminStore = useAdminStore(pinia); + + beforeEach(() => { + appStore.$reset(); + adminStore.$reset(); + }); + + it('renders', async () => { + appStore.config = { + keycloak: { + serverUrl: 'servU', + realm: 'theRealm', + }, + }; + adminStore.readUser.mockImplementation(() => {}); + adminStore.user = { + fullName: 'alice', + keycloakId: '1', + }; + const wrapper = mount(AdministerUser, { + props: { + userId: 'me', + }, + global: { + plugins: [pinia], + stubs: {}, + }, + }); + + await flushPromises(); + expect(wrapper.text()).toContain('alice'); + expect(wrapper.html()).toContain( + 'servU/admin/theRealm/console/#/realms/theRealm/users/1' + ); + }); +}); diff --git a/frontend/app/frontend/tests/unit/components/admin/Dashboard.spec.js b/frontend/app/frontend/tests/unit/components/admin/Dashboard.spec.js new file mode 100644 index 0000000..71e2f83 --- /dev/null +++ b/frontend/app/frontend/tests/unit/components/admin/Dashboard.spec.js @@ -0,0 +1,21 @@ +import { mount } from '@vue/test-utils'; +import { expect } from 'vitest'; + +import Dashboard from '~/components/admin/Dashboard.vue'; + +describe('Dashboard.vue', () => { + const URL = 'http://somewhere.com'; + + it('renders', async () => { + const wrapper = mount(Dashboard, { + props: { + url: URL, + }, + global: { + plugins: [], + }, + }); + + expect(wrapper.html()).toContain(URL); + }); +}); diff --git a/frontend/app/frontend/tests/unit/components/admin/Developer.spec.js b/frontend/app/frontend/tests/unit/components/admin/Developer.spec.js new file mode 100644 index 0000000..2b58f12 --- /dev/null +++ b/frontend/app/frontend/tests/unit/components/admin/Developer.spec.js @@ -0,0 +1,94 @@ +import { mount } from '@vue/test-utils'; +import { createTestingPinia } from '@pinia/testing'; +import { setActivePinia } from 'pinia'; +import { expect, vi } from 'vitest'; +import { nextTick } from 'vue'; + +import { rbacService } from '~/services'; +import { useAuthStore } from '~/store/auth'; +import Developer from '~/components/admin/Developer.vue'; + +describe('Developer.vue', () => { + const mockConsoleError = vi.spyOn(console, 'error'); + const getCurrentUserSpy = vi.spyOn(rbacService, 'getCurrentUser'); + + const pinia = createTestingPinia(); + setActivePinia(pinia); + + const authStore = useAuthStore(pinia); + + beforeEach(() => { + mockConsoleError.mockReset(); + getCurrentUserSpy.mockReset(); + }); + + afterAll(() => { + mockConsoleError.mockRestore(); + getCurrentUserSpy.mockRestore(); + }); + + it('renders without error', async () => { + const data = {}; + authStore.keycloak = { + tokenParsed: { + email: 'email@email.com', + name: 'lucy', + }, + userName: 'userName', + token: 'token', + fullName: 'fullName', + }; + getCurrentUserSpy.mockImplementation(() => ({ data: data })); + const wrapper = mount(Developer, { + global: { + props: { + textToCopy: 'textToCopy', + }, + plugins: [pinia], + stubs: { + BaseSecure: true, + BaseCopyToClipboard: true, + }, + }, + }); + + await nextTick(); + + expect(wrapper.text()).toMatch('Developer Resources'); + expect(getCurrentUserSpy).toHaveBeenCalledTimes(1); + expect(wrapper.vm.apiRes).toEqual(data); + }); + + it('renders with error', async () => { + authStore.keycloak = { + tokenParsed: { + email: 'email@email.com', + name: 'lucy', + }, + userName: 'userName', + token: 'token', + fullName: 'fullName', + }; + getCurrentUserSpy.mockImplementation(() => { + throw new Error('error'); + }); + const wrapper = mount(Developer, { + global: { + props: { + textToCopy: 'textToCopy', + }, + plugins: [pinia], + stubs: { + BaseSecure: true, + BaseCopyToClipboard: true, + }, + }, + }); + + await nextTick(); + + expect(wrapper.text()).toMatch('Developer Resources'); + expect(getCurrentUserSpy).toHaveBeenCalledTimes(1); + expect(wrapper.vm.apiRes).toMatch(''); + }); +}); diff --git a/frontend/app/frontend/tests/unit/components/admin/FormComponentsProactiveHelp.spec.js b/frontend/app/frontend/tests/unit/components/admin/FormComponentsProactiveHelp.spec.js new file mode 100644 index 0000000..8a6c095 --- /dev/null +++ b/frontend/app/frontend/tests/unit/components/admin/FormComponentsProactiveHelp.spec.js @@ -0,0 +1,36 @@ +import { mount } from '@vue/test-utils'; +import { createTestingPinia } from '@pinia/testing'; +import { setActivePinia } from 'pinia'; +import { expect, vi } from 'vitest'; + +import FormComponentsProactiveHelp from '~/components/admin/FormComponentsProactiveHelp.vue'; + +describe('Dashboard.vue', () => { + const pinia = createTestingPinia(); + setActivePinia(pinia); + const extractGroupComponentsSpy = vi.spyOn( + FormComponentsProactiveHelp.methods, + 'extractGroupComponents' + ); + beforeEach(() => { + extractGroupComponentsSpy.mockReset(); + }); + + afterAll(() => { + extractGroupComponentsSpy.mockRestore(); + }); + + it('renders', async () => { + const wrapper = mount(FormComponentsProactiveHelp, { + global: { + plugins: [pinia], + stubs: { + GeneralLayout: true, + }, + }, + }); + + wrapper.vm.onExpansionPanelClick('Basic Layout'); + expect(extractGroupComponentsSpy).toHaveBeenCalledTimes(1); + }); +}); diff --git a/frontend/app/frontend/tests/unit/components/base/BaseAuthButton.spec.js b/frontend/app/frontend/tests/unit/components/base/BaseAuthButton.spec.js new file mode 100644 index 0000000..ed57037 --- /dev/null +++ b/frontend/app/frontend/tests/unit/components/base/BaseAuthButton.spec.js @@ -0,0 +1,118 @@ +// @vitest-environment happy-dom +// happy-dom is required to access window.location + +import { mount } from '@vue/test-utils'; +import { setActivePinia, createPinia } from 'pinia'; +import { vi } from 'vitest'; + +import getRouter from '~/router'; +import BaseAuthButton from '~/components/base/BaseAuthButton.vue'; +import { useAuthStore } from '~/store/auth'; + +describe('BaseAuthButton.vue', () => { + const pinia = createPinia(); + setActivePinia(pinia); + const authStore = useAuthStore(); + const router = getRouter(); + const windowReplaceSpy = vi.spyOn(window.location, 'replace'); + + beforeEach(async () => { + windowReplaceSpy.mockReset(); + authStore.$reset(); + authStore.keycloak = { + createLoginUrl: vi.fn((opts) => opts), + createLogoutUrl: vi.fn((opts) => opts), + }; + router.currentRoute.value.meta.hasLogin = true; + router.push('/'); + await router.isReady(); + }); + + it('renders nothing when not authenticated and does not hasLogin', () => { + authStore.authenticated = false; + authStore.ready = true; + router.currentRoute.value.meta.hasLogin = false; + const wrapper = mount(BaseAuthButton, { + global: { + plugins: [router, pinia], + }, + }); + + expect(wrapper.text()).toEqual(''); + }); + + it('renders login when not authenticated and hasLogin', () => { + authStore.authenticated = false; + authStore.ready = true; + const wrapper = mount(BaseAuthButton, { + global: { + plugins: [router, pinia], + }, + }); + + wrapper.vm.$route.meta.hasLogin = true; + + expect(wrapper.text()).toEqual('trans.baseAuthButton.login'); + }); + + it('renders logout when authenticated', () => { + authStore.authenticated = true; + authStore.ready = true; + const wrapper = mount(BaseAuthButton, { + global: { + plugins: [router, pinia], + }, + }); + + expect(wrapper.text()).toEqual('trans.baseAuthButton.logout'); + }); + + it('renders nothing if keycloak is not ready', () => { + authStore.authenticated = false; + authStore.ready = false; + const wrapper = mount(BaseAuthButton, { + global: { + plugins: [router, pinia], + }, + }); + + expect(wrapper.text()).toBeFalsy(); + }); + + it('login button redirects to login url', async () => { + authStore.authenticated = false; + authStore.ready = true; + const wrapper = mount(BaseAuthButton, { + global: { + plugins: [router, pinia], + }, + }); + + const replace = vi.spyOn(router, 'replace'); + + wrapper.vm.login(); + expect(wrapper.text()).toMatch('trans.baseAuthButton.login'); + expect(replace).toHaveBeenCalledTimes(1); + expect(replace).toHaveBeenCalledWith({ + name: 'Login', + query: { idpHint: ['idir', 'bceid-business', 'bceid-basic'] }, + }); + }); + + it('logout button redirects to logout url', async () => { + authStore.authenticated = true; + authStore.ready = true; + const wrapper = mount(BaseAuthButton, { + global: { + plugins: [router, pinia], + }, + }); + + wrapper.vm.logout(); + expect(wrapper.text()).toMatch('trans.baseAuthButton.logout'); + expect(windowReplaceSpy).toHaveBeenCalledTimes(1); + expect(windowReplaceSpy).toHaveBeenCalledWith({ + redirectUri: location.origin, + }); + }); +}); diff --git a/frontend/app/frontend/tests/unit/components/base/BaseCopyToClipboard.spec.js b/frontend/app/frontend/tests/unit/components/base/BaseCopyToClipboard.spec.js new file mode 100644 index 0000000..e15f683 --- /dev/null +++ b/frontend/app/frontend/tests/unit/components/base/BaseCopyToClipboard.spec.js @@ -0,0 +1,72 @@ +import { mount } from '@vue/test-utils'; +import { setActivePinia, createPinia } from 'pinia'; +import { vi } from 'vitest'; + +import Clipboard from 'vue3-clipboard'; + +import BaseCopyToClipboard from '~/components/base/BaseCopyToClipboard.vue'; +import { useNotificationStore } from '~/store/notification'; + +describe('BaseCopyToClipboard.vue', () => { + setActivePinia(createPinia()); + const store = useNotificationStore(); + const addNotificationSpy = vi.spyOn(store, 'addNotification'); + + beforeEach(async () => { + store.$reset(); + addNotificationSpy.mockReset(); + }); + + it('renders', () => { + const wrapper = mount(BaseCopyToClipboard, { + props: { + tooltipText: 'test', + textToCopy: 'test', + buttonText: 'test', + }, + global: { + plugins: [[Clipboard, { autoSetContainer: true, appendToBody: true }]], + }, + store, + }); + + expect(wrapper.text()).toEqual('test'); + }); + + it('clipboardSuccessHandler behaves correctly', async () => { + const wrapper = mount(BaseCopyToClipboard, { + props: { + snackBarText: 'test', + tooltipText: 'test', + textToCopy: 'test', + buttonText: 'test', + }, + global: { + plugins: [[Clipboard, { autoSetContainer: true, appendToBody: true }]], + }, + store, + }); + + wrapper.vm.onCopy(); + expect(wrapper.emitted().copied).toBeTruthy(); + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + }); + + it('clipboardErrorHandler behaves correctly', async () => { + const wrapper = mount(BaseCopyToClipboard, { + props: { + snackBarText: 'test', + tooltipText: 'test', + textToCopy: 'test', + buttonText: 'test', + }, + global: { + plugins: [[Clipboard, { autoSetContainer: true, appendToBody: true }]], + }, + store, + }); + + wrapper.vm.onError(); + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + }); +}); diff --git a/frontend/app/frontend/tests/unit/components/base/BaseDialog.spec.js b/frontend/app/frontend/tests/unit/components/base/BaseDialog.spec.js new file mode 100644 index 0000000..c5177cb --- /dev/null +++ b/frontend/app/frontend/tests/unit/components/base/BaseDialog.spec.js @@ -0,0 +1,148 @@ +import { mount } from '@vue/test-utils'; +import { describe, it } from 'vitest'; +import { nextTick } from 'vue'; +import { createTestingPinia } from '@pinia/testing'; + +import BaseDialog from '~/components/base/BaseDialog.vue'; + +describe('BaseDialog.vue', () => { + it('renders with ok button', async () => { + const wrapper = mount(BaseDialog, { + props: { + modelValue: true, + type: 'OK', + }, + global: { + plugins: [createTestingPinia()], + stubs: { + VDialog: { + name: 'VDialog', + template: '
', + props: ['modelValue'], + }, + }, + }, + }); + await wrapper.vm.closeDialog(); + await nextTick(); + + expect(wrapper.text()).toContain('trans.baseDialog.ok'); + }); + + it('renders with continue button', async () => { + const wrapper = mount(BaseDialog, { + props: { + modelValue: true, + type: 'CONTINUE', + }, + global: { + plugins: [createTestingPinia()], + stubs: { + VDialog: { + name: 'VDialog', + template: '
', + props: ['modelValue'], + }, + }, + }, + }); + + expect(wrapper.text()).toContain('trans.baseDialog.continue'); + const continueBtn = wrapper.find('[data-test="continue-btn-continue"]'); + expect(continueBtn.exists()).toBeTruthy(); + await continueBtn.trigger('click'); + expect(wrapper.emitted()).toHaveProperty('continue-dialog'); + }); + + it('renders with the close button', async () => { + const wrapper = mount(BaseDialog, { + props: { + modelValue: true, + showCloseButton: true, + }, + global: { + plugins: [createTestingPinia()], + stubs: { + VDialog: { + name: 'VDialog', + template: '
', + props: ['modelValue'], + }, + }, + }, + }); + + expect(wrapper.find('i.mdi-close.v-icon').exists()).toBeTruthy(); + }); + + it('renders without the close button', async () => { + const wrapper = mount(BaseDialog, { + props: { + modelValue: true, + }, + global: { + plugins: [createTestingPinia()], + stubs: { + VDialog: { + name: 'VDialog', + template: '
', + props: ['modelValue'], + }, + }, + }, + }); + + expect(wrapper.find('i.mdi-close.v-icon').exists()).toBeFalsy(); + }); + + it('renders SAVEDDELETE with delete button', async () => { + const wrapper = mount(BaseDialog, { + props: { + modelValue: true, + type: 'SAVEDDELETE', + }, + global: { + plugins: [createTestingPinia()], + stubs: { + VDialog: { + name: 'VDialog', + template: '
', + props: ['modelValue'], + }, + }, + }, + }); + + expect(wrapper.text()).toContain('trans.baseDialog.continue'); + const deleteBtn = wrapper.find('[data-test="saveddelete-btn-cancel"]'); + expect(deleteBtn.exists()).toBeTruthy(); + await deleteBtn.trigger('click'); + expect(wrapper.emitted()).toHaveProperty('delete-dialog'); + }); + + it('renders CUSTOM with custom button', async () => { + const wrapper = mount(BaseDialog, { + props: { + modelValue: true, + type: 'CUSTOM', + enableCustomButton: true, + }, + global: { + plugins: [createTestingPinia()], + stubs: { + VDialog: { + name: 'VDialog', + template: '
', + props: ['modelValue'], + }, + }, + }, + }); + + expect(wrapper.text()).toContain('trans.baseDialog.continue'); + const customBtn = wrapper.find('[data-test="custom-btn-custom"]'); + expect(customBtn.exists()).toBeTruthy(); + await customBtn.trigger('click'); + expect(wrapper.emitted()).toHaveProperty('custom-dialog'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/components/base/BaseFilter.spec.js b/frontend/app/frontend/tests/unit/components/base/BaseFilter.spec.js new file mode 100644 index 0000000..84b4237 --- /dev/null +++ b/frontend/app/frontend/tests/unit/components/base/BaseFilter.spec.js @@ -0,0 +1,145 @@ +import { flushPromises, mount } from '@vue/test-utils'; +import { describe, it } from 'vitest'; +import { createTestingPinia } from '@pinia/testing'; +import BaseFilter from '~/components/base/BaseFilter.vue'; + +describe('BaseFilter.vue', () => { + it('renders', async () => { + const wrapper = mount(BaseFilter, { + global: { + plugins: [createTestingPinia()], + stubs: { + VDialog: { + name: 'VCard', + template: '
', + }, + }, + }, + }); + + await flushPromises(); + + const search = wrapper.find('[data-test="filter-search"]'); + expect(search.exists()).toBeTruthy(); + const table = wrapper.find('[data-test="filter-table"]'); + expect(table.exists()).toBeTruthy(); + const saveBtn = wrapper.find('[data-test="save-btn"]'); + expect(saveBtn.exists()).toBeTruthy(); + const cancelBtn = wrapper.find('[data-test="cancel-btn"]'); + expect(cancelBtn.exists()).toBeTruthy(); + const checkboxes = wrapper.findAll('tbody input[type="checkbox"]'); + expect(checkboxes.length).toBe(2); + + // Default column name and input data + expect(wrapper.html()).toContain('columnName'); + expect(wrapper.html()).toContain('exampleText'); + expect(wrapper.html()).toContain('exampleText2'); + }); + + it('renders with preset data', async () => { + const wrapper = mount(BaseFilter, { + props: { + inputHeaders: [ + { + title: 'TEST HEADER', + align: 'start', + sortable: true, + key: 'title', + }, + ], + inputData: [ + { + title: 'TEST NAME', + key: 'fullName', + }, + ], + inputFilterPlaceholder: 'Filter Something', + }, + global: { + plugins: [createTestingPinia()], + stubs: { + VDialog: { + name: 'VCard', + template: '
', + }, + }, + }, + }); + + await flushPromises(); + + const search = wrapper.find('[data-test="filter-search"]'); + expect(search.exists()).toBeTruthy(); + const table = wrapper.find('[data-test="filter-table"]'); + expect(table.exists()).toBeTruthy(); + const saveBtn = wrapper.find('[data-test="save-btn"]'); + expect(saveBtn.exists()).toBeTruthy(); + const cancelBtn = wrapper.find('[data-test="cancel-btn"]'); + expect(cancelBtn.exists()).toBeTruthy(); + + // Does not contain default column name and input data + expect(wrapper.html()).not.toContain('Column Name'); + expect(wrapper.html()).not.toContain('Example Text'); + expect(wrapper.html()).not.toContain('Example Text 2'); + + expect(wrapper.html()).toContain('TEST HEADER'); + expect(wrapper.html()).toContain('TEST NAME'); + expect(wrapper.html()).toContain('Filter Something'); + }); + + it('emits save', async () => { + const wrapper = mount(BaseFilter, { + global: { + plugins: [createTestingPinia()], + stubs: { + VDialog: { + name: 'VCard', + template: '
', + }, + }, + }, + }); + + await flushPromises(); + + // emits nothing + await wrapper.vm.savingFilterData(); + await wrapper.vm.$nextTick(); + expect(wrapper.emitted()).toHaveProperty('saving-filter-data'); + + // emits selected data + const selectedData = { + title: 'Example Text', + key: 'exampleText1', + }; + wrapper.vm.selectedData = [selectedData]; + await wrapper.vm.savingFilterData(); + await wrapper.vm.$nextTick(); + // emitted object is wrapped in an array + // selected data is also supposed to be in an array + expect(wrapper.emitted('saving-filter-data')[1]).toEqual([[selectedData]]); + }); + + it('emits cancel', async () => { + const wrapper = mount(BaseFilter, { + global: { + plugins: [createTestingPinia()], + stubs: { + VDialog: { + name: 'VCard', + template: '
', + }, + }, + }, + }); + + await flushPromises(); + + const btn = wrapper.find('[data-test="cancel-btn"]'); + expect(btn.exists()).toBeTruthy(); + + await btn.trigger('click'); + + expect(wrapper.emitted()).toHaveProperty('cancel-filter-data'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/components/base/BaseImagePopout.spec.js b/frontend/app/frontend/tests/unit/components/base/BaseImagePopout.spec.js new file mode 100644 index 0000000..75119f1 --- /dev/null +++ b/frontend/app/frontend/tests/unit/components/base/BaseImagePopout.spec.js @@ -0,0 +1,19 @@ +import { mount } from '@vue/test-utils'; +import { describe, expect, it } from 'vitest'; + +import BaseImagePopout from '~/components/base/BaseImagePopout.vue'; + +describe('BaseImagePopout.vue', () => { + it('renders', async () => { + const wrapper = mount(BaseImagePopout, { + props: { + src: 'test', + }, + global: { + stubs: ['v-dialog', 'v-hover'], + }, + }); + expect(wrapper.html()).toMatch('v-hover'); + expect(wrapper.html()).toMatch('v-dialog'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/components/base/BaseInternationalization.spec.js b/frontend/app/frontend/tests/unit/components/base/BaseInternationalization.spec.js new file mode 100644 index 0000000..1bf0835 --- /dev/null +++ b/frontend/app/frontend/tests/unit/components/base/BaseInternationalization.spec.js @@ -0,0 +1,75 @@ +import { flushPromises, mount } from '@vue/test-utils'; +import { setActivePinia, createPinia } from 'pinia'; +import { beforeEach, describe, it } from 'vitest'; + +import BaseInternationalization from '~/components/base/BaseInternationalization.vue'; +import { useFormStore } from '~/store/form'; + +describe('BaseInternationalization.vue', () => { + const pinia = createPinia(); + setActivePinia(pinia); + const formStore = useFormStore(); + + beforeEach(() => { + formStore.lang = 'en'; + }); + + it('renders', async () => { + const wrapper = mount(BaseInternationalization, { + global: { + stubs: { + VDialog: { + name: 'VMenu', + template: '
', + }, + }, + }, + }); + + await flushPromises(); + + // Default language + expect(wrapper.text()).toContain('English'); + }); + + it('changes language', async () => { + const wrapper = mount(BaseInternationalization, { + global: { + stubs: { + VDialog: { + name: 'VMenu', + template: '
', + }, + }, + }, + }); + + await flushPromises(); + + // Default language + expect(wrapper.text()).toContain('English'); + + expect(formStore.lang).toBe('en'); + + wrapper.vm.languageSelected({ + title: '简体中文 (Simplified Chinese)', + keyword: 'zh', + }); + + expect(formStore.lang).toBe('zh'); + + wrapper.vm.languageSelected({ + title: '繁體中文 (Traditional Chinese)', + keyword: 'zh-TW', + }); + + expect(formStore.lang).toBe('zh-TW'); + + wrapper.vm.languageSelected({ + title: 'UNKNOWN', + keyword: 'zh-CUSTOM', + }); + + expect(formStore.lang).toBe('zh-CUSTOM'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/components/base/BaseNotificationBar.spec.js b/frontend/app/frontend/tests/unit/components/base/BaseNotificationBar.spec.js new file mode 100644 index 0000000..be9b5cb --- /dev/null +++ b/frontend/app/frontend/tests/unit/components/base/BaseNotificationBar.spec.js @@ -0,0 +1,69 @@ +import { createTestingPinia } from '@pinia/testing'; +import { mount } from '@vue/test-utils'; +import { describe, expect, it, vi } from 'vitest'; + +import BaseNotificationBar from '~/components/base/BaseNotificationBar.vue'; +import { useNotificationStore } from '~/store/notification'; +import { NotificationTypes } from '~/utils/constants'; + +describe('BaseNotificationBar.vue', () => { + const notificationProperties = { + text: 'Test Notification', + ...NotificationTypes.ERROR, + }; + + it('renders', async () => { + const wrapper = mount(BaseNotificationBar, { + props: { + notification: { + id: 1, + ...notificationProperties, + }, + }, + global: { + plugins: [createTestingPinia()], + }, + }); + + expect(wrapper.html()).toMatch('v-alert'); + expect(wrapper.text()).toMatch(notificationProperties.text); + }); + + it('alertClosed behaves correctly', async () => { + const wrapper = mount(BaseNotificationBar, { + props: { + notification: { + id: 1, + ...notificationProperties, + }, + }, + global: { + plugins: [createTestingPinia()], + }, + }); + const store = useNotificationStore(); + const deleteNotificationSpy = vi.spyOn(store, 'deleteNotification'); + + wrapper.vm.alertClosed(); + expect(deleteNotificationSpy).toHaveBeenCalledTimes(1); + }); + + it('clears timeout before destroy', async () => { + const wrapper = mount(BaseNotificationBar, { + props: { + notification: { + id: 1, + timeout: 1, + ...notificationProperties, + }, + }, + global: { + plugins: [createTestingPinia()], + }, + }); + + wrapper.unmount(); + + expect(wrapper.vm.timeout).not.toBeNull(); + }); +}); diff --git a/frontend/app/frontend/tests/unit/components/base/BaseNotificationContainer.spec.js b/frontend/app/frontend/tests/unit/components/base/BaseNotificationContainer.spec.js new file mode 100644 index 0000000..d8bba56 --- /dev/null +++ b/frontend/app/frontend/tests/unit/components/base/BaseNotificationContainer.spec.js @@ -0,0 +1,18 @@ +import { createTestingPinia } from '@pinia/testing'; +import { mount } from '@vue/test-utils'; +import { describe, expect, it } from 'vitest'; + +import BaseNotificationContainer from '~/components/base/BaseNotificationContainer.vue'; + +describe('BaseNotificationContainer.vue', () => { + it('renders', async () => { + const wrapper = mount(BaseNotificationContainer, { + global: { + stubs: ['BaseNotificationBar'], + plugins: [createTestingPinia()], + }, + }); + + expect(wrapper.html()).toMatch('notification-container'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/components/base/BasePrintButton.spec.js b/frontend/app/frontend/tests/unit/components/base/BasePrintButton.spec.js new file mode 100644 index 0000000..5316711 --- /dev/null +++ b/frontend/app/frontend/tests/unit/components/base/BasePrintButton.spec.js @@ -0,0 +1,28 @@ +// @vitest-environment happy-dom +// happy-dom is required to access window.location + +import { mount } from '@vue/test-utils'; +import { beforeEach, expect, vi } from 'vitest'; + +import BasePrintButton from '~/components/base/BasePrintButton.vue'; + +describe('BasePrintButton.vue', () => { + const printSpy = vi.spyOn(window, 'print'); + beforeEach(() => { + printSpy.mockReset(); + printSpy.mockImplementation(() => {}); + }); + + afterAll(() => { + printSpy.mockRestore(); + }); + + it('renders nothing if authenticated, user', async () => { + const wrapper = mount(BasePrintButton); + + wrapper.vm.printSubmission(); + + expect(wrapper.html()).toContain('print'); + expect(printSpy).toHaveBeenCalledTimes(1); + }); +}); diff --git a/frontend/app/frontend/tests/unit/components/base/BaseSecure.spec.js b/frontend/app/frontend/tests/unit/components/base/BaseSecure.spec.js new file mode 100644 index 0000000..c2ea0e5 --- /dev/null +++ b/frontend/app/frontend/tests/unit/components/base/BaseSecure.spec.js @@ -0,0 +1,188 @@ +// @vitest-environment happy-dom +// happy-dom is required to access window.location + +import { mount } from '@vue/test-utils'; +import { setActivePinia, createPinia } from 'pinia'; +import { createRouter, createWebHistory } from 'vue-router'; +import { expect, vi } from 'vitest'; + +import getRouter from '~/router'; +import BaseSecure from '~/components/base/BaseSecure.vue'; +import { useAuthStore } from '~/store/auth'; + +describe('BaseSecure.vue', () => { + const pinia = createPinia(); + const router = createRouter({ + history: createWebHistory(), + routes: getRouter().getRoutes(), + }); + + setActivePinia(pinia); + const authStore = useAuthStore(); + + it('renders nothing if authenticated, user', () => { + authStore.authenticated = true; + authStore.ready = true; + authStore.keycloak = { + tokenParsed: { + resource_access: { + chefs: { + roles: ['user'], + }, + }, + }, + }; + const wrapper = mount(BaseSecure, { + global: { + plugins: [router, pinia], + }, + }); + + expect(wrapper.text()).toEqual(''); + }); + + it('renders a message if authenticated, not user', () => { + authStore.authenticated = true; + authStore.ready = true; + authStore.keycloak = { + tokenParsed: { + resource_access: { + chefs: { + roles: [], + }, + }, + }, + }; + const wrapper = mount(BaseSecure, { + global: { + plugins: [router, pinia], + }, + }); + + expect(wrapper.text()).toContain('trans.baseSecure.401UnAuthorized'); + }); + + it('renders a message if admin required, not admin', () => { + authStore.authenticated = true; + authStore.ready = true; + authStore.keycloak = { + tokenParsed: { + resource_access: { + chefs: { + roles: ['user'], + }, + }, + }, + }; + const wrapper = mount(BaseSecure, { + props: { + admin: true, + }, + global: { + plugins: [router, pinia], + }, + }); + + expect(wrapper.text()).toContain('trans.baseSecure.401UnAuthorizedErrMsg'); + }); + + it('renders nothing if admin required, user is admin', () => { + authStore.authenticated = true; + authStore.ready = true; + authStore.keycloak = { + tokenParsed: { + resource_access: { + chefs: { + roles: ['user'], + }, + }, + }, + }; + const wrapper = mount(BaseSecure, { + props: { + admin: true, + }, + global: { + plugins: [router, pinia], + }, + }); + + expect(wrapper.text()).toMatch(''); + }); + + it('renders a message with login button if unauthenticated', () => { + authStore.authenticated = false; + authStore.ready = true; + authStore.keycloak = {}; + const wrapper = mount(BaseSecure, { + props: { + admin: true, + }, + global: { + plugins: [router, pinia], + }, + }); + + expect(wrapper.text()).toMatch('trans.baseSecure.loginInfo'); + }); + + it('renders a message without login button if unauthenticated', () => { + authStore.authenticated = false; + authStore.ready = false; + authStore.keycloak = {}; + const wrapper = mount(BaseSecure, { + props: { + admin: true, + }, + global: { + plugins: [router, pinia], + }, + }); + + expect(wrapper.text()).toMatch('trans.baseSecure.loginInfo'); + }); + + it('login button redirects to login url', async () => { + authStore.authenticated = false; + authStore.ready = true; + authStore.keycloak = {}; + const loginSpy = vi.spyOn(authStore, 'login'); + const wrapper = mount(BaseSecure, { + props: { + admin: true, + }, + global: { + plugins: [router, pinia], + }, + }); + + const loginBtn = wrapper.find('[data-test="login-btn"]'); + await loginBtn.trigger('click'); + expect(loginSpy).toHaveBeenCalledTimes(1); + }); + + it('renders a message with 403 if identity provider does not exist', () => { + authStore.authenticated = true; + authStore.ready = true; + authStore.keycloak = { + tokenParsed: { + resource_access: { + chefs: { + roles: ['user'], + }, + }, + }, + }; + const wrapper = mount(BaseSecure, { + props: { + admin: false, + idp: ['IDIR'], + }, + global: { + plugins: [router, pinia], + }, + }); + + expect(wrapper.text()).toMatch('trans.baseSecure.403Forbidden'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/components/bcgov/BCGovAlertBanner.spec.js b/frontend/app/frontend/tests/unit/components/bcgov/BCGovAlertBanner.spec.js new file mode 100644 index 0000000..8ab59c0 --- /dev/null +++ b/frontend/app/frontend/tests/unit/components/bcgov/BCGovAlertBanner.spec.js @@ -0,0 +1,206 @@ +import { flushPromises, mount } from '@vue/test-utils'; +import { createPinia, setActivePinia } from 'pinia'; +import { describe, expect, it } from 'vitest'; +import { h } from 'vue'; +import { createRouter, createWebHistory } from 'vue-router'; + +import { VApp } from 'vuetify/components'; +import BCGovAlertBanner from '~/components/bcgov/BCGovAlertBanner.vue'; +import getRouter from '~/router'; +import { useAuthStore } from '~/store/auth'; +import { useNotificationStore } from '~/store/notification'; +import { NotificationTypes } from '~/utils/constants'; + +describe('BCGovAlertBanner.vue', () => { + const pinia = createPinia(); + setActivePinia(pinia); + const router = createRouter({ + history: createWebHistory(), + routes: getRouter().getRoutes(), + }); + + it('renders default error', async () => { + const authStore = useAuthStore(pinia); + authStore.authenticated = true; + authStore.ready = true; + + const wrapper = mount(VApp, { + global: { + plugins: [router], + }, + slots: { + default: h(BCGovAlertBanner), + }, + }); + + await flushPromises(); + + expect(wrapper.html()).toContain(NotificationTypes.ERROR.type); + expect(wrapper.html()).toContain('defaultErrMsg'); + }); + + it('renders with a custom error message', async () => { + const message = 'This is a custom error message for testing.'; + const authStore = useAuthStore(pinia); + authStore.authenticated = true; + authStore.ready = true; + + const wrapper = mount(BCGovAlertBanner, { + props: { + text: message, + }, + global: { + plugins: [pinia, router], + }, + }); + + await flushPromises(); + + expect(wrapper.html()).toContain(NotificationTypes.ERROR.type); + expect(wrapper.text()).toMatch(message); + }); + + it('renders with an info message', async () => { + const message = 'This is a custom info message for testing.'; + const authStore = useAuthStore(pinia); + authStore.authenticated = true; + authStore.ready = true; + + const wrapper = mount(BCGovAlertBanner, { + props: { + text: message, + type: 'info', + }, + global: { + plugins: [router], + }, + }); + + await flushPromises(); + + expect(wrapper.html()).toContain(NotificationTypes.INFO.type); + expect(wrapper.text()).toMatch(message); + }); + + it('renders with a success message', async () => { + const message = 'This is a custom success message for testing.'; + const authStore = useAuthStore(pinia); + authStore.authenticated = true; + authStore.ready = true; + + const wrapper = mount(BCGovAlertBanner, { + props: { + text: message, + type: 'success', + }, + global: { + plugins: [router], + }, + }); + + await flushPromises(); + + expect(wrapper.html()).toContain(NotificationTypes.SUCCESS.type); + expect(wrapper.text()).toMatch(message); + }); + + it('renders with a warning message', async () => { + const message = 'This is a custom warning message for testing.'; + const authStore = useAuthStore(pinia); + authStore.authenticated = true; + authStore.ready = true; + + const wrapper = mount(BCGovAlertBanner, { + props: { + text: message, + type: 'warning', + }, + global: { + plugins: [router], + }, + }); + + await flushPromises(); + + expect(wrapper.html()).toContain(NotificationTypes.WARNING.type); + expect(wrapper.text()).toMatch(message); + }); + + it('renders ok with the default if type is wrong', async () => { + const message = 'This is a custom warning message for testing.'; + const authStore = useAuthStore(pinia); + authStore.authenticated = true; + authStore.ready = true; + + const wrapper = mount(BCGovAlertBanner, { + props: { + text: message, + type: 'BROKEN', + }, + global: { + plugins: [router], + }, + }); + + await flushPromises(); + + expect(wrapper.html()).toContain(NotificationTypes.ERROR.type); + expect(wrapper.text()).toMatch(message); + }); + + it('renders html without escaping it', async () => { + const message = 'This is a
custom warning message..'; + const authStore = useAuthStore(pinia); + authStore.authenticated = true; + authStore.ready = true; + + const wrapper = mount(BCGovAlertBanner, { + props: { + text: message, + type: 'BROKEN', + }, + global: { + plugins: [router], + }, + }); + + await flushPromises(); + + expect(wrapper.html()).toContain(NotificationTypes.ERROR.type); + expect(wrapper.text()).not.toContain('href'); + }); + + it('deletes the notification', async () => { + const message = 'This is a custom warning message..'; + const authStore = useAuthStore(pinia); + const notificationStore = useNotificationStore(pinia); + + authStore.authenticated = true; + authStore.ready = true; + + const notification = { + id: 1, + text: message, + ...NotificationTypes.ERROR, + }; + + notificationStore.notifications = [notification]; + + const wrapper = mount(BCGovAlertBanner, { + props: { + id: 1, + text: message, + type: 'warning', + }, + global: { + plugins: [router], + }, + }); + + await flushPromises(); + + wrapper.vm.onClose(); + + expect(notificationStore.notifications.length).toBe(0); + }); +}); diff --git a/frontend/app/frontend/tests/unit/components/bcgov/BCGovFooter.spec.js b/frontend/app/frontend/tests/unit/components/bcgov/BCGovFooter.spec.js new file mode 100644 index 0000000..9046965 --- /dev/null +++ b/frontend/app/frontend/tests/unit/components/bcgov/BCGovFooter.spec.js @@ -0,0 +1,46 @@ +// @vitest-environment happy-dom +import { createTestingPinia } from '@pinia/testing'; +import { mount } from '@vue/test-utils'; +import { describe, expect, it } from 'vitest'; +import { h } from 'vue'; +import { VApp } from 'vuetify/components'; + +import getRouter from '~/router'; +import BCGovFooter from '~/components/bcgov/BCGovFooter.vue'; + +describe('BCGovFooter.vue', () => { + const router = getRouter(); + it('renders', () => { + const wrapper = mount(VApp, { + global: { + plugins: [createTestingPinia(), router], + }, + slots: { + default: h(BCGovFooter), + }, + }); + const footerHome = wrapper.find('[id="footer-home"]'); + expect(footerHome.exists()).toBeTruthy(); + expect(footerHome.text()).toEqual('trans.bCGovFooter.home'); + const footerAbout = wrapper.find('[id="footer-about"]'); + expect(footerAbout.exists()).toBeTruthy(); + expect(footerAbout.text()).toEqual('trans.bCGovFooter.about'); + const footerDisclaimer = wrapper.find('[id="footer-disclaimer"]'); + expect(footerDisclaimer.exists()).toBeTruthy(); + expect(footerDisclaimer.text()).toEqual('trans.bCGovFooter.disclaimer'); + const footerPrivacy = wrapper.find('[id="footer-privacy"]'); + expect(footerPrivacy.exists()).toBeTruthy(); + expect(footerPrivacy.text()).toEqual('trans.bCGovFooter.privacy'); + const footerAccessibility = wrapper.find('[id="footer-accessibility"]'); + expect(footerAccessibility.exists()).toBeTruthy(); + expect(footerAccessibility.text()).toEqual( + 'trans.bCGovFooter.accessibility' + ); + const footerCopyright = wrapper.find('[id="footer-copyright"]'); + expect(footerCopyright.exists()).toBeTruthy(); + expect(footerCopyright.text()).toEqual('trans.bCGovFooter.copyRight'); + const footerContact = wrapper.find('[id="footer-contact"]'); + expect(footerContact.exists()).toBeTruthy(); + expect(footerContact.text()).toEqual('trans.bCGovFooter.contactUs'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/components/bcgov/BCGovHeader.spec.js b/frontend/app/frontend/tests/unit/components/bcgov/BCGovHeader.spec.js new file mode 100644 index 0000000..8dd1de1 --- /dev/null +++ b/frontend/app/frontend/tests/unit/components/bcgov/BCGovHeader.spec.js @@ -0,0 +1,45 @@ +import { setActivePinia, createPinia } from 'pinia'; +import { flushPromises, mount } from '@vue/test-utils'; +import { describe, expect, it } from 'vitest'; +import { createRouter, createWebHistory } from 'vue-router'; + +import BCGovHeader from '~/components/bcgov/BCGovHeader.vue'; +import getRouter from '~/router'; +import { useAuthStore } from '~/store/auth'; + +describe('BCGovHeader.vue', () => { + const pinia = createPinia(); + setActivePinia(pinia); + const authStore = useAuthStore(); + const router = createRouter({ + history: createWebHistory(), + routes: getRouter().getRoutes(), + }); + + it('renders', () => { + // set keycloak ready to true, required for BaseAuthButton + // to be visible + authStore.ready = true; + const wrapper = mount(BCGovHeader, { + global: { + plugins: [router, pinia], + stubs: { + BaseAuthButton: true, + BaseInternationalization: true, + }, + }, + }); + + const btnHeaderTitle = wrapper.find('[data-test="btn-header-title"]'); + expect(btnHeaderTitle.exists()).toBeTruthy(); + expect(btnHeaderTitle.text()).toEqual( + router?.currentRoute?.value?.meta?.title + ? router.currentRoute.value.meta.title + : '' + ); + expect(wrapper.find('[data-test="base-auth-btn"]').exists()).toBeTruthy(); + expect( + wrapper.find('[data-test="base-internationalization"]').exists() + ).toBeTruthy(); + }); +}); diff --git a/frontend/app/frontend/tests/unit/components/bcgov/BCGovNavBar.spec.js b/frontend/app/frontend/tests/unit/components/bcgov/BCGovNavBar.spec.js new file mode 100644 index 0000000..751a050 --- /dev/null +++ b/frontend/app/frontend/tests/unit/components/bcgov/BCGovNavBar.spec.js @@ -0,0 +1,105 @@ +// @vitest-environment happy-dom +import { createPinia, setActivePinia } from 'pinia'; +import { mount } from '@vue/test-utils'; +import { describe, expect, it } from 'vitest'; +import { h } from 'vue'; +import { createRouter, createWebHistory } from 'vue-router'; + +import { VApp } from 'vuetify/components'; +import BCGovNavBar from '~/components/bcgov/BCGovNavBar.vue'; +import getRouter from '~/router'; +import { useAuthStore } from '~/store/auth'; + +describe('BCGovNavBar.vue', () => { + const pinia = createPinia(); + setActivePinia(pinia); + const router = createRouter({ + history: createWebHistory(), + routes: getRouter().getRoutes(), + }); + + it('renders as non-admin', async () => { + const authStore = useAuthStore(); + authStore.keycloak = { + tokenParsed: { + identity_provider: 'idir', + resource_access: { + chefs: { + roles: [], + }, + }, + }, + }; + authStore.authenticated = true; + authStore.ready = true; + + const wrapper = mount(VApp, { + global: { + plugins: [router, pinia], + }, + slots: { + default: h(BCGovNavBar), + }, + }); + const aboutLinks = wrapper.find('[data-cy="aboutLinks"]'); + expect(aboutLinks.exists()).toBeTruthy(); + expect(aboutLinks.text()).toEqual('trans.bCGovNavBar.about'); + const userFormsLinks = wrapper.find('[data-cy="userFormsLinks"]'); + expect(userFormsLinks.exists()).toBeTruthy(); + expect(userFormsLinks.text()).toEqual('trans.bCGovNavBar.myForms'); + const createNewForm = wrapper.find('[data-cy="createNewForm"]'); + expect(createNewForm.exists()).toBeTruthy(); + expect(createNewForm.text()).toEqual('trans.bCGovNavBar.createNewForm'); + const help = wrapper.find('[data-cy="help"]'); + expect(help.exists()).toBeTruthy(); + expect(help.text()).toEqual('trans.bCGovNavBar.help'); + const feedback = wrapper.find('[data-cy="feedback"]'); + expect(feedback.exists()).toBeTruthy(); + expect(feedback.text()).toEqual('trans.bCGovNavBar.feedback'); + const admin = wrapper.find('[data-cy="admin"]'); + expect(admin.exists()).toBeFalsy(); + }); + + it('renders as admin', () => { + const authStore = useAuthStore(); + authStore.keycloak = { + tokenParsed: { + identity_provider: 'idir', + resource_access: { + chefs: { + roles: ['admin'], + }, + }, + }, + }; + authStore.authenticated = true; + authStore.ready = true; + + const wrapper = mount(VApp, { + global: { + plugins: [router, pinia], + }, + slots: { + default: h(BCGovNavBar), + }, + }); + const aboutLinks = wrapper.find('[data-cy="aboutLinks"]'); + expect(aboutLinks.exists()).toBeTruthy(); + expect(aboutLinks.text()).toEqual('trans.bCGovNavBar.about'); + const userFormsLinks = wrapper.find('[data-cy="userFormsLinks"]'); + expect(userFormsLinks.exists()).toBeTruthy(); + expect(userFormsLinks.text()).toEqual('trans.bCGovNavBar.myForms'); + const createNewForm = wrapper.find('[data-cy="createNewForm"]'); + expect(createNewForm.exists()).toBeTruthy(); + expect(createNewForm.text()).toEqual('trans.bCGovNavBar.createNewForm'); + const help = wrapper.find('[data-cy="help"]'); + expect(help.exists()).toBeTruthy(); + expect(help.text()).toEqual('trans.bCGovNavBar.help'); + const feedback = wrapper.find('[data-cy="feedback"]'); + expect(feedback.exists()).toBeTruthy(); + expect(feedback.text()).toEqual('trans.bCGovNavBar.feedback'); + const admin = wrapper.find('[data-cy="admin"]'); + expect(admin.exists()).toBeTruthy(); + expect(admin.text()).toEqual('trans.bCGovNavBar.admin'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/components/designer/FloatButton.spec.js b/frontend/app/frontend/tests/unit/components/designer/FloatButton.spec.js new file mode 100644 index 0000000..a2d2223 --- /dev/null +++ b/frontend/app/frontend/tests/unit/components/designer/FloatButton.spec.js @@ -0,0 +1,203 @@ +import { mount, RouterLinkStub } from '@vue/test-utils'; +import { setActivePinia, createPinia } from 'pinia'; +import { expect, vi } from 'vitest'; + +import FloatButton from '~/components/designer/FloatButton.vue'; + +window.scrollTo = vi.fn(); + +describe('FloatButton.vue', () => { + const pinia = createPinia(); + setActivePinia(pinia); + + it('renders', () => { + const wrapper = mount(FloatButton, { + global: { + plugins: [pinia], + stubs: { + RouterLink: { + name: 'RouterLink', + template: '', + }, + }, + }, + }); + + expect(wrapper.html()).toContain('collapse'); + expect(wrapper.html()).toContain('publish'); + expect(wrapper.html()).toContain('manage'); + expect(wrapper.html()).toContain('redo'); + expect(wrapper.html()).toContain('undo'); + expect(wrapper.html()).toContain('preview'); + expect(wrapper.html()).toContain('bottom'); + }); + + it('test that undo event was triggered', async () => { + const wrapper = mount(FloatButton, { + global: { + plugins: [pinia], + stubs: { + RouterLink: { + name: 'RouterLink', + template: '', + }, + }, + }, + }); + + expect(wrapper.find({ ref: 'undoButton' }).exists()).toBeTruthy(); + + const buttonWrapper = wrapper.find({ ref: 'undoButton' }); + buttonWrapper.trigger('click'); + + wrapper.vm.$emit('undo'); + await wrapper.vm.$nextTick(); + + expect(wrapper.emitted().undo).toBeTruthy(); + expect(wrapper.emitted().undo.length).toBe(1); + }); + + it('test that redo event was triggered', async () => { + const wrapper = mount(FloatButton, { + global: { + plugins: [pinia], + stubs: { + RouterLink: { + name: 'RouterLink', + template: '', + }, + }, + }, + }); + + expect(wrapper.find({ ref: 'redoButton' }).exists()).toBeTruthy(); + + const buttonWrapper = wrapper.find({ ref: 'redoButton' }); + buttonWrapper.trigger('click'); + + wrapper.vm.$emit('redo'); + await wrapper.vm.$nextTick(); + + expect(wrapper.emitted().redo).toBeTruthy(); + expect(wrapper.emitted().redo.length).toBe(1); + }); + + it('test that save event was triggered', async () => { + const wrapper = mount(FloatButton, { + global: { + plugins: [pinia], + stubs: { + RouterLink: { + name: 'RouterLink', + template: '', + }, + }, + }, + }); + + expect(wrapper.find({ ref: 'saveButton' }).exists()).toBe(true); + + const buttonWrapper = wrapper.find({ ref: 'saveButton' }); + buttonWrapper.trigger('click'); + + wrapper.vm.$emit('save'); + await wrapper.vm.$nextTick(); + + expect(wrapper.emitted().save).toBeTruthy(); + expect(wrapper.emitted().save.length).toBe(1); + }); + + it('test that publish button was click', async () => { + const wrapper = mount(FloatButton, { + RouterLink: RouterLinkStub, + props: { + formId: '01fa4a32-ff4a-4304-8277-e69e0bb2d229', + draftId: '0014dfe4-321f-4bc1-9280-e7a1fdeb5dc6', + }, + global: { + plugins: [pinia], + stubs: { + RouterLink: { + name: 'RouterLink', + template: '', + }, + }, + }, + }); + + await wrapper.find('[data-cy="publishRouterLink"]').trigger('click'); + + await wrapper.vm.$nextTick(); + + // We don't need to test that the router-link worked + // that is tested by the vue-router team already + }); + + it('test that manage button was click', async () => { + const wrapper = mount(FloatButton, { + RouterLink: RouterLinkStub, + props: { + formId: '01fa4a32-ff4a-4304-8277-e69e0bb2d229', + draftId: '0014dfe4-321f-4bc1-9280-e7a1fdeb5dc6', + }, + global: { + plugins: [pinia], + stubs: { + RouterLink: { + name: 'RouterLink', + template: '', + }, + }, + }, + }); + + await wrapper.find('[data-cy="settingsRouterLink"]').trigger('click'); + + await wrapper.vm.$nextTick(); + + // We don't need to test that the router-link worked + // that is tested by the vue-router team already + }); + + it('test that preview button was click', async () => { + const mockRouter = { + resolve: vi.fn(), + }; + + window.open = vi.fn(); + + mockRouter.resolve.mockImplementationOnce(() => { + return { + href: '', + }; + }); + + const wrapper = mount(FloatButton, { + RouterLink: RouterLinkStub, + props: { + formId: '01fa4a32-ff4a-4304-8277-e69e0bb2d229', + draftId: '0014dfe4-321f-4bc1-9280-e7a1fdeb5dc6', + }, + global: { + plugins: [pinia], + stubs: { + RouterLink: { + name: 'RouterLink', + template: '', + }, + }, + mocks: { + $router: mockRouter, + }, + }, + }); + + await wrapper.find({ ref: 'previewRouterLink' }).trigger('click'); + + await wrapper.vm.$nextTick(); + + // We don't need to test that the router-link worked + // that is tested by the vue-router team already + expect(mockRouter.resolve).toHaveBeenCalledTimes(1); + }); +}); diff --git a/frontend/app/frontend/tests/unit/components/designer/FormDisclaimer.spec.js b/frontend/app/frontend/tests/unit/components/designer/FormDisclaimer.spec.js new file mode 100644 index 0000000..a3b93b0 --- /dev/null +++ b/frontend/app/frontend/tests/unit/components/designer/FormDisclaimer.spec.js @@ -0,0 +1,23 @@ +import { createTestingPinia } from '@pinia/testing'; +import { mount } from '@vue/test-utils'; +import { describe, expect, it } from 'vitest'; + +import FormDisclaimer from '~/components/designer/FormDisclaimer.vue'; + +describe('FormDisclaimer.vue', () => { + it('renders', () => { + const wrapper = mount(FormDisclaimer, { + global: { + plugins: [createTestingPinia()], + }, + }); + expect(wrapper.text()) + .toContain('trans.formDisclaimer.disclaimerAndStatement') + .toContain('trans.formDisclaimer.privacyLaw') + .toContain('trans.formDisclaimer.disclosure') + .toContain('trans.formDisclaimer.consent') + .toContain('trans.formDisclaimer.formIntention') + .toContain('trans.formDisclaimer.privacyOfficer') + .toContain('trans.formDisclaimer.assement'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/components/designer/MultiUpload.spec.js b/frontend/app/frontend/tests/unit/components/designer/MultiUpload.spec.js new file mode 100644 index 0000000..da73293 --- /dev/null +++ b/frontend/app/frontend/tests/unit/components/designer/MultiUpload.spec.js @@ -0,0 +1,370 @@ +import { mount } from '@vue/test-utils'; +import { setActivePinia, createPinia } from 'pinia'; +import { createRouter, createWebHistory } from 'vue-router'; +import { beforeEach, expect, vi } from 'vitest'; + +import getRouter from '~/router'; +import FormViewerMultiUpload from '~/components/designer/FormViewerMultiUpload.vue'; +import { useAppStore } from '~/store/app'; +import { useNotificationStore } from '~/store/notification'; + +const ERROR = { + UPLOAD_MULTIPLE_FILE_ERROR: + 'trans.formViewerMultiUpload.uploadMultipleFileErr', + DRAG_MULPLE_FILE_ERROR: 'trans.formViewerMultiUpload.dragMultipleFileErr', + FILE_FORMAT_ERROR: 'trans.formViewerMultiUpload.fileFormatErr', + FILE_SIZE_ERROR: 'trans.formViewerMultiUpload.fileSizeErr', + PARSE_JSON_ERROR: 'We can not parse json data from the file', + JSON_OBJECT_NOT_ARRAY: 'Wrong json file format', + JSON_ARRAY_EMPTY: 'This json file is empty.', + ERROR_WHILE_VALIDATE: 'There is something wrong with this file', + ERROR_WHILE_CHECKVALIDITY: 'There is something wrong with this file', + ERROR_AFTER_VALIDATE: 'Some errors found, see below for more information.', +}; + +describe('FormViewerMultiUpload.vue', () => { + const pinia = createPinia(); + const router = createRouter({ + history: createWebHistory(), + routes: getRouter().getRoutes(), + }); + + setActivePinia(pinia); + const appStore = useAppStore(); + const notificationStore = useNotificationStore(); + const addNotificationSpy = vi.spyOn(notificationStore, 'addNotification'); + const fileData = (sizeInByte) => { + // Generate fake file data + const bytesPerItem = Math.floor(sizeInByte / 100); // adjust as needed + const numItems = Math.floor(100 / bytesPerItem); // adjust as needed + const fileData = []; + for (let i = 0; i < numItems; i++) { + const item = {}; + for (let j = 0; j < bytesPerItem / 2; j++) { + item[String.fromCharCode(65 + Math.floor(Math.random() * 26))] = + Math.floor(Math.random() * 10); + } + fileData.push(item); + } + return fileData; + }; + + beforeEach(() => { + appStore.$reset(); + notificationStore.$reset(); + addNotificationSpy.mockReset(); + appStore.config = { + uploads: { + fileMaxSizeBytes: 10000, + }, + }; + }); + + it('renders', () => { + const wrapper = mount(FormViewerMultiUpload, { + props: { + formElement: undefined, + form: {}, + formSchema: {}, + formFields: [], + block: false, + response: { + message: '', + error: false, + upload_state: 0, + response: [], + file_name: '', + }, + jsonCsv: { + data: [], + file_name: '', + }, + }, + global: { + plugins: [router, pinia], + }, + }); + + expect(wrapper.text()).toContain('trans.formViewerMultiUpload.important'); + expect(wrapper.text()).toContain('trans.formViewerMultiUpload.json'); + }); + + describe('#addFile', () => { + it('should return undefined when some data is in process', () => { + const wrapper = mount(FormViewerMultiUpload, { + props: { + formElement: undefined, + form: {}, + formSchema: {}, + formFields: [], + block: true, + response: { + message: '', + error: false, + upload_state: 0, + response: [], + file_name: '', + }, + jsonCsv: { + data: [], + file_name: '', + }, + }, + global: { + plugins: [router, pinia], + }, + }); + const parseFileSpy = vi.spyOn(wrapper.vm, 'parseFile'); + // act + wrapper.vm.addFile(null, 0); + // assert + expect(addNotificationSpy).not.toHaveBeenCalled(); + expect(parseFileSpy).not.toHaveBeenCalled(); + }); + + it('should return undefined when no file select', () => { + const wrapper = mount(FormViewerMultiUpload, { + props: { + formElement: undefined, + form: {}, + formSchema: {}, + formFields: [], + block: false, + response: { + message: '', + error: false, + upload_state: 0, + response: [], + file_name: '', + }, + jsonCsv: { + data: [], + file_name: '', + }, + }, + global: { + plugins: [router, pinia], + }, + }); + // act + wrapper.vm.addFile(null, 1); + // assert + expect(addNotificationSpy).toHaveBeenCalled(); + }); + + it('should return undefined when no file drag', () => { + const wrapper = mount(FormViewerMultiUpload, { + props: { + formElement: undefined, + form: {}, + formSchema: {}, + formFields: [], + block: false, + response: { + message: '', + error: false, + upload_state: 0, + response: [], + file_name: '', + }, + jsonCsv: { + data: [], + file_name: '', + }, + }, + global: { + plugins: [router, pinia], + }, + }); + // act + wrapper.vm.addFile({ dataTransfer: { files: undefined } }, 0); + // assert + expect(addNotificationSpy).not.toHaveBeenCalled(); + }); + + it('should return undefined when a file already drag', () => { + const wrapper = mount(FormViewerMultiUpload, { + props: { + formElement: undefined, + form: {}, + formSchema: {}, + formFields: [], + block: false, + response: { + message: '', + error: false, + upload_state: 0, + response: [], + file_name: '', + }, + jsonCsv: { + data: [], + file_name: '', + }, + }, + global: { + plugins: [router, pinia], + }, + }); + const file = new File(['{}'], 'test.json', { + type: 'application/json', + }); + wrapper.setData({ file: file }); + + // act + wrapper.vm.addFile({}, 0); + // assert + expect(addNotificationSpy).toHaveBeenCalledWith({ + consoleError: ERROR.UPLOAD_MULTIPLE_FILE_ERROR, + text: ERROR.UPLOAD_MULTIPLE_FILE_ERROR, + }); + }); + + it('should show notification when submitter drag multiple files', () => { + const wrapper = mount(FormViewerMultiUpload, { + props: { + formElement: undefined, + form: {}, + formSchema: {}, + formFields: [], + block: false, + response: { + message: '', + error: false, + upload_state: 0, + response: [], + file_name: '', + }, + jsonCsv: { + data: [], + file_name: '', + }, + }, + global: { + plugins: [router, pinia], + }, + }); + const file = new File(['{}'], 'test.json', { + type: 'application/json', + }); + + // act + wrapper.vm.addFile({ dataTransfer: { files: [file, file] } }, 0); + // assert + expect(addNotificationSpy).toHaveBeenCalledWith({ + consoleError: ERROR.DRAG_MULPLE_FILE_ERROR, + text: ERROR.DRAG_MULPLE_FILE_ERROR, + }); + }); + + it('should show notification when file format is not JSON', () => { + const wrapper = mount(FormViewerMultiUpload, { + props: { + formElement: undefined, + form: {}, + formSchema: {}, + formFields: [], + block: false, + response: { + message: '', + error: false, + upload_state: 0, + response: [], + file_name: '', + }, + jsonCsv: { + data: [], + file_name: '', + }, + }, + global: { + plugins: [router, pinia], + }, + }); + const file = new File(['{}'], 'test.csv', { + type: 'text/json', + }); + + // act + wrapper.vm.addFile({ target: { files: [file] } }, 1); + // assert + expect(addNotificationSpy).toHaveBeenCalledWith({ + consoleError: ERROR.FILE_FORMAT_ERROR, + text: ERROR.FILE_FORMAT_ERROR, + }); + }); + + it('should show notification when file size is over', () => { + const wrapper = mount(FormViewerMultiUpload, { + props: { + formElement: undefined, + form: {}, + formSchema: {}, + formFields: [], + block: false, + response: { + message: '', + error: false, + upload_state: 0, + response: [], + file_name: '', + }, + jsonCsv: { + data: [], + file_name: '', + }, + }, + global: { + plugins: [router, pinia], + }, + }); + // act + appStore.config.uploads.fileMaxSizeBytes = 0; + const file = new File([JSON.stringify(fileData(1000))], 'test.json', { + type: 'application/json', + }); + wrapper.vm.addFile({ target: { files: [file] } }, 1); + // assert + expect(addNotificationSpy).toHaveBeenCalledWith({ + consoleError: ERROR.FILE_SIZE_ERROR, + text: ERROR.FILE_SIZE_ERROR, + }); + }); + + it('should show no notification when file is ok', () => { + const wrapper = mount(FormViewerMultiUpload, { + props: { + formElement: undefined, + form: {}, + formSchema: {}, + formFields: [], + block: false, + response: { + message: '', + error: false, + upload_state: 0, + response: [], + file_name: '', + }, + jsonCsv: { + data: [], + file_name: '', + }, + }, + global: { + plugins: [router, pinia], + }, + }); + // act + const parseFileSpy = vi.spyOn(wrapper.vm, 'parseFile'); + const file = new File(['{}'], 'test.json', { + type: 'application/json', + }); + wrapper.vm.addFile({ target: { files: [file] } }, 1); + // assert + expect(addNotificationSpy).not.toHaveBeenCalled(); + expect(parseFileSpy).toHaveBeenCalled(); + }); + }); + // it is not necessary to test if the FileReader functionality or JSON.parse functionality works. +}); diff --git a/frontend/app/frontend/tests/unit/components/forms/manage/ManageLayout.spec.js b/frontend/app/frontend/tests/unit/components/forms/manage/ManageLayout.spec.js new file mode 100644 index 0000000..027d8f0 --- /dev/null +++ b/frontend/app/frontend/tests/unit/components/forms/manage/ManageLayout.spec.js @@ -0,0 +1,90 @@ +import { flushPromises, mount } from '@vue/test-utils'; +import { createTestingPinia } from '@pinia/testing'; +import { setActivePinia } from 'pinia'; +import { createRouter, createWebHistory } from 'vue-router'; +import { beforeEach, expect, vi } from 'vitest'; + +import getRouter from '~/router'; +import ManageLayout from '~/components/forms/manage/ManageLayout.vue'; +import { useFormStore } from '~/store/form'; + +describe('ManageLayout.vue', () => { + const pinia = createTestingPinia(); + const router = createRouter({ + history: createWebHistory(), + routes: getRouter().getRoutes(), + }); + + setActivePinia(pinia); + const formStore = useFormStore(pinia); + + beforeEach(() => { + formStore.$reset(); + }); + + it('renders', () => { + const wrapper = mount(ManageLayout, { + props: { + f: 'f', + }, + global: { + plugins: [router, pinia], + stubs: { + ManageFormActions: true, + ManageForm: true, + }, + }, + }); + + expect(wrapper.text()).toMatch('trans.manageLayout.manageForm'); + }); + + it('calls the store actions', () => { + const formId = '123-456'; + const fetchFormSpy = vi.spyOn(formStore, 'fetchForm'); + const getFormPermissionsForUserSpy = vi.spyOn( + formStore, + 'getFormPermissionsForUser' + ); + mount(ManageLayout, { + props: { + f: formId, + }, + global: { + plugins: [router, pinia], + stubs: { + ManageFormActions: true, + ManageForm: true, + }, + }, + }); + + expect(fetchFormSpy).toHaveBeenCalledTimes(1); + expect(getFormPermissionsForUserSpy).toHaveBeenCalledTimes(1); + }); + + it('shows the form name', async () => { + formStore.fetchForm.mockImplementation(() => { + formStore.form.name = 'myForm'; + }); + formStore.getFormPermissionsForUser.mockImplementation(() => [ + 'design_read', + ]); + const wrapper = mount(ManageLayout, { + props: { + f: 'f', + }, + global: { + plugins: [router, pinia], + stubs: { + ManageFormActions: true, + ManageForm: true, + }, + }, + }); + + await flushPromises(); + + expect(wrapper.html()).toContain('myForm'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/components/forms/submission/ManageSubmissionUsers.spec.js b/frontend/app/frontend/tests/unit/components/forms/submission/ManageSubmissionUsers.spec.js new file mode 100644 index 0000000..5b8ba5c --- /dev/null +++ b/frontend/app/frontend/tests/unit/components/forms/submission/ManageSubmissionUsers.spec.js @@ -0,0 +1,61 @@ +import { mount } from '@vue/test-utils'; +import { createTestingPinia } from '@pinia/testing'; +import { setActivePinia } from 'pinia'; +import { createRouter, createWebHistory } from 'vue-router'; +import { beforeEach, expect, vi } from 'vitest'; + +import { rbacService } from '~/services'; +import getRouter from '~/router'; +import ManageSubmissionUsers from '~/components/forms/submission/ManageSubmissionUsers.vue'; +import { useFormStore } from '~/store/form'; + +describe('ManageSubmissionUsers.vue', () => { + const SUBMISSION_ID = '1111111111-1111-1111-111111111111'; + const getSubmissionUsersSpy = vi.spyOn(rbacService, 'getSubmissionUsers'); + const pinia = createTestingPinia(); + const router = createRouter({ + history: createWebHistory(), + routes: getRouter().getRoutes(), + }); + + setActivePinia(pinia); + const formStore = useFormStore(pinia); + + beforeEach(() => { + getSubmissionUsersSpy.mockReset(); + formStore.$reset(); + }); + + afterAll(() => { + getSubmissionUsersSpy.mockRestore(); + }); + + it('renders', () => { + formStore.form.name = 'myForm'; + getSubmissionUsersSpy.mockImplementation(() => ({ data: [] })); + const wrapper = mount(ManageSubmissionUsers, { + props: { + isDraft: false, + submissionId: SUBMISSION_ID, + }, + global: { + plugins: [router, pinia], + stubs: { + BaseDialog: true, + VDialog: { + name: 'VDialog', + template: '
', + }, + VTooltip: { + name: 'VTooltip', + template: '
', + }, + }, + }, + }); + + expect(wrapper.text()).toContain( + 'trans.manageSubmissionUsers.manageTeamMembers' + ); + }); +}); diff --git a/frontend/app/frontend/tests/unit/components/infolinks/GeneralLayout.spec.js b/frontend/app/frontend/tests/unit/components/infolinks/GeneralLayout.spec.js new file mode 100644 index 0000000..1b41127 --- /dev/null +++ b/frontend/app/frontend/tests/unit/components/infolinks/GeneralLayout.spec.js @@ -0,0 +1,99 @@ +// @vitest-environment happy-dom +// happy-dom is required to access window.location + +import { mount } from '@vue/test-utils'; +import { createTestingPinia } from '@pinia/testing'; +import { setActivePinia } from 'pinia'; +import { createRouter, createWebHistory } from 'vue-router'; +import { expect, vi } from 'vitest'; + +import getRouter from '~/router'; +import GeneralLayout from '~/components/infolinks/GeneralLayout.vue'; + +describe('GeneralLayout.vue', () => { + const pinia = createTestingPinia(); + const router = createRouter({ + history: createWebHistory(), + routes: getRouter().getRoutes(), + }); + + setActivePinia(pinia); + + it('onOpenDialog()', async () => { + const getComponentSpy = vi.spyOn(GeneralLayout.methods, 'getComponent'); + const onDialogSpy = vi.spyOn(GeneralLayout.methods, 'onDialog'); + const wrapper = mount(GeneralLayout, { + props: { + componentsList: [ + { componentName: 'content', status: true }, + { componentName: 'textfiled', status: false }, + ], + layoutList: [ + { componentName: 'content' }, + { componentName: 'textfiled' }, + ], + groupName: '', + }, + global: { + plugins: [router, pinia], + stubs: { + ProactiveHelpDialog: true, + ProactiveHelpPreviewDialog: true, + }, + }, + }); + //wrapper.vm.onOpenDialog('Text Field'); + //expect(getComponentSpy).toHaveBeenCalledTimes(1); + //expect(onDialogSpy).toHaveBeenCalledTimes(1); + }); + + it('onPreviewDialog()', async () => { + const wrapper = mount(GeneralLayout, { + props: { + componentsList: [ + { componentName: 'content', status: true }, + { componentName: 'textfiled', status: false }, + ], + layoutList: [ + { componentName: 'content' }, + { componentName: 'textfiled' }, + ], + groupName: '', + }, + global: { + plugins: [router, pinia], + stubs: { + ProactiveHelpDialog: true, + ProactiveHelpPreviewDialog: true, + }, + }, + }); + //wrapper.vm.onPreviewDialog(); + //expect(wrapper.vm.showPreviewDialog).toBe(true); + }); + + it('onDialog()', async () => { + const wrapper = mount(GeneralLayout, { + props: { + componentsList: [ + { componentName: 'content', status: true }, + { componentName: 'textfiled', status: false }, + ], + layoutList: [ + { componentName: 'content' }, + { componentName: 'textfiled' }, + ], + groupName: '', + }, + global: { + plugins: [router, pinia], + stubs: { + ProactiveHelpDialog: true, + ProactiveHelpPreviewDialog: true, + }, + }, + }); + //wrapper.vm.onDialog(); + //expect(wrapper.vm.showDialog).toBe(true); + }); +}); diff --git a/frontend/app/frontend/tests/unit/components/infolinks/ProactiveHelpDialog.spec.js b/frontend/app/frontend/tests/unit/components/infolinks/ProactiveHelpDialog.spec.js new file mode 100644 index 0000000..d64797a --- /dev/null +++ b/frontend/app/frontend/tests/unit/components/infolinks/ProactiveHelpDialog.spec.js @@ -0,0 +1,44 @@ +// @vitest-environment happy-dom +// happy-dom is required to access window.location + +import { mount } from '@vue/test-utils'; +import { createTestingPinia } from '@pinia/testing'; +import { setActivePinia } from 'pinia'; +import { createRouter, createWebHistory } from 'vue-router'; +import { expect, vi } from 'vitest'; +import { nextTick } from 'vue'; + +import getRouter from '~/router'; +import ProactiveHelpDialog from '~/components/infolinks/ProactiveHelpDialog.vue'; + +describe('ProactiveHelpDialog.vue', () => { + const pinia = createTestingPinia(); + const router = createRouter({ + history: createWebHistory(), + routes: getRouter().getRoutes(), + }); + + setActivePinia(pinia); + + it('resetDialog', async () => { + const wrapper = mount(ProactiveHelpDialog, { + props: { + component: { + componentName: 'content', + description: 'dump text', + imageUrl: 'https://dumpurl.com', + moreHelpInfoLink: 'https://dumpurl.com', + }, + groupName: 'test', + showDialog: true, + }, + global: { + plugins: [router, pinia], + }, + }); + + wrapper.vm.resetDialog(); + await nextTick(); + expect(wrapper.vm.description).toBe(''); + }); +}); diff --git a/frontend/app/frontend/tests/unit/components/infolinks/ProactiveHelpPreviewDialog.spec.js b/frontend/app/frontend/tests/unit/components/infolinks/ProactiveHelpPreviewDialog.spec.js new file mode 100644 index 0000000..1eb4add --- /dev/null +++ b/frontend/app/frontend/tests/unit/components/infolinks/ProactiveHelpPreviewDialog.spec.js @@ -0,0 +1,58 @@ +import { mount } from '@vue/test-utils'; +import { createTestingPinia } from '@pinia/testing'; +import { setActivePinia } from 'pinia'; +import { createRouter, createWebHistory } from 'vue-router'; +import { beforeEach, expect, vi } from 'vitest'; + +import { rbacService } from '~/services'; +import getRouter from '~/router'; +import ProactiveHelpPreviewDialog from '~/components/infolinks/ProactiveHelpPreviewDialog.vue'; +import { useFormStore } from '~/store/form'; + +describe('ProactiveHelpPreviewDialog.vue', () => { + const getSubmissionUsersSpy = vi.spyOn(rbacService, 'getSubmissionUsers'); + const pinia = createTestingPinia(); + const router = createRouter({ + history: createWebHistory(), + routes: getRouter().getRoutes(), + }); + + setActivePinia(pinia); + const formStore = useFormStore(pinia); + + beforeEach(() => { + getSubmissionUsersSpy.mockReset(); + formStore.$reset(); + }); + + afterAll(() => { + getSubmissionUsersSpy.mockRestore(); + }); + + it('renders', () => { + formStore.form.name = 'myForm'; + getSubmissionUsersSpy.mockImplementation(() => ({ data: [] })); + const wrapper = mount(ProactiveHelpPreviewDialog, { + props: { + component: { + componentName: 'content', + description: 'dump description', + imageUrl: 'https://dumpurl.com', + moreHelpInfoLink: 'https://dumpurl.com', + }, + showDialog: true, + }, + global: { + plugins: [router, pinia], + stubs: { + VDialog: { + name: 'VDialog', + template: '
', + }, + }, + }, + }); + + expect(wrapper.text()).toContain('content').toContain('dump description'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/filters/index.spec.js b/frontend/app/frontend/tests/unit/filters/index.spec.js new file mode 100644 index 0000000..4aa3ebe --- /dev/null +++ b/frontend/app/frontend/tests/unit/filters/index.spec.js @@ -0,0 +1,71 @@ +import moment from 'moment'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; + +import * as filters from '~/filters'; + +describe('formatDate', () => { + const now = new Date(); + + beforeEach(() => { + vi.spyOn(console, 'warn').mockImplementation(() => {}); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + it('returns a properly formatted date string when value is a date', () => { + const result = filters.formatDate(now); + + expect(result).toBeTruthy(); + expect(result).toMatch(moment(String(now)).format('MMMM D YYYY')); + }); +}); + +describe('formatDateLong', () => { + const now = new Date(); + + beforeEach(() => { + vi.spyOn(console, 'warn').mockImplementation(() => {}); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + it('returns undefined when value is falsy', () => { + const result = filters.formatDateLong(undefined); + expect(result).toBeFalsy(); + }); + + it('returns a properly formatted date string when value is a date', () => { + const result = filters.formatDateLong(now); + + expect(result).toBeTruthy(); + expect(result).toMatch(moment(String(now)).format('YYYY-MM-DD hh:mm:ss a')); + }); + + it('returns a properly formatted date string in the am', () => { + const date = new Date(2023, 3, 5, 6, 7, 8); // months are origin 0 + const result = filters.formatDateLong(date); + + expect(result).toBeTruthy(); + expect(result).toMatch('2023-04-05 06:07:08 a'); + }); + + it('returns a properly formatted date string in the pm', () => { + const date = new Date(2023, 3, 5, 18, 7, 8); // months are origin 0 + const result = filters.formatDateLong(date); + + expect(result).toBeTruthy(); + expect(result).toMatch('2023-04-05 06:07:08 p'); + }); + + it('returns a properly formatted date with no leading zeroes', () => { + const date = new Date(2023, 9, 10, 10, 10, 10); // months are origin 0 + const result = filters.formatDateLong(date); + + expect(result).toBeTruthy(); + expect(result).toMatch('2023-10-10 10:10:10 a'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/i18n.config.js b/frontend/app/frontend/tests/unit/i18n.config.js new file mode 100644 index 0000000..04b00f5 --- /dev/null +++ b/frontend/app/frontend/tests/unit/i18n.config.js @@ -0,0 +1,46 @@ +import { config } from '@vue/test-utils'; +import { vi } from 'vitest'; + +const i18n = vi.fn(() => {}); +const translate = vi.fn(() => {}); + +translate.mockImplementation((key, options = {}) => { + return { + key, + options, + }; +}); + +i18n.mockImplementation(() => { + return { + locale: 'en', + t: translate, + }; +}); + +vi.mock('vue-i18n', () => { + return { + createI18n: (_options) => { + return { + global: { + t: (key, _options = {}) => key, + }, + }; + }, + useI18n: () => ({ + t: (key, _options = {}) => key, + }), + }; +}); + +config.global.mocks = { + $i18n: () => ({ + locale: 'en', + }), + $t: (tKey) => tKey, +}; + +beforeEach(() => { + translate.mockReset(); + i18n.mockReset(); +}); diff --git a/frontend/app/frontend/tests/unit/router.spec.js b/frontend/app/frontend/tests/unit/router.spec.js new file mode 100644 index 0000000..ccfd0e0 --- /dev/null +++ b/frontend/app/frontend/tests/unit/router.spec.js @@ -0,0 +1,87 @@ +import { describe, expect, it } from 'vitest'; +import getRouter from '~/router'; + +describe('router', () => { + it('has base routes', () => { + const router = getRouter(); + + expect(router.hasRoute('Home')).toBeTruthy(); + expect(router.hasRoute('About')).toBeTruthy(); + expect(router.hasRoute('Alert')).toBeTruthy(); + expect(router.hasRoute('Error')).toBeTruthy(); + expect(router.hasRoute('Login')).toBeTruthy(); + expect(router.hasRoute('NotFound')).toBeTruthy(); + + expect(router.getRoutes().length).toBe(33); + }); + + describe('Admin Routes', () => { + it('has child routes', () => { + const router = getRouter(); + + const route = router.options.routes.filter( + ({ path }) => path === '/admin' + )[0]; + const routes = route.children; + + const ROUTES = ['Admin', 'AdministerForm', 'AdministerUser']; + + expect(routes.filter(({ name }) => ROUTES.includes(name)).length).toBe( + ROUTES.length + ); + }); + }); + + describe('Form Routes', () => { + it('has child routes', () => { + const router = getRouter(); + + const route = router.options.routes.filter( + ({ path }) => path === '/form' + )[0]; + const routes = route.children; + + const ROUTES = [ + 'FormCreate', + 'FormDesigner', + 'SubmissionsExport', + 'FormManage', + 'FormPreview', + 'FormSubmissions', + 'FormSubmit', + 'FormSuccess', + 'FormTeams', + 'FormView', + ]; + + expect(routes.filter(({ name }) => ROUTES.includes(name)).length).toBe( + ROUTES.length + ); + }); + }); + + describe('User Routes', () => { + it('has child routes', () => { + const router = getRouter(); + + const route = router.options.routes.filter( + ({ path }) => path === '/user' + )[0]; + const routes = route.children; + + const ROUTES = [ + 'User', + 'UserFormDraftEdit', + 'UserFormDuplicate', + 'UserForms', + 'UserHistory', + 'UserSubmissions', + 'UserFormView', + ]; + + expect(routes.filter(({ name }) => ROUTES.includes(name)).length).toBe( + ROUTES.length + ); + }); + }); +}); diff --git a/frontend/app/frontend/tests/unit/services/adminService.spec.js b/frontend/app/frontend/tests/unit/services/adminService.spec.js new file mode 100644 index 0000000..43f3e22 --- /dev/null +++ b/frontend/app/frontend/tests/unit/services/adminService.spec.js @@ -0,0 +1,135 @@ +import axios from 'axios'; +import MockAdapter from 'axios-mock-adapter'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +import adminService from '~/services/adminService'; +import { ApiRoutes } from '~/utils/constants'; + +const mockInstance = axios.create(); +const mockAxios = new MockAdapter(mockInstance); + +const zeroUuid = '00000000-0000-0000-0000-000000000000'; + +vi.mock('~/services/interceptors', () => { + return { + appAxios: () => mockInstance, + }; +}); + +describe('Admin Service', () => { + beforeEach(() => { + mockAxios.reset(); + }); + + // + // Forms + // + describe('admin/forms/{formId}/addUser', () => { + const endpoint = `${ApiRoutes.ADMIN}${ApiRoutes.FORMS}/${zeroUuid}/addUser`; + + it('calls update on endpoint', async () => { + mockAxios.onPut(endpoint).reply(200); + + const result = await adminService.addFormUser('usrid', zeroUuid, [ + 'OWNER', + ]); + expect(result).toBeTruthy(); + expect(mockAxios.history.put).toHaveLength(1); + }); + }); + + describe('admin/forms/{formId}/apiKey', () => { + const endpoint = `${ApiRoutes.ADMIN}${ApiRoutes.FORMS}/${zeroUuid}${ApiRoutes.APIKEY}`; + + it('calls get on endpoint', async () => { + mockAxios.onGet(endpoint).reply(200); + + const result = await adminService.readApiDetails(zeroUuid); + expect(result).toBeTruthy(); + expect(mockAxios.history.get).toHaveLength(1); + }); + + it('calls delete on endpoint', async () => { + mockAxios.onDelete(endpoint).reply(200); + + const result = await adminService.deleteApiKey(zeroUuid); + expect(result).toBeTruthy(); + expect(mockAxios.history.delete).toHaveLength(1); + }); + }); + + describe('admin/forms', () => { + const endpoint = `${ApiRoutes.ADMIN}${ApiRoutes.FORMS}`; + + it('calls get endpoint', async () => { + mockAxios.onGet(endpoint).reply(200); + + const result = await adminService.listForms(); + expect(result).toBeTruthy(); + expect(mockAxios.history.get).toHaveLength(1); + }); + }); + + describe('admin/forms/{formId}', () => { + const endpoint = `${ApiRoutes.ADMIN}${ApiRoutes.FORMS}/${zeroUuid}`; + + it('calls get on endpoint', async () => { + mockAxios.onGet(endpoint).reply(200); + + const result = await adminService.readForm(zeroUuid); + expect(result).toBeTruthy(); + expect(mockAxios.history.get).toHaveLength(1); + }); + }); + + describe('admin/forms/{formId}/restore', () => { + const endpoint = `${ApiRoutes.ADMIN}${ApiRoutes.FORMS}/${zeroUuid}/restore`; + + it('calls update on endpoint', async () => { + mockAxios.onPut(endpoint).reply(200); + + const result = await adminService.restoreForm(zeroUuid); + expect(result).toBeTruthy(); + expect(mockAxios.history.put).toHaveLength(1); + }); + }); + + describe('admin/forms/{formId}/formUsers', () => { + const endpoint = `${ApiRoutes.ADMIN}${ApiRoutes.FORMS}/${zeroUuid}/formUsers`; + + it('calls get on endpoint', async () => { + mockAxios.onGet(endpoint).reply(200); + + const result = await adminService.readRoles(zeroUuid); + expect(result).toBeTruthy(); + expect(mockAxios.history.get).toHaveLength(1); + }); + }); + + // + // User + // + describe('admin/users', () => { + const endpoint = `${ApiRoutes.ADMIN}${ApiRoutes.USERS}`; + + it('calls get endpoint', async () => { + mockAxios.onGet(endpoint).reply(200); + + const result = await adminService.listUsers(); + expect(result).toBeTruthy(); + expect(mockAxios.history.get).toHaveLength(1); + }); + }); + + describe('admin/users/{userId}', () => { + const endpoint = `${ApiRoutes.ADMIN}${ApiRoutes.USERS}/${zeroUuid}`; + + it('calls get endpoint', async () => { + mockAxios.onGet(endpoint).reply(200); + + const result = await adminService.readUser(zeroUuid); + expect(result).toBeTruthy(); + expect(mockAxios.history.get).toHaveLength(1); + }); + }); +}); diff --git a/frontend/app/frontend/tests/unit/services/apiKeyService.spec.js b/frontend/app/frontend/tests/unit/services/apiKeyService.spec.js new file mode 100644 index 0000000..147e64b --- /dev/null +++ b/frontend/app/frontend/tests/unit/services/apiKeyService.spec.js @@ -0,0 +1,49 @@ +import axios from 'axios'; +import MockAdapter from 'axios-mock-adapter'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +import apiKeyService from '~/services/apiKeyService'; +import { ApiRoutes } from '~/utils/constants'; + +const mockInstance = axios.create(); +const mockAxios = new MockAdapter(mockInstance); + +const zeroUuid = '00000000-0000-0000-0000-000000000000'; + +vi.mock('~/services/interceptors', () => { + return { + appAxios: () => mockInstance, + }; +}); + +beforeEach(() => { + mockAxios.reset(); +}); + +describe('API Key Service', () => { + const endpoint = `${ApiRoutes.FORMS}/${zeroUuid}${ApiRoutes.APIKEY}`; + + it('calls get on GET apiKey endpoint', async () => { + mockAxios.onGet(endpoint).reply(200); + + const result = await apiKeyService.readApiKey(zeroUuid); + expect(result).toBeTruthy(); + expect(mockAxios.history.get).toHaveLength(1); + }); + + it('calls get on PUT apiKey endpoint', async () => { + mockAxios.onPut(endpoint).reply(200); + + const result = await apiKeyService.generateApiKey(zeroUuid); + expect(result).toBeTruthy(); + expect(mockAxios.history.put).toHaveLength(1); + }); + + it('calls get on PUT apiKey endpoint', async () => { + mockAxios.onDelete(endpoint).reply(204); + + const result = await apiKeyService.deleteApiKey(zeroUuid); + expect(result).toBeTruthy(); + expect(mockAxios.history.delete).toHaveLength(1); + }); +}); diff --git a/frontend/app/frontend/tests/unit/services/formService.spec.js b/frontend/app/frontend/tests/unit/services/formService.spec.js new file mode 100644 index 0000000..c6e9227 --- /dev/null +++ b/frontend/app/frontend/tests/unit/services/formService.spec.js @@ -0,0 +1,521 @@ +import axios from 'axios'; +import MockAdapter from 'axios-mock-adapter'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +import { formService } from '~/services'; +import { ApiRoutes } from '~/utils/constants'; + +const mockInstance = axios.create(); +const mockAxios = new MockAdapter(mockInstance); + +const zeroUuid = '00000000-0000-0000-0000-000000000000'; +const oneUuid = '11111111-1111-1111-1111-111111111111'; + +vi.mock('~/services/interceptors', () => { + return { + appAxios: () => mockInstance, + }; +}); + +describe('Form Service', () => { + beforeEach(() => { + mockAxios.reset(); + }); + + // + // Forms + // + describe('Forms', () => { + const endpoint = `${ApiRoutes.FORMS}`; + + it('calls create on endpoint', async () => { + const data = { test: 'testdata' }; + mockAxios.onPost(endpoint).reply(200, data); + + const result = await formService.createForm(zeroUuid, data); + expect(result).toBeTruthy(); + expect(result.data).toEqual(data); + expect(mockAxios.history.post).toHaveLength(1); + }); + }); + + describe('Forms/{formId}', () => { + const endpoint = `${ApiRoutes.FORMS}/${zeroUuid}`; + + it('calls forms endpoint', async () => { + mockAxios.onGet(endpoint).reply(200); + + const result = await formService.readForm(zeroUuid); + expect(result).toBeTruthy(); + expect(mockAxios.history.get).toHaveLength(1); + }); + + it('calls update on endpoint', async () => { + const data = { test: 'testdata' }; + mockAxios.onPut(endpoint).reply(200, data); + + const result = await formService.updateForm(zeroUuid, data); + expect(result).toBeTruthy(); + expect(result.data).toEqual(data); + expect(mockAxios.history.put).toHaveLength(1); + }); + + it('calls delete on endpoint', async () => { + mockAxios.onDelete(endpoint).reply(200); + + const result = await formService.deleteForm(zeroUuid); + expect(result).toBeTruthy(); + expect(mockAxios.history.delete).toHaveLength(1); + }); + }); + + describe('Forms/{formId}/options', () => { + const endpoint = `${ApiRoutes.FORMS}/${zeroUuid}/options`; + + it('calls read endpoint', async () => { + mockAxios.onGet(endpoint).reply(200); + + const result = await formService.readFormOptions(zeroUuid); + expect(result).toBeTruthy(); + expect(mockAxios.history.get).toHaveLength(1); + }); + }); + + describe('Forms/{formId}/statusCodes', () => { + const endpoint = `${ApiRoutes.FORMS}/${zeroUuid}/statusCodes`; + + it('calls read endpoint', async () => { + mockAxios.onGet(endpoint).reply(200); + + const result = await formService.getStatusCodes(zeroUuid); + expect(result).toBeTruthy(); + expect(mockAxios.history.get).toHaveLength(1); + }); + }); + + describe('Forms/{formId}/version', () => { + const endpoint = `${ApiRoutes.FORMS}/${zeroUuid}/version`; + + it('calls read published endpoint', async () => { + mockAxios.onGet(endpoint).reply(200); + + const result = await formService.readPublished(zeroUuid); + expect(result).toBeTruthy(); + expect(mockAxios.history.get).toHaveLength(1); + }); + }); + + // + // Form Drafts + // + describe('Forms/{formId}/drafts/{formVersionDraftId}', () => { + const endpoint = `${ApiRoutes.FORMS}/${zeroUuid}/drafts/${oneUuid}`; + + it('calls read endpoint', async () => { + mockAxios.onGet(endpoint).reply(200); + + const result = await formService.readDraft(zeroUuid, oneUuid); + expect(result).toBeTruthy(); + expect(mockAxios.history.get).toHaveLength(1); + }); + + it('calls update on endpoint', async () => { + const data = { test: 'testdata' }; + mockAxios.onPut(endpoint).reply(200, data); + + const result = await formService.updateDraft(zeroUuid, oneUuid, data); + expect(result).toBeTruthy(); + expect(result.data).toEqual(data); + expect(mockAxios.history.put).toHaveLength(1); + }); + + it('calls delete on endpoint', async () => { + mockAxios.onDelete(endpoint).reply(200); + + const result = await formService.deleteDraft(zeroUuid, oneUuid); + expect(result).toBeTruthy(); + expect(mockAxios.history.delete).toHaveLength(1); + }); + }); + + describe('Forms/{formId}/drafts', () => { + const endpoint = `${ApiRoutes.FORMS}/${zeroUuid}/drafts`; + + it('calls list endpoint', async () => { + mockAxios.onGet(endpoint).reply(200); + + const result = await formService.listDrafts(zeroUuid); + expect(result).toBeTruthy(); + expect(mockAxios.history.get).toHaveLength(1); + }); + + it('calls create on endpoint', async () => { + const data = { test: 'testdata' }; + mockAxios.onPost(endpoint).reply(200, data); + + const result = await formService.createDraft(zeroUuid, data); + expect(result).toBeTruthy(); + expect(result.data).toEqual(data); + expect(mockAxios.history.post).toHaveLength(1); + }); + }); + + describe('Forms/{formId}/versions/{versionId}/publish', () => { + const endpoint = `${ApiRoutes.FORMS}/${zeroUuid}/versions/${oneUuid}/publish`; + + it('calls publish endpoint', async () => { + mockAxios.onPost(endpoint).reply(200); + + const result = await formService.publishVersion(zeroUuid, oneUuid, true); + expect(result).toBeTruthy(); + expect(mockAxios.history.post).toHaveLength(1); + }); + }); + + describe('Forms/{formId}/drafts/publish', () => { + const endpoint = `${ApiRoutes.FORMS}/${zeroUuid}/drafts/${oneUuid}/publish`; + + it('calls publish endpoint', async () => { + mockAxios.onPost(endpoint).reply(200); + + const result = await formService.publishDraft(zeroUuid, oneUuid); + expect(result).toBeTruthy(); + expect(mockAxios.history.post).toHaveLength(1); + }); + }); + + // + // Email Templates + // + describe('Forms/{formId}/emailTemplates', () => { + const endpoint = `${ApiRoutes.FORMS}/${zeroUuid}/emailTemplates`; + + it('calls list endpoint', async () => { + mockAxios.onGet(endpoint).reply(200); + + const result = await formService.listEmailTemplates(zeroUuid); + expect(result).toBeTruthy(); + expect(mockAxios.history.get).toHaveLength(1); + }); + }); + + describe('Forms/{formId}/emailTemplate', () => { + const endpoint = `${ApiRoutes.FORMS}/${zeroUuid}/emailTemplate`; + + it('calls update on endpoint', async () => { + const data = { formId: zeroUuid, test: 'testdata' }; + mockAxios.onPut(endpoint).reply(200, data); + + const result = await formService.updateEmailTemplate(data); + expect(result).toBeTruthy(); + expect(result.data).toEqual(data); + expect(mockAxios.history.put).toHaveLength(1); + }); + }); + + // + // Form Versions + // + describe('Forms/{formId}/versions/{formVersionId}', () => { + const endpoint = `${ApiRoutes.FORMS}/${zeroUuid}/versions/${oneUuid}`; + + it('calls read endpoint', async () => { + mockAxios.onGet(endpoint).reply(200); + + const result = await formService.readVersion(zeroUuid, oneUuid); + expect(result).toBeTruthy(); + expect(mockAxios.history.get).toHaveLength(1); + }); + + it('calls update on endpoint', async () => { + const data = { test: 'testdata' }; + mockAxios.onPut(endpoint).reply(200, data); + + const result = await formService.updateVersion(zeroUuid, oneUuid, data); + expect(result).toBeTruthy(); + expect(result.data).toEqual(data); + expect(mockAxios.history.put).toHaveLength(1); + }); + }); + + describe('Forms/{formId}/version', () => { + const endpoint = `${ApiRoutes.FORMS}/${zeroUuid}/version`; + + it('calls read published endpoint', async () => { + mockAxios.onGet(endpoint).reply(200); + + const result = await formService.readPublished(zeroUuid); + expect(result).toBeTruthy(); + expect(mockAxios.history.get).toHaveLength(1); + }); + }); + + // + // Submissions + // + describe('forms/{formId}/versions/{formVersionId}/submissions', () => { + const endpoint = `${ApiRoutes.FORMS}/${zeroUuid}/versions/${oneUuid}/submissions`; + + it('calls create on endpoint', async () => { + const data = { test: 'testdata' }; + mockAxios.onPost(endpoint).reply(200, data); + + const result = await formService.createSubmission( + zeroUuid, + oneUuid, + data + ); + expect(result).toBeTruthy(); + expect(result.data).toEqual(data); + expect(mockAxios.history.post).toHaveLength(1); + }); + }); + + describe('submissions/{submissionId}', () => { + const endpoint = `submissions/${zeroUuid}`; + + it('calls get on endpoint', async () => { + mockAxios.onGet(endpoint).reply(200); + + const result = await formService.getSubmission(zeroUuid); + expect(result).toBeTruthy(); + expect(mockAxios.history.get).toHaveLength(1); + }); + }); + + describe('submissions/{submissionId}/options', () => { + const endpoint = `submissions/${zeroUuid}/options`; + + it('calls get on endpoint', async () => { + mockAxios.onGet(endpoint).reply(200); + + const result = await formService.getSubmissionOptions(zeroUuid); + expect(result).toBeTruthy(); + expect(mockAxios.history.get).toHaveLength(1); + }); + }); + + describe('delete submissions/{submissionId}', () => { + const endpoint = `submissions/${zeroUuid}`; + + it('calls get on endpoint', async () => { + mockAxios.onDelete(endpoint).reply(200); + + const result = await formService.deleteSubmission(zeroUuid); + expect(result).toBeTruthy(); + expect(mockAxios.history.delete).toHaveLength(1); + }); + }); + + describe('put submissions/{submissionId}', () => { + const endpoint = `submissions/${zeroUuid}`; + + it('calls update on endpoint', async () => { + const data = { test: 'testdata' }; + mockAxios.onPut(endpoint).reply(200, data); + + const result = await formService.updateSubmission(zeroUuid, data); + expect(result).toBeTruthy(); + expect(result.data).toEqual(data); + expect(mockAxios.history.put).toHaveLength(1); + }); + }); + + describe('forms/{formId}/submissions', () => { + const endpoint = `${ApiRoutes.FORMS}/${zeroUuid}/submissions`; + + it('calls get on endpoint', async () => { + mockAxios.onGet(endpoint).reply(200); + + const result = await formService.listSubmissions(zeroUuid); + expect(result).toBeTruthy(); + expect(mockAxios.history.get).toHaveLength(1); + }); + }); + + describe('submissions/{submissionId}/edits', () => { + const endpoint = `submissions/${zeroUuid}/edits`; + + it('calls get on endpoint', async () => { + mockAxios.onGet(endpoint).reply(200); + + const result = await formService.listSubmissionEdits(zeroUuid); + expect(result).toBeTruthy(); + expect(mockAxios.history.get).toHaveLength(1); + }); + }); + + describe('forms/{formId}/export/fields', () => { + const endpoint = `${ApiRoutes.FORMS}/${zeroUuid}/export/fields`; + + it('calls get on endpoint', async () => { + mockAxios.onPost(endpoint).reply(200); + + const result = await formService.exportSubmissions(zeroUuid, 'csv'); + expect(result).toBeTruthy(); + expect(mockAxios.history.post).toHaveLength(1); + }); + }); + + // + // Email + // + describe('submission/{submissionId}/email', () => { + const endpoint = `${ApiRoutes.SUBMISSION}/${zeroUuid}/email`; + + it('calls email endpoint', async () => { + const data = { test: 'testdata' }; + mockAxios.onPost(endpoint).reply(200, data); + + const result = await formService.requestReceiptEmail(zeroUuid, data); + expect(result).toBeTruthy(); + expect(result.data).toEqual(data); + expect(mockAxios.history.post).toHaveLength(1); + }); + }); + + // + // Notes and Status + // + describe('submission/{submissionId}/email', () => { + const endpoint = `${ApiRoutes.SUBMISSION}/${zeroUuid}/notes`; + + it('calls get endpoint', async () => { + mockAxios.onGet(endpoint).reply(200); + + const result = await formService.getSubmissionNotes(zeroUuid); + expect(result).toBeTruthy(); + expect(mockAxios.history.get).toHaveLength(1); + }); + + it('calls post endpoint', async () => { + const data = { test: 'testdata' }; + mockAxios.onPost(endpoint).reply(200, data); + + const result = await formService.addNote(zeroUuid, data); + expect(result).toBeTruthy(); + expect(result.data).toEqual(data); + expect(mockAxios.history.post).toHaveLength(1); + }); + }); + + describe('submission/{submissionId}/template/render', () => { + const endpoint = `${ApiRoutes.SUBMISSION}/${zeroUuid}/template/render`; + + it('calls post endpoint', async () => { + mockAxios.onPost(endpoint).reply(200); + const parsedContext = { + firstName: 'Jane', + lastName: 'Smith', + }; + const content = 'SGVsbG8ge2Quc2ltcGxldGV4dGZpZWxkfSEK'; + const contentFileType = 'txt'; + const outputFileName = 'template_hello_world'; + const outputFileType = 'pdf'; + + const mockBody = { + data: parsedContext, + options: { + reportName: outputFileName, + convertTo: outputFileType, + overwrite: true, + }, + template: { + content: content, + encodingType: 'base64', + fileType: contentFileType, + }, + }; + + const result = await formService.docGen(zeroUuid, mockBody); + expect(result).toBeTruthy(); + expect(mockAxios.history.post).toHaveLength(1); + }); + }); + + describe('submission/{submissionId}/status', () => { + const endpoint = `${ApiRoutes.SUBMISSION}/${zeroUuid}/status`; + + it('calls get endpoint', async () => { + mockAxios.onGet(endpoint).reply(200); + + const result = await formService.getSubmissionStatuses(zeroUuid); + expect(result).toBeTruthy(); + expect(mockAxios.history.get).toHaveLength(1); + }); + + it('calls post endpoint', async () => { + const data = { test: 'testdata' }; + mockAxios.onPost(endpoint).reply(200, data); + + const result = await formService.updateSubmissionStatus(zeroUuid, data); + expect(result).toBeTruthy(); + expect(result.data).toEqual(data); + expect(mockAxios.history.post).toHaveLength(1); + }); + }); + + describe('submissions/${submissionId}/${formId}/submissions', () => { + let submissionId = 'ac4ef441-43b1-414a-a0d4-1e2f67c2a745'; + let formId = 'd15a8c14-c78a-42fa-8afd-b3f1fed59159'; + + const endpoint = `${ApiRoutes.SUBMISSION}/${submissionId}/${formId}/submissions`; + + it('calls delete endpoint', async () => { + mockAxios.onDelete(endpoint).reply(200); + + let submissionIds = [ + 'ac4ef441-43b1-414a-a0d4-1e2f67c2a745', + '0715b1ac-4069-4778-a868-b4f71fdea18d', + ]; + + const result = await formService.deleteMultipleSubmissions( + submissionId, + formId, + { data: { submissionIds } } + ); + expect(result).toBeTruthy(); + expect(mockAxios.history.delete).toHaveLength(1); + }); + }); + + describe('submissions/${submissionId}/${formId}/submissions/restore', () => { + let submissionId = 'ac4ef441-43b1-414a-a0d4-1e2f67c2a745'; + let formId = 'd15a8c14-c78a-42fa-8afd-b3f1fed59159'; + const endpoint = `${ApiRoutes.SUBMISSION}/${submissionId}/${formId}/submissions/restore`; + + it('calls restore multiple submission endpoint', async () => { + mockAxios.onPut(endpoint).reply(200); + let submissionIds = [ + 'ac4ef441-43b1-414a-a0d4-1e2f67c2a745', + '0715b1ac-4069-4778-a868-b4f71fdea18d', + ]; + + const result = await formService.restoreMutipleSubmissions( + submissionId, + formId, + { submissionIds } + ); + expect(result).toBeTruthy(); + expect(mockAxios.history.put).toHaveLength(1); + }); + }); + describe('submissions/${formId}/csvexport/fields', () => { + let formId = 'd15a8c14-c78a-42fa-8afd-b3f1fed59159'; + + const endpoint = `${ApiRoutes.FORMS}/${formId}/csvexport/fields`; + + it('calls to get submissions fields for csv export', async () => { + mockAxios.onGet(endpoint).reply(200); + const result = await formService.readCSVExportFields( + formId, + 'submissions', + false, + false, + 1 + ); + expect(result).toBeTruthy(); + expect(mockAxios.history.get).toHaveLength(1); + }); + }); +}); diff --git a/frontend/app/frontend/tests/unit/services/rbacService.spec.js b/frontend/app/frontend/tests/unit/services/rbacService.spec.js new file mode 100644 index 0000000..7497863 --- /dev/null +++ b/frontend/app/frontend/tests/unit/services/rbacService.spec.js @@ -0,0 +1,95 @@ +import axios from 'axios'; +import MockAdapter from 'axios-mock-adapter'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +import rbacService from '~/services/rbacService'; +import { ApiRoutes } from '~/utils/constants'; + +const mockInstance = axios.create(); +const mockAxios = new MockAdapter(mockInstance); + +vi.mock('~/services/interceptors', () => { + return { + appAxios: () => mockInstance, + }; +}); + +describe('RBAC Service', () => { + beforeEach(() => { + mockAxios.reset(); + }); + + describe('rbac/current', () => { + const endpoint = `${ApiRoutes.RBAC}/current`; + + it('calls rbac/current endpoint', async () => { + mockAxios.onGet(endpoint).reply(200); + + const result = await rbacService.getCurrentUser({ idp: 'idir' }); + expect(result).toBeTruthy(); + expect(mockAxios.history.get).toHaveLength(1); + expect(Object.keys(mockAxios.history.get[0].params)).toEqual(['idp']); + }); + }); + + describe('rbac/current/submissions', () => { + const endpoint = `${ApiRoutes.RBAC}/current/submissions`; + + it('calls rbac/current endpoint', async () => { + mockAxios.onGet(endpoint).reply(200); + + const result = await rbacService.getUserSubmissions({ formId: '123' }); + expect(result).toBeTruthy(); + expect(mockAxios.history.get).toHaveLength(1); + expect(Object.keys(mockAxios.history.get[0].params)).toEqual(['formId']); + }); + }); + + describe('rbac/forms', () => { + const endpoint = `${ApiRoutes.RBAC}/forms`; + + it('calls get on endpoint', async () => { + mockAxios.onGet(endpoint).reply(200); + + const result = await rbacService.getFormUsers({ idp: 'idir' }); + expect(result).toBeTruthy(); + expect(mockAxios.history.get).toHaveLength(1); + expect(Object.keys(mockAxios.history.get[0].params)).toEqual(['idp']); + }); + + it('calls put on endpoint', async () => { + const data = { test: 'data' }; + mockAxios.onPut(endpoint).reply(200, data); + + const result = await rbacService.setFormUsers(data, { idp: 'idir' }); + expect(result).toBeTruthy(); + expect(result.data).toEqual(data); + expect(mockAxios.history.put).toHaveLength(1); + expect(Object.keys(mockAxios.history.put[0].params)).toEqual(['idp']); + }); + }); + + describe('rbac/users', () => { + const endpoint = `${ApiRoutes.RBAC}/users`; + + it('calls get on endpoint', async () => { + mockAxios.onGet(endpoint).reply(200); + + const result = await rbacService.getUserForms({ idp: 'idir' }); + expect(result).toBeTruthy(); + expect(mockAxios.history.get).toHaveLength(1); + expect(Object.keys(mockAxios.history.get[0].params)).toEqual(['idp']); + }); + + it('calls put on endpoint', async () => { + const data = { test: 'data' }; + mockAxios.onPut(endpoint).reply(200, data); + + const result = await rbacService.setUserForms(data, { idp: 'idir' }); + expect(result).toBeTruthy(); + expect(result.data).toEqual(data); + expect(mockAxios.history.put).toHaveLength(1); + expect(Object.keys(mockAxios.history.put[0].params)).toEqual(['idp']); + }); + }); +}); diff --git a/frontend/app/frontend/tests/unit/services/roleService.spec.js b/frontend/app/frontend/tests/unit/services/roleService.spec.js new file mode 100644 index 0000000..f58b651 --- /dev/null +++ b/frontend/app/frontend/tests/unit/services/roleService.spec.js @@ -0,0 +1,31 @@ +import axios from 'axios'; +import MockAdapter from 'axios-mock-adapter'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +import roleService from '~/services/roleService'; +import { ApiRoutes } from '~/utils/constants'; + +const mockInstance = axios.create(); +const mockAxios = new MockAdapter(mockInstance); + +vi.mock('~/services/interceptors', () => { + return { + appAxios: () => mockInstance, + }; +}); + +describe('Role Service', () => { + const endpoint = `${ApiRoutes.ROLES}`; + + beforeEach(() => { + mockAxios.reset(); + }); + + it('calls get on roles/ endpoint', async () => { + mockAxios.onGet(endpoint).reply(200); + + const result = await roleService.list(); + expect(result).toBeTruthy(); + expect(mockAxios.history.get).toHaveLength(1); + }); +}); diff --git a/frontend/app/frontend/tests/unit/services/userService.spec.js b/frontend/app/frontend/tests/unit/services/userService.spec.js new file mode 100644 index 0000000..5141d6f --- /dev/null +++ b/frontend/app/frontend/tests/unit/services/userService.spec.js @@ -0,0 +1,53 @@ +import axios from 'axios'; +import MockAdapter from 'axios-mock-adapter'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +import userService from '~/services/userService'; +import { ApiRoutes } from '~/utils/constants'; + +const mockInstance = axios.create(); +const mockAxios = new MockAdapter(mockInstance); + +const zeroUuid = '00000000-0000-0000-0000-000000000000'; + +vi.mock('~/services/interceptors', () => { + return { + appAxios: () => mockInstance, + }; +}); + +beforeEach(() => { + mockAxios.reset(); +}); + +describe('users', () => { + const endpoint = `${ApiRoutes.USERS}/`; + + it('calls get on users/ endpoint', async () => { + mockAxios.onGet(endpoint).reply(200); + + const result = await userService.getUsers(); + expect(result).toBeTruthy(); + expect(mockAxios.history.get).toHaveLength(1); + }); +}); + +describe('user preferences', () => { + const endpoint = `${ApiRoutes.USERS}/preferences/forms/${zeroUuid}`; + + it('calls get on users/ endpoint', async () => { + mockAxios.onGet(endpoint).reply(200); + + const result = await userService.getUserFormPreferences(zeroUuid); + expect(result).toBeTruthy(); + expect(mockAxios.history.get).toHaveLength(1); + }); + + it('calls put on users/preferences/forms endpoint', async () => { + mockAxios.onPut(endpoint).reply(200); + + const result = await userService.updateUserFormPreferences(zeroUuid, {}); + expect(result).toBeTruthy(); + expect(mockAxios.history.put).toHaveLength(1); + }); +}); diff --git a/frontend/app/frontend/tests/unit/setup.js b/frontend/app/frontend/tests/unit/setup.js new file mode 100644 index 0000000..6ab1d3e --- /dev/null +++ b/frontend/app/frontend/tests/unit/setup.js @@ -0,0 +1,7 @@ +class ResizeObserverStub { + observe() {} + unobserve() {} + disconnect() {} +} + +window.ResizeObserver = window.ResizeObserver || ResizeObserverStub; diff --git a/frontend/app/frontend/tests/unit/store/modules/admin.actions.spec.js b/frontend/app/frontend/tests/unit/store/modules/admin.actions.spec.js new file mode 100644 index 0000000..49dd64b --- /dev/null +++ b/frontend/app/frontend/tests/unit/store/modules/admin.actions.spec.js @@ -0,0 +1,253 @@ +import { setActivePinia, createPinia } from 'pinia'; +import { afterAll, beforeEach, describe, expect, it, vi } from 'vitest'; + +import { adminService } from '~/services'; +import { useAdminStore } from '~/store/admin'; +import { useNotificationStore } from '~/store/notification'; +import { NotificationTypes } from '~/utils/constants'; + +vi.mock('~/services'); + +describe('admin actions', () => { + setActivePinia(createPinia()); + const mockStore = useAdminStore(); + const notificationStore = useNotificationStore(); + const addNotificationSpy = vi.spyOn(notificationStore, 'addNotification'); + const addFormUserSpy = vi.spyOn(adminService, 'addFormUser'); + const readRolesSpy = vi.spyOn(adminService, 'readRoles'); + const mockConsoleError = vi.spyOn(console, 'error'); + + beforeEach(() => { + mockStore.$reset(); + notificationStore.$reset(); + addNotificationSpy.mockReset(); + addFormUserSpy.mockReset(); + readRolesSpy.mockReset(); + mockConsoleError.mockReset(); + }); + + afterAll(() => { + mockConsoleError.mockRestore(); + addNotificationSpy.mockRestore(); + addFormUserSpy.mockRestore(); + readRolesSpy.mockRestore(); + }); + + describe('admin forms actions', () => { + it('adminFormUser should dispatch to notifications/addNotification on an error', async () => { + adminService.addFormUser.mockRejectedValue(''); + await mockStore.addFormUser({ + formId: 'fId', + userId: 'usrId', + role: 'OWNER', + }); + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(addNotificationSpy).toHaveBeenCalledWith({ + consoleError: 'trans.store.admin.addRowError', + text: 'trans.store.admin.addRowError', + }); + }); + + it('adminFormUser should dispatch a success notification when the service call resolves', async () => { + adminService.addFormUser.mockResolvedValue({ + data: [{ fullName: 'User' }], + }); + adminService.readRoles.mockResolvedValue({ data: ['OWNER'] }); + await mockStore.addFormUser({ + formId: 'fId', + userId: 'usrId', + roles: ['OWNER'], + }); + + expect(addFormUserSpy).toHaveBeenCalledWith('usrId', 'fId', ['OWNER']); + expect(addFormUserSpy).toHaveBeenCalledTimes(1); + expect(readRolesSpy).toHaveBeenCalledTimes(1); + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(addNotificationSpy).toHaveBeenCalledWith({ + text: 'trans.store.admin.addFormOwnerRole', + ...NotificationTypes.SUCCESS, + }); + }); + + it('deleteApiKey should commit to SET_API_KEY', async () => { + mockStore.apiKey = 'TEST'; + adminService.deleteApiKey.mockResolvedValue({ data: { form: {} } }); + await mockStore.deleteApiKey('fId'); + + expect(mockStore.apiKey).toBe(undefined); + }); + + it('deleteApiKey should dispatch to notifications/addNotification', async () => { + adminService.deleteApiKey.mockRejectedValue(''); + await mockStore.deleteApiKey('fId'); + + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(addNotificationSpy).toHaveBeenCalledWith({ + consoleError: 'trans.store.admin.apiKeyDelMsg', + text: 'trans.store.admin.errDeletingApiKey', + }); + }); + + it('readForm should commit to SET_FORM', async () => { + adminService.readForm.mockResolvedValue({ + data: { form: { id: 'fId' } }, + }); + await mockStore.readForm('fId'); + expect(mockStore.form).toEqual({ form: { id: 'fId' } }); + }); + + it('readForm should dispatch to notifications/addNotification', async () => { + adminService.readForm.mockRejectedValue(''); + await mockStore.readForm('fId'); + + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(addNotificationSpy).toHaveBeenCalledWith({ + consoleError: 'trans.store.admin.fecthingFormsErrMsg', + text: 'trans.store.admin.fecthingFormErrMsg', + }); + }); + + it('readRoles should commit to SET_ROLES', async () => { + adminService.readRoles.mockResolvedValue({ data: ['OWNER'] }); + await mockStore.readRoles('fId'); + + expect(mockStore.roles).toEqual(['OWNER']); + }); + + it('readRoles should dispatch to notifications/addNotification', async () => { + adminService.readRoles.mockRejectedValue(); + await mockStore.readRoles('fId'); + + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(addNotificationSpy).toHaveBeenCalledWith({ + consoleError: 'trans.store.admin.fecthFormUserRolesConsErrMsg', + text: 'trans.store.admin.fecthFormUserRolesErrMsg', + }); + }); + + it('readApiDetails should commit to SET_API_KEY', async () => { + mockStore.apiKey = undefined; + adminService.readApiDetails.mockResolvedValue({ data: '' }); + await mockStore.readApiDetails('fId'); + + expect(mockStore.apiKey).toEqual(''); + }); + + it('readApiDetails should dispatch to notifications/addNotification', async () => { + adminService.readApiDetails.mockRejectedValue(''); + await mockStore.readApiDetails('fId'); + + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(addNotificationSpy).toHaveBeenCalledWith({ + consoleError: 'trans.store.admin.fecthApiDetailsConsErrMsg', + text: 'trans.store.admin.fecthApiDetailsErrMsg', + }); + }); + + it('getForms should commit to SET_FORMLIST', async () => { + mockStore.formList = undefined; + adminService.listForms.mockResolvedValue({ data: [{ form: { id: 1 } }] }); + await mockStore.getForms(true); + + expect(mockStore.formList).toEqual([{ form: { id: 1 } }]); + }); + + it('fetchDrafts should dispatch to notifications/addNotification', async () => { + adminService.listForms.mockRejectedValue(''); + await mockStore.getForms(true); + + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(addNotificationSpy).toHaveBeenCalledWith({ + consoleError: 'trans.store.admin.fecthingFormsErrMsg', + text: 'trans.store.admin.fecthingFormsErrMsg', + }); + }); + + it('restoreForm should commit to SET_FORM', async () => { + mockStore.form = undefined; + adminService.restoreForm.mockResolvedValue({ data: { form: {} } }); + await mockStore.restoreForm('fId'); + + expect(mockStore.form).toEqual({ form: {} }); + }); + + it('restoreForm should dispatch to notifications/addNotification', async () => { + adminService.restoreForm.mockRejectedValue(''); + await mockStore.restoreForm('fId'); + + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(addNotificationSpy).toHaveBeenCalledWith({ + consoleError: 'trans.store.admin.restoreFormConsErrMsg', + text: 'trans.store.admin.restoreFormErrMsg', + }); + }); + + it('getUsers should commit to SET_USERLIST', async () => { + mockStore.userList = undefined; + adminService.listUsers.mockResolvedValue({ data: [] }); + await mockStore.getUsers(); + + expect(mockStore.userList).toEqual([]); + }); + + it('getUsers should dispatch to notifications/addNotification', async () => { + adminService.listUsers.mockRejectedValue(''); + await mockStore.getUsers(); + + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(addNotificationSpy).toHaveBeenCalledWith({ + consoleError: 'trans.store.admin.getUsersConsErrMsg', + text: 'trans.store.admin.getUsersErrMsg', + }); + }); + + it('readUser should commit to SET_USER', async () => { + mockStore.user = undefined; + adminService.readUser.mockResolvedValue({ data: {} }); + await mockStore.readUser('userId'); + + expect(mockStore.user).toEqual(expect.any(Object)); + }); + + it('readUser should dispatch to notifications/addNotification', async () => { + adminService.readUser.mockRejectedValue(''); + await mockStore.readUser('userId'); + + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(addNotificationSpy).toHaveBeenCalledWith({ + consoleError: 'trans.store.admin.getUserConsErrMsg', + text: 'trans.store.admin.getUserErrMsg', + }); + }); + + it('addFCProactiveHelp should commit to SET_FCPROACTIVEHELP', async () => { + mockStore.fcProactiveHelp = undefined; + adminService.addFCProactiveHelp.mockResolvedValue({ data: {} }); + await mockStore.addFCProactiveHelp({}); + + expect(mockStore.fcProactiveHelp).toEqual({}); + }); + + it('addFCProactiveHelp should commit to SET_FCPROACTIVEHELPGROUPLIST', async () => { + mockStore.fcProactiveHelpGroupList = undefined; + adminService.listFCProactiveHelp.mockResolvedValue({ data: [] }); + await mockStore.listFCProactiveHelp(); + + expect(mockStore.fcProactiveHelpGroupList).toEqual([]); + }); + + it('updateFCProactiveHelpStatus should update publish status and commit to SET_FCPROACTIVEHELP', async () => { + adminService.updateFCProactiveHelpStatus.mockRejectedValue(''); + await mockStore.updateFCProactiveHelpStatus({ + componentId: '5b97417a-252c-46c2-b132-85adac5ab3bc', + publishStatus: true, + }); + + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(addNotificationSpy).toHaveBeenCalledWith({ + consoleError: 'trans.store.admin.updatingFCStatusConsErrMsg', + text: 'trans.store.admin.updatingFCStatusErrMsg', + }); + }); + }); +}); diff --git a/frontend/app/frontend/tests/unit/store/modules/auth.actions.spec.js b/frontend/app/frontend/tests/unit/store/modules/auth.actions.spec.js new file mode 100644 index 0000000..920aac5 --- /dev/null +++ b/frontend/app/frontend/tests/unit/store/modules/auth.actions.spec.js @@ -0,0 +1,119 @@ +// @vitest-environment happy-dom +// happy-dom is required to access window.location +import { setActivePinia, createPinia } from 'pinia'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import getRouter from '~/router'; + +import { useAuthStore } from '~/store/auth'; +import { useFormStore } from '~/store/form'; + +describe('auth actions', () => { + let router = getRouter(); + const replaceSpy = vi.spyOn(router, 'replace'); + const windowReplaceSpy = vi.spyOn(window.location, 'replace'); + setActivePinia(createPinia()); + const mockStore = useAuthStore(); + const formStore = useFormStore(); + + describe('login', () => { + beforeEach(() => { + mockStore.$reset(); + formStore.$reset(); + mockStore.keycloak = { + createLoginUrl: vi.fn(() => 'about:blank'), + createLogoutUrl: vi.fn(() => 'about:blank'), + }; + replaceSpy.mockReset(); + windowReplaceSpy.mockReset(); + router.replace.mockReset(); + }); + + it('should do nothing if keycloak is not ready', () => { + mockStore.ready = false; + mockStore.login(); + + expect(windowReplaceSpy).toHaveBeenCalledTimes(0); + }); + + it('should update redirectUri if not defined', () => { + mockStore.ready = true; + mockStore.redirectUri = undefined; + + mockStore.login('test'); + + expect(windowReplaceSpy).toHaveBeenCalledTimes(1); + expect(mockStore.redirectUri).toEqual('about:blank'); + }); + + it('should not update redirectUri if already defined', () => { + mockStore.ready = true; + mockStore.redirectUri = 'value'; + + mockStore.login('test'); + + expect(windowReplaceSpy).toHaveBeenCalledTimes(1); + expect(mockStore.redirectUri).toEqual('value'); + }); + + it('should navigate with provided idpHint', () => { + mockStore.ready = true; + mockStore.redirectUri = 'value'; + + mockStore.login('test'); + + expect(windowReplaceSpy).toHaveBeenCalledTimes(1); + }); + + it('should navigate with pinia store idpHint', () => { + mockStore.ready = true; + mockStore.redirectUri = undefined; + formStore.form = { idps: ['test'] }; + + mockStore.login(); + + expect(replaceSpy).toHaveBeenCalledTimes(1); + expect(replaceSpy).toHaveBeenCalledWith({ + name: 'Login', + query: { idpHint: ['idir', 'bceid-business', 'bceid-basic'] }, + }); + }); + + // TODO: Figure out how to mock and intercept vue-router instantiation + // it('should router navigate to login page without idpHint', () => { + // mockStore.ready = true; + // mockStore.redirectUri = undefined; + // mockStore.rootGetters['form/form'] = { idps: [] }; + + // mockStore.login(mockStore); + + // expect(mockStore.commit).toHaveBeenCalledTimes(1); + // expect(replaceSpy).toHaveBeenCalledTimes(0); + // expect(mockStore.getters.createLoginUrl).toHaveBeenCalledTimes(0); + // }); + }); + + describe('logout', () => { + beforeEach(() => { + mockStore.$reset(); + mockStore.keycloak = { + createLoginUrl: vi.fn(() => 'about:blank'), + createLogoutUrl: vi.fn(() => 'about:blank'), + }; + windowReplaceSpy.mockReset(); + }); + + it('should do nothing if keycloak is not ready', () => { + mockStore.ready = false; + mockStore.logout(); + + expect(windowReplaceSpy).toHaveBeenCalledTimes(0); + }); + + it('should trigger navigation action if keycloak is ready', () => { + mockStore.ready = true; + mockStore.logout(); + + expect(windowReplaceSpy).toHaveBeenCalledTimes(1); + }); + }); +}); diff --git a/frontend/app/frontend/tests/unit/store/modules/auth.getters.spec.js b/frontend/app/frontend/tests/unit/store/modules/auth.getters.spec.js new file mode 100644 index 0000000..bf44fba --- /dev/null +++ b/frontend/app/frontend/tests/unit/store/modules/auth.getters.spec.js @@ -0,0 +1,252 @@ +import { setActivePinia, createPinia } from 'pinia'; +import { beforeEach, describe, expect, it } from 'vitest'; +import { createApp } from 'vue'; + +import { useAuthStore } from '~/store/auth'; + +const zeroUuid = '00000000-0000-0000-0000-000000000000'; +const zeroGuid = '00000000000000000000000000000000'; + +describe('auth getters', () => { + let roles; + const app = createApp({}); + const pinia = createPinia(); + app.use(pinia); + setActivePinia(pinia); + const store = useAuthStore(); + + beforeEach(() => { + store.$reset(); + store.authenticated = true; + store.ready = true; + store.keycloak = { + createLoginUrl: () => 'loginUrl', + createLogoutUrl: () => 'logoutUrl', + fullName: 'fName', + subject: zeroUuid, + token: 'token', + tokenParsed: { + given_name: 'John', + family_name: 'Doe', + name: 'John Doe', + email: 'e@mail.com', + identity_provider: 'idir', + idp_userid: zeroGuid, + preferred_username: 'johndoe', + realm_access: {}, + resource_access: { + chefs: { + roles: roles, + }, + }, + }, + userName: 'uName', + }; + }); + + it('authenticated should return a boolean', () => { + expect(store.authenticated).toBeTruthy(); + }); + + it('createLoginUrl should return a string', () => { + expect(store.createLoginUrl).toBeTruthy(); + expect(typeof store.createLoginUrl).toBe('function'); + expect(store.createLoginUrl()).toMatch('loginUrl'); + }); + + it('createLogoutUrl should return a string', () => { + expect(store.createLogoutUrl).toBeTruthy(); + expect(typeof store.createLogoutUrl).toBe('function'); + expect(store.createLogoutUrl()).toMatch('logoutUrl'); + }); + + it('email should return a string', () => { + expect(store.email).toBeTruthy(); + expect(store.email).toMatch('e@mail.com'); + }); + + it('email should return an empty string', () => { + store.keycloak.tokenParsed = undefined; + expect(store.email).toBeFalsy(); + expect(store.email).toEqual(''); + }); + + it('fullName should return a string', () => { + expect(store.fullName).toBeTruthy(); + expect(store.fullName).toMatch('John Doe'); + }); + + it('hasResourceRoles should return false if unauthenticated', () => { + store.authenticated = false; + + expect(store.authenticated).toBeFalsy(); + expect(store.hasResourceRoles('app', roles)).toBeFalsy(); + }); + + it('hasResourceRoles should return true when checking no roles', () => { + store.authenticated = true; + roles = []; + + expect(store.authenticated).toBeTruthy(); + expect(store.hasResourceRoles('app', roles)).toBeTruthy(); + }); + + it('hasResourceRoles should return true when role exists', () => { + store.authenticated = true; + roles = []; + + expect(store.authenticated).toBeTruthy(); + expect(store.hasResourceRoles('app', roles)).toBeTruthy(); + }); + + it('hasResourceRoles should return false when resource does not exist', () => { + store.authenticated = true; + store.keycloak.tokenParsed = { + realm_access: {}, + resource_access: {}, + }; + roles = ['non-existent-role']; + + expect(store.authenticated).toBeTruthy(); + expect(store.hasResourceRoles('app', roles)).toBeFalsy(); + }); + + it('identityProvider should return a string', () => { + expect(store.identityProvider).toBeTruthy(); + expect(typeof store.identityProvider).toBe('string'); + }); + + it('isAdmin should return false if no admin role', () => { + store.authenticated = true; + roles = []; + store.keycloak.tokenParsed = { + resource_access: { + chefs: { + roles: roles, + }, + }, + }; + + expect(store.authenticated).toBeTruthy(); + expect(store.isAdmin).toBeFalsy(); + }); + + it('isAdmin should return true if admin role', () => { + store.authenticated = true; + roles = ['admin']; + store.keycloak.tokenParsed = { + resource_access: { + chefs: { + roles: roles, + }, + }, + }; + + expect(store.authenticated).toBeTruthy(); + expect(store.isAdmin).toBeTruthy(); + }); + + it('isUser should return false if no user role', () => { + store.authenticated = true; + roles = []; + + expect(store.authenticated).toBeTruthy(); + expect(store.isUser).toBeFalsy(); + }); + + it('isUser should return true if user role', () => { + store.authenticated = true; + roles = ['user']; + store.keycloak.tokenParsed = { + resource_access: { + chefs: { + roles: roles, + }, + }, + }; + + expect(store.authenticated).toBeTruthy(); + expect(store.isUser).toBeTruthy(); + }); + + it('ready should return a boolean', () => { + expect(store.ready).toBeTruthy(); + }); + + it('identityProviderIdentity should return a string', () => { + expect(store.identityProviderIdentity).toBeTruthy(); + expect(store.identityProviderIdentity).toMatch(zeroGuid); + }); + + it('keycloakSubject should return a string', () => { + expect(store.keycloakSubject).toBeTruthy(); + expect(store.keycloakSubject).toMatch(zeroUuid); + }); + + it('moduleLoaded should return a boolean', () => { + expect(store.moduleLoaded).toBeTruthy(); + }); + + it('realmAccess should return an object', () => { + expect(store.realmAccess).toBeTruthy(); + expect(typeof store.realmAccess).toBe('object'); + }); + + it('realmAccess should return a string', () => { + const uri = 'http://foo.bar'; + store.redirectUri = uri; + + expect(store.redirectUri).toBeTruthy(); + expect(typeof store.redirectUri).toBe('string'); + expect(store.redirectUri).toEqual(uri); + }); + + it('resourceAccess should return an object', () => { + expect(store.resourceAccess).toBeTruthy(); + expect(typeof store.resourceAccess).toBe('object'); + }); + + it('token should return a string', () => { + expect(store.token).toBeTruthy(); + expect(store.token).toMatch('token'); + }); + + it('tokenParsed should return an object', () => { + expect(store.tokenParsed).toBeTruthy(); + expect(typeof store.tokenParsed).toBe('object'); + }); + + it('userName should return a string', () => { + expect(store.userName).toBeTruthy(); + expect(store.userName).toMatch('johndoe'); + }); + + it('creates an auth user when authenticated', () => { + expect(store.user).toBeTruthy(); + expect(store.user).toEqual({ + username: 'johndoe', + firstName: 'John', + lastName: 'Doe', + fullName: 'John Doe', + email: 'e@mail.com', + idp: 'idir', + public: false, + }); + }); + + it('creates a public user when not authenticated', () => { + store.authenticated = false; + store.keycloak.tokenParsed = undefined; + + expect(store.user).toBeTruthy(); + expect(store.user).toEqual({ + username: '', + firstName: '', + lastName: '', + fullName: '', + email: '', + idp: 'public', + public: true, + }); + }); +}); diff --git a/frontend/app/frontend/tests/unit/store/modules/form.actions.spec.js b/frontend/app/frontend/tests/unit/store/modules/form.actions.spec.js new file mode 100644 index 0000000..6d559c4 --- /dev/null +++ b/frontend/app/frontend/tests/unit/store/modules/form.actions.spec.js @@ -0,0 +1,445 @@ +import { setActivePinia, createPinia } from 'pinia'; +import { afterAll, beforeEach, describe, expect, it, vi } from 'vitest'; + +import { + formService, + rbacService, + userService, + adminService, +} from '~/services'; +import { useFormStore } from '~/store/form'; +import { useNotificationStore } from '~/store/notification'; + +vi.mock('~/services'); + +describe('form actions', () => { + setActivePinia(createPinia()); + const mockStore = useFormStore(); + const notificationStore = useNotificationStore(); + const addNotificationSpy = vi.spyOn(notificationStore, 'addNotification'); + const listSubmissionsSpy = vi.spyOn(formService, 'listSubmissions'); + const getUserSubmissionsSpy = vi.spyOn(rbacService, 'getUserSubmissions'); + const mockConsoleError = vi.spyOn(console, 'error'); + + beforeEach(() => { + mockStore.$reset(); + mockConsoleError.mockReset(); + notificationStore.$reset(); + addNotificationSpy.mockReset(); + listSubmissionsSpy.mockReset(); + getUserSubmissionsSpy.mockReset(); + }); + + afterAll(() => { + mockConsoleError.mockRestore(); + addNotificationSpy.mockRestore(); + listSubmissionsSpy.mockRestore(); + getUserSubmissionsSpy.mockRestore(); + }); + + describe('current user', () => { + it('getFormsForCurrentUser should commit to SET_FORMLIST', async () => { + rbacService.getCurrentUser.mockResolvedValue({ data: { forms: [] } }); + await mockStore.getFormsForCurrentUser(); + + expect(mockStore.formList).toEqual(expect.any(Array)); + }); + + it('getFormsForCurrentUser should dispatch to notifications/addNotification', async () => { + rbacService.getCurrentUser.mockRejectedValue(''); + await mockStore.getFormsForCurrentUser(); + + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(addNotificationSpy).toHaveBeenCalledWith(expect.any(Object)); + }); + + it('getFormPermissionsForUser should commit to SET_FORM_PERMISSIONS', async () => { + rbacService.getCurrentUser.mockResolvedValue({ + data: { + forms: [ + { + permissions: [], + }, + ], + }, + }); + mockStore.permissions = undefined; + await mockStore.getFormPermissionsForUser('fId'); + + expect(mockStore.permissions).toEqual(expect.any(Array)); + }); + + it('getFormPermissionsForUser should dispatch to notifications/addNotification', async () => { + rbacService.getCurrentUser.mockResolvedValue({ data: { forms: [] } }); + mockStore.permissions = undefined; + await mockStore.getFormPermissionsForUser('fId'); + + expect(mockStore.permissions).toEqual([]); + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(addNotificationSpy).toHaveBeenCalledWith(expect.any(Object)); + }); + + it('getFormPreferencesForCurrentUser should commit to SET_USER_FORM_PREFERENCES', async () => { + userService.getUserFormPreferences.mockResolvedValue({ + data: { + preferences: ['foo', 'bar'], + userId: '123', + }, + }); + mockStore.userFormPreferences = undefined; + await mockStore.getFormPreferencesForCurrentUser('fId'); + + expect(mockStore.userFormPreferences).toEqual(expect.any(Object)); + }); + + it('getFormPreferencesForCurrentUser should dispatch to notifications/addNotification', async () => { + userService.getUserFormPreferences.mockRejectedValue(''); + await mockStore.getFormPreferencesForCurrentUser('fId'); + + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(addNotificationSpy).toHaveBeenCalledWith(expect.any(Object)); + }); + + it('updateFormPreferencesForCurrentUser should commit to SET_USER_FORM_PREFERENCES', async () => { + userService.updateUserFormPreferences.mockResolvedValue({ + data: { + preferences: ['foo', 'bar'], + userId: '123', + }, + }); + mockStore.userFormPreferences = undefined; + await mockStore.updateFormPreferencesForCurrentUser({ + formId: 'fId', + preferences: {}, + }); + + expect(mockStore.userFormPreferences).toEqual(expect.any(Object)); + }); + + it('updateFormPreferencesForCurrentUser should dispatch to notifications/addNotification', async () => { + userService.updateUserFormPreferences.mockRejectedValue(''); + await mockStore.updateFormPreferencesForCurrentUser({ + formId: 'fId', + preferences: {}, + }); + + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(addNotificationSpy).toHaveBeenCalledWith(expect.any(Object)); + }); + }); + + describe('form', () => { + it('fetchForm should commit to SET_FORM', async () => { + formService.readForm.mockResolvedValue({ data: { form: {} } }); + mockStore.apiKey = undefined; + mockStore.form = undefined; + await mockStore.fetchForm({ formId: 'fId' }); + + expect(mockStore.apiKey).toEqual(null); + expect(mockStore.form).toEqual(expect.any(Object)); + }); + + it('fetchForm should dispatch to notifications/addNotification', async () => { + formService.readForm.mockRejectedValue(''); + await mockStore.fetchSubmission({ formId: 'fId' }); + + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(addNotificationSpy).toHaveBeenCalledWith(expect.any(Object)); + }); + + it('fetchFormFields should commit to SET_FORM_FIELDS', async () => { + formService.readVersionFields.mockResolvedValue({ data: { form: {} } }); + mockStore.formFields = undefined; + await mockStore.fetchFormFields({ + formId: 'fId', + formVersionId: 'vid', + }); + + expect(mockStore.formFields).toEqual(expect.any(Object)); + }); + + it('fetchForm should dispatch to notifications/addNotification', async () => { + formService.readVersionFields.mockRejectedValue(''); + await mockStore.fetchFormFields({ + formId: 'fId', + formVersionId: 'vid', + }); + + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(addNotificationSpy).toHaveBeenCalledWith(expect.any(Object)); + }); + + it('fetchDrafts should commit to SET_DRAFTS', async () => { + formService.listDrafts.mockResolvedValue({ data: [] }); + mockStore.drafts = undefined; + await mockStore.fetchDrafts('dId'); + + expect(mockStore.drafts).toEqual(expect.any(Array)); + }); + + it('fetchDrafts should dispatch to notifications/addNotification', async () => { + formService.listDrafts.mockRejectedValue(''); + await mockStore.fetchDrafts('dId'); + + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(addNotificationSpy).toHaveBeenCalledWith(expect.any(Object)); + }); + }); + + describe('emailTemplates', () => { + it('fetchEmailTemplates should commit to SET_EMAIL_TEMPLATES', async () => { + mockStore.emailTemplates = undefined; + formService.listEmailTemplates.mockResolvedValue({ data: [] }); + await mockStore.fetchEmailTemplates(mockStore, 'dId'); + + expect(mockStore.emailTemplates).toEqual(expect.any(Array)); + }); + + it('fetchEmailTemplates should dispatch to notifications/addNotification', async () => { + mockStore.emailTemplates = undefined; + formService.listEmailTemplates.mockRejectedValue(''); + await mockStore.fetchEmailTemplates(mockStore, 'dId'); + + expect(mockStore.emailTemplates).toBe(expect.undefined); + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(addNotificationSpy).toHaveBeenCalledWith(expect.any(Object)); + }); + + it('updateEmailTemplate should call the form service update', async () => { + formService.updateEmailTemplate.mockResolvedValue({ data: [] }); + const data = { + body: 'sample email body', + subject: 'sample email subject', + title: 'sample email title', + type: 'submissionConfirmation', + }; + + await mockStore.updateEmailTemplate(mockStore, data); + + expect(formService.updateEmailTemplate).toHaveBeenCalledTimes(1); + expect(formService.updateEmailTemplate).toHaveBeenCalledWith( + expect.any(Object) + ); + }); + + it('updateEmailTemplate should dispatch to notifications/addNotification', async () => { + formService.updateEmailTemplate.mockRejectedValue(''); + await mockStore.updateEmailTemplate(mockStore, 'dId'); + + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(addNotificationSpy).toHaveBeenCalledWith(expect.any(Object)); + }); + }); + + describe('submission', () => { + it('deleteSubmission should commit to SET_FORMSUBMISSION', async () => { + formService.deleteSubmission.mockResolvedValue({ + data: { submission: {}, form: {} }, + }); + await mockStore.deleteSubmission('sId'); + + expect(formService.deleteSubmission).toHaveBeenCalledTimes(1); + expect(formService.deleteSubmission).toHaveBeenCalledWith('sId'); + }); + + it('deleteSubmission should dispatch to notifications/addNotification', async () => { + formService.deleteSubmission.mockRejectedValue(''); + await mockStore.deleteSubmission('sId'); + + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(addNotificationSpy).toHaveBeenCalledWith(expect.any(Object)); + }); + + it('deleteMultiSubmissions should dispatch to notifications/addNotification', async () => { + formService.deleteMultipleSubmissions.mockRejectedValue(''); + await mockStore.deleteMultiSubmissions(['sId']); + + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(addNotificationSpy).toHaveBeenCalledWith(expect.any(Object)); + }); + + it('restoreMultiSubmissions should dispatch to notifications/addNotification', async () => { + formService.restoreMutipleSubmissions.mockRejectedValue(''); + await mockStore.restoreMultiSubmissions(['sId']); + + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(addNotificationSpy).toHaveBeenCalledWith(expect.any(Object)); + }); + + it('fetchSubmission should commit to SET_FORMSUBMISSION', async () => { + formService.getSubmission.mockResolvedValue({ + data: { submission: {}, form: {} }, + }); + mockStore.formSubmission = undefined; + mockStore.form = undefined; + await mockStore.fetchSubmission({ submissionId: 'sId' }); + + expect(mockStore.formSubmission).toEqual(expect.any(Object)); + expect(mockStore.form).toEqual(expect.any(Object)); + }); + + it('fetchSubmission should dispatch to notifications/addNotification', async () => { + formService.getSubmission.mockRejectedValue(''); + await mockStore.fetchSubmission({ submissionId: 'sId' }); + + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(addNotificationSpy).toHaveBeenCalledWith(expect.any(Object)); + }); + + it('fetchSubmissions should commit to SET_SUBMISSIONLIST', async () => { + formService.listSubmissions.mockResolvedValue({ + data: [], + }); + await mockStore.fetchSubmissions({ formId: 'fId' }); + + expect(mockStore.submissionList).toEqual([]); + expect(listSubmissionsSpy).toHaveBeenCalledTimes(1); + expect(listSubmissionsSpy).toHaveBeenCalledWith('fId', { + createdAt: undefined, + deleted: false, + createdBy: '', + fields: undefined, + filterformSubmissionStatusCode: undefined, + itemsPerPage: undefined, + page: undefined, + sortBy: undefined, + totalSubmissions: 0, + }); + expect(getUserSubmissionsSpy).toHaveBeenCalledTimes(0); + }); + + it('fetchSubmissions should call the formService if not for userView', async () => { + formService.listSubmissions.mockResolvedValue({ + data: [], + }); + await mockStore.fetchSubmissions({ + formId: 'fId', + userView: false, + }); + + expect(mockStore.submissionList).toEqual([]); + expect(listSubmissionsSpy).toHaveBeenCalledTimes(1); + expect(listSubmissionsSpy).toHaveBeenCalledWith('fId', { + createdAt: undefined, + deleted: false, + createdBy: '', + fields: undefined, + filterformSubmissionStatusCode: undefined, + itemsPerPage: undefined, + page: undefined, + sortBy: undefined, + totalSubmissions: 0, + }); + expect(getUserSubmissionsSpy).toHaveBeenCalledTimes(0); + }); + + it('fetchSubmissions should call the rbacService if for userView', async () => { + rbacService.getUserSubmissions.mockResolvedValue({ + data: [], + }); + await mockStore.fetchSubmissions({ + formId: 'fId', + userView: true, + }); + expect(mockStore.submissionList).toEqual([]); + expect(listSubmissionsSpy).toHaveBeenCalledTimes(0); + expect(getUserSubmissionsSpy).toHaveBeenCalledTimes(1); + expect(getUserSubmissionsSpy).toHaveBeenCalledWith({ + formId: 'fId', + }); + }); + + it('fetchSubmissions should dispatch to notifications/addNotification', async () => { + formService.listSubmissions.mockRejectedValue(''); + mockStore.submissionList = undefined; + await mockStore.fetchSubmissions({ formId: 'fId' }); + + expect(mockStore.submissionList).toEqual([]); + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(addNotificationSpy).toHaveBeenCalledWith(expect.any(Object)); + expect(listSubmissionsSpy).toHaveBeenCalledTimes(1); + expect(listSubmissionsSpy).toHaveBeenCalledWith('fId', { + createdAt: undefined, + deleted: false, + createdBy: '', + fields: undefined, + filterformSubmissionStatusCode: undefined, + itemsPerPage: undefined, + page: undefined, + sortBy: undefined, + totalSubmissions: 0, + }); + expect(getUserSubmissionsSpy).toHaveBeenCalledTimes(0); + }); + + it('fetchVersion should commit to SET_FORMSUBMISSION and SET_VERSION', async () => { + formService.readVersion.mockResolvedValue({ data: [] }); + mockStore.formSubmission = undefined; + mockStore.version = undefined; + await mockStore.fetchVersion({ + formId: 'fId', + versionId: 'vId', + }); + expect(mockStore.formSubmission).toEqual(expect.any(Object)); + expect(mockStore.version).toEqual(expect.any(Object)); + }); + + it('fetchVersion should dispatch to notifications/addNotification', async () => { + formService.readVersion.mockRejectedValue(''); + mockStore.version = undefined; + await mockStore.fetchVersion({ + formId: 'fId', + versionId: 'vId', + }); + + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(addNotificationSpy).toHaveBeenCalledWith(expect.any(Object)); + }); + }); + describe('form components proactive help', () => { + it('listFCProactiveHelp should commit to SET_FCPROACTIVEHELPGROUPLIST', async () => { + adminService.listFCProactiveHelp.mockResolvedValue({ data: [] }); + await mockStore.listFCProactiveHelp(); + + expect(mockStore.fcProactiveHelpGroupList).toEqual(expect.any(Object)); + }); + + it('listFCProactiveHelp should dispatch to notifications/addNotification', async () => { + adminService.listFCProactiveHelp.mockRejectedValue(''); + await mockStore.listFCProactiveHelp(); + + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(addNotificationSpy).toHaveBeenCalledWith(expect.any(Object)); + }); + + it('getFCProactiveHelpImageUrl should commit to SET_FCPROACTIVEHELPIMAGEURL', async () => { + adminService.getFCProactiveHelpImageUrl.mockResolvedValue({ data: {} }); + await mockStore.getFCProactiveHelpImageUrl(); + expect(mockStore.fcProactiveHelpImageUrl).toEqual(expect.any(Object)); + }); + + it('getFCProactiveHelpImageUrl should dispatch to notifications/addNotification', async () => { + adminService.getFCProactiveHelpImageUrl.mockRejectedValue(''); + await mockStore.getFCProactiveHelpImageUrl(); + + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(addNotificationSpy).toHaveBeenCalledWith(expect.any(Object)); + }); + }); + it('fetchFormCSVExportFields should commit to SET_FORM_FIELDS', async () => { + formService.readCSVExportFields.mockRejectedValue([]); + mockStore.formFields = undefined; + await mockStore.fetchFormCSVExportFields({ + formId: 'bd4dcf26-65bd-429b-967f-125500bfd8a4', + type: false, + draft: false, + deleted: false, + version: 2, + }); + + expect(mockStore.formFields).toEqual(expect.any(Array)); + + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(addNotificationSpy).toHaveBeenCalledWith(expect.any(Object)); + }); +}); diff --git a/frontend/app/frontend/tests/unit/store/modules/notifications.actions.spec.js b/frontend/app/frontend/tests/unit/store/modules/notifications.actions.spec.js new file mode 100644 index 0000000..32513bf --- /dev/null +++ b/frontend/app/frontend/tests/unit/store/modules/notifications.actions.spec.js @@ -0,0 +1,98 @@ +import { setActivePinia, createPinia } from 'pinia'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { useNotificationStore } from '~/store/notification'; +import { NotificationTypes } from '~/utils/constants'; + +describe('notifications actions', () => { + beforeEach(() => { + setActivePinia(createPinia()); + }); + + it('addNotification should add notification', () => { + const mockStore = useNotificationStore(); + const obj = { + message: 'foo', + consoleError: 'bar', + }; + const addNotificationSpy = vi.spyOn(mockStore, 'addNotification'); + mockStore.addNotification(obj); + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(mockStore.notifications).toEqual([ + { + color: 'error', + type: 'error', + icon: '$error', + ...obj, + id: 1, + }, + ]); + }); + + it('addNotification as warning should add notification', () => { + const mockStore = useNotificationStore(); + const obj = { + message: 'foo', + consoleError: 'bar', + ...NotificationTypes.WARNING, + }; + + const addNotificationSpy = vi.spyOn(mockStore, 'addNotification'); + mockStore.addNotification(obj); + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(mockStore.notifications).toEqual([ + { + color: 'warning', + type: 'warning', + icon: '$warning', + ...obj, + id: 1, + }, + ]); + }); + + it('addNotification without consoleError should add notification', () => { + const mockStore = useNotificationStore(); + const obj = { + message: 'foo', + }; + const addNotificationSpy = vi.spyOn(mockStore, 'addNotification'); + mockStore.addNotification(obj); + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(mockStore.notifications).toEqual([ + { + color: 'error', + type: 'error', + icon: '$error', + ...obj, + id: 1, + }, + ]); + }); + + it('deleteNotification should commit to DELETE', () => { + const mockStore = useNotificationStore(); + const obj = { + id: 1, + }; + mockStore.notifications = [ + { + color: 'error', + type: 'error', + icon: '$error', + ...obj, + id: 1, + }, + ]; + expect(mockStore.notifications).toEqual([ + { + color: 'error', + type: 'error', + icon: '$error', + ...obj, + id: 1, + }, + ]); + mockStore.deleteNotification(obj); + expect(mockStore.notifications).toEqual([]); + }); +}); diff --git a/frontend/app/frontend/tests/unit/utils/constants.spec.js b/frontend/app/frontend/tests/unit/utils/constants.spec.js new file mode 100644 index 0000000..058d3a4 --- /dev/null +++ b/frontend/app/frontend/tests/unit/utils/constants.spec.js @@ -0,0 +1,110 @@ +import { describe, expect, it } from 'vitest'; +import * as constants from '~/utils/constants'; + +describe('Constants', () => { + it('ApiRoutes has the right values defined', () => { + expect(constants.ApiRoutes).toEqual({ + ADMIN: '/admin', + APIKEY: '/apiKey', + FILES: '/files', + FORMS: '/forms', + RBAC: '/rbac', + ROLES: '/roles', + SUBMISSION: '/submissions', + USERS: '/users', + UTILS: '/utils', + }); + }); + + it('FormRoleCodes has the right values defined', () => { + expect(constants.FormRoleCodes).toEqual({ + OWNER: 'owner', + TEAM_MANAGER: 'team_manager', + FORM_DESIGNER: 'form_designer', + SUBMISSION_REVIEWER: 'submission_reviewer', + FORM_SUBMITTER: 'form_submitter', + }); + }); + + it('FormPermissions has the right values defined', () => { + expect(constants.FormPermissions).toEqual({ + EMAIL_TEMPLATE_READ: 'email_template_read', + EMAIL_TEMPLATE_UPDATE: 'email_template_update', + FORM_API_CREATE: 'form_api_create', + FORM_API_READ: 'form_api_read', + FORM_API_UPDATE: 'form_api_update', + FORM_API_DELETE: 'form_api_delete', + FORM_READ: 'form_read', + FORM_UPDATE: 'form_update', + FORM_DELETE: 'form_delete', + SUBMISSION_CREATE: 'submission_create', + SUBMISSION_READ: 'submission_read', + SUBMISSION_UPDATE: 'submission_update', + SUBMISSION_DELETE: 'submission_delete', + DESIGN_CREATE: 'design_create', + DESIGN_READ: 'design_read', + DESIGN_UPDATE: 'design_update', + DESIGN_DELETE: 'design_delete', + TEAM_READ: 'team_read', + TEAM_UPDATE: 'team_update', + }); + }); + + it('FormManagePermissions has the right values defined', () => { + expect(constants.FormManagePermissions).toEqual([ + constants.FormPermissions.FORM_UPDATE, + constants.FormPermissions.FORM_DELETE, + constants.FormPermissions.DESIGN_UPDATE, + constants.FormPermissions.DESIGN_DELETE, + constants.FormPermissions.TEAM_UPDATE, + ]); + }); + + it('IdentityMode has the right values defined', () => { + expect(constants.IdentityMode).toEqual({ + LOGIN: 'login', + PUBLIC: 'public', + TEAM: 'team', + }); + }); + + it('IdentityProviders has the right values defined', () => { + expect(constants.IdentityProviders).toEqual({ + BCEIDBASIC: 'bceid-basic', + BCEIDBUSINESS: 'bceid-business', + IDIR: 'idir', + }); + }); + + it('NotificationTypes has the right values defined', () => { + expect(constants.NotificationTypes).toEqual({ + ERROR: { + color: 'error', + type: 'error', + icon: '$error', + }, + SUCCESS: { + color: 'success', + type: 'success', + icon: 'mdi:mdi-check-circle', + }, + INFO: { + color: 'info', + type: 'info', + icon: '$info', + }, + WARNING: { + color: 'warning', + type: 'warning', + icon: '$warning', + }, + }); + }); + + it('Regex has the right values defined', () => { + expect(constants.Regex).toEqual({ + EMAIL: + "^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$", + }); + }); +}); diff --git a/frontend/app/frontend/tests/unit/utils/permissionUtils.spec.js b/frontend/app/frontend/tests/unit/utils/permissionUtils.spec.js new file mode 100644 index 0000000..c14bf5b --- /dev/null +++ b/frontend/app/frontend/tests/unit/utils/permissionUtils.spec.js @@ -0,0 +1,394 @@ +import { setActivePinia, createPinia } from 'pinia'; +import { describe, expect, it, vi } from 'vitest'; + +import { formService } from '~/services'; +import { useAuthStore } from '~/store/auth'; +import { useNotificationStore } from '~/store/notification'; +import { + FormPermissions, + IdentityProviders, + IdentityMode, +} from '~/utils/constants'; +import * as permissionUtils from '~/utils/permissionUtils'; + +describe('checkFormSubmit', () => { + it('should be false when userForm is undefined', () => { + expect(permissionUtils.checkFormSubmit(undefined)).toBeFalsy(); + }); + + it('should be false when idps is undefined', () => { + expect(permissionUtils.checkFormSubmit({ permissions: [] })).toBeFalsy(); + }); + + it('should be false when permissions is undefined', () => { + expect(permissionUtils.checkFormSubmit({ idps: [] })).toBeFalsy(); + }); + + it('should be true when idps is public', () => { + expect( + permissionUtils.checkFormSubmit({ idps: [IdentityProviders.PUBLIC] }) + ).toBeTruthy(); + }); + + it('should be true when permissions is submission creator', () => { + expect( + permissionUtils.checkFormSubmit({ + permissions: [FormPermissions.SUBMISSION_CREATE], + }) + ).toBeTruthy(); + }); +}); + +describe('checkFormManage', () => { + it('should be false when permissions is undefined', () => { + expect(permissionUtils.checkFormManage(undefined)).toBeFalsy(); + }); + + it('should be false when permissions is empty', () => { + expect(permissionUtils.checkFormManage([])).toBeFalsy(); + }); + + it('should be false when no appropriate permission exists', () => { + let permissions = new Array(FormPermissions) + .filter((p) => p !== FormPermissions.FORM_UPDATE) + .filter((p) => p !== FormPermissions.FORM_DELETE) + .filter((p) => p !== FormPermissions.DESIGN_UPDATE) + .filter((p) => p !== FormPermissions.DESIGN_DELETE) + .filter((p) => p !== FormPermissions.TEAM_UPDATE); + + expect(permissionUtils.checkFormManage(permissions)).not.toBeTruthy(); + }); + + it('should be true when at least one appropriate permission exists', () => { + expect( + permissionUtils.checkFormManage([FormPermissions.FORM_UPDATE]) + ).toBeTruthy(); + expect( + permissionUtils.checkFormManage([FormPermissions.FORM_DELETE]) + ).toBeTruthy(); + expect( + permissionUtils.checkFormManage([FormPermissions.DESIGN_UPDATE]) + ).toBeTruthy(); + expect( + permissionUtils.checkFormManage([FormPermissions.DESIGN_DELETE]) + ).toBeTruthy(); + expect( + permissionUtils.checkFormManage([FormPermissions.TEAM_UPDATE]) + ).toBeTruthy(); + }); +}); + +describe('checkSubmissionView', () => { + it('should be false when permissions is undefined', () => { + expect(permissionUtils.checkSubmissionView(undefined)).toBeFalsy(); + }); + + it('should be false when permissions is empty', () => { + expect(permissionUtils.checkSubmissionView([])).toBeFalsy(); + }); + + it('should be false when no appropriate permission exists', () => { + let permissions = new Array(FormPermissions) + .filter((p) => p !== FormPermissions.SUBMISSION_READ) + .filter((p) => p !== FormPermissions.SUBMISSION_UPDATE); + + expect(permissionUtils.checkSubmissionView(permissions)).not.toBeTruthy(); + }); + + it('should be true when at least one appropriate permission exists', () => { + expect( + permissionUtils.checkSubmissionView([FormPermissions.SUBMISSION_READ]) + ).toBeTruthy(); + expect( + permissionUtils.checkSubmissionView([FormPermissions.SUBMISSION_UPDATE]) + ).toBeTruthy(); + }); +}); + +describe('preFlightAuth', () => { + setActivePinia(createPinia()); + const authStore = useAuthStore(); + const notificationStore = useNotificationStore(); + const mockNext = vi.fn(); + const addNotificationSpy = vi.spyOn(notificationStore, 'addNotification'); + const alertNavigateSpy = vi.spyOn(notificationStore, 'alertNavigate'); + const errorNavigateSpy = vi.spyOn(notificationStore, 'errorNavigate'); + const getSubmissionOptionsSpy = vi.spyOn(formService, 'getSubmissionOptions'); + const readFormOptionsSpy = vi.spyOn(formService, 'readFormOptions'); + + beforeEach(() => { + authStore.$reset(); + notificationStore.$reset(); + mockNext.mockReset(); + addNotificationSpy.mockReset(); + alertNavigateSpy.mockReset(); + errorNavigateSpy.mockReset(); + getSubmissionOptionsSpy.mockReset(); + readFormOptionsSpy.mockReset(); + }); + + afterAll(() => { + mockNext.mockRestore(); + getSubmissionOptionsSpy.mockReset(); + readFormOptionsSpy.mockRestore(); + }); + + it('should create error notification if options are missing attributes', async () => { + await permissionUtils.preFlightAuth({}, mockNext); + expect(mockNext).toHaveBeenCalledTimes(0); + expect(getSubmissionOptionsSpy).toHaveBeenCalledTimes(0); + expect(readFormOptionsSpy).toHaveBeenCalledTimes(0); + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(errorNavigateSpy).toHaveBeenCalledTimes(1); + }); + + it('should create custom error message if form is 404', async () => { + authStore.authenticated = true; + authStore.keycloak = { + tokenParsed: { + identity_provider: IdentityProviders.PUBLIC, + }, + }; + + readFormOptionsSpy.mockImplementation(() => { + const error = new Error('Not Found'); + error.response = { + status: 404, + }; + + throw error; + }); + + await permissionUtils.preFlightAuth({ formId: 'f' }, mockNext); + + expect(getSubmissionOptionsSpy).toHaveBeenCalledTimes(0); + expect(readFormOptionsSpy).toHaveBeenCalledTimes(1); + expect(readFormOptionsSpy).toHaveBeenCalledWith('f'); + expect(mockNext).toHaveBeenCalledTimes(0); + expect(alertNavigateSpy).toHaveBeenCalledTimes(1); + }); + + it('should create custom error message if form is 422', async () => { + authStore.authenticated = true; + authStore.keycloak = { + tokenParsed: { + identity_provider: IdentityProviders.PUBLIC, + }, + }; + readFormOptionsSpy.mockImplementation(() => { + const error = new Error('Not Found'); + error.response = { + status: 422, + }; + + throw error; + }); + + await permissionUtils.preFlightAuth({ formId: 'f' }, mockNext); + + expect(getSubmissionOptionsSpy).toHaveBeenCalledTimes(0); + expect(readFormOptionsSpy).toHaveBeenCalledTimes(1); + expect(readFormOptionsSpy).toHaveBeenCalledWith('f'); + expect(mockNext).toHaveBeenCalledTimes(0); + expect(alertNavigateSpy).toHaveBeenCalledTimes(1); + }); + + it('should not create custom error message if form is 500', async () => { + authStore.authenticated = true; + authStore.keycloak = { + tokenParsed: { + identity_provider: IdentityProviders.PUBLIC, + }, + }; + const addNotificationSpy = vi.spyOn(notificationStore, 'addNotification'); + const errorNavigateSpy = vi.spyOn(notificationStore, 'errorNavigate'); + readFormOptionsSpy.mockImplementation(() => { + const error = new Error('Not Found'); + error.response = { + status: 500, + }; + + throw error; + }); + + await permissionUtils.preFlightAuth({ formId: 'f' }, mockNext); + + expect(getSubmissionOptionsSpy).toHaveBeenCalledTimes(0); + expect(readFormOptionsSpy).toHaveBeenCalledTimes(1); + expect(readFormOptionsSpy).toHaveBeenCalledWith('f'); + expect(mockNext).toHaveBeenCalledTimes(0); + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(errorNavigateSpy).toHaveBeenCalledTimes(1); + }); + + it('should not create custom error message if sub is missing', async () => { + authStore.authenticated = true; + authStore.keycloak = { + tokenParsed: { + identity_provider: IdentityProviders.PUBLIC, + }, + }; + const addNotificationSpy = vi.spyOn(notificationStore, 'addNotification'); + const errorNavigateSpy = vi.spyOn(notificationStore, 'errorNavigate'); + readFormOptionsSpy.mockImplementation(() => { + const error = new Error('Not Found'); + error.response = { + status: 404, + }; + + throw error; + }); + + await permissionUtils.preFlightAuth({ submissionId: 's' }, mockNext); + + expect(readFormOptionsSpy).toHaveBeenCalledTimes(0); + expect(getSubmissionOptionsSpy).toHaveBeenCalledTimes(1); + expect(getSubmissionOptionsSpy).toHaveBeenCalledWith('s'); + expect(mockNext).toHaveBeenCalledTimes(0); + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(errorNavigateSpy).toHaveBeenCalledTimes(1); + }); + + it('should call readFormOptions and next callback if authenticated and public', async () => { + authStore.authenticated = true; + authStore.keycloak = { + tokenParsed: { + identity_provider: IdentityProviders.PUBLIC, + }, + }; + readFormOptionsSpy.mockResolvedValue({ + data: { idpHints: [IdentityMode.PUBLIC] }, + }); + + await permissionUtils.preFlightAuth({ formId: 'f' }, mockNext); + + expect(mockNext).toHaveBeenCalledTimes(1); + expect(getSubmissionOptionsSpy).toHaveBeenCalledTimes(0); + expect(readFormOptionsSpy).toHaveBeenCalledTimes(1); + expect(readFormOptionsSpy).toHaveBeenCalledWith('f'); + }); + + it('should call readFormOptions and next callback if authenticated and idps match', async () => { + authStore.authenticated = true; + authStore.keycloak = { + tokenParsed: { + identity_provider: IdentityProviders.IDIR, + }, + }; + readFormOptionsSpy.mockResolvedValue({ + data: { idpHints: [IdentityProviders.IDIR] }, + }); + + await permissionUtils.preFlightAuth({ formId: 'f' }, mockNext); + + expect(mockNext).toHaveBeenCalledTimes(1); + expect(getSubmissionOptionsSpy).toHaveBeenCalledTimes(0); + expect(readFormOptionsSpy).toHaveBeenCalledTimes(1); + expect(readFormOptionsSpy).toHaveBeenCalledWith('f'); + }); + + it('should call readFormOptions and create error notification with idp mismatch', async () => { + authStore.authenticated = true; + authStore.keycloak = { + tokenParsed: { + identity_provider: IdentityProviders.IDIR, + }, + }; + const addNotificationSpy = vi.spyOn(notificationStore, 'addNotification'); + const errorNavigateSpy = vi.spyOn(notificationStore, 'errorNavigate'); + readFormOptionsSpy.mockResolvedValue({ + data: { idpHints: [IdentityProviders.BCEIDBASIC] }, + }); + + await permissionUtils.preFlightAuth({ formId: 'f' }, mockNext); + + expect(mockNext).toHaveBeenCalledTimes(0); + expect(addNotificationSpy).toHaveBeenCalledTimes(1); + expect(errorNavigateSpy).toHaveBeenCalledTimes(1); + expect(getSubmissionOptionsSpy).toHaveBeenCalledTimes(0); + expect(readFormOptionsSpy).toHaveBeenCalledTimes(1); + expect(readFormOptionsSpy).toHaveBeenCalledWith('f'); + }); + + it('should call getSubmissionOptions and next callback if not authenticated and public', async () => { + authStore.authenticated = false; + getSubmissionOptionsSpy.mockResolvedValue({ + data: { form: { idpHints: [IdentityMode.PUBLIC] } }, + }); + + await permissionUtils.preFlightAuth({ submissionId: 's' }, mockNext); + + expect(mockNext).toHaveBeenCalledTimes(1); + expect(getSubmissionOptionsSpy).toHaveBeenCalledTimes(1); + expect(getSubmissionOptionsSpy).toHaveBeenCalledWith('s'); + expect(readFormOptionsSpy).toHaveBeenCalledTimes(0); + }); + + it('should call getSubmissionOptions and login flow with idpHint', async () => { + authStore.authenticated = false; + getSubmissionOptionsSpy.mockResolvedValue({ + data: { form: { idpHints: [IdentityProviders.IDIR] } }, + }); + + await permissionUtils.preFlightAuth({ submissionId: 's' }, mockNext); + + expect(mockNext).toHaveBeenCalledTimes(0); + expect(getSubmissionOptionsSpy).toHaveBeenCalledTimes(1); + expect(getSubmissionOptionsSpy).toHaveBeenCalledWith('s'); + expect(readFormOptionsSpy).toHaveBeenCalledTimes(0); + }); + + it('should call getSubmissionOptions and login flow without idpHint', async () => { + authStore.authenticated = false; + getSubmissionOptionsSpy.mockResolvedValue({ + data: { form: { idpHints: ['idp'] } }, + }); + + await permissionUtils.preFlightAuth({ submissionId: 's' }, mockNext); + + expect(mockNext).toHaveBeenCalledTimes(0); + expect(getSubmissionOptionsSpy).toHaveBeenCalledTimes(1); + expect(getSubmissionOptionsSpy).toHaveBeenCalledWith('s'); + expect(readFormOptionsSpy).toHaveBeenCalledTimes(0); + }); +}); + +describe('isFormPublic', () => { + it('should be false when form is undefined', () => { + expect(permissionUtils.isFormPublic(undefined)).toBeFalsy(); + }); + + it('should be false when idps is undefined', () => { + expect(permissionUtils.isFormPublic({ blah: [] })).toBeFalsy(); + }); + + it('should be true when idps is public', () => { + expect( + permissionUtils.isFormPublic({ + identityProviders: [{ code: IdentityMode.PUBLIC }], + }) + ).toBeTruthy(); + }); + + it('should be true when idps includes public', () => { + expect( + permissionUtils.isFormPublic({ + identityProviders: [ + { code: IdentityMode.LOGIN }, + { code: IdentityMode.PUBLIC }, + ], + }) + ).toBeTruthy(); + }); + + it('should be false when idps has something else', () => { + expect( + permissionUtils.isFormPublic({ + identityProviders: [ + { code: IdentityMode.TEAM }, + { code: IdentityMode.LOGIN }, + ], + }) + ).toBeFalsy(); + }); +}); diff --git a/frontend/app/frontend/tests/unit/utils/transformUtils.spec.js b/frontend/app/frontend/tests/unit/utils/transformUtils.spec.js new file mode 100644 index 0000000..78d39ea --- /dev/null +++ b/frontend/app/frontend/tests/unit/utils/transformUtils.spec.js @@ -0,0 +1,89 @@ +import moment from 'moment'; +import { describe, expect, it } from 'vitest'; + +import { IdentityMode } from '~/utils/constants'; +import * as transformUtils from '~/utils/transformUtils'; + +describe('generateIdps', () => { + it('returns an empty array when empty object', () => { + expect(transformUtils.generateIdps({})).toEqual([]); + }); + + it('returns an empty array when usertype is team', () => { + expect( + transformUtils.generateIdps({ userType: IdentityMode.TEAM }) + ).toEqual([]); + }); + + it('returns correct values when usertype is login', () => { + expect( + transformUtils.generateIdps({ + idps: ['foo', 'bar'], + userType: IdentityMode.LOGIN, + }) + ).toEqual([{ code: 'foo' }, { code: 'bar' }]); + }); + + it('returns correct values when usertype is public', () => { + expect( + transformUtils.generateIdps({ userType: IdentityMode.PUBLIC }) + ).toEqual([{ code: IdentityMode.PUBLIC }]); + }); +}); + +describe('parseIdps', () => { + it('returns an empty array idps and usertype team when undefined', () => { + expect(transformUtils.parseIdps(undefined)).toEqual({ + idps: [], + userType: IdentityMode.TEAM, + }); + }); + + it('returns an empty array idps and usertype team when empty array', () => { + expect(transformUtils.parseIdps([])).toEqual({ + idps: [], + userType: IdentityMode.TEAM, + }); + }); + + it('returns an empty array idps and usertype public when public', () => { + expect(transformUtils.parseIdps([{ code: IdentityMode.PUBLIC }])).toEqual({ + idps: [], + userType: IdentityMode.PUBLIC, + }); + }); + + it('returns correct idps and usertype login when login', () => { + expect( + transformUtils.parseIdps([{ code: 'foo' }, { code: 'bar' }]) + ).toEqual({ + idps: ['foo', 'bar'], + userType: IdentityMode.LOGIN, + }); + }); +}); + +describe('calculateCloseDate', () => { + it('Returns Moment Object when supply Valid date(Moment OBJ),term(Int),interval(Str) as parameters.', () => { + expect(transformUtils.calculateCloseDate(moment(), 2, 'days')).toEqual( + expect.any(String) + ); + }); +}); + +describe('getCalculatedCloseSubmissionDate', () => { + it('Returns Moment Object when supply Valid data as parameters.', () => { + expect( + transformUtils.getCalculatedCloseSubmissionDate( + moment('2022-11-01'), + 1, + 'days', + 4, + 'days', + 1, + 'months', + moment('2023-02-03') + ) + ).toBeTruthy(); + }); +}); diff --git a/frontend/app/frontend/tests/unit/views/About.spec.js b/frontend/app/frontend/tests/unit/views/About.spec.js new file mode 100644 index 0000000..25f2caf --- /dev/null +++ b/frontend/app/frontend/tests/unit/views/About.spec.js @@ -0,0 +1,65 @@ +import { createTestingPinia } from '@pinia/testing'; +import { flushPromises, mount } from '@vue/test-utils'; +import { setActivePinia } from 'pinia'; +import { beforeEach, describe, expect, it } from 'vitest'; + +import { useAuthStore } from '~/store/auth'; +import About from '~/views/About.vue'; + +describe('About.vue', () => { + const pinia = createTestingPinia(); + setActivePinia(pinia); + + const authStore = useAuthStore(pinia); + + beforeEach(() => { + authStore.$reset(); + }); + + it('renders', () => { + const wrapper = mount(About, { + global: { + plugins: [pinia], + }, + }); + + expect(wrapper.text()).toMatch('trans.homePage.title'); + expect(wrapper.text()).toMatch('trans.homePage.subTitle'); + expect(wrapper.text()).toMatch('trans.homePage.takeATourOfChefs'); + expect(wrapper.text()).toMatch('trans.homePage.chefsHowToTitle'); + expect(wrapper.text()).toMatch('trans.homePage.chefsHowToSub'); + expect(wrapper.text()).toMatch('trans.homePage.getStarted'); + expect(wrapper.text()).toMatch('trans.homePage.createCustomFormTitle'); + expect(wrapper.text()).toMatch('trans.homePage.createCustomFormSub1'); + expect(wrapper.text()).toMatch('trans.homePage.manageAccessTitle'); + expect(wrapper.text()).toMatch('trans.homePage.manageAccessSub1'); + expect(wrapper.text()).toMatch('trans.homePage.manageAccessSub2'); + expect(wrapper.text()).toMatch('trans.homePage.getStartedToChefs'); + expect(wrapper.text()).toMatch('trans.homePage.createOnlineTitle'); + }); + + it('renders with login button', () => { + const wrapper = mount(About, { + global: { + plugins: [pinia], + }, + }); + + const createOrLoginBtn = wrapper.find('[data-test="create-or-login-btn"]'); + expect(createOrLoginBtn.exists()).toBeTruthy(); + expect(createOrLoginBtn.text()).toMatch('trans.homePage.loginToStart'); + }); + + it('renders with create form button', () => { + authStore.authenticated = true; + const wrapper = mount(About, { + global: { + plugins: [pinia], + }, + }); + + const createOrLoginBtn = wrapper.find('[data-test="create-or-login-btn"]'); + expect(createOrLoginBtn.exists()).toBeTruthy(); + expect(createOrLoginBtn.text()).toMatch('trans.homePage.createFormLabel'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/views/Admin.spec.js b/frontend/app/frontend/tests/unit/views/Admin.spec.js new file mode 100644 index 0000000..1bf04e2 --- /dev/null +++ b/frontend/app/frontend/tests/unit/views/Admin.spec.js @@ -0,0 +1,40 @@ +import { createTestingPinia } from '@pinia/testing'; +import { mount } from '@vue/test-utils'; +import { setActivePinia } from 'pinia'; +import { beforeEach, describe, expect, it } from 'vitest'; +import { nextTick } from 'vue'; + +import { useAuthStore } from '~/store/auth'; +import Admin from '~/views/Admin.vue'; + +describe('Admin.vue', () => { + const pinia = createTestingPinia(); + setActivePinia(pinia); + + const authStore = useAuthStore(pinia); + + beforeEach(() => { + authStore.$reset(); + }); + + it('renders', async () => { + authStore.isAdmin = true; + const wrapper = mount(Admin, { + global: { + plugins: [pinia], + stubs: { + RouterView: true, + BaseSecure: { + name: 'BaseSecure', + template: '
', + }, + }, + }, + }); + + await nextTick(); + + expect(wrapper.html()).toMatch('v-container'); + expect(wrapper.html()).toMatch('router-view'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/views/Error.spec.js b/frontend/app/frontend/tests/unit/views/Error.spec.js new file mode 100644 index 0000000..3c1a4ca --- /dev/null +++ b/frontend/app/frontend/tests/unit/views/Error.spec.js @@ -0,0 +1,52 @@ +import { createTestingPinia } from '@pinia/testing'; +import { mount } from '@vue/test-utils'; +import { setActivePinia } from 'pinia'; +import { beforeEach, describe, expect, it } from 'vitest'; +import { nextTick } from 'vue'; + +import { useAuthStore } from '~/store/auth'; +import Error from '~/views/Error.vue'; + +describe('Error.vue', () => { + const pinia = createTestingPinia(); + setActivePinia(pinia); + + const authStore = useAuthStore(pinia); + + beforeEach(() => { + authStore.$reset(); + }); + + it('renders', async () => { + const wrapper = mount(Error, { + global: { + plugins: [pinia], + stubs: { + RouterLink: true, + }, + }, + }); + + await nextTick(); + + expect(wrapper.text()).toMatch('trans.error.somethingWentWrong'); + }); + + it('renders with a custom error message', async () => { + const wrapper = mount(Error, { + props: { + text: 'Custom Error Message', + }, + global: { + plugins: [pinia], + stubs: { + RouterLink: true, + }, + }, + }); + + await nextTick(); + + expect(wrapper.text()).toMatch('Custom Error Message'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/views/Form.spec.js b/frontend/app/frontend/tests/unit/views/Form.spec.js new file mode 100644 index 0000000..4d84e20 --- /dev/null +++ b/frontend/app/frontend/tests/unit/views/Form.spec.js @@ -0,0 +1,18 @@ +import { mount } from '@vue/test-utils'; +import { describe, expect, it } from 'vitest'; + +import Form from '~/views/Form.vue'; + +describe('Form.vue', () => { + it('renders', () => { + const wrapper = mount(Form, { + global: { + stubs: { + RouterView: true, + }, + }, + }); + + expect(wrapper.html()).toMatch('router-view'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/views/Login.spec.js b/frontend/app/frontend/tests/unit/views/Login.spec.js new file mode 100644 index 0000000..30dbbcc --- /dev/null +++ b/frontend/app/frontend/tests/unit/views/Login.spec.js @@ -0,0 +1,74 @@ +import { createTestingPinia } from '@pinia/testing'; +import { mount } from '@vue/test-utils'; +import { setActivePinia } from 'pinia'; +import { beforeEach, describe, expect, it } from 'vitest'; +import { nextTick } from 'vue'; + +import { useAuthStore } from '~/store/auth'; +import Login from '~/views/Login.vue'; +import { IdentityProviders } from '~/utils/constants'; + +describe('Login.vue', () => { + const pinia = createTestingPinia(); + setActivePinia(pinia); + + const authStore = useAuthStore(pinia); + + beforeEach(() => { + authStore.$reset(); + }); + + it('shows error if keycloak is not ready', async () => { + const wrapper = mount(Login, { + global: { + plugins: [pinia], + stubs: { + RouterLink: true, + }, + }, + }); + + await nextTick(); + + expect(wrapper.text()).toMatch( + 'Identity and Access Management not ready, please contact technical support.' + ); + }); + + it('shows already logged in if ready and authenticated', async () => { + authStore.authenticated = true; + authStore.ready = true; + const wrapper = mount(Login, { + global: { + plugins: [pinia], + stubs: { + RouterLink: true, + }, + }, + }); + + await nextTick(); + + expect(wrapper.text()).toMatch('trans.login.alreadyLoggedIn'); + }); + + it('shows login options', async () => { + authStore.authenticated = false; + authStore.ready = true; + const wrapper = mount(Login, { + global: { + plugins: [pinia], + stubs: { + RouterLink: true, + }, + }, + }); + + await nextTick(); + + Object.values(IdentityProviders).forEach((idp) => { + const button = wrapper.find(`[data-test="${idp}"]`); + expect(button.exists()).toBeTruthy(); + }); + }); +}); diff --git a/frontend/app/frontend/tests/unit/views/NotFound.spec.js b/frontend/app/frontend/tests/unit/views/NotFound.spec.js new file mode 100644 index 0000000..4bda126 --- /dev/null +++ b/frontend/app/frontend/tests/unit/views/NotFound.spec.js @@ -0,0 +1,24 @@ +import { createTestingPinia } from '@pinia/testing'; +import { mount } from '@vue/test-utils'; +import { setActivePinia } from 'pinia'; +import { describe, expect, it } from 'vitest'; + +import NotFound from '~/views/NotFound.vue'; + +describe('NotFound.vue', () => { + const pinia = createTestingPinia(); + setActivePinia(pinia); + + it('renders', () => { + const wrapper = mount(NotFound, { + global: { + stubs: { + RouterLink: true, + }, + plugins: [pinia], + }, + }); + + expect(wrapper.text()).toMatch('trans.notFound.pageNotFound'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/views/User.spec.js b/frontend/app/frontend/tests/unit/views/User.spec.js new file mode 100644 index 0000000..37c019a --- /dev/null +++ b/frontend/app/frontend/tests/unit/views/User.spec.js @@ -0,0 +1,18 @@ +import { mount } from '@vue/test-utils'; +import { describe, expect, it } from 'vitest'; + +import User from '~/views/User.vue'; + +describe('User.vue', () => { + it('renders', () => { + const wrapper = mount(User, { + global: { + stubs: { + RouterView: true, + }, + }, + }); + + expect(wrapper.html()).toMatch('router-view'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/views/admin/Form.spec.js b/frontend/app/frontend/tests/unit/views/admin/Form.spec.js new file mode 100644 index 0000000..209d11c --- /dev/null +++ b/frontend/app/frontend/tests/unit/views/admin/Form.spec.js @@ -0,0 +1,28 @@ +import { createTestingPinia } from '@pinia/testing'; +import { mount } from '@vue/test-utils'; +import { setActivePinia } from 'pinia'; +import { describe, expect, it } from 'vitest'; + +import Form from '~/views/admin/Form.vue'; + +describe('Form.vue', () => { + const pinia = createTestingPinia(); + setActivePinia(pinia); + + it('renders', () => { + const wrapper = mount(Form, { + props: { + f: 'f', + }, + global: { + stubs: { + AdministerForm: true, + }, + plugins: [pinia], + }, + }); + + expect(wrapper.text()).toMatch('trans.admin.form.administerForm'); + expect(wrapper.html()).toMatch('administer-form'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/views/admin/Root.spec.js b/frontend/app/frontend/tests/unit/views/admin/Root.spec.js new file mode 100644 index 0000000..771a856 --- /dev/null +++ b/frontend/app/frontend/tests/unit/views/admin/Root.spec.js @@ -0,0 +1,28 @@ +import { createTestingPinia } from '@pinia/testing'; +import { mount } from '@vue/test-utils'; +import { setActivePinia } from 'pinia'; +import { describe, expect, it } from 'vitest'; + +import Root from '~/views/admin/Root.vue'; + +describe('Root.vue', () => { + const pinia = createTestingPinia(); + setActivePinia(pinia); + + it('renders', () => { + const wrapper = mount(Root, { + props: { + f: 'f', + }, + global: { + stubs: { + AdminPage: true, + }, + plugins: [pinia], + }, + }); + + expect(wrapper.text()).toMatch('trans.admin.root.admin'); + expect(wrapper.html()).toMatch('admin-page'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/views/admin/User.spec.js b/frontend/app/frontend/tests/unit/views/admin/User.spec.js new file mode 100644 index 0000000..b603057 --- /dev/null +++ b/frontend/app/frontend/tests/unit/views/admin/User.spec.js @@ -0,0 +1,28 @@ +import { createTestingPinia } from '@pinia/testing'; +import { mount } from '@vue/test-utils'; +import { setActivePinia } from 'pinia'; +import { describe, expect, it } from 'vitest'; + +import User from '~/views/admin/User.vue'; + +describe('User.vue', () => { + const pinia = createTestingPinia(); + setActivePinia(pinia); + + it('renders', () => { + const wrapper = mount(User, { + props: { + u: 'u', + }, + global: { + stubs: { + AdministerUser: true, + }, + plugins: [pinia], + }, + }); + + expect(wrapper.text()).toMatch('trans.admin.user.administerUser'); + expect(wrapper.html()).toMatch('administer-user'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/views/file/Download.spec.js b/frontend/app/frontend/tests/unit/views/file/Download.spec.js new file mode 100644 index 0000000..1e5e7aa --- /dev/null +++ b/frontend/app/frontend/tests/unit/views/file/Download.spec.js @@ -0,0 +1,125 @@ +// @vitest-environment happy-dom +// happy-dom is required to access window.URL + +import { createTestingPinia } from '@pinia/testing'; +import { flushPromises, mount } from '@vue/test-utils'; +import { setActivePinia } from 'pinia'; +import { describe, expect, it, vi } from 'vitest'; + +import { useFormStore } from '~/store/form'; +import { useNotificationStore } from '~/store/notification'; +import Download from '~/views/file/Download.vue'; + +describe('Download.vue', () => { + const pinia = createTestingPinia(); + setActivePinia(pinia); + const formStore = useFormStore(pinia); + const notificationStore = useNotificationStore(pinia); + + beforeEach(() => { + formStore.$reset(); + notificationStore.$reset(); + }); + + it('renders and downloads json', async () => { + const getFileSpy = vi.spyOn(Download.methods, 'getFile'); + vi.spyOn(window.URL, 'createObjectURL').mockImplementation(() => { + return '#'; + }); + formStore.downloadFile.mockImplementation(() => {}); + formStore.downloadedFile = { + data: '{}', + headers: { + 'content-type': 'application/json', + 'content-disposition': 'attachment; filename=test.csv', + }, + }; + const wrapper = mount(Download, { + props: { + id: '1', + }, + global: { + stubs: { + BaseSecure: { + name: 'BaseSecure', + template: '
', + }, + FormSubmission: true, + }, + plugins: [pinia], + }, + }); + + await flushPromises(); + + expect(wrapper.html()).toMatch('base-secure'); + expect(wrapper.html()).toMatch('trans.download.chefsDataExport'); + expect(wrapper.html()).not.toMatch( + 'trans.download.preparingForDownloading' + ); + expect(getFileSpy).toHaveBeenCalledTimes(1); + }); + + /* it('renders and downloads some file', async () => { + const getFileSpy = vi.spyOn(Download.methods, 'getFile'); + vi.spyOn(window.URL, 'createObjectURL').mockImplementation(() => { + return '#'; + }); + formStore.downloadFile.mockImplementation(() => {}); + formStore.downloadedFile = { + data: '{}', + headers: { + 'content-type': 'text/plain', + 'content-disposition': 'attachment; filename=test.txt', + }, + }; + const wrapper = mount(Download, { + props: { + id: '1', + }, + global: { + stubs: { + BaseSecure: { + name: 'BaseSecure', + template: '
', + }, + FormSubmission: true, + }, + }, + }); + + await flushPromises(); + + expect(wrapper.html()).toMatch('base-secure'); + expect(wrapper.html()).toMatch('CHEFS Data Export'); + expect(wrapper.html()).not.toMatch('Preparing for download...'); + expect(getFileSpy).toHaveBeenCalledTimes(1); + }); */ + + it('does not render if failed download', async () => { + const getFileSpy = vi.spyOn(Download.methods, 'getFile'); + formStore.downloadFile.mockImplementation(() => {}); + const wrapper = mount(Download, { + props: { + id: '1', + }, + global: { + stubs: { + BaseSecure: { + name: 'BaseSecure', + template: '
', + }, + FormSubmission: true, + }, + plugins: [pinia], + }, + }); + + await flushPromises(); + + expect(wrapper.html()).toMatch('base-secure'); + expect(wrapper.html()).toMatch('trans.download.chefsDataExport'); + expect(wrapper.html()).toMatch('trans.download.preparingForDownloading'); + expect(getFileSpy).toHaveBeenCalledTimes(1); + }); +}); diff --git a/frontend/app/frontend/tests/unit/views/form/Create.spec.js b/frontend/app/frontend/tests/unit/views/form/Create.spec.js new file mode 100644 index 0000000..42ec72f --- /dev/null +++ b/frontend/app/frontend/tests/unit/views/form/Create.spec.js @@ -0,0 +1,293 @@ +// @vitest-environment happy-dom +// happy-dom is required to access window.confirm + +import { createTestingPinia } from '@pinia/testing'; +import { flushPromises, mount } from '@vue/test-utils'; +import { setActivePinia } from 'pinia'; +import { afterAll, beforeEach, describe, expect, it, vi } from 'vitest'; + +import { useFormStore } from '~/store/form'; +import Create from '~/views/form/Create.vue'; +import { IdentityMode } from '~/utils/constants'; +import { nextTick } from 'vue'; + +describe('Create.vue', () => { + const onFormLoad = vi.fn(); + const mockWindowConfirm = vi.spyOn(window, 'confirm'); + const pinia = createTestingPinia(); + setActivePinia(pinia); + + const formStore = useFormStore(pinia); + + beforeEach(() => { + formStore.$reset(); + mockWindowConfirm.mockReset(); + }); + + afterAll(() => { + mockWindowConfirm.mockRestore(); + }); + + it('renders first page', async () => { + formStore.form = { + userType: IdentityMode.TEAM, + }; + const wrapper = mount(Create, { + global: { + plugins: [pinia], + stubs: { + FormSettings: { + name: 'FormSettings', + template: '
', + }, + BaseStepper: { + name: 'BaseStepper', + template: '
', + }, + BasePanel: { + name: 'BasePanel', + template: '
', + }, + FormDisclaimer: true, + FormDesigner: { + name: 'FormDesigner', + methods: { + onFormLoad, + }, + template: '
', + }, + VForm: { + name: 'VForm', + template: '
', + }, + VStepper: { + name: 'VStepper', + template: '
', + }, + VStepperWindow: { + name: 'VStepperWindow', + template: '
', + }, + VStepperHeader: { + name: 'VStepperHeader', + template: '
', + }, + VStepperWindowItem: { + name: 'VStepperWindowItem', + template: '
', + }, + VStepperItem: { + name: 'VStepperItem', + template: '
', + }, + }, + }, + }); + + await flushPromises(); + + expect(wrapper.html()).toMatch('form-settings'); + expect(wrapper.html()).toMatch('form-disclaimer'); + expect(wrapper.find('button').text()).toMatch('trans.create.continue'); + + formStore.$patch({ + form: { + userType: IdentityMode.LOGIN, + }, + }); + + await nextTick(); + }); + + it('renders second page', async () => { + const wrapper = mount(Create, { + data() { + return { + creatorStep: 2, + }; + }, + global: { + plugins: [pinia], + stubs: { + BaseStepper: { + name: 'BaseStepper', + template: '
', + }, + FormSettings: { + name: 'FormSettings', + template: '
', + }, + BasePanel: { + name: 'BasePanel', + template: '
', + }, + FormDisclaimer: true, + FormDesigner: { + name: 'FormDesigner', + methods: { + onFormLoad, + }, + template: '
', + }, + VStepper: { + name: 'VStepper', + template: '
', + }, + VStepperWindow: { + name: 'VStepperWindow', + template: '
', + }, + VStepperHeader: { + name: 'VStepperHeader', + template: '
', + }, + VStepperWindowItem: { + name: 'VStepperWindowItem', + template: '
', + }, + VStepperItem: { + name: 'VStepperItem', + template: '
', + }, + }, + }, + }); + + await flushPromises(); + + expect(wrapper.html()).toMatch('form-designer'); + expect(wrapper.find('button').text()).toMatch('trans.create.continue'); + }); + + it('continue and back button works', async () => { + const wrapper = mount(Create, { + data() { + return { + creatorStep: 1, + settingsFormValid: true, + }; + }, + global: { + plugins: [pinia], + stubs: { + BaseStepper: { + name: 'BaseStepper', + template: '
', + }, + FormSettings: { + name: 'FormSettings', + template: '
', + }, + BasePanel: { + name: 'BasePanel', + template: '
', + }, + FormDisclaimer: true, + FormDesigner: { + name: 'FormDesigner', + methods: { + onFormLoad, + }, + template: '
', + }, + VForm: true, + VStepper: { + name: 'VStepper', + template: '
', + }, + VStepperWindow: { + name: 'VStepperWindow', + template: '
', + }, + VStepperHeader: { + name: 'VStepperHeader', + template: '
', + }, + VStepperWindowItem: { + name: 'VStepperWindowItem', + template: '
', + }, + VStepperItem: { + name: 'VStepperItem', + template: '
', + }, + }, + }, + }); + + await flushPromises(); + + const continueBtn = wrapper.find('[data-test="continue-btn"]'); + expect(continueBtn.text()).toMatch('trans.create.continue'); + await continueBtn.trigger('click'); + await flushPromises(); + const backBtn = wrapper.find('[data-test="back-btn"]'); + expect(wrapper.html()).toMatch('form-designer'); + expect(backBtn.text()).toMatch('trans.create.back'); + await backBtn.trigger('click'); + await flushPromises(); + expect(wrapper.html()).toMatch('v-form-stub'); + expect(wrapper.html()).toMatch('trans.create.continue'); + }); + + it('beforeRouteLeave guard works when not dirty', () => { + const next = vi.fn(); + const wrapper = mount(Create, { + data() { + return { + creatorStep: 2, + }; + }, + global: { + plugins: [pinia], + stubs: { + BaseStepper: { + name: 'BaseStepper', + template: '
', + }, + FormSettings: { + name: 'FormSettings', + template: '
', + }, + BasePanel: { + name: 'BasePanel', + template: '
', + }, + FormDisclaimer: true, + FormDesigner: { + name: 'FormDesigner', + methods: { + onFormLoad, + }, + template: '
', + }, + VStepper: { + name: 'VStepper', + template: '
', + }, + VStepperWindow: { + name: 'VStepperWindow', + template: '
', + }, + VStepperHeader: { + name: 'VStepperHeader', + template: '
', + }, + VStepperWindowItem: { + name: 'VStepperWindowItem', + template: '
', + }, + VStepperItem: { + name: 'VStepperItem', + template: '
', + }, + }, + }, + }); + + Create.beforeRouteLeave.call(wrapper.vm, undefined, undefined, next); + + expect(next).toHaveBeenCalledTimes(1); + expect(mockWindowConfirm).toHaveBeenCalledTimes(0); + }); +}); diff --git a/frontend/app/frontend/tests/unit/views/form/Design.spec.js b/frontend/app/frontend/tests/unit/views/form/Design.spec.js new file mode 100644 index 0000000..ca113b2 --- /dev/null +++ b/frontend/app/frontend/tests/unit/views/form/Design.spec.js @@ -0,0 +1,116 @@ +// @vitest-environment happy-dom +// happy-dom is required to access window.confirm + +import { createTestingPinia } from '@pinia/testing'; +import { mount } from '@vue/test-utils'; +import { setActivePinia } from 'pinia'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; + +import { useFormStore } from '~/store/form'; +import Design from '~/views/form/Design.vue'; + +describe('Design.vue', () => { + const onFormLoad = vi.fn(); + const mockWindowConfirm = vi.spyOn(window, 'confirm'); + const pinia = createTestingPinia(); + setActivePinia(pinia); + + const formStore = useFormStore(pinia); + + beforeEach(() => { + formStore.$reset(); + mockWindowConfirm.mockReset(); + }); + + afterAll(() => { + mockWindowConfirm.mockRestore(); + }); + + it('renders', async () => { + const wrapper = mount(Design, { + global: { + plugins: [pinia], + stubs: { + BaseStepper: { + name: 'BaseStepper', + template: '
', + }, + FormDesigner: { + name: 'FormDesigner', + methods: { + onFormLoad, + }, + template: '
', + }, + }, + }, + }); + + expect(wrapper.html()).toMatch('base-stepper'); + }); + + it('beforeRouteLeave guard works when not dirty', () => { + const next = vi.fn(); + formStore.form = { + isDirty: false, + }; + const wrapper = mount(Design, { + data() { + return { + step: 2, + }; + }, + global: { + plugins: [pinia], + stubs: { + BaseStepper: { + name: 'BaseStepper', + template: '
', + }, + FormDesigner: { + name: 'FormDesigner', + methods: { + onFormLoad, + }, + template: '
', + }, + }, + }, + }); + + Design.beforeRouteLeave.call(wrapper.vm, undefined, undefined, next); + + expect(next).toHaveBeenCalledTimes(1); + expect(mockWindowConfirm).toHaveBeenCalledTimes(0); + }); + + it('beforeRouteLeave guard works when not dirty', () => { + const next = vi.fn(); + formStore.form = { + isDirty: true, + }; + const wrapper = mount(Design, { + global: { + plugins: [pinia], + stubs: { + BaseStepper: { + name: 'BaseStepper', + template: '
', + }, + FormDesigner: { + name: 'FormDesigner', + methods: { + onFormLoad, + }, + template: '
', + }, + }, + }, + }); + + Design.beforeRouteLeave.call(wrapper.vm, undefined, undefined, next); + + expect(next).toHaveBeenCalledTimes(1); + expect(mockWindowConfirm).toHaveBeenCalledTimes(1); + }); +}); diff --git a/frontend/app/frontend/tests/unit/views/form/Export.spec.js b/frontend/app/frontend/tests/unit/views/form/Export.spec.js new file mode 100644 index 0000000..97d064f --- /dev/null +++ b/frontend/app/frontend/tests/unit/views/form/Export.spec.js @@ -0,0 +1,26 @@ +import { mount } from '@vue/test-utils'; +import { describe, expect, it } from 'vitest'; + +import Export from '~/views/form/Export.vue'; + +describe('Export.vue', () => { + it('renders', () => { + const wrapper = mount(Export, { + props: { + f: 'f', + }, + global: { + stubs: { + BaseSecure: { + name: 'BaseSecure', + template: '
', + }, + ExportSubmissions: true, + }, + }, + }); + + expect(wrapper.html()).toMatch('base-secure'); + expect(wrapper.html()).toMatch('export-submissions'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/views/form/Manage.spec.js b/frontend/app/frontend/tests/unit/views/form/Manage.spec.js new file mode 100644 index 0000000..4bba70a --- /dev/null +++ b/frontend/app/frontend/tests/unit/views/form/Manage.spec.js @@ -0,0 +1,26 @@ +import { mount } from '@vue/test-utils'; +import { describe, expect, it } from 'vitest'; + +import Manage from '~/views/form/Manage.vue'; + +describe('Manage.vue', () => { + it('renders', () => { + const wrapper = mount(Manage, { + props: { + f: 'f', + }, + global: { + stubs: { + BaseSecure: { + name: 'BaseSecure', + template: '
', + }, + ManageLayout: true, + }, + }, + }); + + expect(wrapper.html()).toMatch('base-secure'); + expect(wrapper.html()).toMatch('manage-layout'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/views/form/Preview.spec.js b/frontend/app/frontend/tests/unit/views/form/Preview.spec.js new file mode 100644 index 0000000..9a7f8d9 --- /dev/null +++ b/frontend/app/frontend/tests/unit/views/form/Preview.spec.js @@ -0,0 +1,40 @@ +import { createTestingPinia } from '@pinia/testing'; +import { mount } from '@vue/test-utils'; +import { setActivePinia } from 'pinia'; +import { describe, expect, it } from 'vitest'; + +import Preview from '~/views/form/Preview.vue'; + +describe('Preview.vue', () => { + const pinia = createTestingPinia(); + setActivePinia(pinia); + + it('renders', () => { + const wrapper = mount(Preview, { + props: { + f: 'f', + d: 'd', + v: 'v', + }, + global: { + stubs: { + BaseSecure: { + name: 'BaseSecure', + template: '
', + }, + FormViewer: true, + VTooltip: { + name: 'VTooltip', + template: '
', + }, + }, + plugins: [pinia], + }, + }); + + expect(wrapper.html()).toMatch('base-secure'); + expect(wrapper.html()).toMatch('trans.preview.preview'); + expect(wrapper.html()).toMatch('trans.preview.previewToolTip'); + expect(wrapper.html()).toMatch('form-viewer'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/views/form/Submissions.spec.js b/frontend/app/frontend/tests/unit/views/form/Submissions.spec.js new file mode 100644 index 0000000..1627ec0 --- /dev/null +++ b/frontend/app/frontend/tests/unit/views/form/Submissions.spec.js @@ -0,0 +1,26 @@ +import { mount } from '@vue/test-utils'; +import { describe, expect, it } from 'vitest'; + +import Submissions from '~/views/form/Submissions.vue'; + +describe('Submissions.vue', () => { + it('renders', () => { + const wrapper = mount(Submissions, { + props: { + f: 'f', + }, + global: { + stubs: { + BaseSecure: { + name: 'BaseSecure', + template: '
', + }, + SubmissionsTable: true, + }, + }, + }); + + expect(wrapper.html()).toMatch('base-secure'); + expect(wrapper.html()).toMatch('submissions-table'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/views/form/Submit.spec.js b/frontend/app/frontend/tests/unit/views/form/Submit.spec.js new file mode 100644 index 0000000..a0d368a --- /dev/null +++ b/frontend/app/frontend/tests/unit/views/form/Submit.spec.js @@ -0,0 +1,21 @@ +import { mount } from '@vue/test-utils'; +import { describe, expect, it } from 'vitest'; + +import Submit from '~/views/form/Submit.vue'; + +describe('Submit.vue', () => { + it('renders', () => { + const wrapper = mount(Submit, { + props: { + f: 'f', + }, + global: { + stubs: { + FormViewer: true, + }, + }, + }); + + expect(wrapper.html()).toMatch('form-viewer'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/views/form/Success.spec.js b/frontend/app/frontend/tests/unit/views/form/Success.spec.js new file mode 100644 index 0000000..ba704e6 --- /dev/null +++ b/frontend/app/frontend/tests/unit/views/form/Success.spec.js @@ -0,0 +1,25 @@ +import { mount } from '@vue/test-utils'; +import { describe, expect, it } from 'vitest'; +import { nextTick } from 'vue'; + +import Success from '~/views/form/Success.vue'; + +describe('Success.vue', () => { + it('renders', async () => { + const wrapper = mount(Success, { + props: { + s: 's', + }, + global: { + stubs: { + FormViewer: true, + RequestReceipt: true, + }, + }, + }); + + await nextTick(); + + expect(wrapper.html()).toMatch('form-viewer'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/views/form/Teams.spec.js b/frontend/app/frontend/tests/unit/views/form/Teams.spec.js new file mode 100644 index 0000000..aea15ab --- /dev/null +++ b/frontend/app/frontend/tests/unit/views/form/Teams.spec.js @@ -0,0 +1,26 @@ +import { mount } from '@vue/test-utils'; +import { describe, expect, it } from 'vitest'; + +import Teams from '~/views/form/Teams.vue'; + +describe('Teams.vue', () => { + it('renders', () => { + const wrapper = mount(Teams, { + props: { + f: 'f', + }, + global: { + stubs: { + BaseSecure: { + name: 'BaseSecure', + template: '
', + }, + TeamManagement: true, + }, + }, + }); + + expect(wrapper.html()).toMatch('base-secure'); + expect(wrapper.html()).toMatch('team-management'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/views/form/View.spec.js b/frontend/app/frontend/tests/unit/views/form/View.spec.js new file mode 100644 index 0000000..1304a56 --- /dev/null +++ b/frontend/app/frontend/tests/unit/views/form/View.spec.js @@ -0,0 +1,26 @@ +import { mount } from '@vue/test-utils'; +import { describe, expect, it } from 'vitest'; + +import View from '~/views/form/View.vue'; + +describe('View.vue', () => { + it('renders', () => { + const wrapper = mount(View, { + props: { + s: 's', + }, + global: { + stubs: { + BaseSecure: { + name: 'BaseSecure', + template: '
', + }, + FormSubmission: true, + }, + }, + }); + + expect(wrapper.html()).toMatch('base-secure'); + expect(wrapper.html()).toMatch('form-submission'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/views/user/Forms.spec.js b/frontend/app/frontend/tests/unit/views/user/Forms.spec.js new file mode 100644 index 0000000..ef99306 --- /dev/null +++ b/frontend/app/frontend/tests/unit/views/user/Forms.spec.js @@ -0,0 +1,18 @@ +import { mount } from '@vue/test-utils'; +import { describe, expect, it } from 'vitest'; + +import Forms from '~/views/user/Forms.vue'; + +describe('Forms.vue', () => { + it('renders', () => { + const wrapper = mount(Forms, { + global: { + stubs: { + FormsTable: true, + }, + }, + }); + + expect(wrapper.html()).toMatch('forms-table'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/views/user/History.spec.js b/frontend/app/frontend/tests/unit/views/user/History.spec.js new file mode 100644 index 0000000..ec194be --- /dev/null +++ b/frontend/app/frontend/tests/unit/views/user/History.spec.js @@ -0,0 +1,27 @@ +import { createTestingPinia } from '@pinia/testing'; +import { mount } from '@vue/test-utils'; +import { setActivePinia } from 'pinia'; +import { describe, expect, it } from 'vitest'; + +import History from '~/views/user/History.vue'; + +describe('History.vue', () => { + const pinia = createTestingPinia(); + setActivePinia(pinia); + + it('renders', () => { + const wrapper = mount(History, { + global: { + stubs: { + BaseSecure: { + name: 'BaseSecure', + template: '
', + }, + }, + plugins: [pinia], + }, + }); + + expect(wrapper.text()).toMatch('trans.history.submissnHistory'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/views/user/Root.spec.js b/frontend/app/frontend/tests/unit/views/user/Root.spec.js new file mode 100644 index 0000000..fe6698d --- /dev/null +++ b/frontend/app/frontend/tests/unit/views/user/Root.spec.js @@ -0,0 +1,37 @@ +import { createTestingPinia } from '@pinia/testing'; +import { mount } from '@vue/test-utils'; +import { setActivePinia } from 'pinia'; +import { describe, expect, it } from 'vitest'; + +import Root from '~/views/user/Root.vue'; + +describe('Root.vue', () => { + const pinia = createTestingPinia(); + setActivePinia(pinia); + + it('renders', () => { + const wrapper = mount(Root, { + global: { + stubs: { + BaseSecure: { + name: 'BaseSecure', + template: '
', + }, + RouterLink: { + name: 'RouterLink', + template: '', + }, + }, + plugins: [pinia], + }, + }); + + expect(wrapper.find('h1').text()).toMatch('trans.user.root.user'); + expect(wrapper.find('[data-test="my-forms-btn"]').text()).toMatch( + 'trans.user.root.myForms' + ); + expect(wrapper.find('[data-test="history-btn"]').text()).toMatch( + 'trans.user.root.history' + ); + }); +}); diff --git a/frontend/app/frontend/tests/unit/views/user/SubmissionDraftEdit.spec.js b/frontend/app/frontend/tests/unit/views/user/SubmissionDraftEdit.spec.js new file mode 100644 index 0000000..caf1419 --- /dev/null +++ b/frontend/app/frontend/tests/unit/views/user/SubmissionDraftEdit.spec.js @@ -0,0 +1,21 @@ +import { mount } from '@vue/test-utils'; +import { describe, expect, it } from 'vitest'; + +import SubmissionDraftEdit from '~/views/user/SubmissionDraftEdit.vue'; + +describe('SubmissionDraftEdit.vue', () => { + it('renders', () => { + const wrapper = mount(SubmissionDraftEdit, { + props: { + s: 's', + }, + global: { + stubs: { + UserSubmission: true, + }, + }, + }); + + expect(wrapper.html()).toMatch('user-submission'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/views/user/SubmissionDuplicate.spec.js b/frontend/app/frontend/tests/unit/views/user/SubmissionDuplicate.spec.js new file mode 100644 index 0000000..9349f40 --- /dev/null +++ b/frontend/app/frontend/tests/unit/views/user/SubmissionDuplicate.spec.js @@ -0,0 +1,22 @@ +import { mount } from '@vue/test-utils'; +import { describe, expect, it } from 'vitest'; + +import SubmissionDuplicate from '~/views/user/SubmissionDuplicate.vue'; + +describe('SubmissionDuplicate.vue', () => { + it('renders', () => { + const wrapper = mount(SubmissionDuplicate, { + props: { + s: 's', + f: 'f', + }, + global: { + stubs: { + UserDuplicateSubmission: true, + }, + }, + }); + + expect(wrapper.html()).toMatch('user-duplicate-submission'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/views/user/SubmissionView.spec.js b/frontend/app/frontend/tests/unit/views/user/SubmissionView.spec.js new file mode 100644 index 0000000..7884b5a --- /dev/null +++ b/frontend/app/frontend/tests/unit/views/user/SubmissionView.spec.js @@ -0,0 +1,21 @@ +import { mount } from '@vue/test-utils'; +import { describe, expect, it } from 'vitest'; + +import SubmissionView from '~/views/user/SubmissionView.vue'; + +describe('SubmissionView.vue', () => { + it('renders', () => { + const wrapper = mount(SubmissionView, { + props: { + s: 's', + }, + global: { + stubs: { + FormSubmission: true, + }, + }, + }); + + expect(wrapper.html()).toMatch('form-submission'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/views/user/Submissions.spec.js b/frontend/app/frontend/tests/unit/views/user/Submissions.spec.js new file mode 100644 index 0000000..5fa618a --- /dev/null +++ b/frontend/app/frontend/tests/unit/views/user/Submissions.spec.js @@ -0,0 +1,26 @@ +import { mount } from '@vue/test-utils'; +import { describe, expect, it } from 'vitest'; + +import Submissions from '~/views/user/Submissions.vue'; + +describe('Submissions.vue', () => { + it('renders', () => { + const wrapper = mount(Submissions, { + props: { + f: 'f', + }, + global: { + stubs: { + BaseSecure: { + name: 'BaseSecure', + template: '
', + }, + MySubmissionsTable: true, + }, + }, + }); + + expect(wrapper.html()).toMatch('base-secure'); + expect(wrapper.html()).toMatch('my-submissions-table'); + }); +}); diff --git a/frontend/app/frontend/tests/unit/vuetify.config.js b/frontend/app/frontend/tests/unit/vuetify.config.js new file mode 100644 index 0000000..5b5330d --- /dev/null +++ b/frontend/app/frontend/tests/unit/vuetify.config.js @@ -0,0 +1,59 @@ +import { config } from '@vue/test-utils'; +import { createVuetify } from 'vuetify'; +import * as components from 'vuetify/components'; +import * as directives from 'vuetify/directives'; +import { fa } from 'vuetify/iconsets/fa'; +import { aliases, mdi } from 'vuetify/iconsets/mdi'; +import { VDataTable, VDataTableServer } from 'vuetify/labs/VDataTable'; +import { VSkeletonLoader } from 'vuetify/labs/VSkeletonLoader'; +import { VStepper } from 'vuetify/labs/VStepper'; + +global.CSS = { supports: () => false }; + +const chefsTheme = { + dark: false, + colors: { + primary: '#003366', + secondary: '#FCBA19', + anchor: '#1A5A96', + accent: '#82B1FF', + error: '#D8292F', + info: '#2196F3', + success: '#2E8540', + warning: '#FFC107', + }, +}; + +const vuetify = createVuetify({ + defaultAssets: { + font: true, + icons: 'mdi', + }, + icons: { + defaultSet: 'mdi', + aliases, + sets: { + mdi, + fa, + }, + }, + theme: { + defaultTheme: 'chefsTheme', + options: { + customProperties: true, + }, + themes: { + chefsTheme, + }, + }, + components: { + ...components, + VDataTable, + VDataTableServer, + VSkeletonLoader, + VStepper, + }, + directives, +}); + +config.global.plugins = [...config.global.plugins, vuetify]; diff --git a/frontend/app/frontend/vite.config.js b/frontend/app/frontend/vite.config.js new file mode 100644 index 0000000..5ae7281 --- /dev/null +++ b/frontend/app/frontend/vite.config.js @@ -0,0 +1,70 @@ +import Vue from '@vitejs/plugin-vue'; +import { resolve } from 'path'; +import { defineConfig, loadEnv } from 'vite'; +import eslintPlugin from 'vite-plugin-eslint'; +import vuetify from 'vite-plugin-vuetify'; + +const proxyObject = { + target: 'http://localhost:8080', + ws: true, + changeOrigin: true, +}; + +// https://vitejs.dev/config/ +// eslint-disable-next-line no-unused-vars +export default defineConfig(({ command, mode }) => { + const env = loadEnv(mode, process.cwd(), ''); + return { + base: env.VITE_FRONTEND_BASEPATH ? env.VITE_FRONTEND_BASEPATH : '/app', + server: { + base: env.VITE_FRONTEND_BASEPATH ? env.VITE_FRONTEND_BASEPATH : '/app', + proxy: { + '^/pr-*/api': proxyObject, + '^/pr-*/config': proxyObject, + '^/app/api': proxyObject, + '^/app/config': proxyObject, + }, + }, + plugins: [Vue(), vuetify(), eslintPlugin()], + resolve: { + alias: { + '~': resolve(__dirname, './src'), + '~formiojs': resolve(__dirname, './node_modules/formiojs'), + '~font-awesome': resolve(__dirname, './node_modules/font-awesome'), + '~vuetify': resolve(__dirname, './node_modules/vuetify'), + // no clue why crypto is required, but unit tests will not run without it + crypto: 'crypto-js', + }, + }, + test: { + mockReset: true, + clearMocks: true, + coverage: { + enabled: true, + include: [ + 'src/**/*.{js,vue}', + '!src/main.js', + '!src/formio/**/*.*', + '!src/plugins/*.*', + ], + extension: ['.js', '.json', '.vue', '.jsx'], + }, + setupFiles: [ + './tests/unit/vuetify.config.js', + './tests/unit/i18n.config.js', + './tests/unit/setup.js', + ], + include: [ + '**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)', + ], + environmentOptions: { + url: 'http://localhost/', + }, + globals: true, + environment: 'jsdom', + deps: { + inline: ['vuetify', 'i18n'], + }, + }, + }; +}); diff --git a/frontend/app/jest.config.js b/frontend/app/jest.config.js new file mode 100644 index 0000000..0eac637 --- /dev/null +++ b/frontend/app/jest.config.js @@ -0,0 +1,15 @@ +module.exports = { + clearMocks: true, + collectCoverage: true, + collectCoverageFrom: ['src/**/*.js', '!src/db/migrations/*.js', '!src/db/seeds/*.js', '!frontend/**/*.*'], + moduleFileExtensions: ['js', 'json'], + moduleNameMapper: { + '^~/(.*)$': '/src/$1', + }, + testMatch: ['**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)'], + testPathIgnorePatterns: ['frontend'], + testEnvironmentOptions: { + url: 'http://localhost/', + }, + transformIgnorePatterns: ['/node_modules/(?!@json2csv|@streamparser)'], +}; diff --git a/frontend/app/knexfile.js b/frontend/app/knexfile.js new file mode 100644 index 0000000..4bbfde4 --- /dev/null +++ b/frontend/app/knexfile.js @@ -0,0 +1,66 @@ +const config = require('config'); +const log = require('./src/components/log')(module.filename); +const moment = require('moment'); + +/** Knex configuration + * Set database configuration for application and knex configuration for migrations + * and seeding. Since configuration values can change via env. vars or property + * files, we only need one runtime 'environment' for knex. + * + * Note: it appears that the knexfile must be in the root for the config values + * to be read correctly when running the 'npm run migrate:*' scripts. + * @module knexfile + * @see module:knex + * @see module:config + */ + +const types = require('pg').types; +// To handle JSON Schema validation, we treat dates and timestamps outside of the database as strings. +// Prevent the automatic conversion of dates/timestamps into Objects, leave as strings. +types.setTypeParser(1082, (value) => { + // dates must be in the date only part of 2020-05-16T13:18:27.160Z + return moment(value).format('YYYY-MM-DD'); +}); +// timestamps... +types.setTypeParser(1114, (value) => { + return moment(value).toISOString(); +}); +// timestamps with zone +types.setTypeParser(1184, (value) => { + return moment(value).toISOString(); +}); + +const logWrapper = (level, msg) => log.log(level, msg); + +module.exports = { + client: 'pg', + connection: { + host: config.get('db.host'), + user: config.get('db.username'), + password: config.get('db.password'), + database: config.get('db.database'), + port: config.get('db.port'), + }, + debug: ['silly', 'debug'].includes(config.get('server.logLevel')), + log: { + debug: (msg) => logWrapper('debug', msg), + deprecate: (msg) => logWrapper('warn', msg), + error: (msg) => logWrapper('error', msg), + info: (msg) => logWrapper('info', msg), + silly: (msg) => logWrapper('silly', msg), + verbose: (msg) => logWrapper('verbose', msg), + warn: (msg) => logWrapper('warn', msg), + }, + migrations: { + directory: __dirname + '/src/db/migrations', + }, + pool: { + min: 2, + max: 10, + // This shouldn't be here: https://github.com/knex/knex/issues/3455#issuecomment-535554401 + // propagateCreateError: false + }, + seeds: { + directory: __dirname + '/src/db/seeds', + }, +}; diff --git a/frontend/app/lcov-fix.js b/frontend/app/lcov-fix.js new file mode 100644 index 0000000..a788e90 --- /dev/null +++ b/frontend/app/lcov-fix.js @@ -0,0 +1,15 @@ +// Jest 25.x onwards emits coverage reports on a different source path +// https://stackoverflow.com/q/60323177 +const fs = require('fs'); +const file = './coverage/lcov.info'; + +fs.readFile(file, 'utf8', (err, data) => { + if (err) { + return console.error(err); // eslint-disable-line no-console + } + const result = data.replace(/src/g, `${process.cwd()}/src`); + + fs.writeFile(file, result, 'utf8', (err) => { + if (err) return console.error(err); // eslint-disable-line no-console + }); +}); diff --git a/frontend/app/nodemon.json b/frontend/app/nodemon.json new file mode 100644 index 0000000..1dff008 --- /dev/null +++ b/frontend/app/nodemon.json @@ -0,0 +1,9 @@ +{ + "ignore": [ + "frontend/node_modules", + "frontend/src", + "frontend/tests", + "node_modules/**/node_modules", + "tests" + ] +} diff --git a/frontend/app/package-lock.json b/frontend/app/package-lock.json new file mode 100644 index 0000000..076bd47 --- /dev/null +++ b/frontend/app/package-lock.json @@ -0,0 +1,19178 @@ +{ + "name": "common-hosted-form-service-app", + "version": "1.5.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "common-hosted-form-service-app", + "version": "1.5.0", + "license": "Apache-2.0", + "dependencies": { + "@json2csv/node": "^6.1.3", + "@json2csv/transforms": "^6.1.3", + "api-problem": "^7.0.4", + "aws-sdk": "^2.1376.0", + "axios": "^0.27.2", + "axios-oauth-client": "^1.5.0", + "axios-token-interceptor": "^0.2.0", + "body-parser": "^1.20.2", + "bytes": "^3.1.2", + "compression": "^1.7.4", + "config": "^3.3.9", + "crypto": "^1.0.1", + "express": "^4.18.2", + "express-basic-auth": "^1.2.1", + "express-rate-limit": "^7.1.3", + "express-winston": "^4.2.0", + "falsey": "^1.0.0", + "fast-json-patch": "^3.1.1", + "form-data": "^4.0.0", + "fs-extra": "^10.1.0", + "handlebars": "^4.7.8", + "js-yaml": "^4.1.0", + "jsonwebtoken": "^9.0.0", + "keycloak-connect": "^21.1.1", + "knex": "^2.4.2", + "lodash": "^4.17.21", + "mime-types": "^2.1.35", + "moment": "^2.29.4", + "multer": "^1.4.5-lts.1", + "nested-objects-util": "^1.1.2", + "objection": "^3.0.1", + "pg": "^8.10.0", + "uuid": "^8.3.2", + "winston": "^3.8.2" + }, + "devDependencies": { + "eslint": "^8.40.0", + "eslint-config-prettier": "^8.8.0", + "eslint-config-recommended": "^4.1.0", + "eslint-plugin-prettier": "^4.2.1", + "jest": "^28.0.0", + "nodemon": "^2.0.22", + "prettier": "^2.8.8", + "prettier-eslint": "^15.0.1", + "supertest": "^6.3.3" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/code-frame/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/code-frame/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/code-frame/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.6.tgz", + "integrity": "sha512-29tfsWTq2Ftu7MXmimyC0C5FDZv5DYxOZkh3XD3+QW4V/BYuv/LyEsjj3c0hqedEaDt6DBfDvexMKU8YevdqFg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.6.tgz", + "integrity": "sha512-HPIyDa6n+HKw5dEuway3vVAhBboYCtREBMp+IWeseZy6TFtzn6MHkCH2KKYUOC/vKKwgSMHQW4htBOrmuRPXfw==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helpers": "^7.22.6", + "@babel/parser": "^7.22.6", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.6", + "@babel/types": "^7.22.5", + "@nicolo-ribaudo/semver-v6": "^6.3.3", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/core/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@babel/generator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.3.tgz", + "integrity": "sha512-keeZWAV4LU3tW0qRi19HRpabC/ilM0HRBBzf9/k8FFiG4KVpiv0FIy4hHfLfFQZNhziCTPTmd59zoyv6DNISzg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.23.3", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.6.tgz", + "integrity": "sha512-534sYEqWD9VfUm3IPn2SLcH4Q3P86XL+QvqdC7ZsFrzyyPF3T4XGiVghF6PTYNdWg6pXuoqXxNQAhbYeEInTzA==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-validator-option": "^7.22.5", + "@nicolo-ribaudo/semver-v6": "^6.3.3", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", + "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.5.tgz", + "integrity": "sha512-+hGKDt/Ze8GFExiVHno/2dvG5IdstpzCq0y4Qc9OJ25D4q3pKfiIP/4Vp3/JvhDkLKsDK2api3q3fpIgiIF5bw==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.5", + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.21.5.tgz", + "integrity": "sha512-0WDaIlXKOX/3KfBK/dwP1oQGiPh6rjMkT7HIRv7i5RR2VUMwrx5ZL0dwBkKx7+SW1zwNdgjHd34IMk5ZjTeHVg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", + "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.6.tgz", + "integrity": "sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.6", + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.3.tgz", + "integrity": "sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.21.4.tgz", + "integrity": "sha512-xz0D39NvhQn4t4RNsHmDnnsaQizIlUkdtYvLs8La1BlfjQ6JEwxkJGeqJMW2tAXx+q6H+WFuUTXNdYVpEya0YA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.3.tgz", + "integrity": "sha512-+K0yF1/9yR0oHdE0StHuEj3uTPzwwbrLGfNOndVJVV2TqA5+j3oljJUb4nmB954FLGjNem976+B+eDuLIjesiQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.3", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.3", + "@babel/types": "^7.23.3", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/traverse/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@babel/types": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.3.tgz", + "integrity": "sha512-OZnvoH2l8PK5eUvEcUyCt/sXgr/h+UWpVuBbOljwcrAgUl6lpchoQ++PHGyQy1AtYnVA6CEq3y5xeEI10brpXw==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", + "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", + "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.5.2", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/eslintrc/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@eslint/js": { + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.40.0.tgz", + "integrity": "sha512-ElyB54bJIhXQYVKjDSvCkPO1iU1tSAeVQJbllWJq1XQSmmA4dgFk8CbiBGpiOPxleE48vDogxCtmMYku4HSVLA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.3.tgz", + "integrity": "sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", + "slash": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/core": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-28.1.3.tgz", + "integrity": "sha512-CIKBrlaKOzA7YG19BEqCw3SLIsEwjZkeJzf5bdooVnW4bH5cktqe3JX+G2YV1aK5vP8N9na1IGWFzYaTp6k6NA==", + "dev": true, + "dependencies": { + "@jest/console": "^28.1.3", + "@jest/reporters": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^28.1.3", + "jest-config": "^28.1.3", + "jest-haste-map": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.3", + "jest-resolve-dependencies": "^28.1.3", + "jest-runner": "^28.1.3", + "jest-runtime": "^28.1.3", + "jest-snapshot": "^28.1.3", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", + "jest-watcher": "^28.1.3", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.3.tgz", + "integrity": "sha512-1bf40cMFTEkKyEf585R9Iz1WayDjHoHqvts0XFYEqyKM3cFWDpeMoqKKTAF9LSYQModPUlh8FKptoM2YcMWAXA==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "jest-mock": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-28.1.3.tgz", + "integrity": "sha512-lzc8CpUbSoE4dqT0U+g1qODQjBRHPpCPXissXD4mS9+sWQdmmpeJ9zSH1rS1HEkrsMN0fb7nKrJ9giAR1d3wBw==", + "dev": true, + "dependencies": { + "expect": "^28.1.3", + "jest-snapshot": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.3.tgz", + "integrity": "sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA==", + "dev": true, + "dependencies": { + "jest-get-type": "^28.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.3.tgz", + "integrity": "sha512-D/wOkL2POHv52h+ok5Oj/1gOG9HSywdoPtFsRCUmlCILXNn5eIWmcnd3DIiWlJnpGvQtmajqBP95Ei0EimxfLw==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@sinonjs/fake-timers": "^9.1.2", + "@types/node": "*", + "jest-message-util": "^28.1.3", + "jest-mock": "^28.1.3", + "jest-util": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-28.1.3.tgz", + "integrity": "sha512-XFU4P4phyryCXu1pbcqMO0GSQcYe1IsalYCDzRNyhetyeyxMcIxa11qPNDpVNLeretItNqEmYYQn1UYz/5x1NA==", + "dev": true, + "dependencies": { + "@jest/environment": "^28.1.3", + "@jest/expect": "^28.1.3", + "@jest/types": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-28.1.3.tgz", + "integrity": "sha512-JuAy7wkxQZVNU/V6g9xKzCGC5LVXx9FDcABKsSXp5MiKPEE2144a/vXTEDoyzjUpZKfVwp08Wqg5A4WfTMAzjg==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", + "@jridgewell/trace-mapping": "^0.3.13", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", + "jest-worker": "^28.1.3", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", + "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.24.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-28.1.2.tgz", + "integrity": "sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.13", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.3.tgz", + "integrity": "sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg==", + "dev": true, + "dependencies": { + "@jest/console": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-28.1.3.tgz", + "integrity": "sha512-NIMPEqqa59MWnDi1kvXXpYbqsfQmSJsIbnd85mdVGkiDfQ9WQQTXOLsvISUfonmnBT+w85WEgneCigEEdHDFxw==", + "dev": true, + "dependencies": { + "@jest/test-result": "^28.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "slash": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.3.tgz", + "integrity": "sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^28.1.3", + "@jridgewell/trace-mapping": "^0.3.13", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/types": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", + "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.1.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", + "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@json2csv/formatters": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/@json2csv/formatters/-/formatters-6.1.3.tgz", + "integrity": "sha512-Yhs6eXTMhSrNFLTuVnhwjgJem2x+z0YZc0YxdCavoDf/tfz6LBVPVVoJPl9tXaCIfPZY9ybRB6sqPQqZTzkNuw==" + }, + "node_modules/@json2csv/node": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/@json2csv/node/-/node-6.1.3.tgz", + "integrity": "sha512-AYtaZDhmiMW9uiUDPlbFBWcj5JX485TLT7GBukTQh6509Ha/1GXjLpHUQq594Yn2OQeA4BNZAT70InXDm95soA==", + "dependencies": { + "@json2csv/plainjs": "^6.1.3" + } + }, + "node_modules/@json2csv/plainjs": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/@json2csv/plainjs/-/plainjs-6.1.3.tgz", + "integrity": "sha512-8cH/yVAPt1edDq/2Krr4elS2uJFWAdMQDH+ocuepjyh7lmBHEHv5kU0bqbYpd5ZpKTizshotsKk7KYA3nx4CCw==", + "dependencies": { + "@json2csv/formatters": "^6.1.3", + "@streamparser/json": "^0.0.12", + "lodash.get": "^4.4.2" + } + }, + "node_modules/@json2csv/transforms": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/@json2csv/transforms/-/transforms-6.1.3.tgz", + "integrity": "sha512-MwJsNUt68/0B7kdlZOn7R4jn7EXOhNEZ3bwKfYwPtyAM/GD4ctSIazfV69hI+i5jxmIEvizh8rRgU/8/qrjsAA==", + "dependencies": { + "lodash.get": "^4.4.2" + } + }, + "node_modules/@nicolo-ribaudo/semver-v6": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/semver-v6/-/semver-v6-6.3.3.tgz", + "integrity": "sha512-3Yc1fUTs69MG/uZbJlLSI3JISMn2UV2rg+1D/vROUqZyh3l6iYHCs7GMp+M40ZD7yOdDbYjJcU1oTJhrc+dGKg==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.24.51", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "dev": true + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", + "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/@streamparser/json": { + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/@streamparser/json/-/json-0.0.12.tgz", + "integrity": "sha512-+kmRpd+EeTFd3qNt1AoKphJqbAN26ZDsbiwqjBFeoAmdCyiUO19xMXPtYi9vovAj9a7OAJnvWtiHkwwjU2Fx4Q==" + }, + "node_modules/@types/babel__core": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", + "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.18.5", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.5.tgz", + "integrity": "sha512-enCvTL8m/EHS/zIvJno9nE+ndYPh1/oNFzRYRmtUqJICG2VnCSBzMLW5VN2KCQU91f23tsNKR8v7VJJQMatl7Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.3.0" + } + }, + "node_modules/@types/eslint": { + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.37.0.tgz", + "integrity": "sha512-Piet7dG2JBuDIfohBngQ3rCt7MgO9xCO4xIMKxBThCq5PNRB91IjlJ10eJVwfoNtvTErmxLzwBZ7rHZtbOMmFQ==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", + "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", + "dev": true + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", + "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.1.2.tgz", + "integrity": "sha512-CTO/wa8x+rZU626cL2BlbCDzydgnFNgc19h4YvizpTO88MFQxab8wqisxaofQJ/9bLGugRdWIuX/TbIs6VVF6g==", + "dev": true + }, + "node_modules/@types/prettier": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", + "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", + "dev": true + }, + "node_modules/@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "node_modules/@types/triple-beam": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.2.tgz", + "integrity": "sha512-txGIh+0eDFzKGC25zORnswy+br1Ha7hj5cMVwKIU7+s0U2AxxJru/jZSMU6OC9MJWP6+pc/hc6ZjyZShpsyY2g==" + }, + "node_modules/@types/yargs": { + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.59.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.5.tgz", + "integrity": "sha512-NJXQC4MRnF9N9yWqQE2/KLRSOLvrrlZb48NGVfBa+RuPMN6B7ZcK5jZOvhuygv4D64fRKnZI4L4p8+M+rfeQuw==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.59.5", + "@typescript-eslint/types": "5.59.5", + "@typescript-eslint/typescript-estree": "5.59.5", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.59.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.5.tgz", + "integrity": "sha512-jVecWwnkX6ZgutF+DovbBJirZcAxgxC0EOHYt/niMROf8p4PwxxG32Qdhj/iIQQIuOflLjNkxoXyArkcIP7C3A==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.59.5", + "@typescript-eslint/visitor-keys": "5.59.5" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.59.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.5.tgz", + "integrity": "sha512-xkfRPHbqSH4Ggx4eHRIO/eGL8XL4Ysb4woL8c87YuAo8Md7AUjyWKa9YMwTL519SyDPrfEgKdewjkxNCVeJW7w==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.59.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.5.tgz", + "integrity": "sha512-+XXdLN2CZLZcD/mO7mQtJMvCkzRfmODbeSKuMY/yXbGkzvA9rJyDY5qDYNoiz2kP/dmyAxXquL2BvLQLJFPQIg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.59.5", + "@typescript-eslint/visitor-keys": "5.59.5", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.59.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.5.tgz", + "integrity": "sha512-qL+Oz+dbeBRTeyJTIy0eniD3uvqU7x+y1QceBismZ41hd4aBSRh8UAw4pZP0+XzLuPZmx4raNMq/I+59W2lXKA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.59.5", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/api-problem": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/api-problem/-/api-problem-7.0.4.tgz", + "integrity": "sha512-8f/Dg1LY26YSMzhguscyJWw2qVafdczyK82+X7zcnv73iN1mh4KmVEm2w7xAL3ttpWddPE7lTKMRFdidH/dFYA==", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/ahmadnassri" + } + }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/array-includes": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz", + "integrity": "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.1.3" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true + }, + "node_modules/asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/aws-sdk": { + "version": "2.1376.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1376.0.tgz", + "integrity": "sha512-ja/Xnft8BDcDEz786VJFPrWpuWpOgsA+QzBAwzsjYeIolQ/vEs/bbXkoS085fOoeAPEhYWQh9wog7cVvrQPJFQ==", + "dependencies": { + "buffer": "4.9.2", + "events": "1.1.1", + "ieee754": "1.1.13", + "jmespath": "0.16.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "util": "^0.12.4", + "uuid": "8.0.0", + "xml2js": "0.5.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/aws-sdk/node_modules/uuid": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", + "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/axios": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", + "dependencies": { + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" + } + }, + "node_modules/axios-oauth-client": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/axios-oauth-client/-/axios-oauth-client-1.5.0.tgz", + "integrity": "sha512-CFuTfK9KdRnDDR6LQlUJ0GNKUZ3tHRSFdKPM9WqeCtUdcuKDgWt9aDFH7Xl87VpUcfNt5qRVl4iHdayqtXVv7g==", + "dependencies": { + "qs": "^6.10.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/axios-token-interceptor": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/axios-token-interceptor/-/axios-token-interceptor-0.2.0.tgz", + "integrity": "sha512-la74OEsXBH1IS9yI6p2oTIynPtBzs0PVUSOwOBgFg2kBwTeDqQ+YJ6jaOWxsTYyqJO510OzHTfnzAn3GFuf9xA==", + "dependencies": { + "lock": "^1.1.0" + } + }, + "node_modules/babel-eslint": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", + "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", + "deprecated": "babel-eslint is now @babel/eslint-parser. This package will no longer receive updates.", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.0", + "@babel/traverse": "^7.7.0", + "@babel/types": "^7.7.0", + "eslint-visitor-keys": "^1.0.0", + "resolve": "^1.12.0" + }, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "eslint": ">= 4.12.1" + } + }, + "node_modules/babel-eslint/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/babel-jest": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.3.tgz", + "integrity": "sha512-epUaPOEWMk3cWX0M/sPvCHHCe9fMFAa/9hXEgKP8nFfNl/jlGkE9ucq9NqkZGXLDduCJYS0UvSlPUwC0S+rH6Q==", + "dev": true, + "dependencies": { + "@jest/transform": "^28.1.3", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^28.1.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.1.3.tgz", + "integrity": "sha512-Ys3tUKAmfnkRUpPdpa98eYrAR0nV+sSFUZZEGuQ2EbFd1y4SOLtD5QDNHAq+bb9a+bbXvYQC4b+ID/THIMcU6Q==", + "dev": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-28.1.3.tgz", + "integrity": "sha512-L+fupJvlWAHbQfn74coNX3zf60LXMJsezNvvx8eIh7iOR1luJ1poxYgQk1F8PYtNq/6QODDHCqsSnTFSWC491A==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^28.1.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + }, + "node_modules/browserslist": { + "version": "4.21.9", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz", + "integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001503", + "electron-to-chromium": "^1.4.431", + "node-releases": "^2.0.12", + "update-browserslist-db": "^1.0.11" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001512", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001512.tgz", + "integrity": "sha512-2S9nK0G/mE+jasCUsMPlARhRCts1ebcp2Ji8Y8PWi4NDE1iRdLCnEPHkEfeBrGC45L4isBx5ur3IQ6yTE2mRZw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/ci-info": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "dev": true + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": true + }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==" + }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/common-tags": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", + "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/concat-stream/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/concat-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/config": { + "version": "3.3.9", + "resolved": "https://registry.npmjs.org/config/-/config-3.3.9.tgz", + "integrity": "sha512-G17nfe+cY7kR0wVpc49NCYvNtelm/pPy8czHoFkAgtV1lkmcp7DHtWCdDu+C9Z7gb2WVqa9Tm3uF9aKaPbCfhg==", + "dependencies": { + "json5": "^2.2.3" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-disposition/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/cookiejar": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", + "dev": true + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz", + "integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==", + "deprecated": "This package is no longer supported. It's now a built-in Node module. If you've depended on crypto, you should switch to the one that's built-in." + }, + "node_modules/db-errors": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/db-errors/-/db-errors-0.2.3.tgz", + "integrity": "sha512-OOgqgDuCavHXjYSJoV2yGhv6SeG8nk42aoCSoyXLZUH7VwFG27rxbavU1z+VrZbZjphw5UkDQwUlD21MwZpUng==" + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": true + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dev": true, + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, + "dependencies": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "node_modules/diff-sequences": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", + "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/electron-to-chromium": { + "version": "1.4.451", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.451.tgz", + "integrity": "sha512-YYbXHIBxAHe3KWvGOJOuWa6f3tgow44rBW+QAuwVp2DvGqNZeE//K2MowNdWS7XE8li5cgQDrX1LdBr41LufkA==", + "dev": true + }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/emittery": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", + "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.21.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz", + "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.2.0", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.7", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.40.0.tgz", + "integrity": "sha512-bvR+TsP9EHL3TqNtj9sCNJVAFK3fBN8Q7g5waghxyRsPLIMwL73XSKnZFK0hk/O2ANC+iAoq6PWMQ+IfBAJIiQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.0.3", + "@eslint/js": "8.40.0", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.0", + "eslint-visitor-keys": "^3.4.1", + "espree": "^9.5.2", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-esnext": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-esnext/-/eslint-config-esnext-4.1.0.tgz", + "integrity": "sha512-GhfVEXdqYKEIIj7j+Fw2SQdL9qyZMekgXfq6PyXM66cQw0B435ddjz3P3kxOBVihMRJ0xGYjosaveQz5Y6z0uA==", + "dev": true, + "dependencies": { + "babel-eslint": "^10.0.1", + "eslint": "^6.8.0", + "eslint-plugin-babel": "^5.2.1", + "eslint-plugin-import": "^2.14.0" + }, + "peerDependencies": { + "eslint": "^6.0.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-config-esnext/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-esnext/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/eslint-config-esnext/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-esnext/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/eslint-config-esnext/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/eslint-config-esnext/node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/eslint-config-esnext/node_modules/cross-spawn/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/eslint-config-esnext/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint-config-esnext/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-esnext/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-esnext/node_modules/espree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "dev": true, + "dependencies": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "dependencies": { + "flat-cache": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-esnext/node_modules/flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "dependencies": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-esnext/node_modules/flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "node_modules/eslint-config-esnext/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/eslint-config-esnext/node_modules/globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "dependencies": { + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-config-esnext/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-esnext/node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/eslint-config-esnext/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint-config-esnext/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/eslint-config-esnext/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-esnext/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/eslint-config-esnext/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-config-esnext/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-esnext/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-esnext/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint-config-esnext/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/eslint-config-node": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-node/-/eslint-config-node-4.1.0.tgz", + "integrity": "sha512-Wz17xV5O2WFG8fGdMYEBdbiL6TL7YNJSJvSX9V4sXQownewfYmoqlly7wxqLkOUv/57pq6LnnotMiQQrrPjCqQ==", + "dev": true, + "dependencies": { + "eslint": "^6.8.0", + "eslint-config-esnext": "^4.1.0" + }, + "peerDependencies": { + "eslint": "^6.0.0" + } + }, + "node_modules/eslint-config-node/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/eslint-config-node/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-config-node/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-node/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/eslint-config-node/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-node/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/eslint-config-node/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/eslint-config-node/node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/eslint-config-node/node_modules/cross-spawn/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/eslint-config-node/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint-config-node/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint-config-node/node_modules/eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-node/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-config-node/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-node/node_modules/espree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "dev": true, + "dependencies": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/eslint-config-node/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-config-node/node_modules/file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "dependencies": { + "flat-cache": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-node/node_modules/flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "dependencies": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-node/node_modules/flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "node_modules/eslint-config-node/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/eslint-config-node/node_modules/globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "dependencies": { + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-config-node/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-node/node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/eslint-config-node/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint-config-node/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-node/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/eslint-config-node/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-node/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-node/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-node/node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/eslint-config-node/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-node/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-node/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-config-node/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-node/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-node/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint-config-node/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/eslint-config-prettier": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz", + "integrity": "sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-config-react-native": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-react-native/-/eslint-config-react-native-4.1.0.tgz", + "integrity": "sha512-kNND+cs+ztawH7wgajf/K6FfNshjlDsFDAkkFZF9HAXDgH1w1sNMIfTfwzufg0hOcSK7rbiL4qbG/gg/oR507Q==", + "dev": true, + "dependencies": { + "eslint": "^6.8.0", + "eslint-config-esnext": "^4.1.0", + "eslint-plugin-react": "^7.19.0", + "eslint-plugin-react-native": "^3.8.1" + }, + "peerDependencies": { + "eslint": "^6.0.0" + } + }, + "node_modules/eslint-config-react-native/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/eslint-config-react-native/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-config-react-native/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-react-native/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/eslint-config-react-native/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-react-native/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/eslint-config-react-native/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/eslint-config-react-native/node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/eslint-config-react-native/node_modules/cross-spawn/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/eslint-config-react-native/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint-config-react-native/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint-config-react-native/node_modules/eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-react-native/node_modules/eslint-plugin-react-native": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-native/-/eslint-plugin-react-native-3.11.0.tgz", + "integrity": "sha512-7F3OTwrtQPfPFd+VygqKA2VZ0f2fz0M4gJmry/TRE18JBb94/OtMxwbL7Oqwu7FGyrdeIOWnXQbBAveMcSTZIA==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.7.4", + "eslint-plugin-react-native-globals": "^0.1.1" + }, + "peerDependencies": { + "eslint": "^3.17.0 || ^4 || ^5 || ^6 || ^7" + } + }, + "node_modules/eslint-config-react-native/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-config-react-native/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-react-native/node_modules/espree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "dev": true, + "dependencies": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/eslint-config-react-native/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-config-react-native/node_modules/file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "dependencies": { + "flat-cache": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-react-native/node_modules/flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "dependencies": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-react-native/node_modules/flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "node_modules/eslint-config-react-native/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/eslint-config-react-native/node_modules/globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "dependencies": { + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-config-react-native/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-react-native/node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/eslint-config-react-native/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint-config-react-native/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-react-native/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/eslint-config-react-native/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-react-native/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-react-native/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-react-native/node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/eslint-config-react-native/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-react-native/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-react-native/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-config-react-native/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-react-native/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-react-native/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint-config-react-native/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/eslint-config-recommended": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-recommended/-/eslint-config-recommended-4.1.0.tgz", + "integrity": "sha512-2evA0SX1VqtyFiExmBI2WAO4XQCKlr7wmNELE8rcT5PyZY2ixsY881ofVZWKuI/dywpgLiES1gR/XUQcnVLRzQ==", + "dev": true, + "dependencies": { + "eslint": "^6.8.0", + "eslint-config-esnext": "^4.1.0", + "eslint-config-node": "^4.1.0", + "eslint-config-react-native": "^4.1.0" + }, + "peerDependencies": { + "eslint": "^6.0.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-config-recommended/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-recommended/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/eslint-config-recommended/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-recommended/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/eslint-config-recommended/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/eslint-config-recommended/node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/eslint-config-recommended/node_modules/cross-spawn/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/eslint-config-recommended/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint-config-recommended/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^8.10.0 || ^10.13.0 || >=11.10.1" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-recommended/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-recommended/node_modules/espree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "dev": true, + "dependencies": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "dependencies": { + "flat-cache": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-recommended/node_modules/flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "dependencies": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-recommended/node_modules/flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "node_modules/eslint-config-recommended/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/eslint-config-recommended/node_modules/globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "dependencies": { + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-config-recommended/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-recommended/node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/eslint-config-recommended/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint-config-recommended/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/eslint-config-recommended/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-recommended/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/eslint-config-recommended/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-config-recommended/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-config-recommended/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint-config-recommended/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint-config-recommended/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", + "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.11.0", + "resolve": "^1.22.1" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/eslint-module-utils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", + "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/eslint-plugin-babel": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-babel/-/eslint-plugin-babel-5.3.1.tgz", + "integrity": "sha512-VsQEr6NH3dj664+EyxJwO4FCYm/00JhYb3Sk3ft8o+fpKuIfQ9TaW6uVUfvwMXHcf/lsnRIoyFPsLMyiWCSL/g==", + "dev": true, + "dependencies": { + "eslint-rule-composer": "^0.3.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": ">=4.0.0" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.27.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", + "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.1", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.7.4", + "has": "^1.0.3", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.6", + "resolve": "^1.22.1", + "semver": "^6.3.0", + "tsconfig-paths": "^3.14.1" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/eslint-plugin-prettier": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", + "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "eslint": ">=7.28.0", + "prettier": ">=2.0.0" + }, + "peerDependenciesMeta": { + "eslint-config-prettier": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.32.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz", + "integrity": "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", + "array.prototype.tosorted": "^1.1.1", + "doctrine": "^2.1.0", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", + "object.hasown": "^1.1.2", + "object.values": "^1.1.6", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.4", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.8" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-native-globals": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-native-globals/-/eslint-plugin-react-native-globals-0.1.2.tgz", + "integrity": "sha512-9aEPf1JEpiTjcFAmmyw8eiIXmcNZOqaZyHO77wgm0/dWfT/oxC1SrIq8ET38pMxHYrcB6Uew+TzUVsBeczF88g==", + "dev": true + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", + "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-rule-composer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", + "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", + "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", + "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/esm": { + "version": "3.2.25", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", + "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/espree": { + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", + "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", + "dev": true, + "dependencies": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.3.tgz", + "integrity": "sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express-basic-auth": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/express-basic-auth/-/express-basic-auth-1.2.1.tgz", + "integrity": "sha512-L6YQ1wQ/mNjVLAmK3AG1RK6VkokA1BIY6wmiH304Xtt/cLTps40EusZsU1Uop+v9lTDPxdtzbFmdXfFO3KEnwA==", + "dependencies": { + "basic-auth": "^2.0.1" + } + }, + "node_modules/express-rate-limit": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.1.3.tgz", + "integrity": "sha512-BDes6WeNYSGRRGQU8QDNwUnwqaBro28HN/TTweM3RlxXRHDld8RLoH7tbfCxAc0hamQyn6aL0KrfR45+ZxknYg==", + "engines": { + "node": ">= 16" + }, + "peerDependencies": { + "express": "4 || 5 || ^5.0.0-beta.1" + } + }, + "node_modules/express-winston": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/express-winston/-/express-winston-4.2.0.tgz", + "integrity": "sha512-EMD74g63nVHi7pFleQw7KHCxiA1pjF5uCwbCfzGqmFxs9KvlDPIVS3cMGpULm6MshExMT9TjC3SqmRGB9kb7yw==", + "dependencies": { + "chalk": "^2.4.2", + "lodash": "^4.17.21" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "winston": ">=3.x <4" + } + }, + "node_modules/express-winston/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/express-winston/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/express-winston/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/express-winston/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/express-winston/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/express-winston/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/express-winston/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/express/node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/express/node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/express/node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/express/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/falsey": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/falsey/-/falsey-1.0.0.tgz", + "integrity": "sha512-zMDNZ/Ipd8MY0+346CPvhzP1AsiVyNfTOayJza4reAIWf72xbkuFUDcJNxSAsQE1b9Bu0wijKb8Ngnh/a7fI5w==", + "engines": { + "node": ">=4" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-patch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz", + "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/formidable": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz", + "integrity": "sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==", + "dev": true, + "dependencies": { + "dezalgo": "^1.0.4", + "hexoid": "^1.0.0", + "once": "^1.4.0", + "qs": "^6.11.0" + }, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/getopts": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/getopts/-/getopts-2.3.0.tgz", + "integrity": "sha512-5eDf9fuSXwxBL6q5HX+dhDj+dslFGWzU5thZ9kNKUkcPtaPdatmUFKwHFrLb/uf/WpA4BHET+AX3Scl56cAjpA==" + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hexoid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", + "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/inquirer": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", + "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.19", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.6.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz", + "integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest/-/jest-28.1.3.tgz", + "integrity": "sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA==", + "dev": true, + "dependencies": { + "@jest/core": "^28.1.3", + "@jest/types": "^28.1.3", + "import-local": "^3.0.2", + "jest-cli": "^28.1.3" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-28.1.3.tgz", + "integrity": "sha512-esaOfUWJXk2nfZt9SPyC8gA1kNfdKLkQWyzsMlqq8msYSlNKfmZxfRgZn4Cd4MGVUF+7v6dBs0d5TOAKa7iIiA==", + "dev": true, + "dependencies": { + "execa": "^5.0.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-28.1.3.tgz", + "integrity": "sha512-cZ+eS5zc79MBwt+IhQhiEp0OeBddpc1n8MBo1nMB8A7oPMKEO+Sre+wHaLJexQUj9Ya/8NOBY0RESUgYjB6fow==", + "dev": true, + "dependencies": { + "@jest/environment": "^28.1.3", + "@jest/expect": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^28.1.3", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-runtime": "^28.1.3", + "jest-snapshot": "^28.1.3", + "jest-util": "^28.1.3", + "p-limit": "^3.1.0", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-cli": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-28.1.3.tgz", + "integrity": "sha512-roY3kvrv57Azn1yPgdTebPAXvdR2xfezaKKYzVxZ6It/5NCxzJym6tUI5P1zkdWhfUYkxEI9uZWcQdaFLo8mJQ==", + "dev": true, + "dependencies": { + "@jest/core": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^28.1.3", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", + "prompts": "^2.0.1", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-28.1.3.tgz", + "integrity": "sha512-MG3INjByJ0J4AsNBm7T3hsuxKQqFIiRo/AUqb1q9LRKI5UU6Aar9JHbr9Ivn1TVwfUD9KirRoM/T6u8XlcQPHQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^28.1.3", + "@jest/types": "^28.1.3", + "babel-jest": "^28.1.3", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^28.1.3", + "jest-environment-node": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.3", + "jest-runner": "^28.1.3", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", + "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^28.1.1", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-28.1.1.tgz", + "integrity": "sha512-3wayBVNiOYx0cwAbl9rwm5kKFP8yHH3d/fkEaL02NPTkDojPtheGB7HZSFY4wzX+DxyrvhXz0KSCVksmCknCuA==", + "dev": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-each": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-28.1.3.tgz", + "integrity": "sha512-arT1z4sg2yABU5uogObVPvSlSMQlDA48owx07BDPAiasW0yYpYHYOo4HHLz9q0BVzDVU4hILFjzJw0So9aCL/g==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "chalk": "^4.0.0", + "jest-get-type": "^28.0.2", + "jest-util": "^28.1.3", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-28.1.3.tgz", + "integrity": "sha512-ugP6XOhEpjAEhGYvp5Xj989ns5cB1K6ZdjBYuS30umT4CQEETaxSiPcZ/E1kFktX4GkrcM4qu07IIlDYX1gp+A==", + "dev": true, + "dependencies": { + "@jest/environment": "^28.1.3", + "@jest/fake-timers": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "jest-mock": "^28.1.3", + "jest-util": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", + "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "jest-worker": "^28.1.3", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-28.1.3.tgz", + "integrity": "sha512-WFVJhnQsiKtDEo5lG2mM0v40QWnBM+zMdHHyJs8AWZ7J0QZJS59MsyKeJHWhpBZBH32S48FOVvGyOFT1h0DlqA==", + "dev": true, + "dependencies": { + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz", + "integrity": "sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^28.1.3", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", + "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-mock": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.3.tgz", + "integrity": "sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-28.1.3.tgz", + "integrity": "sha512-Z1W3tTjE6QaNI90qo/BJpfnvpxtaFTFw5CDgwpyE/Kz8U/06N1Hjf4ia9quUhCh39qIGWF1ZuxFiBiJQwSEYKQ==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.3.tgz", + "integrity": "sha512-qa0QO2Q0XzQoNPouMbCc7Bvtsem8eQgVPNkwn9LnS+R2n8DaVDPL/U1gngC0LTl1RYXJU0uJa2BMC2DbTfFrHA==", + "dev": true, + "dependencies": { + "jest-regex-util": "^28.0.2", + "jest-snapshot": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runner": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-28.1.3.tgz", + "integrity": "sha512-GkMw4D/0USd62OVO0oEgjn23TM+YJa2U2Wu5zz9xsQB1MxWKDOlrnykPxnMsN0tnJllfLPinHTka61u0QhaxBA==", + "dev": true, + "dependencies": { + "@jest/console": "^28.1.3", + "@jest/environment": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "graceful-fs": "^4.2.9", + "jest-docblock": "^28.1.1", + "jest-environment-node": "^28.1.3", + "jest-haste-map": "^28.1.3", + "jest-leak-detector": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-resolve": "^28.1.3", + "jest-runtime": "^28.1.3", + "jest-util": "^28.1.3", + "jest-watcher": "^28.1.3", + "jest-worker": "^28.1.3", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-28.1.3.tgz", + "integrity": "sha512-NU+881ScBQQLc1JHG5eJGU7Ui3kLKrmwCPPtYsJtBykixrM2OhVQlpMmFWJjMyDfdkGgBMNjXCGB/ebzsgNGQw==", + "dev": true, + "dependencies": { + "@jest/environment": "^28.1.3", + "@jest/fake-timers": "^28.1.3", + "@jest/globals": "^28.1.3", + "@jest/source-map": "^28.1.2", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-mock": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.3", + "jest-snapshot": "^28.1.3", + "jest-util": "^28.1.3", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-28.1.3.tgz", + "integrity": "sha512-4lzMgtiNlc3DU/8lZfmqxN3AYD6GGLbl+72rdBpXvcV+whX7mDrREzkPdp2RnmfIiWBg1YbuFSkXduF2JcafJg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/babel__traverse": "^7.0.6", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^28.1.3", + "graceful-fs": "^4.2.9", + "jest-diff": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-haste-map": "^28.1.3", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", + "natural-compare": "^1.4.0", + "pretty-format": "^28.1.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-snapshot/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-validate": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-28.1.3.tgz", + "integrity": "sha512-SZbOGBWEsaTxBGCOpsRWlXlvNkvTkY0XxRfh7zYmvd8uL5Qzyg0CHAXiXKROflh801quA6+/DsT4ODDthOC/OA==", + "dev": true, + "dependencies": { + "@jest/types": "^28.1.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^28.0.2", + "leven": "^3.1.0", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.3.tgz", + "integrity": "sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g==", + "dev": true, + "dependencies": { + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "jest-util": "^28.1.3", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jmespath": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", + "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/js-sdsl": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", + "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonwebtoken": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", + "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", + "dependencies": { + "jws": "^3.2.2", + "lodash": "^4.17.21", + "ms": "^2.1.1", + "semver": "^7.3.8" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jsonwebtoken/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/jsonwebtoken/node_modules/semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jsonwebtoken/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", + "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.5", + "object.assign": "^4.1.3" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jwk-to-pem": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/jwk-to-pem/-/jwk-to-pem-2.0.5.tgz", + "integrity": "sha512-L90jwellhO8jRKYwbssU9ifaMVqajzj3fpRjDKcsDzrslU9syRbFqfkXtT4B89HYAap+xsxNcxgBSB09ig+a7A==", + "dependencies": { + "asn1.js": "^5.3.0", + "elliptic": "^6.5.4", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/keycloak-connect": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/keycloak-connect/-/keycloak-connect-21.1.1.tgz", + "integrity": "sha512-FFLhsnXjo+OmzMJpFhHcTjLHLwT18aZi1hJj/TLwXjijyHUFDBdVyD+uF7Hspcs4A4s00xwteAqkQGMlFQa6Yw==", + "deprecated": "This package is deprecated and will be removed in the future. We will shortly provide more details on removal date, and recommended alternatives.", + "dependencies": { + "jwk-to-pem": "^2.0.0" + }, + "engines": { + "node": ">=14" + }, + "optionalDependencies": { + "chromedriver": "latest" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/knex": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/knex/-/knex-2.4.2.tgz", + "integrity": "sha512-tMI1M7a+xwHhPxjbl/H9K1kHX+VncEYcvCx5K00M16bWvpYPKAZd6QrCu68PtHAdIZNQPWZn0GVhqVBEthGWCg==", + "dependencies": { + "colorette": "2.0.19", + "commander": "^9.1.0", + "debug": "4.3.4", + "escalade": "^3.1.1", + "esm": "^3.2.25", + "get-package-type": "^0.1.0", + "getopts": "2.3.0", + "interpret": "^2.2.0", + "lodash": "^4.17.21", + "pg-connection-string": "2.5.0", + "rechoir": "^0.8.0", + "resolve-from": "^5.0.0", + "tarn": "^3.0.2", + "tildify": "2.0.0" + }, + "bin": { + "knex": "bin/cli.js" + }, + "engines": { + "node": ">=12" + }, + "peerDependenciesMeta": { + "better-sqlite3": { + "optional": true + }, + "mysql": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "pg": { + "optional": true + }, + "pg-native": { + "optional": true + }, + "sqlite3": { + "optional": true + }, + "tedious": { + "optional": true + } + } + }, + "node_modules/knex/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "node_modules/knex/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/knex/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/knex/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lock": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/lock/-/lock-1.1.0.tgz", + "integrity": "sha512-NZQIJJL5Rb9lMJ0Yl1JoVr9GSdo4HTPsUEWsSFzB8dE8DSoiLCVavWZPi7Rnlv/o73u6I24S/XYc/NmG4l8EKA==" + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/logform": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.5.1.tgz", + "integrity": "sha512-9FyqAm9o9NKKfiAKfZoYo9bGXXuwMkxQiQttkT4YjjVtQVIQtK6LmVtlxmCaFswo6N4AfEkHqZTV0taDtPotNg==", + "dependencies": { + "@colors/colors": "1.5.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + } + }, + "node_modules/logform/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/loglevel": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.8.1.tgz", + "integrity": "sha512-tCRIJM51SHjAayKwC+QAg8hT8vg6z7GSgLJKGvzuPb1Wc+hLzqtuVLxp6/HzSPOozuK+8ErAhy7U/sVzw8Dgfg==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/loglevel" + } + }, + "node_modules/loglevel-colored-level-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/loglevel-colored-level-prefix/-/loglevel-colored-level-prefix-1.0.0.tgz", + "integrity": "sha512-u45Wcxxc+SdAlh4yeF/uKlC1SPUPCy0gullSNKXod5I4bmifzk+Q4lSLExNEVn19tGaJipbZ4V4jbFn79/6mVA==", + "dev": true, + "dependencies": { + "chalk": "^1.1.3", + "loglevel": "^1.4.1" + } + }, + "node_modules/loglevel-colored-level-prefix/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loglevel-colored-level-prefix/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loglevel-colored-level-prefix/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loglevel-colored-level-prefix/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/loglevel-colored-level-prefix/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loglevel-colored-level-prefix/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/multer": { + "version": "1.4.5-lts.1", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz", + "integrity": "sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^1.0.0", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.4", + "object-assign": "^4.1.1", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "node_modules/nested-objects-util": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/nested-objects-util/-/nested-objects-util-1.1.2.tgz", + "integrity": "sha512-jNUcnODTq1HpGGFFo9aDXP7JxrJ1ilLHSaUElSyW5Zw8EJHyYyujdBIdTwa0K4lBC/9M23dJyhExo9XyhO39LQ==" + }, + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz", + "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==", + "dev": true + }, + "node_modules/nodemon": { + "version": "2.0.22", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", + "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==", + "dev": true, + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/nodemon/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/nodemon/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/nodemon/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/nodemon/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz", + "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", + "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.hasown": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz", + "integrity": "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/objection": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/objection/-/objection-3.0.1.tgz", + "integrity": "sha512-rqNnyQE+C55UHjdpTOJEKQHJGZ/BGtBBtgxdUpKG4DQXRUmqxfmgS/MhPWxB9Pw0mLSVLEltr6soD4c0Sddy0Q==", + "dependencies": { + "ajv": "^8.6.2", + "db-errors": "^0.2.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "knex": ">=0.95.0" + } + }, + "node_modules/objection/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/objection/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dependencies": { + "fn.name": "1.x.x" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pg": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.10.0.tgz", + "integrity": "sha512-ke7o7qSTMb47iwzOSaZMfeR7xToFdkE71ifIipOAAaLIM0DYzfOAXlgFFmYUIE2BcJtvnVlGCID84ZzCegE8CQ==", + "dependencies": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.5.0", + "pg-pool": "^3.6.0", + "pg-protocol": "^1.6.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-connection-string": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", + "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.0.tgz", + "integrity": "sha512-clFRf2ksqd+F497kWFyM21tMjeikn60oGDmqMT8UBrynEwVEX/5R5xd2sdvdo1cZCFlguORNpVuqxIj+aK4cfQ==", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.0.tgz", + "integrity": "sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-eslint": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/prettier-eslint/-/prettier-eslint-15.0.1.tgz", + "integrity": "sha512-mGOWVHixSvpZWARqSDXbdtTL54mMBxc5oQYQ6RAqy8jecuNJBgN3t9E5a81G66F8x8fsKNiR1HWaBV66MJDOpg==", + "dev": true, + "dependencies": { + "@types/eslint": "^8.4.2", + "@types/prettier": "^2.6.0", + "@typescript-eslint/parser": "^5.10.0", + "common-tags": "^1.4.0", + "dlv": "^1.1.0", + "eslint": "^8.7.0", + "indent-string": "^4.0.0", + "lodash.merge": "^4.6.0", + "loglevel-colored-level-prefix": "^1.0.0", + "prettier": "^2.5.1", + "pretty-format": "^23.0.1", + "require-relative": "^0.8.7", + "typescript": "^4.5.4", + "vue-eslint-parser": "^8.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/prettier-eslint/node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/prettier-eslint/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/prettier-eslint/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/prettier-eslint/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/prettier-eslint/node_modules/pretty-format": { + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", + "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", + "dev": true, + "dependencies": { + "ansi-regex": "^3.0.0", + "ansi-styles": "^3.2.0" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/pretty-format": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.1.3", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.1.tgz", + "integrity": "sha512-0wsrzgTz/kAVIeuxSjnpGC56rzYtr6JT/2BwEvMaPhFIoYa1aGO8LbzuU1R0uUYQkLpWBTOj0l/CLAJB64J6nQ==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "dependencies": { + "resolve": "^1.20.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", + "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true, + "engines": { + "node": ">=6.5.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-relative": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz", + "integrity": "sha512-AKGr4qvHiryxRb19m3PsLRGuKVAbJLUD7E6eOaHkfKhwc+vSgVOCY5xNvm9EkolBKTOf0GrQAZKLimOCz81Khg==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "dependencies": { + "is-core-module": "^2.11.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve.exports": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.1.tgz", + "integrity": "sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-stable-stringify": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", + "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", + "engines": { + "node": ">=10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sax": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", + "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, + "node_modules/simple-update-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", + "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", + "dev": true, + "dependencies": { + "semver": "~7.0.0" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/slice-ansi/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/slice-ansi/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "engines": { + "node": "*" + } + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", + "integrity": "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.4.3", + "side-channel": "^1.0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", + "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/superagent": { + "version": "8.0.9", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.0.9.tgz", + "integrity": "sha512-4C7Bh5pyHTvU33KpZgwrNKh/VQnvgtCSqPRfJAUdmrtSYePVzVg4E4OzsrbkhJj9O7SO6Bnv75K/F8XVZT8YHA==", + "dev": true, + "dependencies": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.4", + "debug": "^4.3.4", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.0", + "formidable": "^2.1.2", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.11.0", + "semver": "^7.3.8" + }, + "engines": { + "node": ">=6.4.0 <13 || >=14" + } + }, + "node_modules/superagent/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/superagent/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/superagent/node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/superagent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/superagent/node_modules/semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/superagent/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/supertest": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.3.3.tgz", + "integrity": "sha512-EMCG6G8gDu5qEqRQ3JjjPs6+FYT1a7Hv5ApHvtSghmOFJYtsU5S+pSb6Y2EUeCEY3CmEL3mmQ8YWlPOzQomabA==", + "dev": true, + "dependencies": { + "methods": "^1.1.2", + "superagent": "^8.0.5" + }, + "engines": { + "node": ">=6.4.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "dependencies": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/table/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/table/node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "node_modules/table/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/table/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/table/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tarn": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tarn/-/tarn-3.0.2.tgz", + "integrity": "sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "node_modules/tildify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tildify/-/tildify-2.0.0.tgz", + "integrity": "sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + }, + "node_modules/tsconfig-paths": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", + "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tsconfig-paths/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", + "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", + "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", + "dependencies": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "node_modules/url/node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "node_modules/v8-to-istanbul": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", + "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vue-eslint-parser": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-8.3.0.tgz", + "integrity": "sha512-dzHGG3+sYwSf6zFBa0Gi9ZDshD7+ad14DGOdTLjruRVgZXe2J+DcZ9iUhyR48z5g1PqRa20yt3Njna/veLJL/g==", + "dev": true, + "dependencies": { + "debug": "^4.3.2", + "eslint-scope": "^7.0.0", + "eslint-visitor-keys": "^3.1.0", + "espree": "^9.0.0", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/vue-eslint-parser/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/vue-eslint-parser/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/vue-eslint-parser/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/vue-eslint-parser/node_modules/semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/vue-eslint-parser/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/winston": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.8.2.tgz", + "integrity": "sha512-MsE1gRx1m5jdTTO9Ld/vND4krP2To+lgDoMEHGGa4HIlAUyXJtfc7CxQcGXVyz2IBpw5hbFkj2b/AtUdQwyRew==", + "dependencies": { + "@colors/colors": "1.5.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.4.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.5.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz", + "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==", + "dependencies": { + "logform": "^2.3.2", + "readable-stream": "^3.6.0", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 6.4.0" + } + }, + "node_modules/winston-transport/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/winston-transport/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/winston-transport/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/winston/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/winston/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/winston/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "dependencies": { + "mkdirp": "^0.5.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true + }, + "@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@babel/code-frame": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "dev": true, + "requires": { + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/compat-data": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.6.tgz", + "integrity": "sha512-29tfsWTq2Ftu7MXmimyC0C5FDZv5DYxOZkh3XD3+QW4V/BYuv/LyEsjj3c0hqedEaDt6DBfDvexMKU8YevdqFg==", + "dev": true + }, + "@babel/core": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.6.tgz", + "integrity": "sha512-HPIyDa6n+HKw5dEuway3vVAhBboYCtREBMp+IWeseZy6TFtzn6MHkCH2KKYUOC/vKKwgSMHQW4htBOrmuRPXfw==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.22.5", + "@babel/generator": "^7.22.5", + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-module-transforms": "^7.22.5", + "@babel/helpers": "^7.22.6", + "@babel/parser": "^7.22.6", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.6", + "@babel/types": "^7.22.5", + "@nicolo-ribaudo/semver-v6": "^6.3.3", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.2" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.3.tgz", + "integrity": "sha512-keeZWAV4LU3tW0qRi19HRpabC/ilM0HRBBzf9/k8FFiG4KVpiv0FIy4hHfLfFQZNhziCTPTmd59zoyv6DNISzg==", + "dev": true, + "requires": { + "@babel/types": "^7.23.3", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.6.tgz", + "integrity": "sha512-534sYEqWD9VfUm3IPn2SLcH4Q3P86XL+QvqdC7ZsFrzyyPF3T4XGiVghF6PTYNdWg6pXuoqXxNQAhbYeEInTzA==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-validator-option": "^7.22.5", + "@nicolo-ribaudo/semver-v6": "^6.3.3", + "browserslist": "^4.21.9", + "lru-cache": "^5.1.1" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true + }, + "@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "requires": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-module-imports": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", + "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-module-transforms": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.5.tgz", + "integrity": "sha512-+hGKDt/Ze8GFExiVHno/2dvG5IdstpzCq0y4Qc9OJ25D4q3pKfiIP/4Vp3/JvhDkLKsDK2api3q3fpIgiIF5bw==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.5", + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.21.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.21.5.tgz", + "integrity": "sha512-0WDaIlXKOX/3KfBK/dwP1oQGiPh6rjMkT7HIRv7i5RR2VUMwrx5ZL0dwBkKx7+SW1zwNdgjHd34IMk5ZjTeHVg==", + "dev": true + }, + "@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-string-parser": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "dev": true + }, + "@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", + "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", + "dev": true + }, + "@babel/helpers": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.6.tgz", + "integrity": "sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA==", + "dev": true, + "requires": { + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.6", + "@babel/types": "^7.22.5" + } + }, + "@babel/highlight": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/parser": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.3.tgz", + "integrity": "sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw==", + "dev": true + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.21.4.tgz", + "integrity": "sha512-xz0D39NvhQn4t4RNsHmDnnsaQizIlUkdtYvLs8La1BlfjQ6JEwxkJGeqJMW2tAXx+q6H+WFuUTXNdYVpEya0YA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2" + } + }, + "@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + } + }, + "@babel/traverse": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.3.tgz", + "integrity": "sha512-+K0yF1/9yR0oHdE0StHuEj3uTPzwwbrLGfNOndVJVV2TqA5+j3oljJUb4nmB954FLGjNem976+B+eDuLIjesiQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.3", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.3", + "@babel/types": "^7.23.3", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.3.tgz", + "integrity": "sha512-OZnvoH2l8PK5eUvEcUyCt/sXgr/h+UWpVuBbOljwcrAgUl6lpchoQ++PHGyQy1AtYnVA6CEq3y5xeEI10brpXw==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + } + }, + "@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==" + }, + "@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "requires": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^3.3.0" + } + }, + "@eslint-community/regexpp": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", + "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", + "dev": true + }, + "@eslint/eslintrc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", + "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.5.2", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@eslint/js": { + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.40.0.tgz", + "integrity": "sha512-ElyB54bJIhXQYVKjDSvCkPO1iU1tSAeVQJbllWJq1XQSmmA4dgFk8CbiBGpiOPxleE48vDogxCtmMYku4HSVLA==", + "dev": true + }, + "@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + } + } + }, + "@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true + }, + "@jest/console": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.3.tgz", + "integrity": "sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw==", + "dev": true, + "requires": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", + "slash": "^3.0.0" + } + }, + "@jest/core": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-28.1.3.tgz", + "integrity": "sha512-CIKBrlaKOzA7YG19BEqCw3SLIsEwjZkeJzf5bdooVnW4bH5cktqe3JX+G2YV1aK5vP8N9na1IGWFzYaTp6k6NA==", + "dev": true, + "requires": { + "@jest/console": "^28.1.3", + "@jest/reporters": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^28.1.3", + "jest-config": "^28.1.3", + "jest-haste-map": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.3", + "jest-resolve-dependencies": "^28.1.3", + "jest-runner": "^28.1.3", + "jest-runtime": "^28.1.3", + "jest-snapshot": "^28.1.3", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", + "jest-watcher": "^28.1.3", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "@jest/environment": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.3.tgz", + "integrity": "sha512-1bf40cMFTEkKyEf585R9Iz1WayDjHoHqvts0XFYEqyKM3cFWDpeMoqKKTAF9LSYQModPUlh8FKptoM2YcMWAXA==", + "dev": true, + "requires": { + "@jest/fake-timers": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "jest-mock": "^28.1.3" + } + }, + "@jest/expect": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-28.1.3.tgz", + "integrity": "sha512-lzc8CpUbSoE4dqT0U+g1qODQjBRHPpCPXissXD4mS9+sWQdmmpeJ9zSH1rS1HEkrsMN0fb7nKrJ9giAR1d3wBw==", + "dev": true, + "requires": { + "expect": "^28.1.3", + "jest-snapshot": "^28.1.3" + } + }, + "@jest/expect-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.3.tgz", + "integrity": "sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA==", + "dev": true, + "requires": { + "jest-get-type": "^28.0.2" + } + }, + "@jest/fake-timers": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.3.tgz", + "integrity": "sha512-D/wOkL2POHv52h+ok5Oj/1gOG9HSywdoPtFsRCUmlCILXNn5eIWmcnd3DIiWlJnpGvQtmajqBP95Ei0EimxfLw==", + "dev": true, + "requires": { + "@jest/types": "^28.1.3", + "@sinonjs/fake-timers": "^9.1.2", + "@types/node": "*", + "jest-message-util": "^28.1.3", + "jest-mock": "^28.1.3", + "jest-util": "^28.1.3" + } + }, + "@jest/globals": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-28.1.3.tgz", + "integrity": "sha512-XFU4P4phyryCXu1pbcqMO0GSQcYe1IsalYCDzRNyhetyeyxMcIxa11qPNDpVNLeretItNqEmYYQn1UYz/5x1NA==", + "dev": true, + "requires": { + "@jest/environment": "^28.1.3", + "@jest/expect": "^28.1.3", + "@jest/types": "^28.1.3" + } + }, + "@jest/reporters": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-28.1.3.tgz", + "integrity": "sha512-JuAy7wkxQZVNU/V6g9xKzCGC5LVXx9FDcABKsSXp5MiKPEE2144a/vXTEDoyzjUpZKfVwp08Wqg5A4WfTMAzjg==", + "dev": true, + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", + "@jridgewell/trace-mapping": "^0.3.13", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", + "jest-worker": "^28.1.3", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^9.0.1" + } + }, + "@jest/schemas": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", + "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "dev": true, + "requires": { + "@sinclair/typebox": "^0.24.1" + } + }, + "@jest/source-map": { + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-28.1.2.tgz", + "integrity": "sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.13", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + } + }, + "@jest/test-result": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.3.tgz", + "integrity": "sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg==", + "dev": true, + "requires": { + "@jest/console": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + } + }, + "@jest/test-sequencer": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-28.1.3.tgz", + "integrity": "sha512-NIMPEqqa59MWnDi1kvXXpYbqsfQmSJsIbnd85mdVGkiDfQ9WQQTXOLsvISUfonmnBT+w85WEgneCigEEdHDFxw==", + "dev": true, + "requires": { + "@jest/test-result": "^28.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "slash": "^3.0.0" + } + }, + "@jest/transform": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.3.tgz", + "integrity": "sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@jest/types": "^28.1.3", + "@jridgewell/trace-mapping": "^0.3.13", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.1" + } + }, + "@jest/types": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", + "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", + "dev": true, + "requires": { + "@jest/schemas": "^28.1.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + } + }, + "@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", + "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + }, + "dependencies": { + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + } + } + }, + "@json2csv/formatters": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/@json2csv/formatters/-/formatters-6.1.3.tgz", + "integrity": "sha512-Yhs6eXTMhSrNFLTuVnhwjgJem2x+z0YZc0YxdCavoDf/tfz6LBVPVVoJPl9tXaCIfPZY9ybRB6sqPQqZTzkNuw==" + }, + "@json2csv/node": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/@json2csv/node/-/node-6.1.3.tgz", + "integrity": "sha512-AYtaZDhmiMW9uiUDPlbFBWcj5JX485TLT7GBukTQh6509Ha/1GXjLpHUQq594Yn2OQeA4BNZAT70InXDm95soA==", + "requires": { + "@json2csv/plainjs": "^6.1.3" + } + }, + "@json2csv/plainjs": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/@json2csv/plainjs/-/plainjs-6.1.3.tgz", + "integrity": "sha512-8cH/yVAPt1edDq/2Krr4elS2uJFWAdMQDH+ocuepjyh7lmBHEHv5kU0bqbYpd5ZpKTizshotsKk7KYA3nx4CCw==", + "requires": { + "@json2csv/formatters": "^6.1.3", + "@streamparser/json": "^0.0.12", + "lodash.get": "^4.4.2" + } + }, + "@json2csv/transforms": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/@json2csv/transforms/-/transforms-6.1.3.tgz", + "integrity": "sha512-MwJsNUt68/0B7kdlZOn7R4jn7EXOhNEZ3bwKfYwPtyAM/GD4ctSIazfV69hI+i5jxmIEvizh8rRgU/8/qrjsAA==", + "requires": { + "lodash.get": "^4.4.2" + } + }, + "@nicolo-ribaudo/semver-v6": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/semver-v6/-/semver-v6-6.3.3.tgz", + "integrity": "sha512-3Yc1fUTs69MG/uZbJlLSI3JISMn2UV2rg+1D/vROUqZyh3l6iYHCs7GMp+M40ZD7yOdDbYjJcU1oTJhrc+dGKg==", + "dev": true + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@sinclair/typebox": { + "version": "0.24.51", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "dev": true + }, + "@sinonjs/commons": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", + "integrity": "sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^1.7.0" + } + }, + "@streamparser/json": { + "version": "0.0.12", + "resolved": "https://registry.npmjs.org/@streamparser/json/-/json-0.0.12.tgz", + "integrity": "sha512-+kmRpd+EeTFd3qNt1AoKphJqbAN26ZDsbiwqjBFeoAmdCyiUO19xMXPtYi9vovAj9a7OAJnvWtiHkwwjU2Fx4Q==" + }, + "@types/babel__core": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", + "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", + "dev": true, + "requires": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.18.5", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.5.tgz", + "integrity": "sha512-enCvTL8m/EHS/zIvJno9nE+ndYPh1/oNFzRYRmtUqJICG2VnCSBzMLW5VN2KCQU91f23tsNKR8v7VJJQMatl7Q==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0" + } + }, + "@types/eslint": { + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.37.0.tgz", + "integrity": "sha512-Piet7dG2JBuDIfohBngQ3rCt7MgO9xCO4xIMKxBThCq5PNRB91IjlJ10eJVwfoNtvTErmxLzwBZ7rHZtbOMmFQ==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/estree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", + "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", + "dev": true + }, + "@types/graceful-fs": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", + "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "@types/node": { + "version": "20.1.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.1.2.tgz", + "integrity": "sha512-CTO/wa8x+rZU626cL2BlbCDzydgnFNgc19h4YvizpTO88MFQxab8wqisxaofQJ/9bLGugRdWIuX/TbIs6VVF6g==", + "dev": true + }, + "@types/prettier": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", + "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", + "dev": true + }, + "@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "@types/triple-beam": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.2.tgz", + "integrity": "sha512-txGIh+0eDFzKGC25zORnswy+br1Ha7hj5cMVwKIU7+s0U2AxxJru/jZSMU6OC9MJWP6+pc/hc6ZjyZShpsyY2g==" + }, + "@types/yargs": { + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "@typescript-eslint/parser": { + "version": "5.59.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.5.tgz", + "integrity": "sha512-NJXQC4MRnF9N9yWqQE2/KLRSOLvrrlZb48NGVfBa+RuPMN6B7ZcK5jZOvhuygv4D64fRKnZI4L4p8+M+rfeQuw==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.59.5", + "@typescript-eslint/types": "5.59.5", + "@typescript-eslint/typescript-estree": "5.59.5", + "debug": "^4.3.4" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@typescript-eslint/scope-manager": { + "version": "5.59.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.5.tgz", + "integrity": "sha512-jVecWwnkX6ZgutF+DovbBJirZcAxgxC0EOHYt/niMROf8p4PwxxG32Qdhj/iIQQIuOflLjNkxoXyArkcIP7C3A==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.59.5", + "@typescript-eslint/visitor-keys": "5.59.5" + } + }, + "@typescript-eslint/types": { + "version": "5.59.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.5.tgz", + "integrity": "sha512-xkfRPHbqSH4Ggx4eHRIO/eGL8XL4Ysb4woL8c87YuAo8Md7AUjyWKa9YMwTL519SyDPrfEgKdewjkxNCVeJW7w==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.59.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.5.tgz", + "integrity": "sha512-+XXdLN2CZLZcD/mO7mQtJMvCkzRfmODbeSKuMY/yXbGkzvA9rJyDY5qDYNoiz2kP/dmyAxXquL2BvLQLJFPQIg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.59.5", + "@typescript-eslint/visitor-keys": "5.59.5", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.59.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.5.tgz", + "integrity": "sha512-qL+Oz+dbeBRTeyJTIy0eniD3uvqU7x+y1QceBismZ41hd4aBSRh8UAw4pZP0+XzLuPZmx4raNMq/I+59W2lXKA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.59.5", + "eslint-visitor-keys": "^3.3.0" + } + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + }, + "dependencies": { + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + } + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "api-problem": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/api-problem/-/api-problem-7.0.4.tgz", + "integrity": "sha512-8f/Dg1LY26YSMzhguscyJWw2qVafdczyK82+X7zcnv73iN1mh4KmVEm2w7xAL3ttpWddPE7lTKMRFdidH/dFYA==" + }, + "append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==" + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "array-buffer-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", + "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "is-array-buffer": "^3.0.1" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "array-includes": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz", + "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "is-string": "^1.0.7" + } + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "array.prototype.flat": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz", + "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + } + }, + "array.prototype.flatmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz", + "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0" + } + }, + "array.prototype.tosorted": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz", + "integrity": "sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "es-shim-unscopables": "^1.0.0", + "get-intrinsic": "^1.1.3" + } + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true + }, + "asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" + }, + "aws-sdk": { + "version": "2.1376.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1376.0.tgz", + "integrity": "sha512-ja/Xnft8BDcDEz786VJFPrWpuWpOgsA+QzBAwzsjYeIolQ/vEs/bbXkoS085fOoeAPEhYWQh9wog7cVvrQPJFQ==", + "requires": { + "buffer": "4.9.2", + "events": "1.1.1", + "ieee754": "1.1.13", + "jmespath": "0.16.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "util": "^0.12.4", + "uuid": "8.0.0", + "xml2js": "0.5.0" + }, + "dependencies": { + "uuid": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", + "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==" + } + } + }, + "axios": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", + "requires": { + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" + } + }, + "axios-oauth-client": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/axios-oauth-client/-/axios-oauth-client-1.5.0.tgz", + "integrity": "sha512-CFuTfK9KdRnDDR6LQlUJ0GNKUZ3tHRSFdKPM9WqeCtUdcuKDgWt9aDFH7Xl87VpUcfNt5qRVl4iHdayqtXVv7g==", + "requires": { + "qs": "^6.10.1" + } + }, + "axios-token-interceptor": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/axios-token-interceptor/-/axios-token-interceptor-0.2.0.tgz", + "integrity": "sha512-la74OEsXBH1IS9yI6p2oTIynPtBzs0PVUSOwOBgFg2kBwTeDqQ+YJ6jaOWxsTYyqJO510OzHTfnzAn3GFuf9xA==", + "requires": { + "lock": "^1.1.0" + } + }, + "babel-eslint": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", + "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.0", + "@babel/traverse": "^7.7.0", + "@babel/types": "^7.7.0", + "eslint-visitor-keys": "^1.0.0", + "resolve": "^1.12.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "babel-jest": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.3.tgz", + "integrity": "sha512-epUaPOEWMk3cWX0M/sPvCHHCe9fMFAa/9hXEgKP8nFfNl/jlGkE9ucq9NqkZGXLDduCJYS0UvSlPUwC0S+rH6Q==", + "dev": true, + "requires": { + "@jest/transform": "^28.1.3", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^28.1.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + } + }, + "babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + } + }, + "babel-plugin-jest-hoist": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.1.3.tgz", + "integrity": "sha512-Ys3tUKAmfnkRUpPdpa98eYrAR0nV+sSFUZZEGuQ2EbFd1y4SOLtD5QDNHAq+bb9a+bbXvYQC4b+ID/THIMcU6Q==", + "dev": true, + "requires": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "requires": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + } + }, + "babel-preset-jest": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-28.1.3.tgz", + "integrity": "sha512-L+fupJvlWAHbQfn74coNX3zf60LXMJsezNvvx8eIh7iOR1luJ1poxYgQk1F8PYtNq/6QODDHCqsSnTFSWC491A==", + "dev": true, + "requires": { + "babel-plugin-jest-hoist": "^28.1.3", + "babel-preset-current-node-syntax": "^1.0.0" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "dependencies": { + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "requires": { + "side-channel": "^1.0.4" + } + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + }, + "browserslist": { + "version": "4.21.9", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.9.tgz", + "integrity": "sha512-M0MFoZzbUrRU4KNfCrDLnvyE7gub+peetoTid3TBIqtunaDJyXlwhakT+/VkvSXcfIzFfK/nkCs4nmyTmxdNSg==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001503", + "electron-to-chromium": "^1.4.431", + "node-releases": "^2.0.12", + "update-browserslist-db": "^1.0.11" + } + }, + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "requires": { + "node-int64": "^0.4.0" + } + }, + "buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" + }, + "busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "requires": { + "streamsearch": "^1.1.0" + } + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001512", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001512.tgz", + "integrity": "sha512-2S9nK0G/mE+jasCUsMPlARhRCts1ebcp2Ji8Y8PWi4NDE1iRdLCnEPHkEfeBrGC45L4isBx5ur3IQ6yTE2mRZw==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "ci-info": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "dev": true + }, + "cjs-module-lexer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "dev": true + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true + }, + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true + }, + "collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": true + }, + "color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "requires": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + }, + "dependencies": { + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + } + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==" + }, + "colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "requires": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "common-tags": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", + "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", + "dev": true + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==" + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "config": { + "version": "3.3.9", + "resolved": "https://registry.npmjs.org/config/-/config-3.3.9.tgz", + "integrity": "sha512-G17nfe+cY7kR0wVpc49NCYvNtelm/pPy8czHoFkAgtV1lkmcp7DHtWCdDu+C9Z7gb2WVqa9Tm3uF9aKaPbCfhg==", + "requires": { + "json5": "^2.2.3" + } + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "requires": { + "safe-buffer": "5.2.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, + "content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" + }, + "convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "cookiejar": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz", + "integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==", + "dev": true + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "crypto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/crypto/-/crypto-1.0.1.tgz", + "integrity": "sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig==" + }, + "db-errors": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/db-errors/-/db-errors-0.2.3.tgz", + "integrity": "sha512-OOgqgDuCavHXjYSJoV2yGhv6SeG8nk42aoCSoyXLZUH7VwFG27rxbavU1z+VrZbZjphw5UkDQwUlD21MwZpUng==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": true + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true + }, + "define-properties": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", + "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==", + "dev": true, + "requires": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" + }, + "detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true + }, + "dezalgo": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", + "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, + "requires": { + "asap": "^2.0.0", + "wrappy": "1" + } + }, + "diff-sequences": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", + "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "electron-to-chromium": { + "version": "1.4.451", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.451.tgz", + "integrity": "sha512-YYbXHIBxAHe3KWvGOJOuWa6f3tgow44rBW+QAuwVp2DvGqNZeE//K2MowNdWS7XE8li5cgQDrX1LdBr41LufkA==", + "dev": true + }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "emittery": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", + "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.21.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz", + "integrity": "sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==", + "dev": true, + "requires": { + "array-buffer-byte-length": "^1.0.0", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.2.0", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.10", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.7", + "string.prototype.trimend": "^1.0.6", + "string.prototype.trimstart": "^1.0.6", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.9" + } + }, + "es-set-tostringtag": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz", + "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3", + "has": "^1.0.3", + "has-tostringtag": "^1.0.0" + } + }, + "es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint": { + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.40.0.tgz", + "integrity": "sha512-bvR+TsP9EHL3TqNtj9sCNJVAFK3fBN8Q7g5waghxyRsPLIMwL73XSKnZFK0hk/O2ANC+iAoq6PWMQ+IfBAJIiQ==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.0.3", + "@eslint/js": "8.40.0", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.0", + "eslint-visitor-keys": "^3.4.1", + "espree": "^9.5.2", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "eslint-config-esnext": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-esnext/-/eslint-config-esnext-4.1.0.tgz", + "integrity": "sha512-GhfVEXdqYKEIIj7j+Fw2SQdL9qyZMekgXfq6PyXM66cQw0B435ddjz3P3kxOBVihMRJ0xGYjosaveQz5Y6z0uA==", + "dev": true, + "requires": { + "babel-eslint": "^10.0.1", + "eslint": "^6.8.0", + "eslint-plugin-babel": "^5.2.1", + "eslint-plugin-import": "^2.14.0" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true + } + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "espree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "eslint-config-node": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-node/-/eslint-config-node-4.1.0.tgz", + "integrity": "sha512-Wz17xV5O2WFG8fGdMYEBdbiL6TL7YNJSJvSX9V4sXQownewfYmoqlly7wxqLkOUv/57pq6LnnotMiQQrrPjCqQ==", + "dev": true, + "requires": { + "eslint": "^6.8.0", + "eslint-config-esnext": "^4.1.0" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true + } + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "espree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "eslint-config-prettier": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz", + "integrity": "sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==", + "dev": true, + "requires": {} + }, + "eslint-config-react-native": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-react-native/-/eslint-config-react-native-4.1.0.tgz", + "integrity": "sha512-kNND+cs+ztawH7wgajf/K6FfNshjlDsFDAkkFZF9HAXDgH1w1sNMIfTfwzufg0hOcSK7rbiL4qbG/gg/oR507Q==", + "dev": true, + "requires": { + "eslint": "^6.8.0", + "eslint-config-esnext": "^4.1.0", + "eslint-plugin-react": "^7.19.0", + "eslint-plugin-react-native": "^3.8.1" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true + } + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + } + }, + "eslint-plugin-react-native": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-native/-/eslint-plugin-react-native-3.11.0.tgz", + "integrity": "sha512-7F3OTwrtQPfPFd+VygqKA2VZ0f2fz0M4gJmry/TRE18JBb94/OtMxwbL7Oqwu7FGyrdeIOWnXQbBAveMcSTZIA==", + "dev": true, + "requires": { + "@babel/traverse": "^7.7.4", + "eslint-plugin-react-native-globals": "^0.1.1" + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "espree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "eslint-config-recommended": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-recommended/-/eslint-config-recommended-4.1.0.tgz", + "integrity": "sha512-2evA0SX1VqtyFiExmBI2WAO4XQCKlr7wmNELE8rcT5PyZY2ixsY881ofVZWKuI/dywpgLiES1gR/XUQcnVLRzQ==", + "dev": true, + "requires": { + "eslint": "^6.8.0", + "eslint-config-esnext": "^4.1.0", + "eslint-config-node": "^4.1.0", + "eslint-config-react-native": "^4.1.0" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + }, + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true + } + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "eslint": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "ajv": "^6.10.0", + "chalk": "^2.1.0", + "cross-spawn": "^6.0.5", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "eslint-scope": "^5.0.0", + "eslint-utils": "^1.4.3", + "eslint-visitor-keys": "^1.1.0", + "espree": "^6.1.2", + "esquery": "^1.0.1", + "esutils": "^2.0.2", + "file-entry-cache": "^5.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.0.0", + "globals": "^12.1.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "inquirer": "^7.0.0", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.3.0", + "lodash": "^4.17.14", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "optionator": "^0.8.3", + "progress": "^2.0.0", + "regexpp": "^2.0.1", + "semver": "^6.1.2", + "strip-ansi": "^5.2.0", + "strip-json-comments": "^3.0.1", + "table": "^5.2.3", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "espree": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", + "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "dev": true, + "requires": { + "acorn": "^7.1.1", + "acorn-jsx": "^5.2.0", + "eslint-visitor-keys": "^1.1.0" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "file-entry-cache": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", + "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "dev": true, + "requires": { + "flat-cache": "^2.0.1" + } + }, + "flat-cache": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", + "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "dev": true, + "requires": { + "flatted": "^2.0.0", + "rimraf": "2.6.3", + "write": "1.0.3" + } + }, + "flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", + "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "dev": true, + "requires": { + "type-fest": "^0.8.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + } + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "dev": true + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "eslint-import-resolver-node": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz", + "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==", + "dev": true, + "requires": { + "debug": "^3.2.7", + "is-core-module": "^2.11.0", + "resolve": "^1.22.1" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + } + } + }, + "eslint-module-utils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", + "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "dev": true, + "requires": { + "debug": "^3.2.7" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + } + } + }, + "eslint-plugin-babel": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-babel/-/eslint-plugin-babel-5.3.1.tgz", + "integrity": "sha512-VsQEr6NH3dj664+EyxJwO4FCYm/00JhYb3Sk3ft8o+fpKuIfQ9TaW6uVUfvwMXHcf/lsnRIoyFPsLMyiWCSL/g==", + "dev": true, + "requires": { + "eslint-rule-composer": "^0.3.0" + } + }, + "eslint-plugin-import": { + "version": "2.27.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz", + "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==", + "dev": true, + "requires": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "array.prototype.flatmap": "^1.3.1", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.7", + "eslint-module-utils": "^2.7.4", + "has": "^1.0.3", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.6", + "resolve": "^1.22.1", + "semver": "^6.3.0", + "tsconfig-paths": "^3.14.1" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + } + } + }, + "eslint-plugin-prettier": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz", + "integrity": "sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, + "eslint-plugin-react": { + "version": "7.32.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.32.2.tgz", + "integrity": "sha512-t2fBMa+XzonrrNkyVirzKlvn5RXzzPwRHtMvLAtVZrt8oxgnTQaYbU6SXTOO1mwQgp1y5+toMSKInnzGr0Knqg==", + "dev": true, + "requires": { + "array-includes": "^3.1.6", + "array.prototype.flatmap": "^1.3.1", + "array.prototype.tosorted": "^1.1.1", + "doctrine": "^2.1.0", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.6", + "object.fromentries": "^2.0.6", + "object.hasown": "^1.1.2", + "object.values": "^1.1.6", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.4", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.8" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "resolve": { + "version": "2.0.0-next.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", + "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + } + } + }, + "eslint-plugin-react-native-globals": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-native-globals/-/eslint-plugin-react-native-globals-0.1.2.tgz", + "integrity": "sha512-9aEPf1JEpiTjcFAmmyw8eiIXmcNZOqaZyHO77wgm0/dWfT/oxC1SrIq8ET38pMxHYrcB6Uew+TzUVsBeczF88g==", + "dev": true + }, + "eslint-rule-composer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", + "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", + "dev": true + }, + "eslint-scope": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", + "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", + "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", + "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", + "dev": true + }, + "esm": { + "version": "3.2.25", + "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", + "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==" + }, + "espree": { + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", + "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", + "dev": true, + "requires": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" + }, + "events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==" + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true + }, + "expect": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.3.tgz", + "integrity": "sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g==", + "dev": true, + "requires": { + "@jest/expect-utils": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3" + } + }, + "express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + } + }, + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "requires": { + "side-channel": "^1.0.4" + } + }, + "raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, + "express-basic-auth": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/express-basic-auth/-/express-basic-auth-1.2.1.tgz", + "integrity": "sha512-L6YQ1wQ/mNjVLAmK3AG1RK6VkokA1BIY6wmiH304Xtt/cLTps40EusZsU1Uop+v9lTDPxdtzbFmdXfFO3KEnwA==", + "requires": { + "basic-auth": "^2.0.1" + } + }, + "express-rate-limit": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-7.1.3.tgz", + "integrity": "sha512-BDes6WeNYSGRRGQU8QDNwUnwqaBro28HN/TTweM3RlxXRHDld8RLoH7tbfCxAc0hamQyn6aL0KrfR45+ZxknYg==", + "requires": {} + }, + "express-winston": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/express-winston/-/express-winston-4.2.0.tgz", + "integrity": "sha512-EMD74g63nVHi7pFleQw7KHCxiA1pjF5uCwbCfzGqmFxs9KvlDPIVS3cMGpULm6MshExMT9TjC3SqmRGB9kb7yw==", + "requires": { + "chalk": "^2.4.2", + "lodash": "^4.17.21" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "falsey": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/falsey/-/falsey-1.0.0.tgz", + "integrity": "sha512-zMDNZ/Ipd8MY0+346CPvhzP1AsiVyNfTOayJza4reAIWf72xbkuFUDcJNxSAsQE1b9Bu0wijKb8Ngnh/a7fI5w==" + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "fast-json-patch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz", + "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==" + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true + }, + "fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "requires": { + "bser": "2.1.1" + } + }, + "fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + } + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, + "follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" + }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "requires": { + "is-callable": "^1.1.3" + } + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "formidable": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-2.1.2.tgz", + "integrity": "sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==", + "dev": true, + "requires": { + "dezalgo": "^1.0.4", + "hexoid": "^1.0.0", + "once": "^1.4.0", + "qs": "^6.11.0" + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" + }, + "fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + } + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-intrinsic": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz", + "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==" + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "getopts": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/getopts/-/getopts-2.3.0.tgz", + "integrity": "sha512-5eDf9fuSXwxBL6q5HX+dhDj+dslFGWzU5thZ9kNKUkcPtaPdatmUFKwHFrLb/uf/WpA4BHET+AX3Scl56cAjpA==" + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3" + } + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "requires": { + "get-intrinsic": "^1.1.3" + } + }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "requires": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4", + "wordwrap": "^1.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true + } + } + }, + "has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.1" + } + }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "dev": true + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "requires": { + "has-symbols": "^1.0.2" + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hexoid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", + "integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==", + "dev": true + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, + "ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true + }, + "ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "inquirer": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", + "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.19", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.6.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + } + }, + "internal-slot": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz", + "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, + "interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==" + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-array-buffer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", + "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==" + }, + "is-core-module": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz", + "integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==", + "requires": { + "has": "^1.0.3" + } + }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true + }, + "is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-typed-array": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz", + "integrity": "sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==", + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "requires": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "jest": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest/-/jest-28.1.3.tgz", + "integrity": "sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA==", + "dev": true, + "requires": { + "@jest/core": "^28.1.3", + "@jest/types": "^28.1.3", + "import-local": "^3.0.2", + "jest-cli": "^28.1.3" + } + }, + "jest-changed-files": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-28.1.3.tgz", + "integrity": "sha512-esaOfUWJXk2nfZt9SPyC8gA1kNfdKLkQWyzsMlqq8msYSlNKfmZxfRgZn4Cd4MGVUF+7v6dBs0d5TOAKa7iIiA==", + "dev": true, + "requires": { + "execa": "^5.0.0", + "p-limit": "^3.1.0" + } + }, + "jest-circus": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-28.1.3.tgz", + "integrity": "sha512-cZ+eS5zc79MBwt+IhQhiEp0OeBddpc1n8MBo1nMB8A7oPMKEO+Sre+wHaLJexQUj9Ya/8NOBY0RESUgYjB6fow==", + "dev": true, + "requires": { + "@jest/environment": "^28.1.3", + "@jest/expect": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^28.1.3", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-runtime": "^28.1.3", + "jest-snapshot": "^28.1.3", + "jest-util": "^28.1.3", + "p-limit": "^3.1.0", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-cli": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-28.1.3.tgz", + "integrity": "sha512-roY3kvrv57Azn1yPgdTebPAXvdR2xfezaKKYzVxZ6It/5NCxzJym6tUI5P1zkdWhfUYkxEI9uZWcQdaFLo8mJQ==", + "dev": true, + "requires": { + "@jest/core": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^28.1.3", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", + "prompts": "^2.0.1", + "yargs": "^17.3.1" + } + }, + "jest-config": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-28.1.3.tgz", + "integrity": "sha512-MG3INjByJ0J4AsNBm7T3hsuxKQqFIiRo/AUqb1q9LRKI5UU6Aar9JHbr9Ivn1TVwfUD9KirRoM/T6u8XlcQPHQ==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^28.1.3", + "@jest/types": "^28.1.3", + "babel-jest": "^28.1.3", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^28.1.3", + "jest-environment-node": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.3", + "jest-runner": "^28.1.3", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + } + }, + "jest-diff": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", + "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^28.1.1", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + } + }, + "jest-docblock": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-28.1.1.tgz", + "integrity": "sha512-3wayBVNiOYx0cwAbl9rwm5kKFP8yHH3d/fkEaL02NPTkDojPtheGB7HZSFY4wzX+DxyrvhXz0KSCVksmCknCuA==", + "dev": true, + "requires": { + "detect-newline": "^3.0.0" + } + }, + "jest-each": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-28.1.3.tgz", + "integrity": "sha512-arT1z4sg2yABU5uogObVPvSlSMQlDA48owx07BDPAiasW0yYpYHYOo4HHLz9q0BVzDVU4hILFjzJw0So9aCL/g==", + "dev": true, + "requires": { + "@jest/types": "^28.1.3", + "chalk": "^4.0.0", + "jest-get-type": "^28.0.2", + "jest-util": "^28.1.3", + "pretty-format": "^28.1.3" + } + }, + "jest-environment-node": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-28.1.3.tgz", + "integrity": "sha512-ugP6XOhEpjAEhGYvp5Xj989ns5cB1K6ZdjBYuS30umT4CQEETaxSiPcZ/E1kFktX4GkrcM4qu07IIlDYX1gp+A==", + "dev": true, + "requires": { + "@jest/environment": "^28.1.3", + "@jest/fake-timers": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "jest-mock": "^28.1.3", + "jest-util": "^28.1.3" + } + }, + "jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true + }, + "jest-haste-map": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", + "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "jest-worker": "^28.1.3", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + } + }, + "jest-leak-detector": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-28.1.3.tgz", + "integrity": "sha512-WFVJhnQsiKtDEo5lG2mM0v40QWnBM+zMdHHyJs8AWZ7J0QZJS59MsyKeJHWhpBZBH32S48FOVvGyOFT1h0DlqA==", + "dev": true, + "requires": { + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + } + }, + "jest-matcher-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz", + "integrity": "sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^28.1.3", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + } + }, + "jest-message-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", + "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^28.1.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + } + }, + "jest-mock": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.3.tgz", + "integrity": "sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.3", + "@types/node": "*" + } + }, + "jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "requires": {} + }, + "jest-regex-util": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", + "dev": true + }, + "jest-resolve": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-28.1.3.tgz", + "integrity": "sha512-Z1W3tTjE6QaNI90qo/BJpfnvpxtaFTFw5CDgwpyE/Kz8U/06N1Hjf4ia9quUhCh39qIGWF1ZuxFiBiJQwSEYKQ==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", + "slash": "^3.0.0" + } + }, + "jest-resolve-dependencies": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.3.tgz", + "integrity": "sha512-qa0QO2Q0XzQoNPouMbCc7Bvtsem8eQgVPNkwn9LnS+R2n8DaVDPL/U1gngC0LTl1RYXJU0uJa2BMC2DbTfFrHA==", + "dev": true, + "requires": { + "jest-regex-util": "^28.0.2", + "jest-snapshot": "^28.1.3" + } + }, + "jest-runner": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-28.1.3.tgz", + "integrity": "sha512-GkMw4D/0USd62OVO0oEgjn23TM+YJa2U2Wu5zz9xsQB1MxWKDOlrnykPxnMsN0tnJllfLPinHTka61u0QhaxBA==", + "dev": true, + "requires": { + "@jest/console": "^28.1.3", + "@jest/environment": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "graceful-fs": "^4.2.9", + "jest-docblock": "^28.1.1", + "jest-environment-node": "^28.1.3", + "jest-haste-map": "^28.1.3", + "jest-leak-detector": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-resolve": "^28.1.3", + "jest-runtime": "^28.1.3", + "jest-util": "^28.1.3", + "jest-watcher": "^28.1.3", + "jest-worker": "^28.1.3", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + } + }, + "jest-runtime": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-28.1.3.tgz", + "integrity": "sha512-NU+881ScBQQLc1JHG5eJGU7Ui3kLKrmwCPPtYsJtBykixrM2OhVQlpMmFWJjMyDfdkGgBMNjXCGB/ebzsgNGQw==", + "dev": true, + "requires": { + "@jest/environment": "^28.1.3", + "@jest/fake-timers": "^28.1.3", + "@jest/globals": "^28.1.3", + "@jest/source-map": "^28.1.2", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-mock": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.3", + "jest-snapshot": "^28.1.3", + "jest-util": "^28.1.3", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + } + }, + "jest-snapshot": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-28.1.3.tgz", + "integrity": "sha512-4lzMgtiNlc3DU/8lZfmqxN3AYD6GGLbl+72rdBpXvcV+whX7mDrREzkPdp2RnmfIiWBg1YbuFSkXduF2JcafJg==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/babel__traverse": "^7.0.6", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^28.1.3", + "graceful-fs": "^4.2.9", + "jest-diff": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-haste-map": "^28.1.3", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", + "natural-compare": "^1.4.0", + "pretty-format": "^28.1.3", + "semver": "^7.3.5" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "jest-util": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", + "dev": true, + "requires": { + "@jest/types": "^28.1.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + } + }, + "jest-validate": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-28.1.3.tgz", + "integrity": "sha512-SZbOGBWEsaTxBGCOpsRWlXlvNkvTkY0XxRfh7zYmvd8uL5Qzyg0CHAXiXKROflh801quA6+/DsT4ODDthOC/OA==", + "dev": true, + "requires": { + "@jest/types": "^28.1.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^28.0.2", + "leven": "^3.1.0", + "pretty-format": "^28.1.3" + }, + "dependencies": { + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + } + } + }, + "jest-watcher": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.3.tgz", + "integrity": "sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g==", + "dev": true, + "requires": { + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.10.2", + "jest-util": "^28.1.3", + "string-length": "^4.0.1" + } + }, + "jest-worker": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jmespath": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", + "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==" + }, + "js-sdsl": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", + "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "requires": { + "argparse": "^2.0.1" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==" + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "jsonwebtoken": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", + "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", + "requires": { + "jws": "^3.2.2", + "lodash": "^4.17.21", + "ms": "^2.1.1", + "semver": "^7.3.8" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, + "jsx-ast-utils": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", + "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", + "dev": true, + "requires": { + "array-includes": "^3.1.5", + "object.assign": "^4.1.3" + } + }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jwk-to-pem": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/jwk-to-pem/-/jwk-to-pem-2.0.5.tgz", + "integrity": "sha512-L90jwellhO8jRKYwbssU9ifaMVqajzj3fpRjDKcsDzrslU9syRbFqfkXtT4B89HYAap+xsxNcxgBSB09ig+a7A==", + "requires": { + "asn1.js": "^5.3.0", + "elliptic": "^6.5.4", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, + "keycloak-connect": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/keycloak-connect/-/keycloak-connect-21.1.1.tgz", + "integrity": "sha512-FFLhsnXjo+OmzMJpFhHcTjLHLwT18aZi1hJj/TLwXjijyHUFDBdVyD+uF7Hspcs4A4s00xwteAqkQGMlFQa6Yw==", + "requires": { + "chromedriver": "latest", + "jwk-to-pem": "^2.0.0" + } + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true + }, + "knex": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/knex/-/knex-2.4.2.tgz", + "integrity": "sha512-tMI1M7a+xwHhPxjbl/H9K1kHX+VncEYcvCx5K00M16bWvpYPKAZd6QrCu68PtHAdIZNQPWZn0GVhqVBEthGWCg==", + "requires": { + "colorette": "2.0.19", + "commander": "^9.1.0", + "debug": "4.3.4", + "escalade": "^3.1.1", + "esm": "^3.2.25", + "get-package-type": "^0.1.0", + "getopts": "2.3.0", + "interpret": "^2.2.0", + "lodash": "^4.17.21", + "pg-connection-string": "2.5.0", + "rechoir": "^0.8.0", + "resolve-from": "^5.0.0", + "tarn": "^3.0.2", + "tildify": "2.0.0" + }, + "dependencies": { + "commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==" + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" + } + } + }, + "kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "lock": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/lock/-/lock-1.1.0.tgz", + "integrity": "sha512-NZQIJJL5Rb9lMJ0Yl1JoVr9GSdo4HTPsUEWsSFzB8dE8DSoiLCVavWZPi7Rnlv/o73u6I24S/XYc/NmG4l8EKA==" + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "logform": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.5.1.tgz", + "integrity": "sha512-9FyqAm9o9NKKfiAKfZoYo9bGXXuwMkxQiQttkT4YjjVtQVIQtK6LmVtlxmCaFswo6N4AfEkHqZTV0taDtPotNg==", + "requires": { + "@colors/colors": "1.5.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + }, + "dependencies": { + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "loglevel": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.8.1.tgz", + "integrity": "sha512-tCRIJM51SHjAayKwC+QAg8hT8vg6z7GSgLJKGvzuPb1Wc+hLzqtuVLxp6/HzSPOozuK+8ErAhy7U/sVzw8Dgfg==", + "dev": true + }, + "loglevel-colored-level-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/loglevel-colored-level-prefix/-/loglevel-colored-level-prefix-1.0.0.tgz", + "integrity": "sha512-u45Wcxxc+SdAlh4yeF/uKlC1SPUPCy0gullSNKXod5I4bmifzk+Q4lSLExNEVn19tGaJipbZ4V4jbFn79/6mVA==", + "dev": true, + "requires": { + "chalk": "^1.1.3", + "loglevel": "^1.4.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "dev": true + } + } + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "requires": { + "tmpl": "1.0.5" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "requires": { + "minimist": "^1.2.6" + } + }, + "moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "multer": { + "version": "1.4.5-lts.1", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.5-lts.1.tgz", + "integrity": "sha512-ywPWvcDMeH+z9gQq5qYHCCy+ethsk4goepZ45GLD63fOu0YcNecQxi64nDs3qluZB+murG3/D4dJ7+dGctcCQQ==", + "requires": { + "append-field": "^1.0.0", + "busboy": "^1.0.0", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.4", + "object-assign": "^4.1.1", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + } + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "nested-objects-util": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/nested-objects-util/-/nested-objects-util-1.1.2.tgz", + "integrity": "sha512-jNUcnODTq1HpGGFFo9aDXP7JxrJ1ilLHSaUElSyW5Zw8EJHyYyujdBIdTwa0K4lBC/9M23dJyhExo9XyhO39LQ==" + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true + }, + "node-releases": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz", + "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==", + "dev": true + }, + "nodemon": { + "version": "2.0.22", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", + "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==", + "dev": true, + "requires": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==" + }, + "object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==" + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + } + }, + "object.entries": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.6.tgz", + "integrity": "sha512-leTPzo4Zvg3pmbQ3rDK69Rl8GQvIqMWubrkxONG9/ojtFE2rD9fjMKfSI5BxW3osRH1m6VdzmqK8oAY9aT4x5w==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "object.fromentries": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.6.tgz", + "integrity": "sha512-VciD13dswC4j1Xt5394WR4MzmAQmlgN72phd/riNp9vtD7tp4QQWJ0R4wvclXcafgcYK8veHRed2W6XeGBvcfg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "object.hasown": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.2.tgz", + "integrity": "sha512-B5UIT3J1W+WuWIU55h0mjlwaqxiE5vYENJXIXZ4VFe05pNYrkKuK0U/6aFcb0pKywYJh7IhfoqUfKVmrJJHZHw==", + "dev": true, + "requires": { + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "object.values": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz", + "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "objection": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/objection/-/objection-3.0.1.tgz", + "integrity": "sha512-rqNnyQE+C55UHjdpTOJEKQHJGZ/BGtBBtgxdUpKG4DQXRUmqxfmgS/MhPWxB9Pw0mLSVLEltr6soD4c0Sddy0Q==", + "requires": { + "ajv": "^8.6.2", + "db-errors": "^0.2.3" + }, + "dependencies": { + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + } + } + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "requires": { + "fn.name": "1.x.x" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "requires": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "pg": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.10.0.tgz", + "integrity": "sha512-ke7o7qSTMb47iwzOSaZMfeR7xToFdkE71ifIipOAAaLIM0DYzfOAXlgFFmYUIE2BcJtvnVlGCID84ZzCegE8CQ==", + "requires": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.5.0", + "pg-pool": "^3.6.0", + "pg-protocol": "^1.6.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + } + }, + "pg-connection-string": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", + "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" + }, + "pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" + }, + "pg-pool": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.0.tgz", + "integrity": "sha512-clFRf2ksqd+F497kWFyM21tMjeikn60oGDmqMT8UBrynEwVEX/5R5xd2sdvdo1cZCFlguORNpVuqxIj+aK4cfQ==", + "requires": {} + }, + "pg-protocol": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.0.tgz", + "integrity": "sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==" + }, + "pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "requires": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + } + }, + "pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "requires": { + "split2": "^4.1.0" + } + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + } + } + }, + "postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" + }, + "postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==" + }, + "postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==" + }, + "postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "requires": { + "xtend": "^4.0.0" + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true + }, + "prettier-eslint": { + "version": "15.0.1", + "resolved": "https://registry.npmjs.org/prettier-eslint/-/prettier-eslint-15.0.1.tgz", + "integrity": "sha512-mGOWVHixSvpZWARqSDXbdtTL54mMBxc5oQYQ6RAqy8jecuNJBgN3t9E5a81G66F8x8fsKNiR1HWaBV66MJDOpg==", + "dev": true, + "requires": { + "@types/eslint": "^8.4.2", + "@types/prettier": "^2.6.0", + "@typescript-eslint/parser": "^5.10.0", + "common-tags": "^1.4.0", + "dlv": "^1.1.0", + "eslint": "^8.7.0", + "indent-string": "^4.0.0", + "lodash.merge": "^4.6.0", + "loglevel-colored-level-prefix": "^1.0.0", + "prettier": "^2.5.1", + "pretty-format": "^23.0.1", + "require-relative": "^0.8.7", + "typescript": "^4.5.4", + "vue-eslint-parser": "^8.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "pretty-format": { + "version": "23.6.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-23.6.0.tgz", + "integrity": "sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw==", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0", + "ansi-styles": "^3.2.0" + } + } + } + }, + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "requires": { + "fast-diff": "^1.1.2" + } + }, + "pretty-format": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "dev": true, + "requires": { + "@jest/schemas": "^28.1.3", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, + "prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + }, + "dependencies": { + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + } + } + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, + "pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==" + }, + "qs": { + "version": "6.11.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.1.tgz", + "integrity": "sha512-0wsrzgTz/kAVIeuxSjnpGC56rzYtr6JT/2BwEvMaPhFIoYa1aGO8LbzuU1R0uUYQkLpWBTOj0l/CLAJB64J6nQ==", + "requires": { + "side-channel": "^1.0.4" + } + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==" + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "rechoir": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", + "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==", + "requires": { + "resolve": "^1.20.0" + } + }, + "regexp.prototype.flags": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz", + "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "functions-have-names": "^1.2.3" + } + }, + "regexpp": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", + "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" + }, + "require-relative": { + "version": "0.8.7", + "resolved": "https://registry.npmjs.org/require-relative/-/require-relative-0.8.7.tgz", + "integrity": "sha512-AKGr4qvHiryxRb19m3PsLRGuKVAbJLUD7E6eOaHkfKhwc+vSgVOCY5xNvm9EkolBKTOf0GrQAZKLimOCz81Khg==", + "dev": true + }, + "resolve": { + "version": "1.22.2", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", + "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "requires": { + "is-core-module": "^2.11.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + } + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "resolve.exports": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.1.tgz", + "integrity": "sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==", + "dev": true + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + } + }, + "safe-stable-stringify": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", + "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sax": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", + "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==" + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + } + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "requires": { + "is-arrayish": "^0.3.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + } + } + }, + "simple-update-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", + "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", + "dev": true, + "requires": { + "semver": "~7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true + } + } + }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "slice-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", + "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "astral-regex": "^1.0.0", + "is-fullwidth-code-point": "^2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true + } + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==" + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==" + }, + "stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + } + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" + }, + "streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==" + }, + "string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "requires": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "string.prototype.matchall": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.8.tgz", + "integrity": "sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.4.3", + "side-channel": "^1.0.4" + } + }, + "string.prototype.trim": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz", + "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "string.prototype.trimend": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz", + "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "string.prototype.trimstart": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz", + "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "superagent": { + "version": "8.0.9", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-8.0.9.tgz", + "integrity": "sha512-4C7Bh5pyHTvU33KpZgwrNKh/VQnvgtCSqPRfJAUdmrtSYePVzVg4E4OzsrbkhJj9O7SO6Bnv75K/F8XVZT8YHA==", + "dev": true, + "requires": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.4", + "debug": "^4.3.4", + "fast-safe-stringify": "^2.1.1", + "form-data": "^4.0.0", + "formidable": "^2.1.2", + "methods": "^1.1.2", + "mime": "2.6.0", + "qs": "^6.11.0", + "semver": "^7.3.8" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "supertest": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-6.3.3.tgz", + "integrity": "sha512-EMCG6G8gDu5qEqRQ3JjjPs6+FYT1a7Hv5ApHvtSghmOFJYtsU5S+pSb6Y2EUeCEY3CmEL3mmQ8YWlPOzQomabA==", + "dev": true, + "requires": { + "methods": "^1.1.2", + "superagent": "^8.0.5" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-hyperlinks": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", + "dev": true, + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" + }, + "table": { + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "dev": true, + "requires": { + "ajv": "^6.10.2", + "lodash": "^4.17.14", + "slice-ansi": "^2.1.0", + "string-width": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "tarn": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tarn/-/tarn-3.0.2.tgz", + "integrity": "sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ==" + }, + "terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + } + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, + "text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "tildify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tildify/-/tildify-2.0.0.tgz", + "integrity": "sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==" + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + }, + "touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "requires": { + "nopt": "~1.0.10" + } + }, + "triple-beam": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + }, + "tsconfig-paths": { + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", + "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true + } + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + }, + "typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true + }, + "uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "optional": true + }, + "unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + } + }, + "undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" + }, + "update-browserslist-db": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", + "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "dev": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "requires": { + "punycode": "^2.1.0" + } + }, + "url": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", + "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" + } + } + }, + "util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "requires": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "v8-to-istanbul": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", + "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" + }, + "vue-eslint-parser": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-8.3.0.tgz", + "integrity": "sha512-dzHGG3+sYwSf6zFBa0Gi9ZDshD7+ad14DGOdTLjruRVgZXe2J+DcZ9iUhyR48z5g1PqRa20yt3Njna/veLJL/g==", + "dev": true, + "requires": { + "debug": "^4.3.2", + "eslint-scope": "^7.0.0", + "eslint-visitor-keys": "^3.1.0", + "espree": "^9.0.0", + "esquery": "^1.4.0", + "lodash": "^4.17.21", + "semver": "^7.3.5" + }, + "dependencies": { + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "requires": { + "makeerror": "1.0.12" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-typed-array": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz", + "integrity": "sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==", + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + } + }, + "winston": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.8.2.tgz", + "integrity": "sha512-MsE1gRx1m5jdTTO9Ld/vND4krP2To+lgDoMEHGGa4HIlAUyXJtfc7CxQcGXVyz2IBpw5hbFkj2b/AtUdQwyRew==", + "requires": { + "@colors/colors": "1.5.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.4.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.5.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + } + } + }, + "winston-transport": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.5.0.tgz", + "integrity": "sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q==", + "requires": { + "logform": "^2.3.2", + "readable-stream": "^3.6.0", + "triple-beam": "^1.3.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + } + } + } + }, + "word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==" + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "write": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", + "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", + "dev": true, + "requires": { + "mkdirp": "^0.5.1" + } + }, + "write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + } + }, + "xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + } + } +} diff --git a/frontend/app/package.json b/frontend/app/package.json new file mode 100644 index 0000000..ad8ca04 --- /dev/null +++ b/frontend/app/package.json @@ -0,0 +1,96 @@ +{ + "name": "common-hosted-form-service-app", + "version": "1.5.0", + "private": true, + "license": "Apache-2.0", + "scripts": { + "serve": "nodemon ./bin/www", + "debug": "nodemon --inspect ./bin/www", + "build": "cd frontend && npm run build", + "start": "node ./bin/www", + "test": "jest --verbose --forceExit --detectOpenHandles", + "lint": "eslint . **/www --no-fix --ext .js", + "lint:fix": "eslint . **/www --fix --ext .js", + "prettier": "prettier --check './**/*.js'", + "prettier:fix": "prettier --write \"src/**/*.{js,vue,css,scss}\"", + "pretest": "npm run lint", + "posttest": "node ./lcov-fix.js", + "clean": "rm -rf coverage dist", + "purge": "rm -rf node_modules", + "rebuild": "npm run clean && npm run build", + "reinstall": "npm run purge && npm install", + "all:build": "npm run build", + "all:start": "npm run start", + "all:test": "npm run test && cd frontend && npm run test", + "all:lint": "npm run lint && cd frontend && npm run lint", + "all:lint-fix": "npm run lint:fix && cd frontend && npm run lint:fix", + "all:ci": "npm ci && npm run frontend:ci && npm run components:ci", + "all:install": "npm install && cd frontend && npm install", + "all:clean": "npm run clean && cd frontend && npm run clean", + "all:purge": "npm run purge && npm run frontend:purge && npm run components:purge", + "all:rebuild": "npm run rebuild && cd frontend && npm run rebuild", + "all:reinstall": "npm run reinstall && cd frontend && npm run reinstall", + "all:fresh-start": "npm run all:reinstall && npm run all:rebuild && npm run all:start", + "components:ci": "cd ../components && npm ci", + "components:clean": "cd ../components && npm run clean", + "components:purge": "cd ../components && npm run purge", + "frontend:ci": "cd frontend && npm ci", + "frontend:purge": "cd frontend && npm run purge && npm run purge:formio", + "migrate": "npm run migrate:latest", + "migrate:down": "knex migrate:down", + "migrate:latest": "knex migrate:latest", + "migrate:make": "knex migrate:make", + "migrate:rollback": "knex migrate:rollback", + "migrate:rollback:all": "knex migrate:rollback --all", + "migrate:up": "knex migrate:up", + "seed:run": "knex seed:run", + "dev:reset-db": "npm run migrate:rollback:all && npm run migrate" + }, + "dependencies": { + "@json2csv/node": "^6.1.3", + "@json2csv/transforms": "^6.1.3", + "api-problem": "^7.0.4", + "aws-sdk": "^2.1376.0", + "axios": "^0.27.2", + "axios-oauth-client": "^1.5.0", + "axios-token-interceptor": "^0.2.0", + "body-parser": "^1.20.2", + "bytes": "^3.1.2", + "compression": "^1.7.4", + "config": "^3.3.9", + "crypto": "^1.0.1", + "express": "^4.18.2", + "express-basic-auth": "^1.2.1", + "express-rate-limit": "^7.1.3", + "express-winston": "^4.2.0", + "falsey": "^1.0.0", + "fast-json-patch": "^3.1.1", + "form-data": "^4.0.0", + "fs-extra": "^10.1.0", + "handlebars": "^4.7.8", + "js-yaml": "^4.1.0", + "jsonwebtoken": "^9.0.0", + "keycloak-connect": "^21.1.1", + "knex": "^2.4.2", + "lodash": "^4.17.21", + "mime-types": "^2.1.35", + "moment": "^2.29.4", + "multer": "^1.4.5-lts.1", + "nested-objects-util": "^1.1.2", + "objection": "^3.0.1", + "pg": "^8.10.0", + "uuid": "^8.3.2", + "winston": "^3.8.2" + }, + "devDependencies": { + "eslint": "^8.40.0", + "eslint-config-prettier": "^8.8.0", + "eslint-config-recommended": "^4.1.0", + "eslint-plugin-prettier": "^4.2.1", + "jest": "^28.0.0", + "nodemon": "^2.0.22", + "prettier": "^2.8.8", + "prettier-eslint": "^15.0.1", + "supertest": "^6.3.3" + } +} diff --git a/frontend/app/src/components/cdogsService.js b/frontend/app/src/components/cdogsService.js new file mode 100644 index 0000000..72dea49 --- /dev/null +++ b/frontend/app/src/components/cdogsService.js @@ -0,0 +1,140 @@ +const config = require('config'); +const crypto = require('crypto'); +const FormData = require('form-data'); +const fs = require('fs-extra'); + +const ClientConnection = require('./clientConnection'); +const errorToProblem = require('./errorToProblem'); +const log = require('./log')(module.filename); + +const SERVICE = 'CDOGS'; + +class CdogsService { + constructor({ tokenUrl, clientId, clientSecret, apiUrl }) { + log.debug(`Constructed with ${tokenUrl}, ${clientId}, clientSecret, ${apiUrl}`, { function: 'constructor' }); + if (!tokenUrl || !clientId || !clientSecret || !apiUrl) { + log.error('Invalid configuration.', { function: 'constructor' }); + throw new Error('CdogsService is not configured. Check configuration.'); + } + this.connection = new ClientConnection({ tokenUrl, clientId, clientSecret }); + this.axios = this.connection.axios; + this.apiUrl = apiUrl; + this.apiV2 = `${this.apiUrl}/v2`; + } + + async health() { + try { + const url = `${this.apiV2}/health`; + log.debug(`GET to ${url}`, { function: 'health' }); + + const { data, status } = await this.axios.get(url, { + headers: { + 'Content-Type': 'application/json', + }, + }); + + return { data, status }; + } catch (e) { + errorToProblem(SERVICE, e); + } + } + + async templateUploadAndRender(body) { + try { + const url = `${this.apiV2}/template/render`; + log.debug(`POST to ${url}`, { function: 'templateUploadAndRender' }); + + const { data, headers, status } = await this.axios.post(url, body, { + responseType: 'arraybuffer', // Needed for binaries unless you want pain + }); + + return { data, headers, status }; + } catch (e) { + errorToProblem(SERVICE, e); + } + } + + async templateRender(templateId, body) { + try { + const url = `${this.apiV2}/template/${templateId}/render`; + log.debug(`POST to ${url}`, { function: 'templateRender' }); + + const { data, headers, status } = await this.axios.post(url, body, { + headers: { + 'content-type': 'application/json', + }, + responseType: 'arraybuffer', + }); + + return { data, headers, status }; + } catch (e) { + errorToProblem(SERVICE, e); + } + } + + async getTemplate(templateId) { + try { + const url = `${this.apiV2}/template/${templateId}`; + log.debug(`GET to ${url}`, { function: 'getTemplate' }); + + const { data, status } = await this.axios.get(url, { + headers: { + 'Content-Type': 'application/json', + }, + }); + + return { data, status }; + } catch (e) { + if (e.response && e.response.status === 404) { + return { data: 'Not Found', status: 404 }; + } + errorToProblem(SERVICE, e); + } + } + + async uploadTemplate(path) { + try { + const form = new FormData(); + form.append('template', fs.createReadStream(path)); + + const url = `${this.apiV2}/template`; + log.debug(`POST to ${url}`, { function: 'uploadTemplate' }); + + const { data, headers, status } = await this.axios({ + method: 'post', + url: url, + data: form, + headers: { + 'content-type': `multipart/form-data; boundary=${form._boundary}`, + }, + }); + + return { data, headers, status }; + } catch (e) { + errorToProblem(SERVICE, e); + } + } + + async getHash(file) { + const hash = crypto.createHash('sha256'); + const stream = fs.createReadStream(file); + return new Promise((resolve, reject) => { + stream.on('readable', () => { + let chunk; + while (null !== (chunk = stream.read())) { + hash.update(chunk); + } + }); + stream.on('end', () => resolve(hash.digest('hex'))); + stream.on('error', (error) => reject(error)); + }); + } +} + +const endpoint = config.get('serviceClient.commonServices.cdogs.endpoint'); +const tokenEndpoint = config.get('serviceClient.commonServices.cdogs.tokenEndpoint'); +const clientId = config.get('serviceClient.commonServices.cdogs.clientId'); +const clientSecret = config.get('serviceClient.commonServices.cdogs.clientSecret'); + +let cdogsService = new CdogsService({ tokenUrl: tokenEndpoint, clientId: clientId, clientSecret: clientSecret, apiUrl: endpoint }); +module.exports = cdogsService; diff --git a/frontend/app/src/components/chesService.js b/frontend/app/src/components/chesService.js new file mode 100644 index 0000000..6b89950 --- /dev/null +++ b/frontend/app/src/components/chesService.js @@ -0,0 +1,129 @@ +const config = require('config'); + +const ClientConnection = require('./clientConnection'); +const errorToProblem = require('./errorToProblem'); +const log = require('./log')(module.filename); + +const SERVICE = 'CHES'; + +class ChesService { + constructor({ tokenUrl, clientId, clientSecret, apiUrl }) { + log.debug(`Constructed with ${tokenUrl}, ${clientId}, clientSecret, ${apiUrl}`, { function: 'constructor' }); + if (!tokenUrl || !clientId || !clientSecret || !apiUrl) { + log.error('Invalid configuration.', { function: 'constructor' }); + throw new Error('ChesService is not configured. Check configuration.'); + } + this.connection = new ClientConnection({ tokenUrl, clientId, clientSecret }); + this.axios = this.connection.axios; + this.apiUrl = apiUrl; + this.apiV1 = `${this.apiUrl}/v1`; + } + + async health() { + try { + const response = await this.axios.get(`${this.apiV1}/health`, { + headers: { + 'Content-Type': 'application/json', + }, + }); + return response.data; + } catch (e) { + errorToProblem(SERVICE, e); + } + } + + async statusQuery(params) { + try { + const response = await this.axios.get(`${this.apiV1}/status`, { + params: params, + headers: { + 'Content-Type': 'application/json', + }, + }); + return response.data; + } catch (e) { + errorToProblem(SERVICE, e); + } + } + + async cancelMsg(msgId) { + try { + const response = await this.axios.delete(`${this.apiV1}/cancel/${msgId}`, { + headers: { + 'Content-Type': 'application/json', + }, + }); + return response.data; + } catch (e) { + errorToProblem(SERVICE, e); + } + } + + async cancelQuery(params) { + try { + const response = await this.axios.delete(`${this.apiV1}/cancel`, { + params: params, + headers: { + 'Content-Type': 'application/json', + }, + }); + return response.data; + } catch (e) { + errorToProblem(SERVICE, e); + } + } + + async send(email) { + try { + const response = await this.axios.post(`${this.apiV1}/email`, email, { + headers: { + 'Content-Type': 'application/json', + }, + maxContentLength: Infinity, + maxBodyLength: Infinity, + }); + return response.data; + } catch (e) { + errorToProblem(SERVICE, e); + } + } + + async merge(data) { + // eslint-disable-next-line no-console + try { + const response = await this.axios.post(`${this.apiV1}/emailMerge`, data, { + headers: { + 'Content-Type': 'application/json', + }, + maxContentLength: Infinity, + maxBodyLength: Infinity, + }); + return response.data; + } catch (e) { + errorToProblem(SERVICE, e); + } + } + + async preview(data) { + try { + const response = await this.axios.post(`${this.apiV1}/emailMerge/preview`, data, { + headers: { + 'Content-Type': 'application/json', + }, + maxContentLength: Infinity, + maxBodyLength: Infinity, + }); + return response.data; + } catch (e) { + errorToProblem(SERVICE, e); + } + } +} + +const endpoint = config.get('serviceClient.commonServices.ches.endpoint'); +const tokenEndpoint = config.get('serviceClient.commonServices.ches.tokenEndpoint'); +const clientId = config.get('serviceClient.commonServices.ches.clientId'); +const clientSecret = config.get('serviceClient.commonServices.ches.clientSecret'); + +let chesService = new ChesService({ tokenUrl: tokenEndpoint, clientId: clientId, clientSecret: clientSecret, apiUrl: endpoint }); +module.exports = chesService; diff --git a/frontend/app/src/components/clientConnection.js b/frontend/app/src/components/clientConnection.js new file mode 100644 index 0000000..6b33853 --- /dev/null +++ b/frontend/app/src/components/clientConnection.js @@ -0,0 +1,35 @@ +const axios = require('axios'); +const oauth = require('axios-oauth-client'); +const tokenProvider = require('axios-token-interceptor'); + +const log = require('./log')(module.filename); + +class ClientConnection { + constructor({ tokenUrl, clientId, clientSecret }) { + log.verbose(`Constructed with ${tokenUrl}, ${clientId}, clientSecret`, { function: 'constructor' }); + if (!tokenUrl || !clientId || !clientSecret) { + log.error('Invalid configuration.', { function: 'constructor' }); + throw new Error('ClientConnection is not configured. Check configuration.'); + } + + this.tokenUrl = tokenUrl; + + this.axios = axios.create(); + this.axios.interceptors.request.use( + // Wraps axios-token-interceptor with oauth-specific configuration, + // fetches the token using the desired claim method, and caches + // until the token expires + oauth.interceptor( + tokenProvider, + oauth.client(axios.create(), { + url: this.tokenUrl, + grant_type: 'client_credentials', + client_id: clientId, + client_secret: clientSecret, + }) + ) + ); + } +} + +module.exports = ClientConnection; diff --git a/frontend/app/src/components/errorToProblem.js b/frontend/app/src/components/errorToProblem.js new file mode 100644 index 0000000..e962fc2 --- /dev/null +++ b/frontend/app/src/components/errorToProblem.js @@ -0,0 +1,29 @@ +const Problem = require('api-problem'); + +const log = require('./log')(module.filename); + +module.exports = function (service, e) { + if (e.response) { + // Handle raw data + let data; + if (typeof e.response.data === 'string' || e.response.data instanceof String) { + data = JSON.parse(e.response.data); + } else { + data = e.response.data; + } + + log.error(`Error from ${service}: status = ${e.response.status}, data : ${JSON.stringify(data)}`); + // Validation Error + if (e.response.status === 422) { + throw new Problem(e.response.status, { + detail: data.detail, + errors: data.errors, + }); + } + // Something else happened but there's a response + throw new Problem(e.response.status, { detail: e.response.data.toString() }); + } else { + log.error(`Unknown error calling ${service}: ${e.message}`); + throw new Problem(502, `Unknown ${service} Error`, { detail: e.message }); + } +}; diff --git a/frontend/app/src/components/geoAddressService.js b/frontend/app/src/components/geoAddressService.js new file mode 100644 index 0000000..3e8a214 --- /dev/null +++ b/frontend/app/src/components/geoAddressService.js @@ -0,0 +1,36 @@ +const config = require('config'); +const axios = require('axios'); +const errorToProblem = require('./errorToProblem'); +const SERVICE = 'GeoAddressService'; + +class GeoAddressService { + constructor({ apiKey, bcAddressURL, queryParameters }) { + if (!apiKey || !bcAddressURL || !queryParameters) { + throw new Error('GeoAddressService is not configured. Check configuration.'); + } + + this.apiKey = apiKey; + this.queryParameters = queryParameters; + } + + async addressQuerySearch(query) { + try { + const queryParameters = { ...query, ...this.queryParameters }; + + axios.defaults.headers['X-API-KEY'] = this.apiKey; + + const { data } = await axios.get(config.get('customBcAddressFormioComponent.bcAddressURL'), { params: { ...queryParameters } }); + + return data; + } catch (e) { + errorToProblem(SERVICE, e); + } + } +} +// +const apiKey = config.get('customBcAddressFormioComponent.apikey'); +const bcAddressURL = config.get('customBcAddressFormioComponent.bcAddressURL'); +const queryParameters = config.get('customBcAddressFormioComponent.queryParameters'); + +let geoAddressService = new GeoAddressService({ apiKey: apiKey, bcAddressURL: bcAddressURL, queryParameters: queryParameters }); +module.exports = geoAddressService; diff --git a/frontend/app/src/components/keycloak.js b/frontend/app/src/components/keycloak.js new file mode 100644 index 0000000..3781b33 --- /dev/null +++ b/frontend/app/src/components/keycloak.js @@ -0,0 +1,19 @@ +const config = require('config'); +const Keycloak = require('keycloak-connect'); + +module.exports = new Keycloak( + {}, + { + bearerOnly: true, + 'confidential-port': 0, + clientId: config.get('server.keycloak.clientId'), + 'policy-enforcer': {}, + realm: config.get('server.keycloak.realm'), + realmPublicKey: config.has('server.keycloak.publicKey') ? config.get('server.keycloak.publicKey') : undefined, + secret: config.get('server.keycloak.clientSecret'), + serverUrl: config.get('server.keycloak.serverUrl'), + 'ssl-required': 'external', + 'use-resource-role-mappings': true, + 'verify-token-audience': false, + } +); diff --git a/frontend/app/src/components/log.js b/frontend/app/src/components/log.js new file mode 100644 index 0000000..bcf6571 --- /dev/null +++ b/frontend/app/src/components/log.js @@ -0,0 +1,104 @@ +const config = require('config'); +const jwt = require('jsonwebtoken'); +const { parse } = require('path'); +const Transport = require('winston-transport'); +const { createLogger, format, transports } = require('winston'); +const { logger } = require('express-winston'); + +/** + * Class representing a winston transport writing to null + * @extends Transport + */ +class NullTransport extends Transport { + /** + * Constructor + * @param {object} opts Winston Transport options + */ + constructor(opts) { + super(opts); + } + + /** + * The transport logger + * @param {object} _info Object to log + * @param {function} callback Callback function + */ + log(_info, callback) { + callback(); + } +} + +/** + * Main Winston Logger + * @returns {object} Winston Logger + */ +const log = createLogger({ + exitOnError: false, + format: format.combine( + format.errors({ stack: true }), // Force errors to show stacktrace + format.timestamp(), // Add ISO timestamp to each entry + format.json() // Force output to be in JSON format + ), + level: config.get('server.logLevel'), +}); + +if (process.env.NODE_ENV !== 'test') { + log.add(new transports.Console({ handleExceptions: true })); +} else { + log.add(new NullTransport()); +} + +if (config.has('server.logFile')) { + log.add( + new transports.File({ + filename: config.get('server.logFile'), + handleExceptions: true, + }) + ); +} + +/** + * Returns a Winston Logger or Child Winston Logger + * @param {string} [filename] Optional module filename path to annotate logs with + * @returns {object} A child logger with appropriate metadata if `filename` is defined. Otherwise returns a standard logger. + */ +const getLogger = (filename) => { + return filename ? log.child({ component: parse(filename).name }) : log; +}; + +/** + * Returns an express-winston middleware function for http logging + * @returns {function} An express-winston middleware function + */ +const httpLogger = logger({ + colorize: false, + // Parses express information to insert into log output + dynamicMeta: (req, res) => { + const token = jwt.decode((req.get('authorization') || '').slice(7)); + return { + azp: (token && token.azp) || undefined, + contentLength: res.get('content-length'), + httpVersion: req.httpVersion, + ip: req.ip, + method: req.method, + path: req.path, + query: Object.keys(req.query).length ? req.query : undefined, + responseTime: res.responseTime, + statusCode: res.statusCode, + userAgent: req.get('user-agent'), + }; + }, + expressFormat: true, // Use express style message strings + level: 'http', + meta: true, // Must be true for dynamicMeta to execute + metaField: null, // Set to null for all attributes to be at top level object + requestWhitelist: [], // Suppress default value output + responseWhitelist: [], // Suppress default value output + // Skip logging kube-probe requests + skip: (req) => req.get('user-agent') && req.get('user-agent').includes('kube-probe'), + winstonInstance: log, +}); + +module.exports = getLogger; +module.exports.httpLogger = httpLogger; +module.exports.NullTransport = NullTransport; diff --git a/frontend/app/src/db/.editorconfig b/frontend/app/src/db/.editorconfig new file mode 100644 index 0000000..fedd3a8 --- /dev/null +++ b/frontend/app/src/db/.editorconfig @@ -0,0 +1,2 @@ +[*.js] +indent_size = unset diff --git a/frontend/app/src/db/dataConnection.js b/frontend/app/src/db/dataConnection.js new file mode 100644 index 0000000..ec6286b --- /dev/null +++ b/frontend/app/src/db/dataConnection.js @@ -0,0 +1,164 @@ +const Knex = require('knex'); +const { Model } = require('objection'); + +const knexfile = require('../../knexfile'); +const log = require('../components/log')(module.filename); +const models = require('../../../app/src/forms/common/models'); +const { tableNames } = require('../../../app/src/forms/common/models/utils'); + +class DataConnection { + /** + * Creates a new DataConnection with default (Postgresql) Knex configuration. + * @class + */ + constructor() { + if (!DataConnection.instance) { + this.knex = Knex(knexfile); + DataConnection.instance = this; + } + + return DataConnection.instance; + } + + /** @function connected + * True or false if connected. + */ + get connected() { + return this._connected; + } + + /** @function knex + * Gets the current knex binding + */ + get knex() { + return this._knex; + } + + /** @function knex + * Sets the current knex binding + * @param {object} v - a Knex object. + */ + set knex(v) { + this._knex = v; + this._connected = false; + } + + /** + * @function checkAll + * Checks the Knex connection, the database schema, and Objection models + * @returns {boolean} True if successful, otherwise false + */ + async checkAll() { + const connectOk = await this.checkConnection(); + const schemaOk = await this.checkSchema(); + const modelsOk = this.checkModel(); + + log.debug(`Connect OK: ${connectOk}, Schema OK: ${schemaOk}, Models OK: ${modelsOk}`, { function: 'checkAll' }); + this._connected = connectOk && schemaOk && modelsOk; + if (!connectOk) { + log.error('Could not connect to the database, check configuration and ensure database server is running', { function: 'checkAll' }); + } + if (!schemaOk) { + log.error('Connected to the database, could not verify the schema. Ensure proper migrations have been run.', { function: 'checkAll' }); + } + if (!modelsOk) { + log.error('Connected to the database, schema is ok, could not initialize Knex Models.', { function: 'checkAll' }); + } + return this._connected; + } + + /** + * @function checkConnection + * Checks the current knex connection to Postgres + * If the connected DB is in read-only mode, transaction_read_only will not be off + * @returns {boolean} True if successful, otherwise false + */ + async checkConnection() { + try { + const data = await this.knex.raw('show transaction_read_only'); + const result = data && data.rows && data.rows[0].transaction_read_only === 'off'; + if (result) { + log.debug('Database connection ok', { function: 'checkConnection' }); + } + else { + log.warn('Database connection is read-only', { function: 'checkConnection' }); + } + return result; + } catch (err) { + log.error(`Error with database connection: ${err.message}`, { function: 'checkConnection' }); + return false; + } + } + + /** + * @function checkSchema + * Queries the knex connection to check for the existence of the expected schema tables + * @returns {boolean} True if schema is ok, otherwise false + */ + checkSchema() { + const tables = tableNames(models); + try { + return Promise + .all(tables.map(table => this._knex.schema.hasTable(table))) + .then(exists => exists.every(x => x)) + .then(result => { + if (result) log.debug('Database schema ok', { function: 'checkSchema' }); + return result; + }); + } catch (err) { + log.error(`Error with database schema: ${err.message}`, { function: 'checkSchema' }); + log.error(err); + return false; + } + } + + /** + * @function checkModel + * Attaches the Objection model to the existing knex connection + * @returns {boolean} True if successful, otherwise false + */ + checkModel() { + try { + Model.knex(this.knex); + log.debug('Database models ok', { function: 'checkModel' }); + return true; + } catch (err) { + log.error(`Error attaching Model to connection: ${err.message}`, { function: 'checkModel' }); + log.error(err); + return false; + } + } + + + /** + * @function close + * Will close the DataConnection + * @param {function} [cb] Optional callback + */ + close(cb = undefined) { + if (this.knex) { + try { + this.knex.destroy(() => { + this._connected = false; + log.info('Disconnected', { function: 'close' }); + if (cb) cb(); + }); + } catch (e) { + log.error(e); + } + } + } + + /** + * @function resetConnection + * Invalidates and reconnects existing knex connection + */ + resetConnection() { + log.warn('Attempting to reset database connection pool...', { function: 'resetConnection' }); + this.knex.destroy(() => { + this.knex.initialize(); + }); + } +} + +module.exports = DataConnection; diff --git a/frontend/app/src/db/migrations/20200807133615_000-init.js b/frontend/app/src/db/migrations/20200807133615_000-init.js new file mode 100644 index 0000000..c7bdee3 --- /dev/null +++ b/frontend/app/src/db/migrations/20200807133615_000-init.js @@ -0,0 +1,94 @@ +const stamps = require('../stamps'); + +exports.up = function(knex) { + return Promise.resolve() + .then(() => knex.schema.createTable('identity_provider', table => { + table.string('code').primary(); + table.string('display').notNullable(); + table.boolean('active').notNullable().defaultTo(true); + table.string('idp'); + stamps(knex, table); + })) + .then(() => knex.schema.createTable('user', table => { + table.uuid('id').primary(); + table.string('keycloakId').unique().notNullable().index(); + table.string('firstName'); + table.string('fullName'); + table.string('lastName'); + table.string('username'); + table.string('email'); + stamps(knex, table); + })) + .then(() => knex.schema.createTable('role', table => { + table.string('code').primary(); + table.string('display').notNullable(); + table.boolean('active').notNullable().defaultTo(true); + table.string('description'); + stamps(knex, table); + })) + .then(() => knex.schema.createTable('permission', table => { + table.string('code').primary(); + table.string('display').notNullable(); + table.boolean('active').notNullable().defaultTo(true); + table.string('description'); + stamps(knex, table); + })) + .then(() => knex.schema.createTable('role_permission', table => { + table.uuid('id').primary(); + table.string('role').references('code').inTable('role').notNullable().index(); + table.string('permission').references('code').inTable('permission').notNullable().index(); + stamps(knex, table); + })) + .then(() => knex.schema.createTable('form', table => { + table.uuid('id').primary(); + table.string('name').notNullable(); + table.string('description'); + table.boolean('active').notNullable().defaultTo(true); + table.specificType('labels', 'text ARRAY').comment('Use labels to group forms together, or aid in search. Examples: Ministry name, Branch name, Team name.'); + stamps(knex, table); + })) + .then(() => knex.schema.createTable('form_identity_provider', table => { + table.uuid('id').primary(); + table.uuid('formId').references('id').inTable('form').notNullable().index(); + table.string('code').references('code').inTable('identity_provider').notNullable(); + stamps(knex, table); + })) + .then(() => knex.schema.createTable('form_role_user', table => { + table.uuid('id').primary(); + table.string('role').references('code').inTable('role').notNullable(); + table.uuid('formId').references('id').inTable('form').notNullable().index(); + table.uuid('userId').references('id').inTable('user').notNullable().index(); + stamps(knex, table); + })) + .then(() => knex.schema.createTable('form_version', table => { + table.uuid('id').primary(); + table.uuid('formId').references('id').inTable('form').notNullable().index(); + table.integer('version').notNullable(); + table.jsonb('schema'); + stamps(knex, table); + table.unique(['formId', 'version']); + })) + .then(() => knex.schema.createTable('form_submission', table => { + table.uuid('id').primary(); + table.uuid('formVersionId').references('id').inTable('form_version').notNullable().index(); + table.string('confirmationId').notNullable().unique().index(); + table.boolean('draft').notNullable().defaultTo(false); + table.boolean('deleted').notNullable().defaultTo(false); + table.jsonb('submission'); + stamps(knex, table); + })); +}; + +exports.down = function(knex) { + return Promise.resolve() + .then(() => knex.schema.dropTableIfExists('form_identity_provider')) + .then(() => knex.schema.dropTableIfExists('identity_provider')) + .then(() => knex.schema.dropTableIfExists('form_submission')) + .then(() => knex.schema.dropTableIfExists('form_version')) + .then(() => knex.schema.dropTableIfExists('form_role_user')) + .then(() => knex.schema.dropTableIfExists('form')) + .then(() => knex.schema.dropTableIfExists('role_permission')) + .then(() => knex.schema.dropTableIfExists('permission')) + .then(() => knex.schema.dropTableIfExists('role')) + .then(() => knex.schema.dropTableIfExists('user')); +}; diff --git a/frontend/app/src/db/migrations/20200825155537_001-views.js b/frontend/app/src/db/migrations/20200825155537_001-views.js new file mode 100644 index 0000000..9fe1c31 --- /dev/null +++ b/frontend/app/src/db/migrations/20200825155537_001-views.js @@ -0,0 +1,70 @@ + +exports.up = function(knex) { + return Promise.resolve() + .then(() => knex.schema.raw(`create view form_vw as +SELECT DISTINCT ON ((lower(f.name::text))) f.id, + f.name, + f.active, + f.description, + f.labels, + f."createdAt", + f."createdBy", + f."updatedAt", + f."updatedBy", + fv.id AS "formVersionId", + fv.version, + case when count(fip.code) = 0 then '{}'::varchar[] else array_agg(distinct(fip.code)) end AS "identityProviders", + case when count(ip.idp) = 0 then '{}'::varchar[] else array_agg(distinct(ip.idp)) end AS idps +FROM form f + JOIN form_version fv ON f.id = fv."formId" + LEFT OUTER JOIN form_identity_provider fip ON f.id = fip."formId" + LEFT OUTER JOIN identity_provider ip ON fip.code::text = ip.code::text +GROUP BY f.id, f.name, f.active, f.description, f.labels, f."createdAt", f."createdBy", f."updatedAt", + f."updatedBy", fv.id, fv.version +ORDER BY (lower(f.name::text)), fv.version DESC`)) + .then(() => knex.schema.raw(`create view user_form_permissions_vw as +select fru."userId", fru."formId", array_agg(distinct(p.code)) as permissions +from form_role_user fru +inner join role r on fru.role = r.code +inner join role_permission rp on r.code = rp.role +inner join permission p on rp.permission = p.code +group by fru."userId", fru."formId" +union +select u2.id as "userId", f2.id as "formId", '{submission_create,form_read}'::varchar[] as permissions +from form_vw f2, "user" u2 +where not exists (select * from form_role_user fru2 where fru2."formId"= f2.id and fru2."userId" = u2.id)`)) + .then(() => knex.schema.raw(`create view user_form_roles_vw as +select fru."userId", fru."formId", array_agg(distinct(r.code)) as roles +from form_role_user fru +inner join role r on fru.role = r.code +group by fru."userId", fru."formId" +union +select u2.id as "userId", f2.id as "formId", '{}'::varchar[] as roles +from form_vw f2, "user" u2 +where not exists (select * from form_role_user fru2 where fru2."formId"= f2.id and fru2."userId" = u2.id)`)) + .then(() => knex.schema.raw(`create view user_form_access_vw as +select r."userId", u."keycloakId", u.username, u."fullName", u."firstName", u."lastName", u.email, r."formId", f.name as "formName", f.labels, f."identityProviders", f.idps, f.active, f."formVersionId", f.version, r.roles, p.permissions +from "user" u join user_form_roles_vw r on u.id = r."userId" join user_form_permissions_vw p on r."userId" = p."userId" and r."formId" = p."formId" join form_vw f on f.id = p."formId" +order by lower(u."lastName"::text), lower(u."firstName"::text), lower(f.name::text)`)) + .then(() => knex.schema.raw(`create view public_form_access_vw as +select null as "userId", null as "keycloakId", 'public' as username, 'public' as "fullName", null as "firstName", null as "lastName", null as email, f.id as "formId", f.name as "formName", f.labels, f."identityProviders", f.idps, f.active, f."formVersionId", f.version, '{}'::varchar[] as roles, '{submission_create,form_read}'::varchar[] as permissions +from form_vw f +where 'public' = ANY(f."idps") +order by lower(f.name::text)`)) + .then(() => knex.schema.raw(`create view submissions_vw as +select s.id as "submissionId", s."confirmationId", s.draft, s.deleted, s."createdBy", s."createdAt", f.id as "formId", f.name as "formName", fv.id as"formVersionId", fv.version +from form_submission as s + inner join form_version fv on s."formVersionId" = fv.id + inner join form f on fv."formId" = f.id +order by s."createdAt" desc`)); +}; + +exports.down = function(knex) { + return Promise.resolve() + .then(() => knex.schema.raw('DROP VIEW IF EXISTS submissions_vw')) + .then(() => knex.schema.raw('DROP VIEW IF EXISTS public_form_access_vw')) + .then(() => knex.schema.raw('DROP VIEW IF EXISTS user_form_access_vw')) + .then(() => knex.schema.raw('DROP VIEW IF EXISTS user_form_roles_vw')) + .then(() => knex.schema.raw('DROP VIEW IF EXISTS user_form_permissions_vw')) + .then(() => knex.schema.raw('DROP VIEW IF EXISTS form_vw')); +}; diff --git a/frontend/app/src/db/migrations/20200825155537_002-idp_role_permission_data.js b/frontend/app/src/db/migrations/20200825155537_002-idp_role_permission_data.js new file mode 100644 index 0000000..c05ad87 --- /dev/null +++ b/frontend/app/src/db/migrations/20200825155537_002-idp_role_permission_data.js @@ -0,0 +1,281 @@ +const { v4: uuidv4 } = require('uuid'); + +const CREATED_BY = 'migration-002'; + +exports.up = function(knex) { + return Promise.resolve() + .then(() => { + return knex('form_identity_provider').del(); + }) + .then(() => { + return knex('form_role_user').del(); + }) + .then(() => { + return knex('role_permission').del(); + }) + .then(() => { + return knex('identity_provider').del(); + }) + .then(()=> { + return knex('permission').del(); + }) + .then(()=> { + return knex('role').del(); + }) + .then(()=> { + return knex('user').del(); + }) + .then(() => { + return knex('form_submission').del(); + }) + .then(() => { + return knex('form_version').del(); + }) + .then(() => { + return knex('form').del(); + }) + .then(() => { + const items = [ + { + createdBy: CREATED_BY, + code: 'public', + display: 'Public', + active: true, + idp: 'public' + }, + { + createdBy: CREATED_BY, + code: 'idir', + display: 'IDIR', + active: true, + idp: 'idir' + } + ]; + return knex('identity_provider').insert(items); + }) + .then(() => { + const items = [ + { + createdBy: CREATED_BY, + code: 'owner', + display: 'Owner', + description: 'Owns the form', + active: true + }, + { + createdBy: CREATED_BY, + code: 'team_manager', + display: 'Team Manager', + description: 'Manages Team members for the form', + active: true + }, + { + createdBy: CREATED_BY, + code: 'form_designer', + display: 'Form Designer', + description: 'Designs the form', + active: true + }, + { + createdBy: CREATED_BY, + code: 'submission_reviewer', + display: 'Reviewer', + description: 'Can review and manage all form submissions', + active: true + }, + { + createdBy: CREATED_BY, + code: 'form_submitter', + display: 'Submitter', + description: 'Can fill out and submit the form', + active: true + } + ]; + return knex('role').insert(items).returning('code'); + }) + .then(() => { + const items = [ + { + createdBy: CREATED_BY, + code: 'form_read', + display: 'Form Read', + description: 'Can view the form (read-only)', + active: true + }, + { + createdBy: CREATED_BY, + code: 'form_update', + display: 'Form Update', + description: 'Can edit/update the basic form metadata (not the design)', + active: true + }, + { + createdBy: CREATED_BY, + code: 'form_delete', + display: 'Form Delete', + description: 'Can delete the form', + active: true + }, + { + createdBy: CREATED_BY, + code: 'submission_create', + display: 'Submission Create', + description: 'Can fill out and submit this form', + active: true + }, + { + createdBy: CREATED_BY, + code: 'submission_read', + display: 'Submission Read', + description: 'Can view (all) form submissions (read-only)', + active: true + }, + { + createdBy: CREATED_BY, + code: 'submission_update', + display: 'Submission Update', + description: 'Can edit/update form submissions', + active: true + }, + { + createdBy: CREATED_BY, + code: 'submission_delete', + display: 'Submission Delete', + description: 'Can delete form submissions', + active: true + }, + { + createdBy: CREATED_BY, + code: 'design_create', + display: 'Design Create', + description: 'Can create a form design', + active: true + }, + { + createdBy: CREATED_BY, + code: 'design_read', + display: 'Design Read', + description: 'Can view the form design (read-only)', + active: true + }, + { + createdBy: CREATED_BY, + code: 'design_update', + display: 'Design Update', + description: 'Can edit/update the form design', + active: true + }, + { + createdBy: CREATED_BY, + code: 'design_delete', + display: 'Design Delete', + description: 'Can delete the form design', + active: true + }, + { + createdBy: CREATED_BY, + code: 'team_read', + display: 'Team Read', + description: 'Can view the team members (read-only)', + active: true + }, + { + createdBy: CREATED_BY, + code: 'team_update', + display: 'Team Update', + description: 'Can update the team members (add, remove)', + active: true + } + ]; + return knex('permission').insert(items).returning('code'); + }) + .then(() => { + const items = []; + + ['form_read', 'form_update', 'form_delete'].forEach(p => { + const item = { + id: uuidv4(), + createdBy: CREATED_BY, + role: 'owner', + permission: p + }; + items.push(item); + }); + + ['form_read', 'team_read', 'team_update'].forEach(p => { + const item = { + id: uuidv4(), + createdBy: CREATED_BY, + role: 'team_manager', + permission: p + }; + items.push(item); + }); + + ['form_read', 'design_create', 'design_read', 'design_update', 'design_delete'].forEach(p => { + const item = { + id: uuidv4(), + createdBy: CREATED_BY, + role: 'form_designer', + permission: p + }; + items.push(item); + }); + + ['form_read', 'submission_read', 'submission_update', 'submission_delete'].forEach(p => { + const item = { + id: uuidv4(), + createdBy: CREATED_BY, + role: 'submission_reviewer', + permission: p + }; + items.push(item); + }); + + ['form_read', 'submission_create'].forEach(p => { + const item = { + id: uuidv4(), + createdBy: CREATED_BY, + role: 'form_submitter', + permission: p + }; + items.push(item); + }); + + return knex('role_permission').insert(items).returning('id'); + }); +}; + +exports.down = function(knex) { + return Promise.resolve() + .then(() => { + return knex('form_identity_provider').del(); + }) + .then(() => { + return knex('form_role_user').del(); + }) + .then(() => { + return knex('role_permission').del(); + }) + .then(() => { + return knex('identity_provider').del(); + }) + .then(()=> { + return knex('permission').del(); + }) + .then(()=> { + return knex('role').del(); + }) + .then(()=> { + return knex('user').del(); + }) + .then(() => { + return knex('form_submission').del(); + }) + .then(() => { + return knex('form_version').del(); + }) + .then(() => { + return knex('form').del(); + }); +}; diff --git a/frontend/app/src/db/migrations/20200925103025_003-submission-users.js b/frontend/app/src/db/migrations/20200925103025_003-submission-users.js new file mode 100644 index 0000000..dff0929 --- /dev/null +++ b/frontend/app/src/db/migrations/20200925103025_003-submission-users.js @@ -0,0 +1,22 @@ +const stamps = require('../stamps'); + +exports.up = function(knex) { + return Promise.resolve() + .then(() => knex.schema.createTable('form_submission_user', table => { + table.uuid('id').primary(); + table.uuid('formSubmissionId').references('id').inTable('form_submission').notNullable().index(); + table.uuid('userId').references('id').inTable('user').notNullable().index(); + table.string('permission').references('code').inTable('permission').notNullable(); + stamps(knex, table); + })) + .then(() => knex.schema.raw(`create view form_submission_users_vw as +select fsu."formSubmissionId", fsu."userId", array_agg(distinct(fsu.permission)) as permissions +from form_submission_user fsu +group by fsu."formSubmissionId", fsu."userId"`)); +}; + +exports.down = function(knex) { + return Promise.resolve() + .then(() => knex.schema.raw('DROP VIEW IF EXISTS form_submission_users_vw')) + .then(() => knex.schema.dropTableIfExists('form_submission_user')); +}; diff --git a/frontend/app/src/db/migrations/20201007112921_005-submissions-data-vw.js b/frontend/app/src/db/migrations/20201007112921_005-submissions-data-vw.js new file mode 100644 index 0000000..d991181 --- /dev/null +++ b/frontend/app/src/db/migrations/20201007112921_005-submissions-data-vw.js @@ -0,0 +1,19 @@ + +exports.up = function(knex) { + return Promise.resolve() + .then(() => knex.schema.raw(`create or replace view submissions_data_vw as +select s."confirmationId", s."formName", s.version, s."createdAt", + u."fullName", u.username, u.email, + fs.submission -> 'data' AS "submission", s.deleted, s.draft, + s."submissionId", s."formId", s."formVersionId", u.id as "userId", u."keycloakId", u."firstName", u."lastName" +from submissions_vw s + inner join form_submission fs on s."submissionId" = fs.id + inner join form_submission_user fsu on s."submissionId" = fsu."formSubmissionId" and fsu.permission = 'submission_create' + inner join "user" u on fsu."userId" = u.id +order by s."createdAt", s."formName", s.version`)); +}; + +exports.down = function(knex) { + return Promise.resolve() + .then(() => knex.schema.raw('DROP VIEW IF EXISTS submissions_data_vw')); +}; diff --git a/frontend/app/src/db/migrations/20201007113516_004-alter-form-view.js b/frontend/app/src/db/migrations/20201007113516_004-alter-form-view.js new file mode 100644 index 0000000..769a73c --- /dev/null +++ b/frontend/app/src/db/migrations/20201007113516_004-alter-form-view.js @@ -0,0 +1,51 @@ + +exports.up = function (knex) { + return Promise.resolve() + .then(() => knex.schema.raw(`create or replace view form_vw as + SELECT DISTINCT ON (lower(f.name::text), fv.version, f.id) f.id, + f.name, + f.active, + f.description, + f.labels, + f."createdAt", + f."createdBy", + f."updatedAt", + f."updatedBy", + fv.id AS "formVersionId", + fv.version, + case when count(fip.code) = 0 then '{}'::varchar[] else array_agg(distinct(fip.code)) end AS "identityProviders", + case when count(ip.idp) = 0 then '{}'::varchar[] else array_agg(distinct(ip.idp)) end AS idps + FROM form f + JOIN form_version fv ON f.id = fv."formId" + LEFT OUTER JOIN form_identity_provider fip ON f.id = fip."formId" + LEFT OUTER JOIN identity_provider ip ON fip.code::text = ip.code::text + GROUP BY f.id, f.name, f.active, f.description, f.labels, f."createdAt", f."createdBy", f."updatedAt", + f."updatedBy", fv.id, fv.version + ORDER BY lower(f.name::text), fv.version DESC, f.id`)); +}; + +exports.down = function (knex) { + // Restore original definition of this view from 001-views + return Promise.resolve() + .then(() => knex.schema.raw(`create or replace view form_vw as + SELECT DISTINCT ON ((lower(f.name::text))) f.id, + f.name, + f.active, + f.description, + f.labels, + f."createdAt", + f."createdBy", + f."updatedAt", + f."updatedBy", + fv.id AS "formVersionId", + fv.version, + case when count(fip.code) = 0 then '{}'::varchar[] else array_agg(distinct(fip.code)) end AS "identityProviders", + case when count(ip.idp) = 0 then '{}'::varchar[] else array_agg(distinct(ip.idp)) end AS idps + FROM form f + JOIN form_version fv ON f.id = fv."formId" + LEFT OUTER JOIN form_identity_provider fip ON f.id = fip."formId" + LEFT OUTER JOIN identity_provider ip ON fip.code::text = ip.code::text + GROUP BY f.id, f.name, f.active, f.description, f.labels, f."createdAt", f."createdBy", f."updatedAt", + f."updatedBy", fv.id, fv.version + ORDER BY (lower(f.name::text)), fv.version DESC`)); +}; diff --git a/frontend/app/src/db/migrations/20201008142046_006-version-drafts.js b/frontend/app/src/db/migrations/20201008142046_006-version-drafts.js new file mode 100644 index 0000000..3118f85 --- /dev/null +++ b/frontend/app/src/db/migrations/20201008142046_006-version-drafts.js @@ -0,0 +1,110 @@ +const stamps = require('../stamps'); + +exports.up = function(knex) { + return Promise.resolve() + .then(() => knex.schema.createTable('form_version_draft', table => { + table.uuid('id').primary(); + table.uuid('formId').references('id').inTable('form').notNullable().index(); + table.uuid('formVersionId').references('id').inTable('form_version').nullable(); + table.jsonb('schema'); + stamps(knex, table); + })) + .then(() => knex.schema.alterTable('form_version', table => { + table.boolean('published').notNullable().defaultTo(false); + })) + .then(() => knex.schema.raw(`create or replace view form_vw as + SELECT DISTINCT ON (lower(f.name::text), fv.version, f.id) f.id, + f.name, + f.active, + f.description, + f.labels, + f."createdAt", + f."createdBy", + f."updatedAt", + f."updatedBy", + fv.id AS "formVersionId", + fv.version, + case when count(fip.code) = 0 then '{}'::varchar[] else array_agg(distinct(fip.code)) end AS "identityProviders", + case when count(ip.idp) = 0 then '{}'::varchar[] else array_agg(distinct(ip.idp)) end AS idps, + fv.published, + fv."updatedAt" as "versionUpdatedAt" + FROM form f + LEFT JOIN LATERAL (select v.* from form_version v where v."formId" = f.id order by case when v.published then 1 else 0 end desc, v.version desc limit 1) fv ON true + LEFT OUTER JOIN form_identity_provider fip ON f.id = fip."formId" + LEFT OUTER JOIN identity_provider ip ON fip.code::text = ip.code::text + GROUP BY f.id, f.name, f.active, f.description, f.labels, f."createdAt", f."createdBy", f."updatedAt", + f."updatedBy", fv.id, fv.version, fv.published, fv."updatedAt" + ORDER BY lower(f.name::text), fv.version DESC, f.id`)) + .then(() => knex.schema.raw(`create or replace view user_form_access_vw as +select r."userId", u."keycloakId", u.username, u."fullName", u."firstName", u."lastName", u.email, r."formId", f.name as "formName", f.labels, f."identityProviders", f.idps, f.active, f."formVersionId", f.version, r.roles, p.permissions, f.published, f."versionUpdatedAt" +from "user" u join user_form_roles_vw r on u.id = r."userId" join user_form_permissions_vw p on r."userId" = p."userId" and r."formId" = p."formId" join form_vw f on f.id = p."formId" +order by lower(u."lastName"::text), lower(u."firstName"::text), lower(f.name::text)`)); +}; + +exports.down = function(knex) { + // OK, this is really ugly. + // One cannot simply remove a column from a view. + // One must drop the view and then recreate; however, one must drop ALL the dependant objects too, then recreate them. + // Very lame. + // first, drop the view that uses the new column (and all objects that use that view) + // then we drop the column from the table + // then we re-create the view and all the views that depend on it. + // + // then we are dropping the table added in this migration. + return Promise.resolve() + .then(() => knex.schema.raw('drop view form_vw cascade')) + .then(() => knex.schema.alterTable('form_version', table => { + table.dropColumn('published'); + })) + .then(() => knex.schema.raw(`create or replace view form_vw as + SELECT DISTINCT ON (lower(f.name::text), fv.version, f.id) f.id, + f.name, + f.active, + f.description, + f.labels, + f."createdAt", + f."createdBy", + f."updatedAt", + f."updatedBy", + fv.id AS "formVersionId", + fv.version, + case when count(fip.code) = 0 then '{}'::varchar[] else array_agg(distinct(fip.code)) end AS "identityProviders", + case when count(ip.idp) = 0 then '{}'::varchar[] else array_agg(distinct(ip.idp)) end AS idps + FROM form f + JOIN form_version fv ON f.id = fv."formId" + LEFT OUTER JOIN form_identity_provider fip ON f.id = fip."formId" + LEFT OUTER JOIN identity_provider ip ON fip.code::text = ip.code::text + GROUP BY f.id, f.name, f.active, f.description, f.labels, f."createdAt", f."createdBy", f."updatedAt", + f."updatedBy", fv.id, fv.version + ORDER BY lower(f.name::text), fv.version DESC, f.id`)) + .then(() => knex.schema.raw(`create or replace view user_form_permissions_vw as +select fru."userId", fru."formId", array_agg(distinct(p.code)) as permissions +from form_role_user fru +inner join role r on fru.role = r.code +inner join role_permission rp on r.code = rp.role +inner join permission p on rp.permission = p.code +group by fru."userId", fru."formId" +union +select u2.id as "userId", f2.id as "formId", '{submission_create,form_read}'::varchar[] as permissions +from form_vw f2, "user" u2 +where not exists (select * from form_role_user fru2 where fru2."formId"= f2.id and fru2."userId" = u2.id)`)) + .then(() => knex.schema.raw(`create or replace view user_form_roles_vw as +select fru."userId", fru."formId", array_agg(distinct(r.code)) as roles +from form_role_user fru +inner join role r on fru.role = r.code +group by fru."userId", fru."formId" +union +select u2.id as "userId", f2.id as "formId", '{}'::varchar[] as roles +from form_vw f2, "user" u2 +where not exists (select * from form_role_user fru2 where fru2."formId"= f2.id and fru2."userId" = u2.id)`)) + .then(() => knex.schema.raw(`create or replace view user_form_access_vw as +select r."userId", u."keycloakId", u.username, u."fullName", u."firstName", u."lastName", u.email, r."formId", f.name as "formName", f.labels, f."identityProviders", f.idps, f.active, f."formVersionId", f.version, r.roles, p.permissions +from "user" u join user_form_roles_vw r on u.id = r."userId" join user_form_permissions_vw p on r."userId" = p."userId" and r."formId" = p."formId" join form_vw f on f.id = p."formId" +order by lower(u."lastName"::text), lower(u."firstName"::text), lower(f.name::text)`)) + .then(() => knex.schema.raw(`create view public_form_access_vw as +select null as "userId", null as "keycloakId", 'public' as username, 'public' as "fullName", null as "firstName", null as "lastName", null as email, f.id as "formId", f.name as "formName", f.labels, f."identityProviders", f.idps, f.active, f."formVersionId", f.version, '{}'::varchar[] as roles, '{submission_create,form_read}'::varchar[] as permissions +from form_vw f +where 'public' = ANY(f."idps") +order by lower(f.name::text)`)) + .then(() => knex.schema.dropTableIfExists('form_version_draft')); +}; diff --git a/frontend/app/src/db/migrations/20201019100738_007-public-submission-data-vw.js b/frontend/app/src/db/migrations/20201019100738_007-public-submission-data-vw.js new file mode 100644 index 0000000..ed9896a --- /dev/null +++ b/frontend/app/src/db/migrations/20201019100738_007-public-submission-data-vw.js @@ -0,0 +1,29 @@ + +exports.up = function (knex) { + return Promise.resolve() + .then(() => knex.schema.raw(`create or replace view submissions_data_vw as +select s."confirmationId", s."formName", s.version, s."createdAt", + case when u.id is null then 'public'::varchar(255) else u."fullName" end as "fullName", case when u.id is null then 'public'::varchar(255) else u.username end as "username", u.email, + fs.submission -> 'data' AS "submission", s.deleted, s.draft, + s."submissionId", s."formId", s."formVersionId", u.id as "userId", u."keycloakId", u."firstName", u."lastName" +from submissions_vw s + inner join form_submission fs on s."submissionId" = fs.id + left outer join form_submission_user fsu on s."submissionId" = fsu."formSubmissionId" and fsu.permission = 'submission_create' + left outer join "user" u on fsu."userId" = u.id +order by s."createdAt", s."formName", s.version`)); +}; + +exports.down = function (knex) { + // Restore original definition of this view from 005 + return Promise.resolve() + .then(() => knex.schema.raw(`create or replace view submissions_data_vw as +select s."confirmationId", s."formName", s.version, s."createdAt", + u."fullName", u.username, u.email, + fs.submission -> 'data' AS "submission", s.deleted, s.draft, + s."submissionId", s."formId", s."formVersionId", u.id as "userId", u."keycloakId", u."firstName", u."lastName" +from submissions_vw s + inner join form_submission fs on s."submissionId" = fs.id + inner join form_submission_user fsu on s."submissionId" = fsu."formSubmissionId" and fsu.permission = 'submission_create' + inner join "user" u on fsu."userId" = u.id +order by s."createdAt", s."formName", s.version`)); +}; diff --git a/frontend/app/src/db/migrations/20201029141347_008-form-settings-notifications.js b/frontend/app/src/db/migrations/20201029141347_008-form-settings-notifications.js new file mode 100644 index 0000000..daeeec6 --- /dev/null +++ b/frontend/app/src/db/migrations/20201029141347_008-form-settings-notifications.js @@ -0,0 +1,16 @@ + +exports.up = function (knex) { + return Promise.resolve() + .then(() => knex.schema.alterTable('form', table => { + table.boolean('showSubmissionConfirmation').notNullable().defaultTo(true).comment('Show (when true) confirmation/receipt information to the submitter on success'); + table.specificType('submissionReceivedEmails', 'text ARRAY').comment('Array of email addresses to deliver notifications after a submission is received.'); + })); +}; + +exports.down = function (knex) { + return Promise.resolve() + .then(() => knex.schema.alterTable('form', table => { + table.dropColumn('showSubmissionConfirmation'); + table.dropColumn('submissionReceivedEmails'); + })); +}; diff --git a/frontend/app/src/db/migrations/20201105120909_009-file-upload.js b/frontend/app/src/db/migrations/20201105120909_009-file-upload.js new file mode 100644 index 0000000..3fcc9b7 --- /dev/null +++ b/frontend/app/src/db/migrations/20201105120909_009-file-upload.js @@ -0,0 +1,20 @@ +const stamps = require('../stamps'); + +exports.up = function (knex) { + return Promise.resolve().then(() => + knex.schema.createTable('file_storage', (table) => { + table.uuid('id').primary(); + table.string('originalName', 1024).notNullable(); + table.string('mimeType').notNullable(); + table.integer('size').notNullable(); + table.enu('storage', ['uploads', 'localStorage', 'objectStorage']).notNullable().defaultTo('uploads'); + table.string('path', 1024).notNullable(); + table.uuid('formSubmissionId').references('id').inTable('form_submission').nullable().index(); + stamps(knex, table); + }) + ); +}; + +exports.down = function (knex) { + return Promise.resolve().then(() => knex.schema.dropTableIfExists('file_storage')); +}; diff --git a/frontend/app/src/db/migrations/20210100113516_010-alter-form-view.js b/frontend/app/src/db/migrations/20210100113516_010-alter-form-view.js new file mode 100644 index 0000000..fc489b5 --- /dev/null +++ b/frontend/app/src/db/migrations/20210100113516_010-alter-form-view.js @@ -0,0 +1,82 @@ + +exports.up = function (knex) { + return Promise.resolve() + .then(() => knex.schema.raw(`create or replace + view user_form_access_vw as + select + r."userId", + u."keycloakId", + u.username, + u."fullName", + u."firstName", + u."lastName", + u.email, + r."formId", + f.name as "formName", + f.labels, + f."identityProviders", + f.idps, + f.active, + f."formVersionId", + f.version, + r.roles, + p.permissions, + f.published, + f."versionUpdatedAt", + f.description as "formDescription" + from + "user" u + join user_form_roles_vw r on + u.id = r."userId" + join user_form_permissions_vw p on + r."userId" = p."userId" + and r."formId" = p."formId" + join form_vw f on + f.id = p."formId" + order by + lower(u."lastName"::text), + lower(u."firstName"::text), + lower(f.name::text)`)); +}; + +exports.down = function (knex) { + // drop view 'user_form_access_vw' and everything that depends on it + // then re-create it using DDL for the view from before this migration (from file .006-version-drafts.js) and its dependencies (currenly no dependencies) + return Promise.resolve() + .then(() => knex.schema.raw('drop view user_form_access_vw cascade')) + .then(() => knex.schema.raw(`create or replace + view user_form_access_vw as + select + r."userId", + u."keycloakId", + u.username, + u."fullName", + u."firstName", + u."lastName", + u.email, + r."formId", + f.name as "formName", + f.labels, + f."identityProviders", + f.idps, + f.active, + f."formVersionId", + f.version, + r.roles, + p.permissions, + f.published, + f."versionUpdatedAt" + from + "user" u + join user_form_roles_vw r on + u.id = r."userId" + join user_form_permissions_vw p on + r."userId" = p."userId" + and r."formId" = p."formId" + join form_vw f on + f.id = p."formId" + order by + lower(u."lastName"::text), + lower(u."firstName"::text), + lower(f.name::text)`)); +}; diff --git a/frontend/app/src/db/migrations/20210129120337_012-submission-status.js b/frontend/app/src/db/migrations/20210129120337_012-submission-status.js new file mode 100644 index 0000000..a961e09 --- /dev/null +++ b/frontend/app/src/db/migrations/20210129120337_012-submission-status.js @@ -0,0 +1,160 @@ +const stamps = require('../stamps'); +const { v4: uuidv4 } = require('uuid'); + +const CREATED_BY = 'migration-012'; + +const statusCodes = [ + { code: 'SUBMITTED', display: 'Submitted', nextCodes: ['ASSIGNED', 'COMPLETED'], createdBy: CREATED_BY }, + { code: 'ASSIGNED', display: 'Assigned', nextCodes: ['ASSIGNED', 'COMPLETED'], createdBy: CREATED_BY }, + { code: 'COMPLETED', display: 'Completed', nextCodes: ['ASSIGNED'], createdBy: CREATED_BY } +]; + +exports.up = function (knex) { + return Promise.resolve() + // Add a status update flag + .then(() => knex.schema.alterTable('form', table => { + table.boolean('enableStatusUpdates').notNullable().defaultTo(false).comment('When true, submissions of this form will have status updates available'); + })) + + // add a status_code table + .then(() => knex.schema.createTable('status_code', table => { + table.string('code').primary(); + table.string('display').notNullable(); + table.specificType('nextCodes', 'text ARRAY').comment('This is an array of codes that this status could transition to next'); + stamps(knex, table); + })) + // seed the table + .then(() => { + return knex('status_code').insert(statusCodes); + }) + + // add a form_status_code table + // this links each form to the statuses available to it, could be used to customize in the future + .then(() => knex.schema.createTable('form_status_code', table => { + table.uuid('id').primary(); + table.uuid('formId').references('id').inTable('form').notNullable().index(); + table.string('code').references('code').inTable('status_code').notNullable().index(); + stamps(knex, table); + })) + // Get all form ids + .then(() => { + return knex('form').select('id'); + }) + // Insert the form->status code mapping for each form + .then(forms => { + const formStatuses = forms.flatMap(f => statusCodes.flatMap(sc => ({ + id: uuidv4(), + formId: f.id, + code: sc.code, + createdBy: CREATED_BY + }))); + if (formStatuses && formStatuses.length) return knex('form_status_code').insert(formStatuses); + }) + + // add a form_submission_status table + // links a submission to a status + .then(() => knex.schema.createTable('form_submission_status', table => { + table.uuid('id').primary(); + table.uuid('submissionId').references('id').inTable('form_submission').notNullable().index(); + table.string('code').references('code').inTable('status_code').notNullable().index(); + table.uuid('assignedToUserId').references('id').inTable('user').index(); + table.date('actionDate').nullable(); + stamps(knex, table); + })) + // Backfill submission statuses to "SUBMITTED for each exsiting submission" + // Use the original submitter and time as the creator (store "migrate" in updatedBy for tracking) + .then(() => knex.schema.raw(`INSERT INTO public.form_submission_status + ("id", "submissionId", code, "assignedToUserId", "actionDate", "createdBy", "createdAt", "updatedBy", "updatedAt") + SELECT uuid_in(overlay(overlay(md5(random()::text || ':' || clock_timestamp()::text) placing '4' from 13) placing to_hex(floor(random()*(11-8+1) + 8)::int)::text from 17)::cstring), id, 'SUBMITTED', NULL, NULL, "createdBy", "createdAt", '${CREATED_BY}', now() + FROM public.form_submission`)) + + // add a note table + .then(() => knex.schema.createTable('note', table => { + table.uuid('id').primary(); + table.uuid('submissionId').references('id').inTable('form_submission').index(); + table.uuid('submissionStatusId').references('id').inTable('form_submission_status').index(); + table.string('note', 4000).nullable(); + table.uuid('userId').references('id').inTable('user').index(); + stamps(knex, table); + })) + + // modify the submission view to return status information + .then(() => knex.schema.raw(`create or replace + view submissions_vw as + SELECT s.id AS "submissionId", + s."confirmationId", + s.draft, + s.deleted, + s."createdBy", + s."createdAt", + f.id AS "formId", + f.name AS "formName", + fv.id AS "formVersionId", + fv."version", + st.id AS "formSubmissionStatusId", + st.code AS "formSubmissionStatusCode" + FROM form_submission s + JOIN form_version fv ON s."formVersionId" = fv.id + JOIN form f ON fv."formId" = f.id + LEFT OUTER JOIN LATERAL ( + SELECT id, code, "createdBy", "createdAt" + FROM form_submission_status + WHERE "submissionId" = s.id + ORDER BY "createdAt" DESC + FETCH FIRST 1 ROW ONLY + ) st ON true + ORDER BY s."createdAt" DESC`)) + + // Allow form reviewers to see team members for a form + .then(() => { + const rolePermssion = { + id: uuidv4(), + createdBy: CREATED_BY, + role: 'submission_reviewer', + permission: 'team_read' + }; + return knex('role_permission').insert(rolePermssion); + }); + +}; + +exports.down = function (knex) { + return Promise.resolve() + // undo new form role permission + .then(() => knex('role_permission') + .where({ + role: 'submission_reviewer', + permission: 'team_read' + }) + .del()) + + // reset the submission view to return status information + .then(() => knex.schema.raw('drop view submissions_vw cascade')) + .then(() => knex.schema.raw(`create or replace + view submissions_vw as + SELECT s.id AS "submissionId", + s."confirmationId", + s.draft, + s.deleted, + s."createdBy", + s."createdAt", + f.id AS "formId", + f.name AS "formName", + fv.id AS "formVersionId", + fv.version + FROM form_submission s + JOIN form_version fv ON s."formVersionId" = fv.id + JOIN form f ON fv."formId" = f.id + ORDER BY s."createdAt" DESC;`)) + + // undo the new tables + .then(() => knex.schema.dropTableIfExists('note')) + .then(() => knex.schema.dropTableIfExists('form_submission_status')) + .then(() => knex.schema.dropTableIfExists('form_status_code')) + .then(() => knex.schema.dropTableIfExists('status_code')) + + // undo the new field add + .then(() => knex.schema.alterTable('form', table => { + table.dropColumn('enableStatusUpdates'); + })); +}; diff --git a/frontend/app/src/db/migrations/20210408120337_013-role-permission-for-owner.js b/frontend/app/src/db/migrations/20210408120337_013-role-permission-for-owner.js new file mode 100644 index 0000000..e3b4e9a --- /dev/null +++ b/frontend/app/src/db/migrations/20210408120337_013-role-permission-for-owner.js @@ -0,0 +1,118 @@ +const { v4: uuidv4 } = require('uuid'); + +const CREATED_BY = 'migration-013'; + +exports.up = function (knex) { + return Promise.resolve() + // Allow form owners to do all the other roles' actions + .then(() => { + const rolePermssion = { + id: uuidv4(), + createdBy: CREATED_BY, + role: 'owner', + permission: 'design_create' + }; + return knex('role_permission').insert(rolePermssion); + }) + + .then(() => { + const rolePermssion = { + id: uuidv4(), + createdBy: CREATED_BY, + role: 'owner', + permission: 'design_delete' + }; + return knex('role_permission').insert(rolePermssion); + }) + + .then(() => { + const rolePermssion = { + id: uuidv4(), + createdBy: CREATED_BY, + role: 'owner', + permission: 'design_read' + }; + return knex('role_permission').insert(rolePermssion); + }) + + .then(() => { + const rolePermssion = { + id: uuidv4(), + createdBy: CREATED_BY, + role: 'owner', + permission: 'design_update' + }; + return knex('role_permission').insert(rolePermssion); + }) + + .then(() => { + const rolePermssion = { + id: uuidv4(), + createdBy: CREATED_BY, + role: 'owner', + permission: 'submission_create' + }; + return knex('role_permission').insert(rolePermssion); + }) + + .then(() => { + const rolePermssion = { + id: uuidv4(), + createdBy: CREATED_BY, + role: 'owner', + permission: 'submission_delete' + }; + return knex('role_permission').insert(rolePermssion); + }) + + .then(() => { + const rolePermssion = { + id: uuidv4(), + createdBy: CREATED_BY, + role: 'owner', + permission: 'submission_read' + }; + return knex('role_permission').insert(rolePermssion); + }) + + .then(() => { + const rolePermssion = { + id: uuidv4(), + createdBy: CREATED_BY, + role: 'owner', + permission: 'submission_update' + }; + return knex('role_permission').insert(rolePermssion); + }) + + .then(() => { + const rolePermssion = { + id: uuidv4(), + createdBy: CREATED_BY, + role: 'owner', + permission: 'team_read' + }; + return knex('role_permission').insert(rolePermssion); + }) + + .then(() => { + const rolePermssion = { + id: uuidv4(), + createdBy: CREATED_BY, + role: 'owner', + permission: 'team_update' + }; + return knex('role_permission').insert(rolePermssion); + }); + +}; + +exports.down = function (knex) { + return Promise.resolve() + // undo new form role permission + .then(() => knex('role_permission') + .where({ + createdBy: CREATED_BY + }) + .del()); +}; diff --git a/frontend/app/src/db/migrations/20210426141115_014-form-submission-audit.js b/frontend/app/src/db/migrations/20210426141115_014-form-submission-audit.js new file mode 100644 index 0000000..ce905eb --- /dev/null +++ b/frontend/app/src/db/migrations/20210426141115_014-form-submission-audit.js @@ -0,0 +1,55 @@ +exports.up = function (knex) { + return Promise.resolve() + // add a submission history table + .then(() => knex.schema.createTable('form_submission_audit', table => { + table.specificType( + 'id', + 'integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY' + ); + table.uuid('submissionId').notNullable().index(); + table.string('dbUser').notNullable(); + table.string('updatedByUsername'); + table.timestamp('actionTimestamp', { useTz: true }).defaultTo(knex.fn.now()); + table.string('action').notNullable(); + table.jsonb('originalData'); + })) + + .then(() => knex.schema.raw(`CREATE OR REPLACE FUNCTION public.submission_audited_func() RETURNS trigger AS $body$ + DECLARE + v_old_data json; + BEGIN + if (TG_OP = 'UPDATE') then + v_old_data := row_to_json(OLD); + insert into public.form_submission_audit ("submissionId", "dbUser", "updatedByUsername", "actionTimestamp", "action", "originalData") + values ( + OLD.id, + SESSION_USER, + NEW."updatedBy", + now(), + 'U', + v_old_data); + RETURN NEW; + elsif (TG_OP = 'DELETE') then + v_old_data := row_to_json(OLD); + insert into public.form_submission_audit ("submissionId", "dbUser", "actionTimestamp", "action", "originalData") + values ( + OLD.id, + SESSION_USER, + now(), + 'D', + v_old_data); + end if; + END; + $body$ LANGUAGE plpgsql`)) + + .then(() => knex.schema.raw(`CREATE TRIGGER form_submission_audit_trigger + AFTER UPDATE OR DELETE ON form_submission + FOR EACH ROW EXECUTE PROCEDURE public.submission_audited_func();`)); +}; + +exports.down = function (knex) { + return Promise.resolve() + .then(() => knex.schema.raw('DROP TRIGGER form_submission_audit_trigger ON form_submission')) + .then(() => knex.schema.raw('DROP FUNCTION submission_audited_func()')) + .then(() => knex.schema.dropTableIfExists('form_submission_audit')); +}; diff --git a/frontend/app/src/db/migrations/20210519170000_015-alter-submission-data-vw.js b/frontend/app/src/db/migrations/20210519170000_015-alter-submission-data-vw.js new file mode 100644 index 0000000..f09299e --- /dev/null +++ b/frontend/app/src/db/migrations/20210519170000_015-alter-submission-data-vw.js @@ -0,0 +1,134 @@ +const previousMigration = require('./20201019100738_007-public-submission-data-vw').up; + +exports.up = function (knex) { + return Promise.resolve() + + // JOIN user table to submissions_vw on form_submission_status.assignedToUserId to get 'assigned to' user + .then(() => knex.schema.raw(`create or replace + view submissions_vw as + SELECT + s.id AS "submissionId", + s."confirmationId", + s.draft, + s.deleted, + s."createdBy", + s."createdAt", + f.id AS "formId", + f.name AS "formName", + fv.id AS "formVersionId", + fv."version", + st.id AS "formSubmissionStatusId", + st.code AS "formSubmissionStatusCode", + st."createdBy" AS "formSubmissionStatusCreatedBy", + st."createdAt" AS "formSubmissionStatusCreatedAt", + u."fullName" AS "formSubmissionAssignedToFullName", + u."email" AS "formSubmissionAssignedToEmail" + FROM + form_submission s + JOIN form_version fv ON + s."formVersionId" = fv.id + JOIN form f ON + fv."formId" = f.id + LEFT OUTER JOIN LATERAL ( + SELECT + id, + code, + "createdBy", + "createdAt", + "assignedToUserId" + FROM + form_submission_status + WHERE + "submissionId" = s.id + ORDER BY + "createdAt" DESC + FETCH FIRST 1 ROW ONLY + ) st ON true + LEFT JOIN "user" u ON + st."assignedToUserId" = u."id" + ORDER BY + s."createdAt" DESC`)) + + // add extra columns to submissions_data_vw + .then(() => knex.schema.raw(`create or replace view submissions_data_vw as + select + s."confirmationId", + s."formName", + s.version, + s."createdAt", + case + when u.id is null then 'public'::varchar(255) + else u."fullName" + end as "fullName", + case + when u.id is null then 'public'::varchar(255) + else u.username + end as "username", + u.email, + fs.submission -> 'data' as "submission", + s.deleted, + s.draft, + s."submissionId", + s."formId", + s."formVersionId", + u.id as "userId", + u."keycloakId", + u."firstName", + u."lastName", + s."formSubmissionStatusCode" as "status", + s."formSubmissionAssignedToFullName" as "assignee", + s."formSubmissionAssignedToEmail" as "assigneeEmail" + from + submissions_vw s + inner join form_submission fs on + s."submissionId" = fs.id + left outer join form_submission_user fsu on + s."submissionId" = fsu."formSubmissionId" + and fsu.permission = 'submission_create' + left outer join "user" u on + fsu."userId" = u.id + order by + s."createdAt", + s."formName", + s.version`)); +}; + +exports.down = function (knex) { + // to revert this migration and (remove the new columns) + // we need to drop..cascade the modified view + // AND recreate any dependent views + // currently the only dependent view: 'submissions_data_vw' + return Promise.resolve() + // drop the modified 'submissions_vw' view and all dependent views + .then(() => knex.schema.raw('drop view submissions_vw cascade')) + + // restore 'submissions_vw' from migration 012 + .then(() => knex.schema.raw(`create or replace + view submissions_vw as + SELECT s.id AS "submissionId", + s."confirmationId", + s.draft, + s.deleted, + s."createdBy", + s."createdAt", + f.id AS "formId", + f.name AS "formName", + fv.id AS "formVersionId", + fv."version", + st.id AS "formSubmissionStatusId", + st.code AS "formSubmissionStatusCode" + FROM form_submission s + JOIN form_version fv ON s."formVersionId" = fv.id + JOIN form f ON fv."formId" = f.id + LEFT OUTER JOIN LATERAL ( + SELECT id, code, "createdBy", "createdAt" + FROM form_submission_status + WHERE "submissionId" = s.id + ORDER BY "createdAt" DESC + FETCH FIRST 1 ROW ONLY + ) st ON true + ORDER BY s."createdAt" DESC`)) + + // recreate dependent view 'submissions_data_vw' from migration 007 + .then(() => previousMigration(knex)); +}; diff --git a/frontend/app/src/db/migrations/20210528134214_016-submission-submitters-vw copy.js b/frontend/app/src/db/migrations/20210528134214_016-submission-submitters-vw copy.js new file mode 100644 index 0000000..33ac976 --- /dev/null +++ b/frontend/app/src/db/migrations/20210528134214_016-submission-submitters-vw copy.js @@ -0,0 +1,24 @@ +exports.up = function(knex) { + return Promise.resolve() + .then(() => knex.schema.raw(`create or replace view submissions_submitters_vw as + SELECT + fsu.*, + fv."formId", + fv."version", + sub."id", + sub."confirmationId", + sub."createdAt", + sub."draft", + sub."deleted" + FROM + form_submission_users_vw fsu + INNER JOIN form_submission sub ON + sub."id" = fsu."formSubmissionId" + INNER JOIN form_version fv ON + fv."id" = sub."formVersionId"`)); +}; + +exports.down = function(knex) { + return Promise.resolve() + .then(() => knex.schema.raw('DROP VIEW IF EXISTS submissions_submitters_vw')); +}; diff --git a/frontend/app/src/db/migrations/20210614134214_017-alter-submission-submitters-add-form.js b/frontend/app/src/db/migrations/20210614134214_017-alter-submission-submitters-add-form.js new file mode 100644 index 0000000..f73147d --- /dev/null +++ b/frontend/app/src/db/migrations/20210614134214_017-alter-submission-submitters-add-form.js @@ -0,0 +1,47 @@ +const previousMigration = require('./20210528134214_016-submission-submitters-vw copy').up; + +exports.up = function (knex) { + return Promise.resolve() + // Add a status update flag + .then(() => knex.schema.alterTable('form', table => { + table.boolean('enableSubmitterDraft').notNullable().defaultTo(false).comment('When true, submitters can save drafts'); + })) + + // Update view. Add form join and some fields from form + .then(() => knex.schema.raw(`create or replace view submissions_submitters_vw as + SELECT + fsu.*, + fv."formId", + fv."version", + sub."id", + sub."confirmationId", + sub."createdAt", + sub."draft", + sub."deleted", + f.name, + f.description, + f.active, + f."enableStatusUpdates", + f."enableSubmitterDraft" + FROM + form_submission_users_vw fsu + INNER JOIN form_submission sub ON + sub."id" = fsu."formSubmissionId" + INNER JOIN form_version fv ON + fv."id" = sub."formVersionId" + INNER JOIN form f ON + fv."formId" = f."id"`)); +}; + +exports.down = function (knex) { + return Promise.resolve() + // drop the modified 'submissions_vw' view + .then(() => knex.schema.raw('drop view submissions_submitters_vw')) + // recreate dependent view 'submissions_data_vw' from migration 16 + .then(() => previousMigration(knex)) + + // undo the new field add + .then(() => knex.schema.alterTable('form', table => { + table.dropColumn('enableSubmitterDraft'); + })); +}; diff --git a/frontend/app/src/db/migrations/20210716000000_018-alter-submission-submitters-add-updatedAt.js b/frontend/app/src/db/migrations/20210716000000_018-alter-submission-submitters-add-updatedAt.js new file mode 100644 index 0000000..b78990d --- /dev/null +++ b/frontend/app/src/db/migrations/20210716000000_018-alter-submission-submitters-add-updatedAt.js @@ -0,0 +1,56 @@ +exports.up = function (knex) { + return Promise.resolve() + .then(() => knex.schema.raw('drop view submissions_submitters_vw')) + .then(() => knex.schema.raw(`create or replace view submissions_submitters_vw as + SELECT + fsu.*, + fv."formId", + fv."version", + sub."id", + sub."confirmationId", + sub."createdAt", + sub."updatedAt", + sub."draft", + sub."deleted", + f.name, + f.description, + f.active, + f."enableStatusUpdates", + f."enableSubmitterDraft" + FROM + form_submission_users_vw fsu + INNER JOIN form_submission sub ON + sub."id" = fsu."formSubmissionId" + INNER JOIN form_version fv ON + fv."id" = sub."formVersionId" + INNER JOIN form f ON + fv."formId" = f."id"`)); +}; + +exports.down = function (knex) { + return Promise.resolve() + .then(() => knex.schema.raw('drop view submissions_submitters_vw')) + .then(() => knex.schema.raw(`create or replace view submissions_submitters_vw as + SELECT + fsu.*, + fv."formId", + fv."version", + sub."id", + sub."confirmationId", + sub."createdAt", + sub."draft", + sub."deleted", + f.name, + f.description, + f.active, + f."enableStatusUpdates", + f."enableSubmitterDraft" + FROM + form_submission_users_vw fsu + INNER JOIN form_submission sub ON + sub."id" = fsu."formSubmissionId" + INNER JOIN form_version fv ON + fv."id" = sub."formVersionId" + INNER JOIN form f ON + fv."formId" = f."id"`)); +}; diff --git a/frontend/app/src/db/migrations/20210721210234_019-api-key-models.js b/frontend/app/src/db/migrations/20210721210234_019-api-key-models.js new file mode 100644 index 0000000..f3f7bb0 --- /dev/null +++ b/frontend/app/src/db/migrations/20210721210234_019-api-key-models.js @@ -0,0 +1,170 @@ +const { v4: uuidv4 } = require('uuid'); +const stamps = require('../stamps'); + +const CREATED_BY = 'migration-019'; + +exports.up = function (knex) { + return Promise.resolve() + // Add the new permissions for users managing Form API Keys + .then(() => { + const items = [ + { + createdBy: CREATED_BY, + code: 'form_api_create', + display: 'API Key Create', + description: 'Can create an api key for a form', + active: true + }, + { + createdBy: CREATED_BY, + code: 'form_api_read', + display: 'API Key Read', + description: 'Can view the API key for a form (unencrypted)', + active: true + }, + { + createdBy: CREATED_BY, + code: 'form_api_update', + display: 'API Key Update', + description: 'Can update the API key for a form', + active: true + }, + { + createdBy: CREATED_BY, + code: 'form_api_delete', + display: 'API Key Delete', + description: 'Can remove the API key from a form', + active: true + } + ]; + return knex('permission').insert(items).returning('code'); + }) + + // Form Owners (and only owners now) can do these new permissions + .then(() => { + const rolePermssion = { + id: uuidv4(), + createdBy: CREATED_BY, + role: 'owner', + permission: 'form_api_create' + }; + return knex('role_permission').insert(rolePermssion); + }) + + .then(() => { + const rolePermssion = { + id: uuidv4(), + createdBy: CREATED_BY, + role: 'owner', + permission: 'form_api_read' + }; + return knex('role_permission').insert(rolePermssion); + }) + + .then(() => { + const rolePermssion = { + id: uuidv4(), + createdBy: CREATED_BY, + role: 'owner', + permission: 'form_api_update' + }; + return knex('role_permission').insert(rolePermssion); + }) + + .then(() => { + const rolePermssion = { + id: uuidv4(), + createdBy: CREATED_BY, + role: 'owner', + permission: 'form_api_delete' + }; + return knex('role_permission').insert(rolePermssion); + }) + + // Add the new table for API keys + .then(() => knex.schema.createTable('form_api_key', table => { + table.specificType( + 'id', + 'integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY' + ); + table.uuid('formId').references('id').inTable('form').notNullable().index(); + table.uuid('secret').unique().notNullable(); + stamps(knex, table); + })) + + // Add the new table for API key audit history + .then(() => knex.schema.createTable('form_api_key_audit', table => { + table.specificType( + 'id', + 'integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY' + ); + table.integer('keyId').notNullable(); + table.uuid('formId').notNullable().index(); + table.string('dbUser').notNullable(); + table.string('updatedByUsername'); + table.timestamp('actionTimestamp', { useTz: true }).defaultTo(knex.fn.now()); + table.string('action').notNullable(); + })) + + .then(() => knex.schema.raw(`CREATE OR REPLACE FUNCTION public.form_api_key_audited_func() RETURNS trigger AS $body$ + BEGIN + if (TG_OP = 'UPDATE') then + insert into public.form_api_key_audit ("keyId", "formId", "dbUser", "updatedByUsername", "actionTimestamp", "action") + values ( + OLD.id, + OLD."formId", + SESSION_USER, + NEW."updatedBy", + now(), + TG_OP); + RETURN NEW; + elsif (TG_OP = 'INSERT') then + insert into public.form_api_key_audit ("keyId", "formId", "dbUser", "updatedByUsername", "actionTimestamp", "action") + values ( + NEW.id, + NEW."formId", + SESSION_USER, + NEW."createdBy", + now(), + TG_OP); + RETURN NEW; + elsif (TG_OP = 'DELETE') then + insert into public.form_api_key_audit ("keyId", "formId", "dbUser", "actionTimestamp", "action") + values ( + OLD.id, + OLD."formId", + SESSION_USER, + now(), + TG_OP); + RETURN NEW; + end if; + END; + $body$ LANGUAGE plpgsql`)) + + .then(() => knex.schema.raw(`CREATE TRIGGER form_api_key_audit_trigger + AFTER INSERT OR UPDATE OR DELETE ON form_api_key + FOR EACH ROW EXECUTE PROCEDURE public.form_api_key_audited_func();`)); +}; + +exports.down = function (knex) { + return Promise.resolve() + // drop new tables/function + .then(() => knex.schema.raw('DROP TRIGGER form_api_key_audit_trigger ON form_api_key')) + .then(() => knex.schema.raw('DROP FUNCTION form_api_key_audited_func()')) + .then(() => knex.schema.dropTableIfExists('form_api_key_audit')) + .then(() => knex.schema.dropTableIfExists('form_api_key')) + + // undo new form role permission + .then(() => knex('role_permission') + .where({ + createdBy: CREATED_BY + }) + .del()) + + // undo new permissions + .then(() => knex('permission') + .where({ + createdBy: CREATED_BY + }) + .del()); +}; diff --git a/frontend/app/src/db/migrations/20210816000000_020-user-form-preferences.js b/frontend/app/src/db/migrations/20210816000000_020-user-form-preferences.js new file mode 100644 index 0000000..8614951 --- /dev/null +++ b/frontend/app/src/db/migrations/20210816000000_020-user-form-preferences.js @@ -0,0 +1,17 @@ +const stamps = require('../stamps'); + +exports.up = function (knex) { + return Promise.resolve() + .then(() => knex.schema.createTable('user_form_preferences', table => { + table.primary(['userId', 'formId']); + table.uuid('userId').references('id').inTable('user').notNullable(); + table.uuid('formId').references('id').inTable('form').notNullable(); + table.jsonb('preferences'); + stamps(knex, table); + })); +}; + +exports.down = function (knex) { + return Promise.resolve() + .then(() => knex.schema.dropTableIfExists('user_form_preferences')); +}; diff --git a/frontend/app/src/db/migrations/20210830170000_021-alter-submissions-vw.js b/frontend/app/src/db/migrations/20210830170000_021-alter-submissions-vw.js new file mode 100644 index 0000000..e26b6e3 --- /dev/null +++ b/frontend/app/src/db/migrations/20210830170000_021-alter-submissions-vw.js @@ -0,0 +1,48 @@ +const previousMigration = require('./20210519170000_015-alter-submission-data-vw').up; + +exports.up = function (knex) { + return Promise.resolve() + // add data column to submissions_vw + .then(() => knex.schema.raw(`CREATE OR REPLACE VIEW public.submissions_vw + AS SELECT s.id AS "submissionId", + s."confirmationId", + s.draft, + s.deleted, + s."createdBy", + s."createdAt", + f.id AS "formId", + f.name AS "formName", + fv.id AS "formVersionId", + fv.version, + st.id AS "formSubmissionStatusId", + st.code AS "formSubmissionStatusCode", + st."createdBy" AS "formSubmissionStatusCreatedBy", + st."createdAt" AS "formSubmissionStatusCreatedAt", + u."fullName" AS "formSubmissionAssignedToFullName", + u.email AS "formSubmissionAssignedToEmail", + s.submission + FROM form_submission s + JOIN form_version fv ON s."formVersionId" = fv.id + JOIN form f ON fv."formId" = f.id + LEFT JOIN LATERAL ( SELECT form_submission_status.id, + form_submission_status.code, + form_submission_status."createdBy", + form_submission_status."createdAt", + form_submission_status."assignedToUserId" + FROM form_submission_status + WHERE form_submission_status."submissionId" = s.id + ORDER BY form_submission_status."createdAt" DESC + LIMIT 1) st ON true + LEFT JOIN "user" u ON st."assignedToUserId" = u.id + ORDER BY s."createdAt" DESC;`)); +}; + +exports.down = function (knex) { + return Promise.resolve() + // drop the modified 'submissions_vw' view and all dependent views + .then(() => knex.schema.raw('drop view submissions_vw cascade')) + + // recreate 'submissions_vw' from migration 015 + // recreate dependent view 'submissions_data_vw' from migration 015 + .then(() => previousMigration(knex)); +}; diff --git a/frontend/app/src/db/migrations/20210928000000_022-add-bceid-idps.js b/frontend/app/src/db/migrations/20210928000000_022-add-bceid-idps.js new file mode 100644 index 0000000..88d25ed --- /dev/null +++ b/frontend/app/src/db/migrations/20210928000000_022-add-bceid-idps.js @@ -0,0 +1,30 @@ +const CREATED_BY = 'migration-022'; + +exports.up = function(knex) { + return Promise.resolve() + .then(() => { + return knex('identity_provider').insert([ + { + createdBy: CREATED_BY, + code: 'bceid-basic', + display: 'Basic BCeID', + active: true, + idp: 'bceid-basic' + }, + { + createdBy: CREATED_BY, + code: 'bceid-business', + display: 'Business BCeID', + active: true, + idp: 'bceid-business' + } + ]); + }); +}; + +exports.down = function(knex) { + return Promise.resolve() + .then(() => { + return knex('identity_provider').where('createdBy', CREATED_BY).del(); + }); +}; diff --git a/frontend/app/src/db/migrations/20211006000000_023-add-user-idps.js b/frontend/app/src/db/migrations/20211006000000_023-add-user-idps.js new file mode 100644 index 0000000..703084a --- /dev/null +++ b/frontend/app/src/db/migrations/20211006000000_023-add-user-idps.js @@ -0,0 +1,16 @@ +exports.up = function (knex) { + return Promise.resolve() + // Add optional idpCode foreign key column + .then(() => knex.schema.alterTable('user', table => { + table.string('idpCode').references('code').inTable('identity_provider').comment('The associated identity provider'); + })) + // Set idpCode to 'idir' + .then(() => knex('user').update({ idpCode: 'idir' })); +}; + +exports.down = function (knex) { + return Promise.resolve() + .then(() => knex.schema.alterTable('user', table => { + table.dropColumn('idpCode'); + })); +}; diff --git a/frontend/app/src/db/migrations/20211027000000_024-add-revising.js b/frontend/app/src/db/migrations/20211027000000_024-add-revising.js new file mode 100644 index 0000000..24293bf --- /dev/null +++ b/frontend/app/src/db/migrations/20211027000000_024-add-revising.js @@ -0,0 +1,38 @@ +const { v4: uuidv4 } = require('uuid'); + +const CREATED_BY = 'migration-024'; + +exports.up = function (knex) { + return Promise.resolve() + // Add Revising status code + .then(() => knex('status_code').insert({ code: 'REVISING', display: 'Revising', nextCodes: ['ASSIGNED', 'COMPLETED'], createdBy: CREATED_BY })) + // Update existing status code transitions + .then(() => knex('status_code').where({ code: 'SUBMITTED' }).update({ nextCodes: ['ASSIGNED', 'COMPLETED', 'REVISING'], updatedBy: CREATED_BY })) + .then(() => knex('status_code').where({ code: 'ASSIGNED' }).update({ nextCodes: ['ASSIGNED', 'COMPLETED', 'REVISING'], updatedBy: CREATED_BY })) + .then(() => knex('status_code').where({ code: 'COMPLETED' }).update({ nextCodes: ['ASSIGNED', 'REVISING'], updatedBy: CREATED_BY })) + + // Insert Revising form status code into specific forms + .then(() => knex('form').select('id')) + .then((forms) => { + const formStatuses = forms.map(f => ({ + id: uuidv4(), + formId: f.id, + code: 'REVISING', + createdBy: CREATED_BY + })); + if (formStatuses && formStatuses.length) return knex('form_status_code').insert(formStatuses); + }); +}; + +exports.down = function (knex) { + return Promise.resolve() + // Drop Revising form status code from specific forms + .then(() => knex('form_status_code').where('code', 'REVISING').del()) + + // Revert existing status code transitions + .then(() => knex('status_code').where({ code: 'SUBMITTED' }).update({ nextCodes: ['ASSIGNED', 'COMPLETED'], updatedBy: null })) + .then(() => knex('status_code').where({ code: 'ASSIGNED' }).update({ nextCodes: ['ASSIGNED', 'COMPLETED'], updatedBy: null })) + .then(() => knex('status_code').where({ code: 'COMPLETED' }).update({ nextCodes: ['ASSIGNED'], updatedBy: null })) + // Drop Revising status code + .then(() => knex('status_code').where('createdBy', CREATED_BY).del()); +}; diff --git a/frontend/app/src/db/migrations/20221205215308_025-add-idp-guids.js b/frontend/app/src/db/migrations/20221205215308_025-add-idp-guids.js new file mode 100644 index 0000000..54a9d0a --- /dev/null +++ b/frontend/app/src/db/migrations/20221205215308_025-add-idp-guids.js @@ -0,0 +1,13 @@ +exports.up = function(knex) { + return Promise.resolve() + .then(() => knex.schema.alterTable('user', table => { + table.string('idpUserId').comment('The unique identifier provided by the identity provider'); + })); +}; + +exports.down = function(knex) { + return Promise.resolve() + .then(() => knex.schema.alterTable('user', table => { + table.dropColumn('idpUserId'); + })); +}; diff --git a/frontend/app/src/db/migrations/20221208001614_026-remove-keycloak-id.js b/frontend/app/src/db/migrations/20221208001614_026-remove-keycloak-id.js new file mode 100644 index 0000000..ccbf01f --- /dev/null +++ b/frontend/app/src/db/migrations/20221208001614_026-remove-keycloak-id.js @@ -0,0 +1,180 @@ +exports.up = function(knex) { + return Promise.resolve() + .then(() => knex.schema.dropViewIfExists('user_form_access_vw')) + .then(() => knex.schema.raw(`create or replace + view user_form_access_vw as + select + r."userId", + u."idpUserId", + u.username, + u."fullName", + u."firstName", + u."lastName", + u.email, + r."formId", + f.name as "formName", + f.labels, + f."identityProviders", + f.idps, + f.active, + f."formVersionId", + f.version, + r.roles, + p.permissions, + f.published, + f."versionUpdatedAt", + f.description as "formDescription" + from + "user" u + join user_form_roles_vw r on + u.id = r."userId" + join user_form_permissions_vw p on + r."userId" = p."userId" + and r."formId" = p."formId" + join form_vw f on + f.id = p."formId" + order by + lower(u."lastName"::text), + lower(u."firstName"::text), + lower(f.name::text)`)) + .then(() => knex.schema.dropViewIfExists('public_form_access_vw')) + .then(() => knex.schema.raw(`create view public_form_access_vw as + select null as "userId", null as "idpUserId", 'public' as username, 'public' as "fullName", null as "firstName", null as "lastName", null as email, f.id as "formId", f.name as "formName", f.labels, f."identityProviders", f.idps, f.active, f."formVersionId", f.version, '{}'::varchar[] as roles, '{submission_create,form_read}'::varchar[] as permissions + from form_vw f + where 'public' = ANY(f."idps") + order by lower(f.name::text)`)) + + .then(() => knex.schema.dropViewIfExists('submissions_data_vw')) + .then(() => knex.schema.raw(`create or replace view submissions_data_vw as + select + s."confirmationId", + s."formName", + s.version, + s."createdAt", + case + when u.id is null then 'public'::varchar(255) + else u."fullName" + end as "fullName", + case + when u.id is null then 'public'::varchar(255) + else u.username + end as "username", + u.email, + fs.submission -> 'data' as "submission", + s.deleted, + s.draft, + s."submissionId", + s."formId", + s."formVersionId", + u.id as "userId", + u."idpUserId", + u."firstName", + u."lastName", + s."formSubmissionStatusCode" as "status", + s."formSubmissionAssignedToFullName" as "assignee", + s."formSubmissionAssignedToEmail" as "assigneeEmail" + from + submissions_vw s + inner join form_submission fs on + s."submissionId" = fs.id + left outer join form_submission_user fsu on + s."submissionId" = fsu."formSubmissionId" + and fsu.permission = 'submission_create' + left outer join "user" u on + fsu."userId" = u.id + order by + s."createdAt", + s."formName", + s.version`)); +}; + +exports.down = function(knex) { + return Promise.resolve() + .then(() => knex.schema.dropViewIfExists('user_form_access_vw')) + .then(() => knex.schema.raw(`create or replace + view user_form_access_vw as + select + r."userId", + u."keycloakId", + u.username, + u."fullName", + u."firstName", + u."lastName", + u.email, + r."formId", + f.name as "formName", + f.labels, + f."identityProviders", + f.idps, + f.active, + f."formVersionId", + f.version, + r.roles, + p.permissions, + f.published, + f."versionUpdatedAt", + f.description as "formDescription" + from + "user" u + join user_form_roles_vw r on + u.id = r."userId" + join user_form_permissions_vw p on + r."userId" = p."userId" + and r."formId" = p."formId" + join form_vw f on + f.id = p."formId" + order by + lower(u."lastName"::text), + lower(u."firstName"::text), + lower(f.name::text)`)) + + .then(() => knex.schema.dropViewIfExists('public_form_access_vw')) + .then(() => knex.schema.raw(`create view public_form_access_vw as + select null as "userId", null as "keycloakId", 'public' as username, 'public' as "fullName", null as "firstName", null as "lastName", null as email, f.id as "formId", f.name as "formName", f.labels, f."identityProviders", f.idps, f.active, f."formVersionId", f.version, '{}'::varchar[] as roles, '{submission_create,form_read}'::varchar[] as permissions + from form_vw f + where 'public' = ANY(f."idps") + order by lower(f.name::text)`)) + + .then(() => knex.schema.dropViewIfExists('submissions_data_vw')) + .then(() => knex.schema.raw(`create or replace view submissions_data_vw as + select + s."confirmationId", + s."formName", + s.version, + s."createdAt", + case + when u.id is null then 'public'::varchar(255) + else u."fullName" + end as "fullName", + case + when u.id is null then 'public'::varchar(255) + else u.username + end as "username", + u.email, + fs.submission -> 'data' as "submission", + s.deleted, + s.draft, + s."submissionId", + s."formId", + s."formVersionId", + u.id as "userId", + u."keycloakId", + u."firstName", + u."lastName", + s."formSubmissionStatusCode" as "status", + s."formSubmissionAssignedToFullName" as "assignee", + s."formSubmissionAssignedToEmail" as "assigneeEmail" + from + submissions_vw s + inner join form_submission fs on + s."submissionId" = fs.id + left outer join form_submission_user fsu on + s."submissionId" = fsu."formSubmissionId" + and fsu.permission = 'submission_create' + left outer join "user" u on + fsu."userId" = u.id + order by + s."createdAt", + s."formName", + s.version`)); +}; diff --git a/frontend/app/src/db/migrations/20230110063945_027-form_components_proactive_help.js b/frontend/app/src/db/migrations/20230110063945_027-form_components_proactive_help.js new file mode 100644 index 0000000..8be2822 --- /dev/null +++ b/frontend/app/src/db/migrations/20230110063945_027-form_components_proactive_help.js @@ -0,0 +1,23 @@ +const stamps = require('../stamps'); + +exports.up = function (knex) { + return Promise.resolve().then(() => + knex.schema.createTable('form_components_proactive_help', (table) => { + table.uuid('id').primary(); + table.string('componentName').notNullable(); + table.string('externalLink'); + table.binary('image'); + table.string('imageType'); + table.string('componentImageName'); + table.string('groupName').notNullable(); + table.text('description'); + table.boolean('isLinkEnabled').defaultTo(false); + table.boolean('publishStatus').defaultTo(false); + stamps(knex, table); + }) + ); +}; + +exports.down = function (knex) { + return Promise.resolve().then(() => knex.schema.dropTableIfExists('form_components_proactive_help')); +}; diff --git a/frontend/app/src/db/migrations/20230110063945_028-alter-form-table-to-add-reminder-schedule-copy-col.js b/frontend/app/src/db/migrations/20230110063945_028-alter-form-table-to-add-reminder-schedule-copy-col.js new file mode 100644 index 0000000..ef5117c --- /dev/null +++ b/frontend/app/src/db/migrations/20230110063945_028-alter-form-table-to-add-reminder-schedule-copy-col.js @@ -0,0 +1,19 @@ +exports.up = function (knex) { + return Promise.resolve().then(() => + knex.schema.alterTable('form', (table) => { + table.jsonb('schedule').comment('Form level Schedule settings.'); + table.boolean('reminder_enabled').comment('Form level reminder settings.'); + table.boolean('enableCopyExistingSubmission').notNullable().defaultTo(false).comment('Form level feature settings.'); + }) + ); +}; + +exports.down = function (knex) { + return Promise.resolve().then(() => + knex.schema.alterTable('form', (table) => { + table.dropColumn('schedule'); + table.dropColumn('reminder_enabled'); + table.dropColumn('enableCopyExistingSubmission'); + }) + ); +}; diff --git a/frontend/app/src/db/migrations/20230412141347_029-form-settings-uploadfile.js b/frontend/app/src/db/migrations/20230412141347_029-form-settings-uploadfile.js new file mode 100644 index 0000000..ccdbcd6 --- /dev/null +++ b/frontend/app/src/db/migrations/20230412141347_029-form-settings-uploadfile.js @@ -0,0 +1,15 @@ +exports.up = function (knex) { + return Promise.resolve().then(() => + knex.schema.alterTable('form', (table) => { + table.boolean('allowSubmitterToUploadFile').notNullable().defaultTo(false).comment('This parameter allow submitter to load data from json file'); + }) + ); +}; + +exports.down = function (knex) { + return Promise.resolve().then(() => + knex.schema.alterTable('form', (table) => { + table.dropColumn('allowSubmitterToUploadFile'); + }) + ); +}; diff --git a/frontend/app/src/db/migrations/20230412181347_030-form-settings-uploadfile-form-view.js b/frontend/app/src/db/migrations/20230412181347_030-form-settings-uploadfile-form-view.js new file mode 100644 index 0000000..499f220 --- /dev/null +++ b/frontend/app/src/db/migrations/20230412181347_030-form-settings-uploadfile-form-view.js @@ -0,0 +1,56 @@ +exports.up = function (knex) { + return Promise.resolve().then(() => + knex.schema.raw(`create or replace view form_vw as + SELECT DISTINCT ON (lower(f.name::text), fv.version, f.id) f.id, + f.name, + f.active, + f.description, + f.labels, + f."createdAt", + f."createdBy", + f."updatedAt", + f."updatedBy", + fv.id AS "formVersionId", + fv.version, + case when count(fip.code) = 0 then '{}'::varchar[] else array_agg(distinct(fip.code)) end AS "identityProviders", + case when count(ip.idp) = 0 then '{}'::varchar[] else array_agg(distinct(ip.idp)) end AS idps, + fv.published, + fv."updatedAt" as "versionUpdatedAt", + f."allowSubmitterToUploadFile" AS "allowSubmitterToUploadFile" + FROM form f + LEFT JOIN LATERAL (select v.* from form_version v where v."formId" = f.id order by case when v.published then 1 else 0 end desc, v.version desc limit 1) fv ON true + LEFT OUTER JOIN form_identity_provider fip ON f.id = fip."formId" + LEFT OUTER JOIN identity_provider ip ON fip.code::text = ip.code::text + GROUP BY f.id, f.name, f.active, f.description, f.labels, f."createdAt", f."createdBy", f."updatedAt", + f."updatedBy", fv.id, fv.version, fv.published, fv."updatedAt" + ORDER BY lower(f.name::text), fv.version DESC, f.id`) + ); +}; + +exports.down = function (knex) { + return Promise.resolve().then(() => + knex.schema.raw(`create or replace view form_vw as + SELECT DISTINCT ON (lower(f.name::text), fv.version, f.id) f.id, + f.name, + f.active, + f.description, + f.labels, + f."createdAt", + f."createdBy", + f."updatedAt", + f."updatedBy", + fv.id AS "formVersionId", + fv.version, + case when count(fip.code) = 0 then '{}'::varchar[] else array_agg(distinct(fip.code)) end AS "identityProviders", + case when count(ip.idp) = 0 then '{}'::varchar[] else array_agg(distinct(ip.idp)) end AS idps, + fv.published, + fv."updatedAt" as "versionUpdatedAt" + FROM form f + LEFT JOIN LATERAL (select v.* from form_version v where v."formId" = f.id order by case when v.published then 1 else 0 end desc, v.version desc limit 1) fv ON true + LEFT OUTER JOIN form_identity_provider fip ON f.id = fip."formId" + LEFT OUTER JOIN identity_provider ip ON fip.code::text = ip.code::text + GROUP BY f.id, f.name, f.active, f.description, f.labels, f."createdAt", f."createdBy", f."updatedAt", + f."updatedBy", fv.id, fv.version, fv.published, fv."updatedAt" + ORDER BY lower(f.name::text), fv.version DESC, f.id`) + ); +}; diff --git a/frontend/app/src/db/migrations/20230517012741_alter-user-form-access-view.js b/frontend/app/src/db/migrations/20230517012741_alter-user-form-access-view.js new file mode 100644 index 0000000..7b6b005 --- /dev/null +++ b/frontend/app/src/db/migrations/20230517012741_alter-user-form-access-view.js @@ -0,0 +1,67 @@ +exports.up = function (knex) { + return Promise.resolve() + .then(() => knex.schema.dropViewIfExists('user_form_access_vw')) + .then(() => + knex.schema.raw(`CREATE OR REPLACE VIEW public.user_form_access_vw + AS SELECT r."userId", + u."idpUserId", + u.username, + u."fullName", + u."firstName", + u."lastName", + u.email, + r."formId", + f.name AS "formName", + f.labels, + u."idpCode" AS "user_idpCode", + f."identityProviders", + f."identityProviders" AS "form_login_required", + f.idps, + f.active, + f."formVersionId", + f.version, + r.roles, + p.permissions, + f.published, + f."versionUpdatedAt", + f.description AS "formDescription" + FROM "user" u + JOIN user_form_roles_vw r ON u.id = r."userId" + JOIN user_form_permissions_vw p ON r."userId" = p."userId" AND r."formId" = p."formId" + JOIN form_vw f ON f.id = p."formId" + ORDER BY (lower(u."lastName"::text)), (lower(u."firstName"::text)), (lower(f.name::text))`) + ); +}; + +exports.down = function (knex) { + return Promise.resolve() + .then(() => knex.schema.dropViewIfExists('user_form_access_vw')) + .then(() => + knex.schema.raw(`CREATE OR REPLACE VIEW public.user_form_access_vw + AS SELECT r."userId", + u."idpUserId", + u.username, + u."fullName", + u."firstName", + u."lastName", + u.email, + r."formId", + f.name AS "formName", + f.labels, + f."identityProviders", + f.idps, + f.active, + f."formVersionId", + f.version, + r.roles, + p.permissions, + f.published, + f."versionUpdatedAt", + f.description AS "formDescription" + FROM "user" u + JOIN user_form_roles_vw r ON u.id = r."userId" + JOIN user_form_permissions_vw p ON r."userId" = p."userId" AND r."formId" = p."formId" + JOIN form_vw f ON f.id = p."formId" + ORDER BY (lower(u."lastName"::text)), (lower(u."firstName"::text)), (lower(f.name::text))`) + ); +}; diff --git a/frontend/app/src/db/migrations/20230517012755_32-add-update-col-alter-submissions-vw.js b/frontend/app/src/db/migrations/20230517012755_32-add-update-col-alter-submissions-vw.js new file mode 100644 index 0000000..92fd539 --- /dev/null +++ b/frontend/app/src/db/migrations/20230517012755_32-add-update-col-alter-submissions-vw.js @@ -0,0 +1,92 @@ +exports.up = function(knex) { + return Promise.resolve() + .then(() => knex.schema.dropViewIfExists('submissions_data_vw')) + .then(() => knex.schema.raw(`create or replace view submissions_data_vw as + select + s."confirmationId", + s."formName", + s.version, + s."createdAt", + case + when u.id is null then 'public'::varchar(255) + else u."fullName" + end as "fullName", + case + when u.id is null then 'public'::varchar(255) + else u.username + end as "username", + u.email, + fs.submission -> 'data' as "submission", + fs."updatedAt", + s.deleted, + s.draft, + s."submissionId", + s."formId", + s."formVersionId", + u.id as "userId", + u."idpUserId", + u."firstName", + u."lastName", + s."formSubmissionStatusCode" as "status", + s."formSubmissionAssignedToFullName" as "assignee", + s."formSubmissionAssignedToEmail" as "assigneeEmail" + from + submissions_vw s + inner join form_submission fs on + s."submissionId" = fs.id + left outer join form_submission_user fsu on + s."submissionId" = fsu."formSubmissionId" + and fsu.permission = 'submission_create' + left outer join "user" u on + fsu."userId" = u.id + order by + s."createdAt", + s."formName", + s.version`)); +}; + +exports.down = function(knex) { + return Promise.resolve() + .then(() => knex.schema.dropViewIfExists('submissions_data_vw')) + .then(() => knex.schema.raw(`create or replace view submissions_data_vw as + select + s."confirmationId", + s."formName", + s.version, + s."createdAt", + case + when u.id is null then 'public'::varchar(255) + else u."fullName" + end as "fullName", + case + when u.id is null then 'public'::varchar(255) + else u.username + end as "username", + u.email, + fs.submission -> 'data' as "submission", + s.deleted, + s.draft, + s."submissionId", + s."formId", + s."formVersionId", + u.id as "userId", + u."idpUserId", + u."firstName", + u."lastName", + s."formSubmissionStatusCode" as "status", + s."formSubmissionAssignedToFullName" as "assignee", + s."formSubmissionAssignedToEmail" as "assigneeEmail" + from + submissions_vw s + inner join form_submission fs on + s."submissionId" = fs.id + left outer join form_submission_user fsu on + s."submissionId" = fsu."formSubmissionId" + and fsu.permission = 'submission_create' + left outer join "user" u on + fsu."userId" = u.id + order by + s."createdAt", + s."formName", + s.version`)); +}; diff --git a/frontend/app/src/db/migrations/20230618063952_033-form-subscribe.js b/frontend/app/src/db/migrations/20230618063952_033-form-subscribe.js new file mode 100644 index 0000000..20ece5c --- /dev/null +++ b/frontend/app/src/db/migrations/20230618063952_033-form-subscribe.js @@ -0,0 +1,31 @@ +const stamps = require('../stamps'); + +exports.up = function (knex) { + return Promise.resolve() + .then(() => + knex.schema.createTable('form_subscription', (table) => { + table.uuid('id').primary(); + table.uuid('formId').references('id').inTable('form').notNullable().index(); + table.string('subscribeEvent'); + table.string('endpointUrl').notNullable(); + table.string('endpointToken').notNullable(); + table.string('key').notNullable(); + stamps(knex, table); + }) + ) + .then(() => + knex.schema.alterTable('form', (table) => { + table.jsonb('subscribe').comment('Form subscibe settings.'); + }) + ); +}; + +exports.down = function (knex) { + return Promise.resolve().then(() => + knex.schema + .alterTable('form', (table) => { + table.dropColumn('subscribe'); + }) + .then(() => knex.schema.dropTableIfExists('form_subscription')) + ); +}; diff --git a/frontend/app/src/db/migrations/20230705190020_change_file_storage_constrains.js b/frontend/app/src/db/migrations/20230705190020_change_file_storage_constrains.js new file mode 100644 index 0000000..0082b20 --- /dev/null +++ b/frontend/app/src/db/migrations/20230705190020_change_file_storage_constrains.js @@ -0,0 +1,19 @@ +exports.up = function (knex) { + return Promise.resolve() + .then(() => knex.schema.raw(`ALTER TABLE file_storage DROP CONSTRAINT file_storage_storage_check`)) + .then(() => + knex.schema.raw(`ALTER TABLE file_storage ADD CONSTRAINT + file_storage_storage_check CHECK + ((storage = ANY (ARRAY['uploads'::text, 'localStorage'::text, 'objectStorage'::text, 'exports'::text])))`) + ); +}; + +exports.down = function (knex) { + return Promise.resolve() + .then(() => knex.schema.raw(`ALTER TABLE file_storage DROP CONSTRAINT file_storage_storage_check`)) + .then(() => + knex.schema.raw(`ALTER TABLE file_storage ADD CONSTRAINT + file_storage_storage_check CHECK + ((storage = ANY (ARRAY['uploads'::text, 'localStorage'::text, 'objectStorage'::text, 'exports'::text])))`) + ); +}; diff --git a/frontend/app/src/db/migrations/20230818010845_add_modify_submissions_vw.js b/frontend/app/src/db/migrations/20230818010845_add_modify_submissions_vw.js new file mode 100644 index 0000000..5391eb9 --- /dev/null +++ b/frontend/app/src/db/migrations/20230818010845_add_modify_submissions_vw.js @@ -0,0 +1,156 @@ +// NOTE: before change submissions_vw view we need to delete submissions_data_vw since it's depended on submissions_vw +exports.up = function (knex) { + return Promise.resolve() + .then(() => knex.schema.dropViewIfExists('submissions_data_vw')) + .then(() => knex.schema.dropViewIfExists('submissions_vw')) + .then(() => + knex.schema.raw(`CREATE OR REPLACE VIEW submissions_vw AS + SELECT s.id AS "submissionId", + s."confirmationId", + s.draft, + s.deleted, + s."createdBy", + s."createdAt", + s."updatedAt", + s."updatedBy", + f.id AS "formId", + f.name AS "formName", + fv.id AS "formVersionId", + fv.version, + st.id AS "formSubmissionStatusId", + st.code AS "formSubmissionStatusCode", + st."createdBy" AS "formSubmissionStatusCreatedBy", + st."createdAt" AS "formSubmissionStatusCreatedAt", + u."fullName" AS "formSubmissionAssignedToFullName", + u.email AS "formSubmissionAssignedToEmail", + s.submission + FROM form_submission s + JOIN form_version fv ON s."formVersionId" = fv.id + JOIN form f ON fv."formId" = f.id + LEFT JOIN LATERAL ( SELECT form_submission_status.id, + form_submission_status.code, + form_submission_status."createdBy", + form_submission_status."createdAt", + form_submission_status."assignedToUserId" + FROM form_submission_status + WHERE form_submission_status."submissionId" = s.id + ORDER BY form_submission_status."createdAt" DESC + LIMIT 1) st ON true + LEFT JOIN "user" u ON st."assignedToUserId" = u.id + ORDER BY s."createdAt" DESC`) + ) + .then(() => + knex.schema.raw(`CREATE OR REPLACE VIEW public.submissions_data_vw + AS SELECT s."confirmationId", + s."formName", + s.version, + s."createdAt", + CASE + WHEN u.id IS NULL THEN 'public'::character varying(255) + ELSE u."fullName" + END AS "fullName", + CASE + WHEN u.id IS NULL THEN 'public'::character varying(255) + ELSE u.username + END AS username, + u.email, + fs.submission -> 'data'::text AS submission, + fs."updatedAt", + fs."updatedBy", + s.deleted, + s.draft, + s."submissionId", + s."formId", + s."formVersionId", + u.id AS "userId", + u."idpUserId", + u."firstName", + u."lastName", + s."formSubmissionStatusCode" AS status, + s."formSubmissionAssignedToFullName" AS assignee, + s."formSubmissionAssignedToEmail" AS "assigneeEmail" + FROM submissions_vw s + JOIN form_submission fs ON s."submissionId" = fs.id + LEFT JOIN form_submission_user fsu ON s."submissionId" = fsu."formSubmissionId" AND fsu.permission::text = 'submission_create'::text + LEFT JOIN "user" u ON fsu."userId" = u.id + ORDER BY s."createdAt", s."formName", s.version;`) + ); +}; + +exports.down = function (knex) { + return Promise.resolve() + .then(() => knex.schema.dropViewIfExists('submissions_data_vw')) + .then(() => knex.schema.dropViewIfExists('submissions_vw')) + .then(() => + knex.schema + .raw( + `CREATE OR REPLACE VIEW submissions_vw AS + SELECT s.id AS "submissionId", + s."confirmationId", + s.draft, + s.deleted, + s."createdBy", + s."createdAt", + f.id AS "formId", + f.name AS "formName", + fv.id AS "formVersionId", + fv.version, + st.id AS "formSubmissionStatusId", + st.code AS "formSubmissionStatusCode", + st."createdBy" AS "formSubmissionStatusCreatedBy", + st."createdAt" AS "formSubmissionStatusCreatedAt", + u."fullName" AS "formSubmissionAssignedToFullName", + u.email AS "formSubmissionAssignedToEmail", + s.submission + FROM form_submission s + JOIN form_version fv ON s."formVersionId" = fv.id + JOIN form f ON fv."formId" = f.id + LEFT JOIN LATERAL ( SELECT form_submission_status.id, + form_submission_status.code, + form_submission_status."createdBy", + form_submission_status."createdAt", + form_submission_status."assignedToUserId" + FROM form_submission_status + WHERE form_submission_status."submissionId" = s.id + ORDER BY form_submission_status."createdAt" DESC + LIMIT 1) st ON true + LEFT JOIN "user" u ON st."assignedToUserId" = u.id + ORDER BY s."createdAt" DESC` + ) + .then(() => + knex.schema.raw(`CREATE OR REPLACE VIEW public.submissions_data_vw + AS SELECT s."confirmationId", + s."formName", + s.version, + s."createdAt", + CASE + WHEN u.id IS NULL THEN 'public'::character varying(255) + ELSE u."fullName" + END AS "fullName", + CASE + WHEN u.id IS NULL THEN 'public'::character varying(255) + ELSE u.username + END AS username, + u.email, + fs.submission -> 'data'::text AS submission, + fs."updatedAt", + s.deleted, + s.draft, + s."submissionId", + s."formId", + s."formVersionId", + u.id AS "userId", + u."idpUserId", + u."firstName", + u."lastName", + s."formSubmissionStatusCode" AS status, + s."formSubmissionAssignedToFullName" AS assignee, + s."formSubmissionAssignedToEmail" AS "assigneeEmail" + FROM submissions_vw s + JOIN form_submission fs ON s."submissionId" = fs.id + LEFT JOIN form_submission_user fsu ON s."submissionId" = fsu."formSubmissionId" AND fsu.permission::text = 'submission_create'::text + LEFT JOIN "user" u ON fsu."userId" = u.id + ORDER BY s."createdAt", s."formName", s.version;`) + ) + ); +}; diff --git a/frontend/app/src/db/migrations/20230830164525_036-form-email-template.js b/frontend/app/src/db/migrations/20230830164525_036-form-email-template.js new file mode 100644 index 0000000..ad6d6cd --- /dev/null +++ b/frontend/app/src/db/migrations/20230830164525_036-form-email-template.js @@ -0,0 +1,92 @@ +const { v4: uuidv4 } = require('uuid'); + +const stamps = require('../stamps'); + +const { EmailTypes, Permissions, Roles } = require('../../forms/common/constants'); + +const CREATED_BY = 'migration-036'; + +/** + * @param { import("knex").Knex } knex + * @returns { Promise } + */ +exports.up = function (knex) { + return Promise.resolve().then(() => + knex.schema + .createTable('form_email_template', (table) => { + table.uuid('id').primary(); + table.uuid('formId').references('id').inTable('form').notNullable().index(); + table.enu('type', [EmailTypes.SUBMISSION_CONFIRMATION]).notNullable(); + table.unique(['formId', 'type']); + table.string('subject').notNullable(); + table.string('title').notNullable(); + table.string('body', 4096).notNullable(); + stamps(knex, table); + }) + + .then(() => { + const permission = { + createdBy: CREATED_BY, + code: Permissions.EMAIL_TEMPLATE_READ, + display: 'Email Template Read', + description: 'Can view the email templates for a form', + active: true, + }; + return knex('permission').insert(permission); + }) + .then(() => { + const permission = { + createdBy: CREATED_BY, + code: Permissions.EMAIL_TEMPLATE_UPDATE, + display: 'Email Template Update', + description: 'Can update the email templates for a form', + active: true, + }; + return knex('permission').insert(permission); + }) + + .then(() => { + const rolePermission = { + id: uuidv4(), + createdBy: CREATED_BY, + role: Roles.OWNER, + permission: Permissions.EMAIL_TEMPLATE_READ, + }; + return knex('role_permission').insert(rolePermission); + }) + .then(() => { + const rolePermission = { + id: uuidv4(), + createdBy: CREATED_BY, + role: Roles.OWNER, + permission: Permissions.EMAIL_TEMPLATE_UPDATE, + }; + return knex('role_permission').insert(rolePermission); + }) + ); +}; + +/** + * @param { import("knex").Knex } knex + * @returns { Promise } + */ +exports.down = function (knex) { + return Promise.resolve() + .then(() => + knex('role_permission') + .where({ + createdBy: CREATED_BY, + }) + .del() + ) + + .then(() => + knex('permission') + .where({ + createdBy: CREATED_BY, + }) + .del() + ) + + .then(() => knex.schema.dropTableIfExists('form_email_template')); +}; diff --git a/frontend/app/src/db/migrations/20231017192656_037-user-form-permissions.js b/frontend/app/src/db/migrations/20231017192656_037-user-form-permissions.js new file mode 100644 index 0000000..9d25619 --- /dev/null +++ b/frontend/app/src/db/migrations/20231017192656_037-user-form-permissions.js @@ -0,0 +1,176 @@ +// Having performance problems and these views seem to be a cause of it. +// 1. Remove the join of "role" in user_form_permissions_vw. +// 2. Remove the join of "role" in user_form_roles_vw. +// 3. Simplify the EXISTS SELECT in user_form_permissions_vw. +// 4. Simplify the EXISTS SELECT in user_form_roles_vw. +// 5. Remove the sorting in the user_form_access_vw. + +/** + * @param { import("knex").Knex } knex + * @returns { Promise } + */ +exports.up = function (knex) { + return Promise.resolve() + .then(() => knex.schema.dropViewIfExists('user_form_access_vw')) + .then(() => knex.schema.dropViewIfExists('user_form_permissions_vw')) + .then(() => knex.schema.dropViewIfExists('user_form_roles_vw')) + .then(() => + knex.schema.raw(`CREATE OR REPLACE VIEW public.user_form_roles_vw + AS SELECT fru."userId", + fru."formId", + array_agg(DISTINCT fru.role) AS roles + FROM form_role_user fru + GROUP BY fru."userId", fru."formId" + UNION + SELECT u2.id AS "userId", + f2.id AS "formId", + '{}'::character varying[] AS roles + FROM form_vw f2, + "user" u2 + WHERE NOT EXISTS ( + SELECT 1 FROM form_role_user fru2 + WHERE fru2."formId" = f2.id AND fru2."userId" = u2.id);`) + ) + .then(() => + knex.schema.raw(`CREATE OR REPLACE VIEW public.user_form_permissions_vw + AS SELECT fru."userId", + fru."formId", + array_agg(DISTINCT p.code) AS permissions + FROM form_role_user fru + JOIN role_permission rp ON fru.role::text = rp.role::text + JOIN permission p ON rp.permission::text = p.code::text + GROUP BY fru."userId", fru."formId" + UNION + SELECT u2.id AS "userId", + f2.id AS "formId", + '{submission_create,form_read}'::character varying[] AS permissions + FROM form_vw f2, + "user" u2 + WHERE NOT EXISTS ( + SELECT 1 FROM form_role_user fru2 + WHERE fru2."formId" = f2.id AND fru2."userId" = u2.id);`) + ) + .then(() => + knex.schema.raw(`CREATE OR REPLACE VIEW public.user_form_access_vw + AS SELECT r."userId", + u."idpUserId", + u.username, + u."fullName", + u."firstName", + u."lastName", + u.email, + r."formId", + f.name AS "formName", + f.labels, + u."idpCode" AS "user_idpCode", + f."identityProviders", + f."identityProviders" AS form_login_required, + f.idps, + f.active, + f."formVersionId", + f.version, + r.roles, + p.permissions, + f.published, + f."versionUpdatedAt", + f.description AS "formDescription" + FROM "user" u + JOIN user_form_roles_vw r ON u.id = r."userId" + JOIN user_form_permissions_vw p ON r."userId" = p."userId" AND r."formId" = p."formId" + JOIN form_vw f ON f.id = p."formId";`) + ); +}; + +/** + * @param { import("knex").Knex } knex + * @returns { Promise } + */ +exports.down = function (knex) { + return Promise.resolve() + .then(() => knex.schema.dropViewIfExists('user_form_access_vw')) + .then(() => knex.schema.dropViewIfExists('user_form_permissions_vw')) + .then(() => knex.schema.dropViewIfExists('user_form_roles_vw')) + .then(() => + knex.schema.raw(`CREATE OR REPLACE VIEW public.user_form_roles_vw + AS SELECT fru."userId", + fru."formId", + array_agg(DISTINCT r.code) AS roles + FROM form_role_user fru + JOIN role r ON fru.role::text = r.code::text + GROUP BY fru."userId", fru."formId" + UNION + SELECT u2.id AS "userId", + f2.id AS "formId", + '{}'::character varying[] AS roles + FROM form_vw f2, + "user" u2 + WHERE NOT (EXISTS ( SELECT fru2.id, + fru2.role, + fru2."formId", + fru2."userId", + fru2."createdBy", + fru2."createdAt", + fru2."updatedBy", + fru2."updatedAt" + FROM form_role_user fru2 + WHERE fru2."formId" = f2.id AND fru2."userId" = u2.id));`) + ) + .then(() => + knex.schema.raw(` + CREATE OR REPLACE VIEW public.user_form_permissions_vw + AS SELECT fru."userId", + fru."formId", + array_agg(DISTINCT p.code) AS permissions + FROM form_role_user fru + JOIN role r ON fru.role::text = r.code::text + JOIN role_permission rp ON r.code::text = rp.role::text + JOIN permission p ON rp.permission::text = p.code::text + GROUP BY fru."userId", fru."formId" + UNION + SELECT u2.id AS "userId", + f2.id AS "formId", + '{submission_create,form_read}'::character varying[] AS permissions + FROM form_vw f2, + "user" u2 + WHERE NOT (EXISTS ( SELECT fru2.id, + fru2.role, + fru2."formId", + fru2."userId", + fru2."createdBy", + fru2."createdAt", + fru2."updatedBy", + fru2."updatedAt" + FROM form_role_user fru2 + WHERE fru2."formId" = f2.id AND fru2."userId" = u2.id));`) + ) + .then(() => + knex.schema.raw(`CREATE OR REPLACE VIEW public.user_form_access_vw + AS SELECT r."userId", + u."idpUserId", + u.username, + u."fullName", + u."firstName", + u."lastName", + u.email, + r."formId", + f.name AS "formName", + f.labels, + u."idpCode" AS "user_idpCode", + f."identityProviders", + f."identityProviders" AS form_login_required, + f.idps, + f.active, + f."formVersionId", + f.version, + r.roles, + p.permissions, + f.published, + f."versionUpdatedAt", + f.description AS "formDescription" + FROM "user" u + JOIN user_form_roles_vw r ON u.id = r."userId" + JOIN user_form_permissions_vw p ON r."userId" = p."userId" AND r."formId" = p."formId" + JOIN form_vw f ON f.id = p."formId" + ORDER BY (lower(u."lastName"::text)), (lower(u."firstName"::text)), (lower(f.name::text));`) + ); +}; diff --git a/frontend/app/src/db/migrations/20231019153505_038-view-simplification.js b/frontend/app/src/db/migrations/20231019153505_038-view-simplification.js new file mode 100644 index 0000000..1e8d179 --- /dev/null +++ b/frontend/app/src/db/migrations/20231019153505_038-view-simplification.js @@ -0,0 +1,157 @@ +// Having performance problems and these views seem to be a cause of it. +// 1. Remove the sorting in the public_form_access_vw. +// 2. Remove the sorting in the form_vw. + +/** + * @param { import("knex").Knex } knex + * @returns { Promise } + */ +exports.up = function (knex) { + return Promise.resolve() + .then(() => + knex.schema.raw(`CREATE OR REPLACE VIEW public.public_form_access_vw + AS SELECT NULL::text AS "userId", + NULL::text AS "idpUserId", + 'public'::text AS username, + 'public'::text AS "fullName", + NULL::text AS "firstName", + NULL::text AS "lastName", + NULL::text AS email, + f.id AS "formId", + f.name AS "formName", + f.labels, + f."identityProviders", + f.idps, + f.active, + f."formVersionId", + f.version, + '{}'::character varying[] AS roles, + '{submission_create,form_read}'::character varying[] AS permissions + FROM form_vw f + WHERE 'public'::text = ANY (f.idps::text[])`) + ) + .then(() => + knex.schema.raw(`CREATE OR REPLACE VIEW public.form_vw + AS SELECT DISTINCT ON ((lower(f.name::text)), fv.version, f.id) f.id, + f.name, + f.active, + f.description, + f.labels, + f."createdAt", + f."createdBy", + f."updatedAt", + f."updatedBy", + fv.id AS "formVersionId", + fv.version, + CASE + WHEN count(fip.code) = 0 THEN '{}'::character varying[] + ELSE array_agg(DISTINCT fip.code) + END AS "identityProviders", + CASE + WHEN count(ip.idp) = 0 THEN '{}'::character varying[] + ELSE array_agg(DISTINCT ip.idp) + END AS idps, + fv.published, + fv."updatedAt" AS "versionUpdatedAt", + f."allowSubmitterToUploadFile" + FROM form f + LEFT JOIN LATERAL ( SELECT v.id, + v."formId", + v.version, + v.schema, + v."createdBy", + v."createdAt", + v."updatedBy", + v."updatedAt", + v.published + FROM form_version v + WHERE v."formId" = f.id + ORDER BY ( + CASE + WHEN v.published THEN 1 + ELSE 0 + END) DESC, v.version DESC + LIMIT 1) fv ON true + LEFT JOIN form_identity_provider fip ON f.id = fip."formId" + LEFT JOIN identity_provider ip ON fip.code::text = ip.code::text + GROUP BY f.id, f.name, f.active, f.description, f.labels, f."createdAt", f."createdBy", f."updatedAt", f."updatedBy", fv.id, fv.version, fv.published, fv."updatedAt"`) + ); +}; + +/** + * @param { import("knex").Knex } knex + * @returns { Promise } + */ +exports.down = function (knex) { + return Promise.resolve() + .then(() => + knex.schema.raw(`CREATE OR REPLACE VIEW public.form_vw + AS SELECT DISTINCT ON ((lower(f.name::text)), fv.version, f.id) f.id, + f.name, + f.active, + f.description, + f.labels, + f."createdAt", + f."createdBy", + f."updatedAt", + f."updatedBy", + fv.id AS "formVersionId", + fv.version, + CASE + WHEN count(fip.code) = 0 THEN '{}'::character varying[] + ELSE array_agg(DISTINCT fip.code) + END AS "identityProviders", + CASE + WHEN count(ip.idp) = 0 THEN '{}'::character varying[] + ELSE array_agg(DISTINCT ip.idp) + END AS idps, + fv.published, + fv."updatedAt" AS "versionUpdatedAt", + f."allowSubmitterToUploadFile" + FROM form f + LEFT JOIN LATERAL ( SELECT v.id, + v."formId", + v.version, + v.schema, + v."createdBy", + v."createdAt", + v."updatedBy", + v."updatedAt", + v.published + FROM form_version v + WHERE v."formId" = f.id + ORDER BY ( + CASE + WHEN v.published THEN 1 + ELSE 0 + END) DESC, v.version DESC + LIMIT 1) fv ON true + LEFT JOIN form_identity_provider fip ON f.id = fip."formId" + LEFT JOIN identity_provider ip ON fip.code::text = ip.code::text + GROUP BY f.id, f.name, f.active, f.description, f.labels, f."createdAt", f."createdBy", f."updatedAt", f."updatedBy", fv.id, fv.version, fv.published, fv."updatedAt" + ORDER BY (lower(f.name::text)), fv.version DESC, f.id;`) + ) + .then(() => + knex.schema.raw(`CREATE OR REPLACE VIEW public.public_form_access_vw + AS SELECT NULL::text AS "userId", + NULL::text AS "idpUserId", + 'public'::text AS username, + 'public'::text AS "fullName", + NULL::text AS "firstName", + NULL::text AS "lastName", + NULL::text AS email, + f.id AS "formId", + f.name AS "formName", + f.labels, + f."identityProviders", + f.idps, + f.active, + f."formVersionId", + f.version, + '{}'::character varying[] AS roles, + '{submission_create,form_read}'::character varying[] AS permissions + FROM form_vw f + WHERE 'public'::text = ANY (f.idps::text[]) + ORDER BY (lower(f.name::text));`) + ); +}; diff --git a/frontend/app/src/db/seeds/999-dev-seed-data.js b/frontend/app/src/db/seeds/999-dev-seed-data.js new file mode 100644 index 0000000..2afcc09 --- /dev/null +++ b/frontend/app/src/db/seeds/999-dev-seed-data.js @@ -0,0 +1,311 @@ +const { v4: uuidv4 } = require('uuid'); + +const CREATED_BY = '999-dev-seed-data'; + +const ID = { + users: [], + forms: [], + versions: [] +}; + +exports.seed = function (knex) { + return Promise.resolve() + .then(() => { + return knex('form_identity_provider').where('createdBy', CREATED_BY).del(); + }) + .then(() => { + return knex('form_role_user').where('createdBy', CREATED_BY).del(); + }) + .then(() => { + return knex('role_permission').where('createdBy', CREATED_BY).del(); + }) + .then(() => { + return knex('identity_provider').where('createdBy', CREATED_BY).del(); + }) + .then(()=> { + return knex('permission').where('createdBy', CREATED_BY).del(); + }) + .then(()=> { + return knex('role').where('createdBy', CREATED_BY).del(); + }) + .then(()=> { + return knex('user').where('createdBy', CREATED_BY).del(); + }) + .then(() => { + return knex('form_submission').where('createdBy', CREATED_BY).del(); + }) + .then(() => { + return knex('form_version').where('createdBy', CREATED_BY).del(); + }) + .then(() => { + return knex('form').where('createdBy', CREATED_BY).del(); + }) + .then(() => { + return knex('form_subscription').where('createdBy', CREATED_BY).del(); + }) + .then(() => { + const items = [ + { + id: uuidv4(), + createdBy: CREATED_BY, + keycloakId: 'f417c2b6-2cdb-4141-b024-64abc6fa2bf2', + username: 'chefsadmin', + email: 'chefsadmin@chefsadmin.com', + firstName: 'Chef', + lastName: 'Admin', + fullName: 'Chef Admin' + }, + { + id: uuidv4(), + createdBy: CREATED_BY, + keycloakId: '126362bf-e08a-42d4-a4de-57219ee7e177', + username: 'chefsuser1', + email: 'chefsuser1@chefsuser1.com', + firstName: 'One', + lastName: 'Chefsuser', + fullName: 'One Chefsuser' + }, + { + id: uuidv4(), + createdBy: CREATED_BY, + keycloakId: '00337a98-8afd-4434-aef6-b99112a05c35', + username: 'chefsuser2', + email: 'chefsuser2@chefsuser2.com', + firstName: 'Two', + lastName: 'Chefsuser', + fullName: 'Two Chefsuser' + } + ]; + return knex('user').insert(items).returning('id'); + }) + .then(ids => { + ID.users = ids; + }) + .then(() => { + const items = [ + { + id: uuidv4(), + createdBy: CREATED_BY, + name: '1 Normal Form', + description: 'This is a First Normal Form', + active: true, + labels: ['form', 'first', 'normal'] + }, + { + id: uuidv4(), + createdBy: CREATED_BY, + name: '2 Normal Form', + description: 'This is a Second Normal Form', + active: true, + labels: ['form', 'second', 'normal'] + }, + { + id: uuidv4(), + createdBy: CREATED_BY, + name: '3 Normal Form', + description: 'This is a Third Normal Form', + active: true, + labels: ['form', 'third', 'normal'] + }, + { + id: uuidv4(), + createdBy: CREATED_BY, + name: '4 Normal Form', + description: 'This is a Fourth Normal Form', + active: true, + labels: ['form', 'forth', 'normal'] + }, + { + id: uuidv4(), + createdBy: CREATED_BY, + name: '5 Normal Form', + description: 'This is a Fifth Normal Form', + active: true, + labels: ['form', 'fifth', 'normal'] + }, + { + id: uuidv4(), + createdBy: CREATED_BY, + name: 'Sample Feedback', + description: 'Sample feedback form', + active: true, + labels: ['form', 'sample', 'feedback'] + } + ]; + return knex('form').insert(items).returning('id'); + }) + .then(ids => { + ID.forms = ids; + }) + .then(() => { + const items = [ + { + id: uuidv4(), + createdBy: CREATED_BY, + formId: ID.forms[0].id, + code: 'idir' + }, + { + id: uuidv4(), + createdBy: CREATED_BY, + formId: ID.forms[1].id, + code: 'idir' + }, + { + id: uuidv4(), + createdBy: CREATED_BY, + formId: ID.forms[2].id, + code: 'idir' + }, + { + id: uuidv4(), + createdBy: CREATED_BY, + formId: ID.forms[3].id, + code: 'public' + }, + { + id: uuidv4(), + createdBy: CREATED_BY, + formId: ID.forms[4].id, + code: 'public' + }, + { + id: uuidv4(), + createdBy: CREATED_BY, + formId: ID.forms[5].id, + code: 'idir' + } + ]; + return knex('form_identity_provider').insert(items).returning('id'); + }) + .then(() => { + const items = ID.forms.map(f => { + return { + id: uuidv4(), + createdBy: CREATED_BY, + formId: f.id, + version: 1, + schema: { + components: [{fieldA: {label: 'A', type: 'String'}}, {fieldB: {label: 'B', type: 'Number'}}] + } + }; + }); + // set the last form to have a renderable schema + // eslint-disable-next-line + items[5].schema = {"id": "ek87fkl", "key": "checkbox", "data": {"email": "", "submit": false, "checkbox": false, "hostedFormApi": false, "feedbackOnFormIoTool": "", "embeddingTheFormIntoACustomApp": false}, "name": "", "tags": [], "type": "checkbox", "input": true, "label": "Checkbox", "logic": [], "value": "", "access": [{"type": "create_own", "roles": []}, {"type": "create_all", "roles": []}, {"type": "read_own", "roles": []}, {"type": "read_all", "roles": []}, {"type": "update_own", "roles": []}, {"type": "update_all", "roles": []}, {"type": "delete_own", "roles": []}, {"type": "delete_all", "roles": []}, {"type": "team_read", "roles": []}, {"type": "team_write", "roles": []}, {"type": "team_admin", "roles": []}], "hidden": false, "prefix": "", "suffix": "", "unique": false, "widget": null, "dbIndex": false, "isValid": true, "overlay": {"top": "", "left": "", "page": "", "style": "", "width": "", "height": ""}, "tooltip": "", "disabled": false, "metadata": {}, "multiple": false, "redrawOn": "", "settings": {}, "shortcut": "", "tabindex": "", "validate": {"json": "", "custom": "", "unique": false, "multiple": false, "required": false, "customMessage": "", "customPrivate": false, "strictDateValidation": false}, "autofocus": false, "encrypted": false, "hideLabel": false, "inputType": "checkbox", "modalEdit": false, "protected": false, "refreshOn": "", "tableView": false, "attributes": {}, "components": [{"id": "e66zt5b", "key": "feedbackOnFormIoTool", "mask": false, "rows": 3, "type": "textarea", "input": true, "label": "Feedback on stand-alone forms in the FORM.IO tool:", "editor": "", "hidden": false, "prefix": "", "suffix": "", "unique": false, "widget": {"type": "input"}, "dbIndex": false, "overlay": {"top": "", "left": "", "style": "", "width": "", "height": ""}, "tooltip": "", "wysiwyg": false, "disabled": false, "multiple": false, "redrawOn": "", "tabindex": "", "validate": {"custom": "", "unique": false, "pattern": "", "maxWords": "", "minWords": "", "multiple": false, "required": false, "maxLength": "", "minLength": "", "customPrivate": false, "strictDateValidation": false}, "autofocus": false, "encrypted": false, "fixedSize": true, "hideLabel": false, "inputMask": "", "inputType": "text", "modalEdit": false, "protected": false, "refreshOn": "", "tableView": true, "attributes": {}, "autoExpand": false, "errorLabel": "", "persistent": true, "properties": {}, "spellcheck": true, "validateOn": "change", "clearOnHide": true, "conditional": {"eq": "", "show": null, "when": null}, "customClass": "", "description": "", "inputFormat": "html", "placeholder": "", "defaultValue": null, "labelPosition": "top", "showCharCount": false, "showWordCount": false, "calculateValue": "", "calculateServer": false, "allowMultipleMasks": false, "customDefaultValue": "", "allowCalculateOverride": false}, {"id": "ee4xww", "key": "panel", "tree": false, "type": "panel", "input": false, "label": "Panel", "theme": "default", "title": "What would you use it for?", "hidden": false, "prefix": "", "suffix": "", "unique": false, "widget": null, "dbIndex": false, "overlay": {"top": "", "left": "", "style": "", "width": "", "height": ""}, "tooltip": "", "disabled": false, "multiple": false, "redrawOn": "", "tabindex": "", "validate": {"custom": "", "unique": false, "multiple": false, "required": false, "customPrivate": false, "strictDateValidation": false}, "autofocus": false, "encrypted": false, "hideLabel": false, "modalEdit": false, "protected": false, "refreshOn": "", "tableView": false, "attributes": {}, "breadcrumb": "default", "components": [{"id": "e09gy4e", "key": "embeddingTheFormIntoACustomApp", "name": "", "type": "checkbox", "input": true, "label": "Embedding the form into a custom app", "value": "", "hidden": false, "prefix": "", "suffix": "", "unique": false, "widget": null, "dbIndex": false, "overlay": {"top": "", "left": "", "style": "", "width": "", "height": ""}, "tooltip": "", "disabled": false, "multiple": false, "redrawOn": "", "tabindex": "", "validate": {"custom": "", "unique": false, "multiple": false, "required": false, "customPrivate": false, "strictDateValidation": false}, "autofocus": false, "encrypted": false, "hideLabel": false, "inputType": "checkbox", "modalEdit": false, "protected": false, "refreshOn": "", "tableView": false, "attributes": {}, "errorLabel": "", "persistent": true, "properties": {}, "validateOn": "change", "clearOnHide": true, "conditional": {"eq": "", "show": null, "when": null}, "customClass": "", "description": "", "placeholder": "", "defaultValue": false, "dataGridLabel": true, "labelPosition": "right", "showCharCount": false, "showWordCount": false, "calculateValue": "", "calculateServer": false, "allowMultipleMasks": false, "customDefaultValue": "", "allowCalculateOverride": false}, {"id": "eq69pum", "key": "hostedFormApi", "name": "", "type": "checkbox", "input": true, "label": "Hosting an API of the form for others to hit with their apps", "value": "", "hidden": false, "prefix": "", "suffix": "", "unique": false, "widget": null, "dbIndex": false, "overlay": {"top": "", "left": "", "style": "", "width": "", "height": ""}, "tooltip": "", "disabled": false, "multiple": false, "redrawOn": "", "tabindex": "", "validate": {"custom": "", "unique": false, "multiple": false, "required": false, "customPrivate": false, "strictDateValidation": false}, "autofocus": false, "encrypted": false, "hideLabel": false, "inputType": "checkbox", "modalEdit": false, "protected": false, "refreshOn": "", "tableView": false, "attributes": {}, "errorLabel": "", "persistent": true, "properties": {}, "validateOn": "change", "clearOnHide": true, "conditional": {"eq": "", "show": null, "when": null}, "customClass": "", "description": "", "placeholder": "", "defaultValue": false, "dataGridLabel": true, "labelPosition": "right", "showCharCount": false, "showWordCount": false, "calculateValue": "", "calculateServer": false, "allowMultipleMasks": false, "customDefaultValue": "", "allowCalculateOverride": false}], "errorLabel": "", "persistent": false, "properties": {}, "validateOn": "change", "clearOnHide": false, "collapsible": false, "conditional": {"eq": "", "show": null, "when": null}, "customClass": "", "description": "", "placeholder": "", "defaultValue": null, "labelPosition": "top", "showCharCount": false, "showWordCount": false, "calculateValue": "", "calculateServer": false, "allowMultipleMasks": false, "customDefaultValue": "", "allowCalculateOverride": false}, {"id": "ekofnl", "key": "email", "mask": false, "type": "email", "input": true, "label": "Email", "hidden": false, "prefix": "", "suffix": "", "unique": false, "widget": {"type": "input"}, "dbIndex": false, "kickbox": {"enabled": false}, "overlay": {"top": "", "left": "", "style": "", "width": "", "height": ""}, "tooltip": "", "disabled": false, "multiple": false, "redrawOn": "", "tabindex": "", "validate": {"custom": "", "unique": false, "pattern": "", "multiple": false, "required": false, "maxLength": "", "minLength": "", "customPrivate": false, "strictDateValidation": false}, "autofocus": false, "encrypted": false, "hideLabel": false, "inputMask": "", "inputType": "email", "modalEdit": false, "protected": false, "refreshOn": "", "tableView": true, "attributes": {}, "errorLabel": "", "persistent": true, "properties": {}, "spellcheck": true, "validateOn": "change", "clearOnHide": true, "conditional": {"eq": "", "show": null, "when": null}, "customClass": "", "description": "", "inputFormat": "plain", "placeholder": "", "defaultValue": null, "labelPosition": "top", "showCharCount": false, "showWordCount": false, "calculateValue": "", "calculateServer": false, "allowMultipleMasks": false, "customDefaultValue": "", "allowCalculateOverride": false}, {"id": "emwz28", "key": "submit", "size": "md", "type": "button", "block": false, "input": true, "label": "Submit", "theme": "primary", "action": "submit", "hidden": false, "prefix": "", "suffix": "", "unique": false, "widget": {"type": "input"}, "dbIndex": false, "overlay": {"top": "", "left": "", "style": "", "width": "", "height": ""}, "tooltip": "", "disabled": false, "leftIcon": "", "multiple": false, "redrawOn": "", "tabindex": "", "validate": {"custom": "", "unique": false, "multiple": false, "required": false, "customPrivate": false, "strictDateValidation": false}, "autofocus": false, "encrypted": false, "hideLabel": false, "modalEdit": false, "protected": false, "refreshOn": "", "rightIcon": "", "tableView": false, "attributes": {}, "errorLabel": "", "persistent": false, "properties": {}, "validateOn": "change", "clearOnHide": true, "conditional": {"eq": "", "show": null, "when": null}, "customClass": "", "description": "", "placeholder": "", "defaultValue": null, "dataGridLabel": true, "labelPosition": "top", "showCharCount": false, "showWordCount": false, "calculateValue": "", "calculateServer": false, "disableOnInvalid": true, "allowMultipleMasks": false, "customDefaultValue": "", "allowCalculateOverride": false}], "controller": "", "errorLabel": "", "persistent": true, "properties": {}, "validateOn": "change", "clearOnHide": true, "conditional": {"eq": "", "json": "", "show": null, "when": null}, "customClass": "", "description": "", "placeholder": "", "defaultValue": null, "dataGridLabel": true, "labelPosition": "right", "showCharCount": false, "showWordCount": false, "calculateValue": "", "calculateServer": false, "submissionAccess": [{"type": "create_own", "roles": []}, {"type": "create_all", "roles": []}, {"type": "read_own", "roles": []}, {"type": "read_all", "roles": []}, {"type": "update_own", "roles": []}, {"type": "update_all", "roles": []}, {"type": "delete_own", "roles": []}, {"type": "delete_all", "roles": []}, {"type": "team_read", "roles": []}, {"type": "team_write", "roles": []}, {"type": "team_admin", "roles": []}], "customConditional": "", "allowMultipleMasks": false, "customDefaultValue": "", "allowCalculateOverride": false}; + return knex('form_version').insert(items).returning('id'); + }) + .then(ids => { + ID.versions = ids; + // set some version 2 records + const items = ID.forms.map(f => { + return { + id: uuidv4(), + createdBy: CREATED_BY, + formId: f.id, + version: 2, + schema: { + components: [{fieldA: {label: 'A', type: 'String'}}, {fieldB: {label: 'B', type: 'Number'}}, {fieldC: {label: 'C', type: 'Email'}}] + } + }; + }); + // remove a couple of items, don't want all with 2 versions. + items.pop(); + items.pop(); + return knex('form_version').insert(items); + }) + .then(() => { + const items = []; + // forms 0 - 5, set the owners + [ID.users[0], ID.users[1], ID.users[2], ID.users[0], ID.users[0], ID.users[0]].forEach((u,i) => { + const item = { + id: uuidv4(), + createdBy: CREATED_BY, + formId: ID.forms[i].id, + role: 'owner', + userId: u.id + }; + items.push(item); + }); + // forms 0 - 5, set the team_manager + [ID.users[0], ID.users[0], ID.users[0], ID.users[0], ID.users[0], ID.users[0]].forEach((u,i) => { + const item = { + id: uuidv4(), + createdBy: CREATED_BY, + formId: ID.forms[i].id, + role: 'team_manager', + userId: u.id + }; + items.push(item); + }); + + // forms 0 - 5, set the form_designer + [ID.users[1], ID.users[2], ID.users[1], ID.users[0], ID.users[0], ID.users[0]].forEach((u,i) => { + const item = { + id: uuidv4(), + createdBy: CREATED_BY, + formId: ID.forms[i].id, + role: 'form_designer', + userId: u.id + }; + items.push(item); + }); + + // forms 0 - 5, set the submission_reviewer + [ID.users[0], ID.users[2], ID.users[1], ID.users[0], ID.users[0], ID.users[0]].forEach((u,i) => { + const item = { + id: uuidv4(), + createdBy: CREATED_BY, + formId: ID.forms[i].id, + role: 'submission_reviewer', + userId: u.id + }; + items.push(item); + }); + + // forms 0,1,2, set the form_submitter + [ID.users[0], ID.users[1], ID.users[2]].forEach((u) => { + [ID.forms[0], ID.forms[1], ID.forms[2]].forEach(f => { + const item = { + id: uuidv4(), + createdBy: CREATED_BY, + formId: f.id, + role: 'form_submitter', + userId: u.id + }; + items.push(item); + }); + }); + return knex('form_role_user').insert(items).returning('id'); + }) + .then(() => { + const items = ['abc@def.com','123@456.com','qwerty@asdfg.com'].map(item => { + const sid = uuidv4(); + return { + id: sid, + createdBy: CREATED_BY, + formVersionId: ID.versions[5].id, + confirmationId: sid.substring(0, 8).toUpperCase(), + draft: false, + deleted: false, + // eslint-disable-next-line + submission: {"data": {"email": `${item}`, "submit": true, "hostedFormApi": false, "feedbackOnFormIoTool": `My (${item}) feedback was entered here`, "embeddingTheFormIntoACustomApp": true}} + }; + }); + return knex('form_submission').insert(items); + }) + .then(() => { + const items = [ + { + id: uuidv4(), + createdBy: CREATED_BY, + subscribeEvent: 'client_form_submit_event', + endpointUrl: 'http://test.com', + endpointToken: 'AbCdEf123456', + formId: ID.forms[0].id, + key: 'Authorization' + }, + ]; + return knex('form_subscription').insert(items); + }); +}; diff --git a/frontend/app/src/db/stamps.js b/frontend/app/src/db/stamps.js new file mode 100644 index 0000000..3ccf939 --- /dev/null +++ b/frontend/app/src/db/stamps.js @@ -0,0 +1,6 @@ +module.exports = (knex, table) => { + table.string('createdBy').defaultTo('public'); + table.timestamp('createdAt', {useTz: true}).defaultTo(knex.fn.now()); + table.string('updatedBy'); + table.timestamp('updatedAt', {useTz: true}).defaultTo(knex.fn.now()); +}; diff --git a/frontend/app/src/docs/.editorconfig b/frontend/app/src/docs/.editorconfig new file mode 100644 index 0000000..9066007 --- /dev/null +++ b/frontend/app/src/docs/.editorconfig @@ -0,0 +1,3 @@ +[*postman_collection.json] +indent_style = unset +indent_size = unset diff --git a/frontend/app/src/docs/CHEFS_API_Documentation.postman_collection.json b/frontend/app/src/docs/CHEFS_API_Documentation.postman_collection.json new file mode 100644 index 0000000..a47fbfb --- /dev/null +++ b/frontend/app/src/docs/CHEFS_API_Documentation.postman_collection.json @@ -0,0 +1,3232 @@ +{ + "info": { + "_postman_id": "01f708f4-96c3-4a8f-a0d9-e47f9e2eef9b", + "name": "CHEFS API Documentation", + "description": "A minimally viable API\n\nContact Support:\n Name: Forminators\n Email: submit.digital@gov.bc.ca", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "forms", + "item": [ + { + "name": "{form Id}", + "item": [ + { + "name": "versions", + "item": [ + { + "name": "{form Version Id}", + "item": [ + { + "name": "submissions", + "item": [ + { + "name": "{form Submission Id}", + "item": [ + { + "name": "Get a form submission", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/forms/:formId/versions/:formVersionId/submissions/:formSubmissionId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms", + ":formId", + "versions", + ":formVersionId", + "submissions", + ":formSubmissionId" + ], + "variable": [ + { + "id": "3cb5756a-53f9-4390-a7b6-a10b20805a69", + "key": "formId", + "value": "", + "type": "string", + "description": "(Required) id of the form that version belongs to" + }, + { + "id": "fc58312c-44c2-4a76-826d-f4d4101dd012", + "key": "formVersionId", + "value": "", + "type": "string", + "description": "(Required) id of the form version submission belongs to" + }, + { + "id": "28b4158f-d2d4-429c-aaa5-df3f17a815da", + "key": "formSubmissionId", + "value": "", + "type": "string", + "description": "(Required) id of the form submission to fetch" + } + ] + } + }, + "response": [ + { + "name": "Success", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/forms/:formId/versions/:formVersionId/submissions/:formSubmissionId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms", + ":formId", + "versions", + ":formVersionId", + "submissions", + ":formSubmissionId" + ], + "variable": [ + { + "key": "formId" + }, + { + "key": "formVersionId" + }, + { + "key": "formSubmissionId" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formVersionId\": \"bea3b705-1de5-4f4e-a4e6-0716b7674132\",\n \"confirmationId\": \"AEB3B705\",\n \"draft\": false,\n \"deleted\": false,\n \"submission\": \"\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"consectetur do adipisicing nulla occaecat\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"mollit cupidatat reprehenderit\"\n}" + }, + { + "name": "Unexpected error", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/forms/:formId/versions/:formVersionId/submissions/:formSubmissionId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms", + ":formId", + "versions", + ":formVersionId", + "submissions", + ":formSubmissionId" + ], + "variable": [ + { + "key": "formId" + }, + { + "key": "formVersionId" + }, + { + "key": "formSubmissionId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"type\": \"voluptate eu\",\n \"title\": \"enim Ut ea\",\n \"status\": \"ex cillu\",\n \"detail\": \"quis id sunt irure\"\n}" + } + ] + }, + { + "name": "Update a form submission", + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"id\": \"\",\n \"formVersionId\": \"\",\n \"confirmationId\": \"\",\n \"draft\": \"\",\n \"deleted\": \"\",\n \"submission\": \"\",\n \"createdBy\": \"dolor nisi co\",\n \"createdAt\": \"in\",\n \"updatedBy\": \"dolore eiusmod\",\n \"updatedAt\": \"dolor consectetur\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{baseUrl}}/forms/:formId/versions/:formVersionId/submissions/:formSubmissionId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms", + ":formId", + "versions", + ":formVersionId", + "submissions", + ":formSubmissionId" + ], + "variable": [ + { + "id": "09b81257-135d-48cf-b467-faf0e37cacca", + "key": "formId", + "value": "", + "type": "string", + "description": "(Required) id of the form the version belongs to" + }, + { + "id": "6b3a1d3b-f14f-4a85-9234-caaa2b3c5223", + "key": "formVersionId", + "value": "", + "type": "string", + "description": "(Required) id of the form version" + }, + { + "id": "b601ffed-4197-4509-b3ce-29735fac03ba", + "key": "formSubmissionId", + "value": "", + "type": "string", + "description": "(Required) id of the form submission to update" + } + ] + } + }, + "response": [ + { + "name": "Success", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formVersionId\": \"bea3b705-1de5-4f4e-a4e6-0716b7674132\",\n \"confirmationId\": \"AEB3B705\",\n \"draft\": false,\n \"deleted\": false,\n \"submission\": \"\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"consectetur do adipisicing nulla occaecat\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"mollit cupidatat reprehenderit\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/forms/:formId/versions/:formVersionId/submissions/:formSubmissionId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms", + ":formId", + "versions", + ":formVersionId", + "submissions", + ":formSubmissionId" + ], + "variable": [ + { + "key": "formId" + }, + { + "key": "formVersionId" + }, + { + "key": "formSubmissionId" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formVersionId\": \"bea3b705-1de5-4f4e-a4e6-0716b7674132\",\n \"confirmationId\": \"AEB3B705\",\n \"draft\": false,\n \"deleted\": false,\n \"submission\": \"\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"consectetur do adipisicing nulla occaecat\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"mollit cupidatat reprehenderit\"\n}" + }, + { + "name": "Unexpected error", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formVersionId\": \"bea3b705-1de5-4f4e-a4e6-0716b7674132\",\n \"confirmationId\": \"AEB3B705\",\n \"draft\": false,\n \"deleted\": false,\n \"submission\": \"\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"consectetur do adipisicing nulla occaecat\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"mollit cupidatat reprehenderit\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/forms/:formId/versions/:formVersionId/submissions/:formSubmissionId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms", + ":formId", + "versions", + ":formVersionId", + "submissions", + ":formSubmissionId" + ], + "variable": [ + { + "key": "formId" + }, + { + "key": "formVersionId" + }, + { + "key": "formSubmissionId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"type\": \"voluptate eu\",\n \"title\": \"enim Ut ea\",\n \"status\": \"ex cillu\",\n \"detail\": \"quis id sunt irure\"\n}" + } + ] + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + }, + { + "name": "List submissions for form version", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/forms/:formId/versions/:formVersionId/submissions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms", + ":formId", + "versions", + ":formVersionId", + "submissions" + ], + "variable": [ + { + "id": "8ff9c1b5-b726-46eb-a015-20af66c6ed3f", + "key": "formId", + "value": "", + "type": "string", + "description": "(Required) id of the form" + }, + { + "id": "52bc6334-5884-414e-ae76-94952fcc627e", + "key": "formVersionId", + "value": "", + "type": "string", + "description": "(Required) id of the form version the submissions belong to" + } + ] + } + }, + "response": [ + { + "name": "Success", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/forms/:formId/versions/:formVersionId/submissions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms", + ":formId", + "versions", + ":formVersionId", + "submissions" + ], + "variable": [ + { + "key": "formId" + }, + { + "key": "formVersionId" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formVersionId\": \"bea3b705-1de5-4f4e-a4e6-0716b7674132\",\n \"confirmationId\": \"AEB3B705\",\n \"draft\": false,\n \"deleted\": false,\n \"submission\": \"\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"pariatur labore\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"sunt proident dolore\"\n },\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formVersionId\": \"bea3b705-1de5-4f4e-a4e6-0716b7674132\",\n \"confirmationId\": \"AEB3B705\",\n \"draft\": false,\n \"deleted\": false,\n \"submission\": \"\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"incididunt in consectetur\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"id sed dolor dolor\"\n }\n]" + }, + { + "name": "Unexpected error", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/forms/:formId/versions/:formVersionId/submissions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms", + ":formId", + "versions", + ":formVersionId", + "submissions" + ], + "variable": [ + { + "key": "formId" + }, + { + "key": "formVersionId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"type\": \"voluptate eu\",\n \"title\": \"enim Ut ea\",\n \"status\": \"ex cillu\",\n \"detail\": \"quis id sunt irure\"\n}" + } + ] + }, + { + "name": "Create a new form submission", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"id\": \"\",\n \"formVersionId\": \"\",\n \"confirmationId\": \"\",\n \"draft\": \"\",\n \"deleted\": \"\",\n \"submission\": \"\",\n \"createdBy\": \"dolor nisi co\",\n \"createdAt\": \"in\",\n \"updatedBy\": \"dolore eiusmod\",\n \"updatedAt\": \"dolor consectetur\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{baseUrl}}/forms/:formId/versions/:formVersionId/submissions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms", + ":formId", + "versions", + ":formVersionId", + "submissions" + ], + "variable": [ + { + "id": "51e38e68-2d84-46c0-aca6-959552b46e27", + "key": "formId", + "value": "", + "type": "string", + "description": "(Required) id of the form" + }, + { + "id": "881f2b79-5211-405e-a938-8f72da5ee757", + "key": "formVersionId", + "value": "", + "type": "string", + "description": "(Required) id of the form version to submit to" + } + ] + } + }, + "response": [ + { + "name": "Success", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formVersionId\": \"bea3b705-1de5-4f4e-a4e6-0716b7674132\",\n \"confirmationId\": \"AEB3B705\",\n \"draft\": false,\n \"deleted\": false,\n \"submission\": \"\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"consectetur do adipisicing nulla occaecat\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"mollit cupidatat reprehenderit\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/forms/:formId/versions/:formVersionId/submissions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms", + ":formId", + "versions", + ":formVersionId", + "submissions" + ], + "variable": [ + { + "key": "formId" + }, + { + "key": "formVersionId" + } + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formVersionId\": \"bea3b705-1de5-4f4e-a4e6-0716b7674132\",\n \"confirmationId\": \"AEB3B705\",\n \"draft\": false,\n \"deleted\": false,\n \"submission\": \"\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"consectetur do adipisicing nulla occaecat\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"mollit cupidatat reprehenderit\"\n}" + }, + { + "name": "Unexpected error", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formVersionId\": \"bea3b705-1de5-4f4e-a4e6-0716b7674132\",\n \"confirmationId\": \"AEB3B705\",\n \"draft\": false,\n \"deleted\": false,\n \"submission\": \"\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"consectetur do adipisicing nulla occaecat\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"mollit cupidatat reprehenderit\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/forms/:formId/versions/:formVersionId/submissions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms", + ":formId", + "versions", + ":formVersionId", + "submissions" + ], + "variable": [ + { + "key": "formId" + }, + { + "key": "formVersionId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"type\": \"voluptate eu\",\n \"title\": \"enim Ut ea\",\n \"status\": \"ex cillu\",\n \"detail\": \"quis id sunt irure\"\n}" + } + ] + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + }, + { + "name": "Get a form", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/forms/:formId/versions/:formVersionId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms", + ":formId", + "versions", + ":formVersionId" + ], + "variable": [ + { + "id": "2436370e-ae32-43aa-9a0b-b0bba7679702", + "key": "formId", + "value": "", + "type": "string", + "description": "(Required) id of the form that version belongs to" + }, + { + "id": "7f46da9e-b58a-44b1-a0cd-0c57cebc3ea3", + "key": "formVersionId", + "value": "", + "type": "string", + "description": "(Required) id of the form version to fetch" + } + ] + } + }, + "response": [ + { + "name": "Success", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/forms/:formId/versions/:formVersionId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms", + ":formId", + "versions", + ":formVersionId" + ], + "variable": [ + { + "key": "formId" + }, + { + "key": "formVersionId" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"version\": 1,\n \"schema\": \"\",\n \"submissions\": [\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formVersionId\": \"bea3b705-1de5-4f4e-a4e6-0716b7674132\",\n \"confirmationId\": \"AEB3B705\",\n \"draft\": false,\n \"deleted\": false,\n \"submission\": \"\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"consectetur adipisicing sunt\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"labore incididunt\"\n },\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formVersionId\": \"bea3b705-1de5-4f4e-a4e6-0716b7674132\",\n \"confirmationId\": \"AEB3B705\",\n \"draft\": false,\n \"deleted\": false,\n \"submission\": \"\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"dolore\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"proident nisi quis occaecat\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"incididunt pariatur tempor\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"sit irure id\"\n}" + }, + { + "name": "Unexpected error", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/forms/:formId/versions/:formVersionId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms", + ":formId", + "versions", + ":formVersionId" + ], + "variable": [ + { + "key": "formId" + }, + { + "key": "formVersionId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"type\": \"voluptate eu\",\n \"title\": \"enim Ut ea\",\n \"status\": \"ex cillu\",\n \"detail\": \"quis id sunt irure\"\n}" + } + ] + }, + { + "name": "Update a form version", + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"id\": \"\",\n \"formId\": \"\",\n \"version\": \"\",\n \"schema\": \"\",\n \"submissions\": [\n {\n \"id\": \"\",\n \"formVersionId\": \"\",\n \"confirmationId\": \"\",\n \"draft\": \"\",\n \"deleted\": \"\",\n \"submission\": \"\",\n \"createdBy\": \"consequat in id mollit\",\n \"createdAt\": \"mollit ea aute aliqua\",\n \"updatedBy\": \"incididunt sit in Duis\",\n \"updatedAt\": \"Lorem\"\n },\n {\n \"id\": \"\",\n \"formVersionId\": \"\",\n \"confirmationId\": \"\",\n \"draft\": \"\",\n \"deleted\": \"\",\n \"submission\": \"\",\n \"createdBy\": \"officia pariatur Duis\",\n \"createdAt\": \"magna ea do\",\n \"updatedBy\": \"in Lorem quis incididunt\",\n \"updatedAt\": \"laboris pariatur\"\n }\n ],\n \"createdBy\": \"cupidatat elit Duis occaecat mollit\",\n \"createdAt\": \"sit Excepteur\",\n \"updatedBy\": \"dolor consectetur\",\n \"updatedAt\": \"Ut m\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{baseUrl}}/forms/:formId/versions/:formVersionId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms", + ":formId", + "versions", + ":formVersionId" + ], + "variable": [ + { + "id": "ec12d91d-3e06-4799-8be2-d6cbcd5f7c21", + "key": "formId", + "value": "", + "type": "string", + "description": "(Required) id of the form the version belongs to" + }, + { + "id": "e09ccb0f-217a-4ee3-9b8d-510b344d31c6", + "key": "formVersionId", + "value": "", + "type": "string", + "description": "(Required) id of the form version to update" + } + ] + } + }, + "response": [ + { + "name": "Success", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"version\": 1,\n \"schema\": \"\",\n \"submissions\": [\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formVersionId\": \"bea3b705-1de5-4f4e-a4e6-0716b7674132\",\n \"confirmationId\": \"AEB3B705\",\n \"draft\": false,\n \"deleted\": false,\n \"submission\": \"\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"consectetur adipisicing sunt\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"labore incididunt\"\n },\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formVersionId\": \"bea3b705-1de5-4f4e-a4e6-0716b7674132\",\n \"confirmationId\": \"AEB3B705\",\n \"draft\": false,\n \"deleted\": false,\n \"submission\": \"\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"dolore\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"proident nisi quis occaecat\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"incididunt pariatur tempor\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"sit irure id\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/forms/:formId/versions/:formVersionId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms", + ":formId", + "versions", + ":formVersionId" + ], + "variable": [ + { + "key": "formId" + }, + { + "key": "formVersionId" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"version\": 1,\n \"schema\": \"\",\n \"submissions\": [\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formVersionId\": \"bea3b705-1de5-4f4e-a4e6-0716b7674132\",\n \"confirmationId\": \"AEB3B705\",\n \"draft\": false,\n \"deleted\": false,\n \"submission\": \"\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"consectetur adipisicing sunt\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"labore incididunt\"\n },\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formVersionId\": \"bea3b705-1de5-4f4e-a4e6-0716b7674132\",\n \"confirmationId\": \"AEB3B705\",\n \"draft\": false,\n \"deleted\": false,\n \"submission\": \"\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"dolore\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"proident nisi quis occaecat\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"incididunt pariatur tempor\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"sit irure id\"\n}" + }, + { + "name": "Unexpected error", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"version\": 1,\n \"schema\": \"\",\n \"submissions\": [\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formVersionId\": \"bea3b705-1de5-4f4e-a4e6-0716b7674132\",\n \"confirmationId\": \"AEB3B705\",\n \"draft\": false,\n \"deleted\": false,\n \"submission\": \"\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"consectetur adipisicing sunt\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"labore incididunt\"\n },\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formVersionId\": \"bea3b705-1de5-4f4e-a4e6-0716b7674132\",\n \"confirmationId\": \"AEB3B705\",\n \"draft\": false,\n \"deleted\": false,\n \"submission\": \"\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"dolore\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"proident nisi quis occaecat\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"incididunt pariatur tempor\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"sit irure id\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/forms/:formId/versions/:formVersionId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms", + ":formId", + "versions", + ":formVersionId" + ], + "variable": [ + { + "key": "formId" + }, + { + "key": "formVersionId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"type\": \"voluptate eu\",\n \"title\": \"enim Ut ea\",\n \"status\": \"ex cillu\",\n \"detail\": \"quis id sunt irure\"\n}" + } + ] + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + }, + { + "name": "List versions for form", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/forms/:formId/versions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms", + ":formId", + "versions" + ], + "variable": [ + { + "id": "331c2e88-4dd2-43f5-8264-e83af9c15cf1", + "key": "formId", + "value": "", + "type": "string", + "description": "(Required) id of the form" + } + ] + } + }, + "response": [ + { + "name": "Success", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/forms/:formId/versions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms", + ":formId", + "versions" + ], + "variable": [ + { + "key": "formId" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"version\": 1,\n \"schema\": \"consectetur incididunt in ipsum est\",\n \"submissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"reprehenderit dolore\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"labore voluptate magna\"\n },\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"version\": 1,\n \"schema\": \"minim officia magna voluptate reprehenderit\",\n \"submissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"in reprehenderit exercitation Duis\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"laboris est \"\n }\n]" + }, + { + "name": "Unexpected error", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/forms/:formId/versions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms", + ":formId", + "versions" + ], + "variable": [ + { + "key": "formId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"type\": \"voluptate eu\",\n \"title\": \"enim Ut ea\",\n \"status\": \"ex cillu\",\n \"detail\": \"quis id sunt irure\"\n}" + } + ] + }, + { + "name": "Create a new form version", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"id\": \"\",\n \"formId\": \"\",\n \"version\": \"\",\n \"schema\": \"\",\n \"submissions\": [\n {\n \"id\": \"\",\n \"formVersionId\": \"\",\n \"confirmationId\": \"\",\n \"draft\": \"\",\n \"deleted\": \"\",\n \"submission\": \"\",\n \"createdBy\": \"consequat in id mollit\",\n \"createdAt\": \"mollit ea aute aliqua\",\n \"updatedBy\": \"incididunt sit in Duis\",\n \"updatedAt\": \"Lorem\"\n },\n {\n \"id\": \"\",\n \"formVersionId\": \"\",\n \"confirmationId\": \"\",\n \"draft\": \"\",\n \"deleted\": \"\",\n \"submission\": \"\",\n \"createdBy\": \"officia pariatur Duis\",\n \"createdAt\": \"magna ea do\",\n \"updatedBy\": \"in Lorem quis incididunt\",\n \"updatedAt\": \"laboris pariatur\"\n }\n ],\n \"createdBy\": \"cupidatat elit Duis occaecat mollit\",\n \"createdAt\": \"sit Excepteur\",\n \"updatedBy\": \"dolor consectetur\",\n \"updatedAt\": \"Ut m\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{baseUrl}}/forms/:formId/versions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms", + ":formId", + "versions" + ], + "variable": [ + { + "id": "39984a1b-bc7f-43f8-b341-170a32d9728f", + "key": "formId", + "value": "", + "type": "string", + "description": "(Required) id of the form" + } + ] + } + }, + "response": [ + { + "name": "Unexpected error", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"version\": 1,\n \"schema\": \"\",\n \"submissions\": [\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formVersionId\": \"bea3b705-1de5-4f4e-a4e6-0716b7674132\",\n \"confirmationId\": \"AEB3B705\",\n \"draft\": false,\n \"deleted\": false,\n \"submission\": \"\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"consectetur adipisicing sunt\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"labore incididunt\"\n },\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formVersionId\": \"bea3b705-1de5-4f4e-a4e6-0716b7674132\",\n \"confirmationId\": \"AEB3B705\",\n \"draft\": false,\n \"deleted\": false,\n \"submission\": \"\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"dolore\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"proident nisi quis occaecat\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"incididunt pariatur tempor\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"sit irure id\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/forms/:formId/versions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms", + ":formId", + "versions" + ], + "variable": [ + { + "key": "formId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"type\": \"voluptate eu\",\n \"title\": \"enim Ut ea\",\n \"status\": \"ex cillu\",\n \"detail\": \"quis id sunt irure\"\n}" + }, + { + "name": "Success", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"version\": 1,\n \"schema\": \"\",\n \"submissions\": [\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formVersionId\": \"bea3b705-1de5-4f4e-a4e6-0716b7674132\",\n \"confirmationId\": \"AEB3B705\",\n \"draft\": false,\n \"deleted\": false,\n \"submission\": \"\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"consectetur adipisicing sunt\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"labore incididunt\"\n },\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formVersionId\": \"bea3b705-1de5-4f4e-a4e6-0716b7674132\",\n \"confirmationId\": \"AEB3B705\",\n \"draft\": false,\n \"deleted\": false,\n \"submission\": \"\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"dolore\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"proident nisi quis occaecat\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"incididunt pariatur tempor\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"sit irure id\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/forms/:formId/versions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms", + ":formId", + "versions" + ], + "variable": [ + { + "key": "formId" + } + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"version\": 1,\n \"schema\": \"\",\n \"submissions\": [\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formVersionId\": \"bea3b705-1de5-4f4e-a4e6-0716b7674132\",\n \"confirmationId\": \"AEB3B705\",\n \"draft\": false,\n \"deleted\": false,\n \"submission\": \"\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"consectetur adipisicing sunt\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"labore incididunt\"\n },\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formVersionId\": \"bea3b705-1de5-4f4e-a4e6-0716b7674132\",\n \"confirmationId\": \"AEB3B705\",\n \"draft\": false,\n \"deleted\": false,\n \"submission\": \"\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"dolore\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"proident nisi quis occaecat\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"incididunt pariatur tempor\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"sit irure id\"\n}" + } + ] + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + }, + { + "name": "Get a form", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/forms/:formId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms", + ":formId" + ], + "variable": [ + { + "id": "635c512a-3b52-41ed-aaa2-fd13468e72f2", + "key": "formId", + "value": "", + "type": "string", + "description": "(Required) id of the form to fetch" + } + ] + } + }, + "response": [ + { + "name": "Unexpected error", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/forms/:formId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms", + ":formId" + ], + "variable": [ + { + "key": "formId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"type\": \"voluptate eu\",\n \"title\": \"enim Ut ea\",\n \"status\": \"ex cillu\",\n \"detail\": \"quis id sunt irure\"\n}" + }, + { + "name": "Success", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/forms/:formId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms", + ":formId" + ], + "variable": [ + { + "key": "formId" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"name\": \"Business Form One\",\n \"description\": \"This is Business Form One. It is amazing.\",\n \"active\": \"\",\n \"labels\": [\n \"\",\n \"\"\n ],\n \"identityProviders\": [\n {\n \"code\": \"idir\",\n \"display\": \"IDIR\",\n \"idp\": \"idir\",\n \"active\": true,\n \"deleted\": false,\n \"submission\": \"reprehenderit\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"anim ipsum enim in\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"sed ullamco voluptate\"\n },\n {\n \"code\": \"idir\",\n \"display\": \"IDIR\",\n \"idp\": \"idir\",\n \"active\": true,\n \"deleted\": false,\n \"submission\": \"et adipisicing\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"consequat elit cupidatat consectetur velit\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"enim in anim officia nisi\"\n }\n ],\n \"versions\": [\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"version\": 1,\n \"schema\": \"eiusmod velit\",\n \"submissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"occaecat\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"fugiat\"\n },\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"version\": 1,\n \"schema\": \"aute cillum exer\",\n \"submissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"et quis cillum id\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"non\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"officia veniam\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"est\"\n}" + } + ] + }, + { + "name": "Update a form", + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"id\": \"\",\n \"name\": \"\",\n \"description\": \"\",\n \"active\": \"\",\n \"labels\": [\n \"\",\n \"\"\n ],\n \"identityProviders\": [\n {\n \"code\": \"quis qui sed\",\n \"display\": \"enim ad labore Excepteur nisi\",\n \"idp\": \"et in\",\n \"active\": true,\n \"deleted\": true,\n \"submission\": \"et\",\n \"createdBy\": \"aute incididunt voluptate sit tempor\",\n \"createdAt\": \"elit eu do\",\n \"updatedBy\": \"elit enim voluptate et ut\",\n \"updatedAt\": \"Excepteur minim est dolore\"\n },\n {\n \"code\": \"sit esse ea\",\n \"display\": \"dolor ullamco ut\",\n \"idp\": \"in eiusmod tempor ut\",\n \"active\": false,\n \"deleted\": false,\n \"submission\": \"enim et tempor\",\n \"createdBy\": \"aute aliqua\",\n \"createdAt\": \"mollit nulla velit eu\",\n \"updatedBy\": \"consequat s\",\n \"updatedAt\": \"cupidatat nulla ex\"\n }\n ],\n \"versions\": [\n {\n \"id\": \"v\",\n \"formId\": \"dolor\",\n \"version\": 69113405,\n \"schema\": \"ut\",\n \"submissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"elit eu\",\n \"createdAt\": \"in eu\",\n \"updatedBy\": \"aute in\",\n \"updatedAt\": \"\"\n },\n {\n \"id\": \"esse venia\",\n \"formId\": \"ut in sed\",\n \"version\": 50694489,\n \"schema\": \"non sint\",\n \"submissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"elit Lorem sit adipisicing\",\n \"createdAt\": \"sunt fugiat veni\",\n \"updatedBy\": \"eiusmod cillum officia\",\n \"updatedAt\": \"dolor cupidatat\"\n }\n ],\n \"createdBy\": \"nisi aute minim\",\n \"createdAt\": \"ullamco sit\",\n \"updatedBy\": \"aliqua\",\n \"updatedAt\": \"Lorem culpa tempor\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{baseUrl}}/forms/:formId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms", + ":formId" + ], + "variable": [ + { + "id": "a8ac711a-7602-43fe-940b-a4f5874f8abf", + "key": "formId", + "value": "", + "type": "string", + "description": "(Required) id of the form to update" + } + ] + } + }, + "response": [ + { + "name": "Success", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"name\": \"Business Form One\",\n \"description\": \"This is Business Form One. It is amazing.\",\n \"active\": \"\",\n \"labels\": [\n \"\",\n \"\"\n ],\n \"identityProviders\": [\n {\n \"code\": \"idir\",\n \"display\": \"IDIR\",\n \"idp\": \"idir\",\n \"active\": true,\n \"deleted\": false,\n \"submission\": \"reprehenderit\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"anim ipsum enim in\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"sed ullamco voluptate\"\n },\n {\n \"code\": \"idir\",\n \"display\": \"IDIR\",\n \"idp\": \"idir\",\n \"active\": true,\n \"deleted\": false,\n \"submission\": \"et adipisicing\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"consequat elit cupidatat consectetur velit\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"enim in anim officia nisi\"\n }\n ],\n \"versions\": [\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"version\": 1,\n \"schema\": \"eiusmod velit\",\n \"submissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"occaecat\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"fugiat\"\n },\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"version\": 1,\n \"schema\": \"aute cillum exer\",\n \"submissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"et quis cillum id\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"non\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"officia veniam\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"est\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/forms/:formId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms", + ":formId" + ], + "variable": [ + { + "key": "formId" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"name\": \"Business Form One\",\n \"description\": \"This is Business Form One. It is amazing.\",\n \"active\": \"\",\n \"labels\": [\n \"\",\n \"\"\n ],\n \"identityProviders\": [\n {\n \"code\": \"idir\",\n \"display\": \"IDIR\",\n \"idp\": \"idir\",\n \"active\": true,\n \"deleted\": false,\n \"submission\": \"reprehenderit\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"anim ipsum enim in\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"sed ullamco voluptate\"\n },\n {\n \"code\": \"idir\",\n \"display\": \"IDIR\",\n \"idp\": \"idir\",\n \"active\": true,\n \"deleted\": false,\n \"submission\": \"et adipisicing\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"consequat elit cupidatat consectetur velit\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"enim in anim officia nisi\"\n }\n ],\n \"versions\": [\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"version\": 1,\n \"schema\": \"eiusmod velit\",\n \"submissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"occaecat\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"fugiat\"\n },\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"version\": 1,\n \"schema\": \"aute cillum exer\",\n \"submissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"et quis cillum id\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"non\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"officia veniam\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"est\"\n}" + }, + { + "name": "Unexpected error", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"name\": \"Business Form One\",\n \"description\": \"This is Business Form One. It is amazing.\",\n \"active\": \"\",\n \"labels\": [\n \"\",\n \"\"\n ],\n \"identityProviders\": [\n {\n \"code\": \"idir\",\n \"display\": \"IDIR\",\n \"idp\": \"idir\",\n \"active\": true,\n \"deleted\": false,\n \"submission\": \"reprehenderit\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"anim ipsum enim in\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"sed ullamco voluptate\"\n },\n {\n \"code\": \"idir\",\n \"display\": \"IDIR\",\n \"idp\": \"idir\",\n \"active\": true,\n \"deleted\": false,\n \"submission\": \"et adipisicing\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"consequat elit cupidatat consectetur velit\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"enim in anim officia nisi\"\n }\n ],\n \"versions\": [\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"version\": 1,\n \"schema\": \"eiusmod velit\",\n \"submissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"occaecat\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"fugiat\"\n },\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"version\": 1,\n \"schema\": \"aute cillum exer\",\n \"submissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"et quis cillum id\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"non\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"officia veniam\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"est\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/forms/:formId", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms", + ":formId" + ], + "variable": [ + { + "key": "formId" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"type\": \"voluptate eu\",\n \"title\": \"enim Ut ea\",\n \"status\": \"ex cillu\",\n \"detail\": \"quis id sunt irure\"\n}" + } + ] + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + }, + { + "name": "List forms in the system", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/forms", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms" + ] + } + }, + "response": [ + { + "name": "Unexpected error", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/forms", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms" + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"type\": \"voluptate eu\",\n \"title\": \"enim Ut ea\",\n \"status\": \"ex cillu\",\n \"detail\": \"quis id sunt irure\"\n}" + }, + { + "name": "Success", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/forms", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"name\": \"Business Form One\",\n \"description\": \"This is Business Form One. It is amazing.\",\n \"active\": true,\n \"labels\": [\n \"voluptate\",\n \"enim dolor nostrud est\"\n ],\n \"identityProviders\": [\n {\n \"code\": \"idir\",\n \"display\": \"IDIR\",\n \"idp\": \"idir\",\n \"active\": true,\n \"deleted\": false,\n \"submission\": \"adipisicing ad\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"cillum esse enim exercitation est\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"i\"\n },\n {\n \"code\": \"idir\",\n \"display\": \"IDIR\",\n \"idp\": \"idir\",\n \"active\": true,\n \"deleted\": false,\n \"submission\": \"ut irure\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"fugiat nostrud\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"labore aliquip\"\n }\n ],\n \"versions\": [\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"version\": 1,\n \"schema\": \"cillum sint amet\",\n \"submissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"laborum Ut ea\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"mollit in\"\n },\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"version\": 1,\n \"schema\": \"enim irure\",\n \"submissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"proident\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"veniam Duis\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"officia est eiusm\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"dolore in\"\n },\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"name\": \"Business Form One\",\n \"description\": \"This is Business Form One. It is amazing.\",\n \"active\": true,\n \"labels\": [\n \"amet eu velit veniam\",\n \"offi\"\n ],\n \"identityProviders\": [\n {\n \"code\": \"idir\",\n \"display\": \"IDIR\",\n \"idp\": \"idir\",\n \"active\": true,\n \"deleted\": false,\n \"submission\": \"do officia aliqua tempor\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"sunt dolore dolor\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"id dolor Ut sed nulla\"\n },\n {\n \"code\": \"idir\",\n \"display\": \"IDIR\",\n \"idp\": \"idir\",\n \"active\": true,\n \"deleted\": false,\n \"submission\": \"est nulla labore\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"ea in\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"sed fugiat labore\"\n }\n ],\n \"versions\": [\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"version\": 1,\n \"schema\": \"elit ipsum\",\n \"submissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"elit et Duis mollit\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"ut nulla velit fugiat\"\n },\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"version\": 1,\n \"schema\": \"laborum veniam labore\",\n \"submissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"occaecat proident aute nisi laboris\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"laborum ullamco in\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"ipsum ea\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"consectetur in ut consequat et\"\n }\n]" + } + ] + }, + { + "name": "Create a new form", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"id\": \"\",\n \"name\": \"\",\n \"description\": \"\",\n \"active\": \"\",\n \"labels\": [\n \"\",\n \"\"\n ],\n \"identityProviders\": [\n {\n \"code\": \"quis qui sed\",\n \"display\": \"enim ad labore Excepteur nisi\",\n \"idp\": \"et in\",\n \"active\": true,\n \"deleted\": true,\n \"submission\": \"et\",\n \"createdBy\": \"aute incididunt voluptate sit tempor\",\n \"createdAt\": \"elit eu do\",\n \"updatedBy\": \"elit enim voluptate et ut\",\n \"updatedAt\": \"Excepteur minim est dolore\"\n },\n {\n \"code\": \"sit esse ea\",\n \"display\": \"dolor ullamco ut\",\n \"idp\": \"in eiusmod tempor ut\",\n \"active\": false,\n \"deleted\": false,\n \"submission\": \"enim et tempor\",\n \"createdBy\": \"aute aliqua\",\n \"createdAt\": \"mollit nulla velit eu\",\n \"updatedBy\": \"consequat s\",\n \"updatedAt\": \"cupidatat nulla ex\"\n }\n ],\n \"versions\": [\n {\n \"id\": \"v\",\n \"formId\": \"dolor\",\n \"version\": 69113405,\n \"schema\": \"ut\",\n \"submissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"elit eu\",\n \"createdAt\": \"in eu\",\n \"updatedBy\": \"aute in\",\n \"updatedAt\": \"\"\n },\n {\n \"id\": \"esse venia\",\n \"formId\": \"ut in sed\",\n \"version\": 50694489,\n \"schema\": \"non sint\",\n \"submissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"elit Lorem sit adipisicing\",\n \"createdAt\": \"sunt fugiat veni\",\n \"updatedBy\": \"eiusmod cillum officia\",\n \"updatedAt\": \"dolor cupidatat\"\n }\n ],\n \"createdBy\": \"nisi aute minim\",\n \"createdAt\": \"ullamco sit\",\n \"updatedBy\": \"aliqua\",\n \"updatedAt\": \"Lorem culpa tempor\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{baseUrl}}/forms", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms" + ] + } + }, + "response": [ + { + "name": "Success", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"name\": \"Business Form One\",\n \"description\": \"This is Business Form One. It is amazing.\",\n \"active\": \"\",\n \"labels\": [\n \"\",\n \"\"\n ],\n \"identityProviders\": [\n {\n \"code\": \"idir\",\n \"display\": \"IDIR\",\n \"idp\": \"idir\",\n \"active\": true,\n \"deleted\": false,\n \"submission\": \"reprehenderit\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"anim ipsum enim in\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"sed ullamco voluptate\"\n },\n {\n \"code\": \"idir\",\n \"display\": \"IDIR\",\n \"idp\": \"idir\",\n \"active\": true,\n \"deleted\": false,\n \"submission\": \"et adipisicing\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"consequat elit cupidatat consectetur velit\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"enim in anim officia nisi\"\n }\n ],\n \"versions\": [\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"version\": 1,\n \"schema\": \"eiusmod velit\",\n \"submissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"occaecat\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"fugiat\"\n },\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"version\": 1,\n \"schema\": \"aute cillum exer\",\n \"submissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"et quis cillum id\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"non\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"officia veniam\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"est\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/forms", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms" + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"name\": \"Business Form One\",\n \"description\": \"This is Business Form One. It is amazing.\",\n \"active\": \"\",\n \"labels\": [\n \"\",\n \"\"\n ],\n \"identityProviders\": [\n {\n \"code\": \"idir\",\n \"display\": \"IDIR\",\n \"idp\": \"idir\",\n \"active\": true,\n \"deleted\": false,\n \"submission\": \"reprehenderit\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"anim ipsum enim in\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"sed ullamco voluptate\"\n },\n {\n \"code\": \"idir\",\n \"display\": \"IDIR\",\n \"idp\": \"idir\",\n \"active\": true,\n \"deleted\": false,\n \"submission\": \"et adipisicing\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"consequat elit cupidatat consectetur velit\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"enim in anim officia nisi\"\n }\n ],\n \"versions\": [\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"version\": 1,\n \"schema\": \"eiusmod velit\",\n \"submissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"occaecat\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"fugiat\"\n },\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"version\": 1,\n \"schema\": \"aute cillum exer\",\n \"submissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"et quis cillum id\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"non\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"officia veniam\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"est\"\n}" + }, + { + "name": "Unexpected error", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"name\": \"Business Form One\",\n \"description\": \"This is Business Form One. It is amazing.\",\n \"active\": \"\",\n \"labels\": [\n \"\",\n \"\"\n ],\n \"identityProviders\": [\n {\n \"code\": \"idir\",\n \"display\": \"IDIR\",\n \"idp\": \"idir\",\n \"active\": true,\n \"deleted\": false,\n \"submission\": \"reprehenderit\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"anim ipsum enim in\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"sed ullamco voluptate\"\n },\n {\n \"code\": \"idir\",\n \"display\": \"IDIR\",\n \"idp\": \"idir\",\n \"active\": true,\n \"deleted\": false,\n \"submission\": \"et adipisicing\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"consequat elit cupidatat consectetur velit\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"enim in anim officia nisi\"\n }\n ],\n \"versions\": [\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"version\": 1,\n \"schema\": \"eiusmod velit\",\n \"submissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"occaecat\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"fugiat\"\n },\n {\n \"id\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"version\": 1,\n \"schema\": \"aute cillum exer\",\n \"submissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"et quis cillum id\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"non\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"officia veniam\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"est\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/forms", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "forms" + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"type\": \"voluptate eu\",\n \"title\": \"enim Ut ea\",\n \"status\": \"ex cillu\",\n \"detail\": \"quis id sunt irure\"\n}" + } + ] + } + ], + "protocolProfileBehavior": {} + }, + { + "name": "permissions", + "item": [ + { + "name": "{code}", + "item": [ + { + "name": "Get a Permission", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/permissions/:code", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "permissions", + ":code" + ], + "variable": [ + { + "id": "4c51638d-eecf-48a4-a082-dcac65e8673f", + "key": "code", + "value": "", + "type": "string", + "description": "(Required) code of the permission to fetch" + } + ] + } + }, + "response": [ + { + "name": "Unexpected error", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/permissions/:code", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "permissions", + ":code" + ], + "variable": [ + { + "key": "code" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"type\": \"voluptate eu\",\n \"title\": \"enim Ut ea\",\n \"status\": \"ex cillu\",\n \"detail\": \"quis id sunt irure\"\n}" + }, + { + "name": "Success", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/permissions/:code", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "permissions", + ":code" + ], + "variable": [ + { + "key": "code" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"code\": \"design_update\",\n \"display\": \"Design Update\",\n \"description\": \"'Can edit/update the form design'\",\n \"active\": true,\n \"roles\": [\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"pariatur laboris mollit ipsum\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"cillum dolor\"\n },\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"cillum eiusmod\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"Duis ut\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"nisi sit aliqua adipisicing consectetur\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"d\"\n}" + } + ] + }, + { + "name": "Update a permission", + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"code\": \"\",\n \"display\": \"\",\n \"description\": \"\",\n \"active\": \"\",\n \"roles\": [\n {\n \"code\": \"est in consectetur aliquip\",\n \"display\": \"eu officia anim\",\n \"description\": \"in Lorem et\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"officia incididunt\",\n \"createdAt\": \"sed\",\n \"updatedBy\": \"sed\",\n \"updatedAt\": \"incididunt dolor Duis\"\n },\n {\n \"code\": \"occaecat\",\n \"display\": \"magna minim id dolore\",\n \"description\": \"voluptate labore velit\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"aute reprehenderit culpa\",\n \"createdAt\": \"pariatur in\",\n \"updatedBy\": \"sit deserunt\",\n \"updatedAt\": \"minim commodo ipsum eu\"\n }\n ],\n \"createdBy\": \"Duis ipsum dolore\",\n \"createdAt\": \"in anim \",\n \"updatedBy\": \"commodo c\",\n \"updatedAt\": \"qui\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{baseUrl}}/permissions/:code", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "permissions", + ":code" + ], + "variable": [ + { + "id": "9e912c43-8e42-483f-81b2-919351d4f949", + "key": "code", + "value": "", + "type": "string", + "description": "(Required) code of the permission to update" + } + ] + } + }, + "response": [ + { + "name": "Success", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"code\": \"design_update\",\n \"display\": \"Design Update\",\n \"description\": \"'Can edit/update the form design'\",\n \"active\": true,\n \"roles\": [\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"dolore reprehenderit consectetur veniam\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"et occaecat laborum eiusmod mollit\"\n },\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"labore voluptate\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"Ut Duis\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"eu anim\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"proident qui\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/permissions/:code", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "permissions", + ":code" + ], + "variable": [ + { + "key": "code" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"code\": \"design_update\",\n \"display\": \"Design Update\",\n \"description\": \"'Can edit/update the form design'\",\n \"active\": true,\n \"roles\": [\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"dolore reprehenderit consectetur veniam\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"et occaecat laborum eiusmod mollit\"\n },\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"labore voluptate\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"Ut Duis\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"eu anim\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"proident qui\"\n}" + }, + { + "name": "Unexpected error", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"code\": \"design_update\",\n \"display\": \"Design Update\",\n \"description\": \"'Can edit/update the form design'\",\n \"active\": true,\n \"roles\": [\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"dolore reprehenderit consectetur veniam\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"et occaecat laborum eiusmod mollit\"\n },\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"labore voluptate\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"Ut Duis\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"eu anim\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"proident qui\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/permissions/:code", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "permissions", + ":code" + ], + "variable": [ + { + "key": "code" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"type\": \"voluptate eu\",\n \"title\": \"enim Ut ea\",\n \"status\": \"ex cillu\",\n \"detail\": \"quis id sunt irure\"\n}" + } + ] + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + }, + { + "name": "List permissions in the system", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/permissions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "permissions" + ] + } + }, + "response": [ + { + "name": "Unexpected error", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/permissions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "permissions" + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"type\": \"voluptate eu\",\n \"title\": \"enim Ut ea\",\n \"status\": \"ex cillu\",\n \"detail\": \"quis id sunt irure\"\n}" + }, + { + "name": "Success", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/permissions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "permissions" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"code\": \"design_update\",\n \"display\": \"Design Update\",\n \"description\": \"'Can edit/update the form design'\",\n \"active\": true,\n \"roles\": [\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"Lorem ullamco\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"fugiat consectetur enim tempor\"\n },\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"in ea dolore fugiat\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"in Excepteur\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"ad do\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"Ut\"\n },\n {\n \"code\": \"design_update\",\n \"display\": \"Design Update\",\n \"description\": \"'Can edit/update the form design'\",\n \"active\": true,\n \"roles\": [\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"sint\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"dolore Excepteur\"\n },\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"ut id aliquip\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"velit\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"culpa aute ut\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"anim est i\"\n }\n]" + } + ] + }, + { + "name": "Create a new permission", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "[\n {\n \"code\": \"et laborum elit in\",\n \"display\": \"voluptate ad nostrud\",\n \"description\": \"ut\",\n \"active\": false,\n \"roles\": [\n {\n \"code\": \"anim eiusmod in est\",\n \"display\": \"exercitation amet commodo\",\n \"description\": \"laborum laboris esse eiusmod\",\n \"active\": false,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"ex enim\",\n \"createdAt\": \"elit in \",\n \"updatedBy\": \"fugiat\",\n \"updatedAt\": \"sunt ipsum elit\"\n },\n {\n \"code\": \"consequat Duis\",\n \"display\": \"elit et\",\n \"description\": \"culpa exercitation\",\n \"active\": false,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"nulla esse Excepteur veniam\",\n \"createdAt\": \"cupidatat non\",\n \"updatedBy\": \"amet incididunt\",\n \"updatedAt\": \"qui\"\n }\n ],\n \"createdBy\": \"nisi \",\n \"createdAt\": \"sunt officia\",\n \"updatedBy\": \"nulla sit\",\n \"updatedAt\": \"fugiat ex dolore officia sint\"\n },\n {\n \"code\": \"Ut c\",\n \"display\": \"Excepteur laborum aute\",\n \"description\": \"Duis est quis\",\n \"active\": false,\n \"roles\": [\n {\n \"code\": \"ad nisi pariatur est\",\n \"display\": \"dolor proident\",\n \"description\": \"veniam non reprehenderit sunt\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"dolor velit nulla cupidatat\",\n \"createdAt\": \"do dolore\",\n \"updatedBy\": \"Duis dolor elit in laborum\",\n \"updatedAt\": \"sint pariatur quis magna\"\n },\n {\n \"code\": \"voluptate Lorem sed pariatur enim\",\n \"display\": \"sunt enim eiusmod consectetur non\",\n \"description\": \"pariatur irure in dolore ea\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"Excepteur eiusmod adipisicing laborum pariatur\",\n \"createdAt\": \"amet est\",\n \"updatedBy\": \"labore laboris sit sint\",\n \"updatedAt\": \"enim velit dolor\"\n }\n ],\n \"createdBy\": \"non quis sint labore\",\n \"createdAt\": \"enim Ut\",\n \"updatedBy\": \"in qui\",\n \"updatedAt\": \"fugiat enim amet in\"\n }\n]", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{baseUrl}}/permissions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "permissions" + ] + } + }, + "response": [ + { + "name": "Success", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "[\n {\n \"code\": \"design_update\",\n \"display\": \"Design Update\",\n \"description\": \"'Can edit/update the form design'\",\n \"active\": true,\n \"roles\": [\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"cupidatat culpa\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"magna\"\n },\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"eiusmod\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"magna\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"labore incididunt sint\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"commodo fugiat\"\n },\n {\n \"code\": \"design_update\",\n \"display\": \"Design Update\",\n \"description\": \"'Can edit/update the form design'\",\n \"active\": true,\n \"roles\": [\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"sunt culpa ad\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"dolore est eu\"\n },\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"sed pariat\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"veniam dolor pariatur quis\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"cillum\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"L\"\n }\n]" + }, + "url": { + "raw": "{{baseUrl}}/permissions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "permissions" + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"code\": \"design_update\",\n \"display\": \"Design Update\",\n \"description\": \"'Can edit/update the form design'\",\n \"active\": true,\n \"roles\": [\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"pariatur laboris mollit ipsum\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"cillum dolor\"\n },\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"cillum eiusmod\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"Duis ut\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"nisi sit aliqua adipisicing consectetur\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"d\"\n}" + }, + { + "name": "Unexpected error", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "[\n {\n \"code\": \"design_update\",\n \"display\": \"Design Update\",\n \"description\": \"'Can edit/update the form design'\",\n \"active\": true,\n \"roles\": [\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"cupidatat culpa\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"magna\"\n },\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"eiusmod\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"magna\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"labore incididunt sint\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"commodo fugiat\"\n },\n {\n \"code\": \"design_update\",\n \"display\": \"Design Update\",\n \"description\": \"'Can edit/update the form design'\",\n \"active\": true,\n \"roles\": [\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"sunt culpa ad\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"dolore est eu\"\n },\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"sed pariat\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"veniam dolor pariatur quis\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"cillum\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"L\"\n }\n]" + }, + "url": { + "raw": "{{baseUrl}}/permissions", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "permissions" + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"type\": \"voluptate eu\",\n \"title\": \"enim Ut ea\",\n \"status\": \"ex cillu\",\n \"detail\": \"quis id sunt irure\"\n}" + } + ] + } + ], + "protocolProfileBehavior": {} + }, + { + "name": "roles", + "item": [ + { + "name": "{code}", + "item": [ + { + "name": "Get a Role", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/roles/:code", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "roles", + ":code" + ], + "variable": [ + { + "id": "894f29b6-33bc-47e3-aeb8-58ad8ff0223f", + "key": "code", + "value": "", + "type": "string", + "description": "(Required) code of the role to fetch" + } + ] + } + }, + "response": [ + { + "name": "Unexpected error", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/roles/:code", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "roles", + ":code" + ], + "variable": [ + { + "key": "code" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"type\": \"voluptate eu\",\n \"title\": \"enim Ut ea\",\n \"status\": \"ex cillu\",\n \"detail\": \"quis id sunt irure\"\n}" + }, + { + "name": "Success", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/roles/:code", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "roles", + ":code" + ], + "variable": [ + { + "key": "code" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"code\": \"design_update\",\n \"display\": \"Design Update\",\n \"description\": \"'Can edit/update the form design'\",\n \"active\": true,\n \"roles\": [\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"mollit\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"dolore\"\n },\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"eu\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"id commodo velit\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"exercitation\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"adipisic\"\n },\n {\n \"code\": \"design_update\",\n \"display\": \"Design Update\",\n \"description\": \"'Can edit/update the form design'\",\n \"active\": true,\n \"roles\": [\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"ea in ullamco\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"sint aute officia laboris\"\n },\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"ut esse adipisicing ea\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"enim consequat nulla magna\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"non tempor elit ipsum\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"quis est\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"anim laboris Lorem eu\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"enim velit\"\n}" + } + ] + }, + { + "name": "Update a role", + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"code\": \"\",\n \"display\": \"\",\n \"description\": \"\",\n \"active\": \"\",\n \"permissions\": [\n {\n \"code\": \"\",\n \"display\": \"\",\n \"description\": \"\",\n \"active\": \"\",\n \"roles\": [\n {\n \"code\": \"\",\n \"display\": \"\",\n \"description\": \"\",\n \"active\": \"\",\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"velit cillum sed proident\",\n \"createdAt\": \"officia aute\",\n \"updatedBy\": \"ullamco proident in id\",\n \"updatedAt\": \"tempor\"\n },\n {\n \"code\": \"\",\n \"display\": \"\",\n \"description\": \"\",\n \"active\": \"\",\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"fugiat\",\n \"createdAt\": \"magna non\",\n \"updatedBy\": \"Lorem dolore\",\n \"updatedAt\": \"eu sint\"\n }\n ],\n \"createdBy\": \"aliquip c\",\n \"createdAt\": \"ullamco\",\n \"updatedBy\": \"sint incididunt in nostrud\",\n \"updatedAt\": \"non exercitation c\"\n },\n {\n \"code\": \"\",\n \"display\": \"\",\n \"description\": \"\",\n \"active\": \"\",\n \"roles\": [\n {\n \"code\": \"\",\n \"display\": \"\",\n \"description\": \"\",\n \"active\": \"\",\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"velit culpa\",\n \"createdAt\": \"elit consectetur dolor\",\n \"updatedBy\": \"anim fugiat ut\",\n \"updatedAt\": \"dolo\"\n },\n {\n \"code\": \"\",\n \"display\": \"\",\n \"description\": \"\",\n \"active\": \"\",\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"proident eiusmod ea\",\n \"createdAt\": \"occaecat aute in nisi\",\n \"updatedBy\": \"sit cillum pariatur\",\n \"updatedAt\": \"non quis aliquip\"\n }\n ],\n \"createdBy\": \"nulla ut\",\n \"createdAt\": \"ad dolor irure pariatur\",\n \"updatedBy\": \"officia ex sunt nostrud\",\n \"updatedAt\": \"est reprehenderit\"\n }\n ],\n \"createdBy\": \"est Lor\",\n \"createdAt\": \"velit laboris minim\",\n \"updatedBy\": \"nulla culpa labore commodo in\",\n \"updatedAt\": \"veniam tempor ad\"\n}", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{baseUrl}}/roles/:code", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "roles", + ":code" + ], + "variable": [ + { + "id": "ee8fa772-ca88-4621-8e91-1e76e1a5dd8a", + "key": "code", + "value": "", + "type": "string", + "description": "(Required) code of the role to update" + } + ] + } + }, + "response": [ + { + "name": "Unexpected error", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"code\": \"design_update\",\n \"display\": \"Design Update\",\n \"description\": \"'Can edit/update the form design'\",\n \"active\": true,\n \"roles\": [\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"sint Lorem Duis eu\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"id Lorem ipsum magna\"\n },\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"irure\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"dolor sint con\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"proident aliquip ipsum\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"id occaec\"\n },\n {\n \"code\": \"design_update\",\n \"display\": \"Design Update\",\n \"description\": \"'Can edit/update the form design'\",\n \"active\": true,\n \"roles\": [\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"dolore\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"laborum cupidatat\"\n },\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"et fugiat\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"pariatur aute magna Excepteur\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"in elit fugiat Ut laborum\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"ei\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"irure commodo pariatur\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"Lorem qui elit\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/roles/:code", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "roles", + ":code" + ], + "variable": [ + { + "key": "code" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"type\": \"voluptate eu\",\n \"title\": \"enim Ut ea\",\n \"status\": \"ex cillu\",\n \"detail\": \"quis id sunt irure\"\n}" + }, + { + "name": "Success", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"code\": \"design_update\",\n \"display\": \"Design Update\",\n \"description\": \"'Can edit/update the form design'\",\n \"active\": true,\n \"roles\": [\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"sint Lorem Duis eu\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"id Lorem ipsum magna\"\n },\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"irure\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"dolor sint con\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"proident aliquip ipsum\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"id occaec\"\n },\n {\n \"code\": \"design_update\",\n \"display\": \"Design Update\",\n \"description\": \"'Can edit/update the form design'\",\n \"active\": true,\n \"roles\": [\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"dolore\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"laborum cupidatat\"\n },\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"et fugiat\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"pariatur aute magna Excepteur\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"in elit fugiat Ut laborum\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"ei\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"irure commodo pariatur\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"Lorem qui elit\"\n}" + }, + "url": { + "raw": "{{baseUrl}}/roles/:code", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "roles", + ":code" + ], + "variable": [ + { + "key": "code" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"code\": \"design_update\",\n \"display\": \"Design Update\",\n \"description\": \"'Can edit/update the form design'\",\n \"active\": true,\n \"roles\": [\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"sint Lorem Duis eu\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"id Lorem ipsum magna\"\n },\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"irure\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"dolor sint con\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"proident aliquip ipsum\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"id occaec\"\n },\n {\n \"code\": \"design_update\",\n \"display\": \"Design Update\",\n \"description\": \"'Can edit/update the form design'\",\n \"active\": true,\n \"roles\": [\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"dolore\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"laborum cupidatat\"\n },\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"et fugiat\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"pariatur aute magna Excepteur\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"in elit fugiat Ut laborum\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"ei\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"irure commodo pariatur\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"Lorem qui elit\"\n}" + } + ] + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + }, + { + "name": "List roles in the system", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/roles", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "roles" + ] + } + }, + "response": [ + { + "name": "Success", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/roles", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "roles" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"dolor fugiat\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"pariatur sint qui exercitation\"\n },\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"in nostrud qui sit\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"magna ipsum anim\"\n }\n]" + }, + { + "name": "Unexpected error", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/roles", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "roles" + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"type\": \"voluptate eu\",\n \"title\": \"enim Ut ea\",\n \"status\": \"ex cillu\",\n \"detail\": \"quis id sunt irure\"\n}" + } + ] + }, + { + "name": "Create a new role", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "[\n {\n \"code\": \"Lorem officia Ut minim\",\n \"display\": \"Ut sit\",\n \"description\": \"commodo tempor veniam id\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"velit incididunt culpa\",\n \"createdAt\": \"sunt\",\n \"updatedBy\": \"cupidatat proident\",\n \"updatedAt\": \"sed\"\n },\n {\n \"code\": \"incididunt aute voluptate\",\n \"display\": \"aute ea consequat nulla\",\n \"description\": \"fugiat ea sed laborum\",\n \"active\": false,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"officia tempor\",\n \"createdAt\": \"e\",\n \"updatedBy\": \"dolore anim nostrud\",\n \"updatedAt\": \"irure sint magna\"\n }\n]", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{baseUrl}}/roles", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "roles" + ] + } + }, + "response": [ + { + "name": "Success", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "[\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"ipsum mollit aute sit conse\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"ad sint aliquip laboris ei\"\n },\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"anim\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"eu\"\n }\n]" + }, + "url": { + "raw": "{{baseUrl}}/roles", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "roles" + ] + } + }, + "status": "Created", + "code": 201, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"code\": \"design_update\",\n \"display\": \"Design Update\",\n \"description\": \"'Can edit/update the form design'\",\n \"active\": true,\n \"roles\": [\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"mollit\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"dolore\"\n },\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"eu\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"id commodo velit\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"exercitation\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"adipisic\"\n },\n {\n \"code\": \"design_update\",\n \"display\": \"Design Update\",\n \"description\": \"'Can edit/update the form design'\",\n \"active\": true,\n \"roles\": [\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"ea in ullamco\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"sint aute officia laboris\"\n },\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"ut esse adipisicing ea\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"enim consequat nulla magna\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"non tempor elit ipsum\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"quis est\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"anim laboris Lorem eu\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"enim velit\"\n}" + }, + { + "name": "Unexpected error", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "[\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"ipsum mollit aute sit conse\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"ad sint aliquip laboris ei\"\n },\n {\n \"code\": \"form_designer\",\n \"display\": \"Form Designer\",\n \"description\": \"'Designs the form'\",\n \"active\": true,\n \"permissions\": [\n {\n \"value\": \"\"\n },\n {\n \"value\": \"\"\n }\n ],\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"anim\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"eu\"\n }\n]" + }, + "url": { + "raw": "{{baseUrl}}/roles", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "roles" + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"type\": \"voluptate eu\",\n \"title\": \"enim Ut ea\",\n \"status\": \"ex cillu\",\n \"detail\": \"quis id sunt irure\"\n}" + } + ] + } + ], + "protocolProfileBehavior": {} + }, + { + "name": "rbac", + "item": [ + { + "name": "forms", + "item": [ + { + "name": "Get the list of form and associated users", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/rbac/forms?userId=&idpUserId=&username=&fullName=&fullname=&firstName=&lastName=&email=&formId=&formName=&active=&idps=&roles=&permissions=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "rbac", + "forms" + ], + "query": [ + { + "key": "userId", + "value": "", + "description": "user id" + }, + { + "key": "idpUserId", + "value": "", + "description": "user identity provider id" + }, + { + "key": "username", + "value": "", + "description": "user username" + }, + { + "key": "fullName", + "value": "", + "description": "user fullName" + }, + { + "key": "fullname", + "value": "", + "description": "user username" + }, + { + "key": "firstName", + "value": "", + "description": "user firstName" + }, + { + "key": "lastName", + "value": "", + "description": "user lastName" + }, + { + "key": "email", + "value": "", + "description": "user email" + }, + { + "key": "formId", + "value": "", + "description": "form id" + }, + { + "key": "formName", + "value": "", + "description": "form name" + }, + { + "key": "active", + "value": "", + "description": "is the form active flag" + }, + { + "key": "idps", + "value": "", + "description": "identity provider (idp field) associated with form" + }, + { + "key": "roles", + "value": "", + "description": "roles (code field) user has on form" + }, + { + "key": "permissions", + "value": "", + "description": "permissions (code field) user has on form" + } + ] + } + }, + "response": [ + { + "name": "Unexpected error", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/rbac/forms?userId=&idpUserId=&username=&fullName=&fullname=&firstName=&lastName=&email=&formId=&formName=&active=&idps=&roles=&permissions=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "rbac", + "forms" + ], + "query": [ + { + "key": "userId", + "value": "" + }, + { + "key": "idpUserId", + "value": "" + }, + { + "key": "username", + "value": "" + }, + { + "key": "fullName", + "value": "" + }, + { + "key": "fullname", + "value": "" + }, + { + "key": "firstName", + "value": "" + }, + { + "key": "lastName", + "value": "" + }, + { + "key": "email", + "value": "" + }, + { + "key": "formId", + "value": "" + }, + { + "key": "formName", + "value": "" + }, + { + "key": "active", + "value": "" + }, + { + "key": "idps", + "value": "" + }, + { + "key": "roles", + "value": "" + }, + { + "key": "permissions", + "value": "" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"type\": \"voluptate eu\",\n \"title\": \"enim Ut ea\",\n \"status\": \"ex cillu\",\n \"detail\": \"quis id sunt irure\"\n}" + }, + { + "name": "Success", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/rbac/forms?userId=&idpUserId=&username=&fullName=&fullname=&firstName=&lastName=&email=&formId=&formName=&active=&idps=&roles=&permissions=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "rbac", + "forms" + ], + "query": [ + { + "key": "userId", + "value": "" + }, + { + "key": "idpUserId", + "value": "" + }, + { + "key": "username", + "value": "" + }, + { + "key": "fullName", + "value": "" + }, + { + "key": "fullname", + "value": "" + }, + { + "key": "firstName", + "value": "" + }, + { + "key": "lastName", + "value": "" + }, + { + "key": "email", + "value": "" + }, + { + "key": "formId", + "value": "" + }, + { + "key": "formName", + "value": "" + }, + { + "key": "active", + "value": "" + }, + { + "key": "idps", + "value": "" + }, + { + "key": "roles", + "value": "" + }, + { + "key": "permissions", + "value": "" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"userId\": \"5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987\",\n \"idpUserId\": \"ao9rsqw60nvf24pemkdik5e3fmo2kb6l\",\n \"username\": \"jsmith\",\n \"firstName\": \"Jane\",\n \"fullName\": \"Jane Smith\",\n \"lastName\": \"Smith\",\n \"email\": \"jsmith@gov.bc.ca\",\n \"formId\": \"5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987\",\n \"formName\": \"jsmith@gov.bc.ca\",\n \"labels\": [\n \"cillum ad officia sint tempor\",\n \"tempor enim\"\n ],\n \"active\": true,\n \"identityProviders\": [\n \"bceid\",\n \"idir\"\n ],\n \"idps\": [\n \"bceid\",\n \"idir\"\n ],\n \"formVersionId\": \"5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987\",\n \"version\": 1,\n \"roles\": [\n \"owner\",\n \"team_manager\"\n ],\n \"permissions\": [\n \"design_update\",\n \"submission_create\"\n ]\n },\n {\n \"userId\": \"5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987\",\n \"idpUserId\": \"ao9rsqw60nvf24pemkdik5e3fmo2kb6l\",\n \"username\": \"jsmith\",\n \"firstName\": \"Jane\",\n \"fullName\": \"Jane Smith\",\n \"lastName\": \"Smith\",\n \"email\": \"jsmith@gov.bc.ca\",\n \"formId\": \"5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987\",\n \"formName\": \"jsmith@gov.bc.ca\",\n \"labels\": [\n \"est\",\n \"culpa laborum\"\n ],\n \"active\": true,\n \"identityProviders\": [\n \"bceid\",\n \"idir\"\n ],\n \"idps\": [\n \"bceid\",\n \"idir\"\n ],\n \"formVersionId\": \"5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987\",\n \"version\": 1,\n \"roles\": [\n \"owner\",\n \"team_manager\"\n ],\n \"permissions\": [\n \"design_update\",\n \"submission_create\"\n ]\n }\n]" + } + ] + }, + { + "name": "Set relationships between forms, roles, users", + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "[\n {\n \"formId\": \"\",\n \"role\": \"\",\n \"userId\": \"\"\n },\n {\n \"formId\": \"\",\n \"role\": \"\",\n \"userId\": \"\"\n }\n]", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{baseUrl}}/rbac/forms?userId=&formId=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "rbac", + "forms" + ], + "query": [ + { + "key": "userId", + "value": "", + "description": "user id" + }, + { + "key": "formId", + "value": "", + "description": "form id" + } + ] + } + }, + "response": [ + { + "name": "Unexpected error", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "[\n {\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"role\": \"team_manager\",\n \"userId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\"\n },\n {\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"role\": \"team_manager\",\n \"userId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\"\n }\n]" + }, + "url": { + "raw": "{{baseUrl}}/rbac/forms?userId=&formId=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "rbac", + "forms" + ], + "query": [ + { + "key": "userId", + "value": "" + }, + { + "key": "formId", + "value": "" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"type\": \"voluptate eu\",\n \"title\": \"enim Ut ea\",\n \"status\": \"ex cillu\",\n \"detail\": \"quis id sunt irure\"\n}" + }, + { + "name": "Success", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "[\n {\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"role\": \"team_manager\",\n \"userId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\"\n },\n {\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"role\": \"team_manager\",\n \"userId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\"\n }\n]" + }, + "url": { + "raw": "{{baseUrl}}/rbac/forms?userId=&formId=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "rbac", + "forms" + ], + "query": [ + { + "key": "userId", + "value": "" + }, + { + "key": "formId", + "value": "" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"userId\": \"5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987\",\n \"idpUserId\": \"ao9rsqw60nvf24pemkdik5e3fmo2kb6l\",\n \"username\": \"jsmith\",\n \"firstName\": \"Jane\",\n \"fullName\": \"Jane Smith\",\n \"lastName\": \"Smith\",\n \"email\": \"jsmith@gov.bc.ca\",\n \"formId\": \"5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987\",\n \"formName\": \"jsmith@gov.bc.ca\",\n \"labels\": [\n \"cillum ad officia sint tempor\",\n \"tempor enim\"\n ],\n \"active\": true,\n \"identityProviders\": [\n \"bceid\",\n \"idir\"\n ],\n \"idps\": [\n \"bceid\",\n \"idir\"\n ],\n \"formVersionId\": \"5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987\",\n \"version\": 1,\n \"roles\": [\n \"owner\",\n \"team_manager\"\n ],\n \"permissions\": [\n \"design_update\",\n \"submission_create\"\n ]\n },\n {\n \"userId\": \"5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987\",\n \"idpUserId\": \"ao9rsqw60nvf24pemkdik5e3fmo2kb6l\",\n \"username\": \"jsmith\",\n \"firstName\": \"Jane\",\n \"fullName\": \"Jane Smith\",\n \"lastName\": \"Smith\",\n \"email\": \"jsmith@gov.bc.ca\",\n \"formId\": \"5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987\",\n \"formName\": \"jsmith@gov.bc.ca\",\n \"labels\": [\n \"est\",\n \"culpa laborum\"\n ],\n \"active\": true,\n \"identityProviders\": [\n \"bceid\",\n \"idir\"\n ],\n \"idps\": [\n \"bceid\",\n \"idir\"\n ],\n \"formVersionId\": \"5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987\",\n \"version\": 1,\n \"roles\": [\n \"owner\",\n \"team_manager\"\n ],\n \"permissions\": [\n \"design_update\",\n \"submission_create\"\n ]\n }\n]" + } + ] + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + }, + { + "name": "users", + "item": [ + { + "name": "Get the list of users and associated forms", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/rbac/users?userId=&idpUserId=&username=&fullName=&fullname=&firstName=&lastName=&email=&formId=&formName=&active=&idps=&roles=&permissions=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "rbac", + "users" + ], + "query": [ + { + "key": "userId", + "value": "", + "description": "user id" + }, + { + "key": "idpUserId", + "value": "", + "description": "user identity provider id" + }, + { + "key": "username", + "value": "", + "description": "user username" + }, + { + "key": "fullName", + "value": "", + "description": "user fullName" + }, + { + "key": "fullname", + "value": "", + "description": "user username" + }, + { + "key": "firstName", + "value": "", + "description": "user firstName" + }, + { + "key": "lastName", + "value": "", + "description": "user lastName" + }, + { + "key": "email", + "value": "", + "description": "user email" + }, + { + "key": "formId", + "value": "", + "description": "(Required) form id" + }, + { + "key": "formName", + "value": "", + "description": "form name" + }, + { + "key": "active", + "value": "", + "description": "is the form active flag" + }, + { + "key": "idps", + "value": "", + "description": "identity provider (idp field) associated with form" + }, + { + "key": "roles", + "value": "", + "description": "roles (code field) user has on form" + }, + { + "key": "permissions", + "value": "", + "description": "permissions (code field) user has on form" + } + ] + } + }, + "response": [ + { + "name": "Success", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/rbac/users?userId=&idpUserId=&username=&fullName=&fullname=&firstName=&lastName=&email=&formId=&formName=&active=&idps=&roles=&permissions=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "rbac", + "users" + ], + "query": [ + { + "key": "userId", + "value": "" + }, + { + "key": "idpUserId", + "value": "" + }, + { + "key": "username", + "value": "" + }, + { + "key": "fullName", + "value": "" + }, + { + "key": "fullname", + "value": "" + }, + { + "key": "firstName", + "value": "" + }, + { + "key": "lastName", + "value": "" + }, + { + "key": "email", + "value": "" + }, + { + "key": "formId", + "value": "" + }, + { + "key": "formName", + "value": "" + }, + { + "key": "active", + "value": "" + }, + { + "key": "idps", + "value": "" + }, + { + "key": "roles", + "value": "" + }, + { + "key": "permissions", + "value": "" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"userId\": \"5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987\",\n \"idpUserId\": \"ao9rsqw60nvf24pemkdik5e3fmo2kb6l\",\n \"username\": \"jsmith\",\n \"firstName\": \"Jane\",\n \"fullName\": \"Jane Smith\",\n \"lastName\": \"Smith\",\n \"email\": \"jsmith@gov.bc.ca\",\n \"formId\": \"5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987\",\n \"formName\": \"jsmith@gov.bc.ca\",\n \"labels\": [\n \"cillum ad officia sint tempor\",\n \"tempor enim\"\n ],\n \"active\": true,\n \"identityProviders\": [\n \"bceid\",\n \"idir\"\n ],\n \"idps\": [\n \"bceid\",\n \"idir\"\n ],\n \"formVersionId\": \"5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987\",\n \"version\": 1,\n \"roles\": [\n \"owner\",\n \"team_manager\"\n ],\n \"permissions\": [\n \"design_update\",\n \"submission_create\"\n ]\n },\n {\n \"userId\": \"5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987\",\n \"idpUserId\": \"ao9rsqw60nvf24pemkdik5e3fmo2kb6l\",\n \"username\": \"jsmith\",\n \"firstName\": \"Jane\",\n \"fullName\": \"Jane Smith\",\n \"lastName\": \"Smith\",\n \"email\": \"jsmith@gov.bc.ca\",\n \"formId\": \"5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987\",\n \"formName\": \"jsmith@gov.bc.ca\",\n \"labels\": [\n \"est\",\n \"culpa laborum\"\n ],\n \"active\": true,\n \"identityProviders\": [\n \"bceid\",\n \"idir\"\n ],\n \"idps\": [\n \"bceid\",\n \"idir\"\n ],\n \"formVersionId\": \"5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987\",\n \"version\": 1,\n \"roles\": [\n \"owner\",\n \"team_manager\"\n ],\n \"permissions\": [\n \"design_update\",\n \"submission_create\"\n ]\n }\n]" + }, + { + "name": "Unexpected error", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/rbac/users?userId=&idpUserId=&username=&fullName=&fullname=&firstName=&lastName=&email=&formId=&formName=&active=&idps=&roles=&permissions=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "rbac", + "users" + ], + "query": [ + { + "key": "userId", + "value": "" + }, + { + "key": "idpUserId", + "value": "" + }, + { + "key": "username", + "value": "" + }, + { + "key": "fullName", + "value": "" + }, + { + "key": "fullname", + "value": "" + }, + { + "key": "firstName", + "value": "" + }, + { + "key": "lastName", + "value": "" + }, + { + "key": "email", + "value": "" + }, + { + "key": "formId", + "value": "" + }, + { + "key": "formName", + "value": "" + }, + { + "key": "active", + "value": "" + }, + { + "key": "idps", + "value": "" + }, + { + "key": "roles", + "value": "" + }, + { + "key": "permissions", + "value": "" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"type\": \"voluptate eu\",\n \"title\": \"enim Ut ea\",\n \"status\": \"ex cillu\",\n \"detail\": \"quis id sunt irure\"\n}" + } + ] + }, + { + "name": "Set relationships between users, forms, roles", + "request": { + "method": "PUT", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "[\n {\n \"formId\": \"\",\n \"role\": \"\",\n \"userId\": \"\"\n },\n {\n \"formId\": \"\",\n \"role\": \"\",\n \"userId\": \"\"\n }\n]", + "options": { + "raw": {} + } + }, + "url": { + "raw": "{{baseUrl}}/rbac/users?userId=&formId=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "rbac", + "users" + ], + "query": [ + { + "key": "userId", + "value": "", + "description": "user id" + }, + { + "key": "formId", + "value": "", + "description": "form id" + } + ] + } + }, + "response": [ + { + "name": "Unexpected error", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "[\n {\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"role\": \"team_manager\",\n \"userId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\"\n },\n {\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"role\": \"team_manager\",\n \"userId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\"\n }\n]" + }, + "url": { + "raw": "{{baseUrl}}/rbac/users?userId=&formId=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "rbac", + "users" + ], + "query": [ + { + "key": "userId", + "value": "" + }, + { + "key": "formId", + "value": "" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"type\": \"voluptate eu\",\n \"title\": \"enim Ut ea\",\n \"status\": \"ex cillu\",\n \"detail\": \"quis id sunt irure\"\n}" + }, + { + "name": "Success", + "originalRequest": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "[\n {\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"role\": \"team_manager\",\n \"userId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\"\n },\n {\n \"formId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\",\n \"role\": \"team_manager\",\n \"userId\": \"aeb3b705-1de5-4f4e-a4e6-0716b7671034\"\n }\n]" + }, + "url": { + "raw": "{{baseUrl}}/rbac/users?userId=&formId=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "rbac", + "users" + ], + "query": [ + { + "key": "userId", + "value": "" + }, + { + "key": "formId", + "value": "" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"userId\": \"5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987\",\n \"idpUserId\": \"ao9rsqw60nvf24pemkdik5e3fmo2kb6l\",\n \"username\": \"jsmith\",\n \"firstName\": \"Jane\",\n \"fullName\": \"Jane Smith\",\n \"lastName\": \"Smith\",\n \"email\": \"jsmith@gov.bc.ca\",\n \"formId\": \"5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987\",\n \"formName\": \"jsmith@gov.bc.ca\",\n \"labels\": [\n \"cillum ad officia sint tempor\",\n \"tempor enim\"\n ],\n \"active\": true,\n \"identityProviders\": [\n \"bceid\",\n \"idir\"\n ],\n \"idps\": [\n \"bceid\",\n \"idir\"\n ],\n \"formVersionId\": \"5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987\",\n \"version\": 1,\n \"roles\": [\n \"owner\",\n \"team_manager\"\n ],\n \"permissions\": [\n \"design_update\",\n \"submission_create\"\n ]\n },\n {\n \"userId\": \"5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987\",\n \"idpUserId\": \"ao9rsqw60nvf24pemkdik5e3fmo2kb6l\",\n \"username\": \"jsmith\",\n \"firstName\": \"Jane\",\n \"fullName\": \"Jane Smith\",\n \"lastName\": \"Smith\",\n \"email\": \"jsmith@gov.bc.ca\",\n \"formId\": \"5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987\",\n \"formName\": \"jsmith@gov.bc.ca\",\n \"labels\": [\n \"est\",\n \"culpa laborum\"\n ],\n \"active\": true,\n \"identityProviders\": [\n \"bceid\",\n \"idir\"\n ],\n \"idps\": [\n \"bceid\",\n \"idir\"\n ],\n \"formVersionId\": \"5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987\",\n \"version\": 1,\n \"roles\": [\n \"owner\",\n \"team_manager\"\n ],\n \"permissions\": [\n \"design_update\",\n \"submission_create\"\n ]\n }\n]" + } + ] + } + ], + "protocolProfileBehavior": {}, + "_postman_isSubFolder": true + }, + { + "name": "Get the list of form/roles/permissions for the logged in user", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/rbac/current?formId=&formName=&active=&idps=&roles=&permissions=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "rbac", + "current" + ], + "query": [ + { + "key": "formId", + "value": "", + "description": "form id" + }, + { + "key": "formName", + "value": "", + "description": "form name" + }, + { + "key": "active", + "value": "", + "description": "is the form active flag" + }, + { + "key": "idps", + "value": "", + "description": "identity provider (idp field) associated with form" + }, + { + "key": "roles", + "value": "", + "description": "roles (code field) user has on form" + }, + { + "key": "permissions", + "value": "", + "description": "permissions (code field) user has on form" + } + ] + } + }, + "response": [ + { + "name": "Unexpected error", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/rbac/current?formId=&formName=&active=&idps=&roles=&permissions=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "rbac", + "current" + ], + "query": [ + { + "key": "formId", + "value": "" + }, + { + "key": "formName", + "value": "" + }, + { + "key": "active", + "value": "" + }, + { + "key": "idps", + "value": "" + }, + { + "key": "roles", + "value": "" + }, + { + "key": "permissions", + "value": "" + } + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"type\": \"voluptate eu\",\n \"title\": \"enim Ut ea\",\n \"status\": \"ex cillu\",\n \"detail\": \"quis id sunt irure\"\n}" + }, + { + "name": "Success", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/rbac/current?formId=&formName=&active=&idps=&roles=&permissions=", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "rbac", + "current" + ], + "query": [ + { + "key": "formId", + "value": "" + }, + { + "key": "formName", + "value": "" + }, + { + "key": "active", + "value": "" + }, + { + "key": "idps", + "value": "" + }, + { + "key": "roles", + "value": "" + }, + { + "key": "permissions", + "value": "" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"userId\": \"5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987\",\n \"idpUserId\": \"ao9rsqw60nvf24pemkdik5e3fmo2kb6l\",\n \"username\": \"jsmith\",\n \"firstName\": \"Jane\",\n \"fullName\": \"Jane Smith\",\n \"lastName\": \"Smith\",\n \"email\": \"jsmith@gov.bc.ca\",\n \"formId\": \"5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987\",\n \"formName\": \"jsmith@gov.bc.ca\",\n \"labels\": [\n \"cillum ad officia sint tempor\",\n \"tempor enim\"\n ],\n \"active\": true,\n \"identityProviders\": [\n \"bceid\",\n \"idir\"\n ],\n \"idps\": [\n \"bceid\",\n \"idir\"\n ],\n \"formVersionId\": \"5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987\",\n \"version\": 1,\n \"roles\": [\n \"owner\",\n \"team_manager\"\n ],\n \"permissions\": [\n \"design_update\",\n \"submission_create\"\n ]\n },\n {\n \"userId\": \"5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987\",\n \"idpUserId\": \"ao9rsqw60nvf24pemkdik5e3fmo2kb6l\",\n \"username\": \"jsmith\",\n \"firstName\": \"Jane\",\n \"fullName\": \"Jane Smith\",\n \"lastName\": \"Smith\",\n \"email\": \"jsmith@gov.bc.ca\",\n \"formId\": \"5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987\",\n \"formName\": \"jsmith@gov.bc.ca\",\n \"labels\": [\n \"est\",\n \"culpa laborum\"\n ],\n \"active\": true,\n \"identityProviders\": [\n \"bceid\",\n \"idir\"\n ],\n \"idps\": [\n \"bceid\",\n \"idir\"\n ],\n \"formVersionId\": \"5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987\",\n \"version\": 1,\n \"roles\": [\n \"owner\",\n \"team_manager\"\n ],\n \"permissions\": [\n \"design_update\",\n \"submission_create\"\n ]\n }\n]" + } + ] + }, + { + "name": "Get the list of identity providers", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/rbac/idps", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "rbac", + "idps" + ] + } + }, + "response": [ + { + "name": "Unexpected error", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/rbac/idps", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "rbac", + "idps" + ] + } + }, + "status": "Internal Server Error", + "code": 500, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "{\n \"type\": \"voluptate eu\",\n \"title\": \"enim Ut ea\",\n \"status\": \"ex cillu\",\n \"detail\": \"quis id sunt irure\"\n}" + }, + { + "name": "Success", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "{{baseUrl}}/rbac/idps", + "host": [ + "{{baseUrl}}" + ], + "path": [ + "rbac", + "idps" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "cookie": [], + "body": "[\n {\n \"code\": \"idir\",\n \"display\": \"IDIR\",\n \"idp\": \"idir\",\n \"active\": true,\n \"deleted\": false,\n \"submission\": \"aliquip cillum cupidatat\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"Duis officia\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"cillum minim magna elit laborum\"\n },\n {\n \"code\": \"idir\",\n \"display\": \"IDIR\",\n \"idp\": \"idir\",\n \"active\": true,\n \"deleted\": false,\n \"submission\": \"aliqua\",\n \"createdBy\": \"migration-011\",\n \"createdAt\": \"occaecat aliquip\",\n \"updatedBy\": \"jsmith\",\n \"updatedAt\": \"laborum fugiat\"\n }\n]" + } + ] + } + ], + "protocolProfileBehavior": {} + } + ], + "variable": [ + { + "id": "baseUrl", + "key": "baseUrl", + "value": "/api/v1", + "type": "string" + } + ], + "protocolProfileBehavior": {} +} diff --git a/frontend/app/src/docs/docs.js b/frontend/app/src/docs/docs.js new file mode 100644 index 0000000..cba1a2f --- /dev/null +++ b/frontend/app/src/docs/docs.js @@ -0,0 +1,25 @@ +const config = require('config'); + +const docs = { + getDocHTML: (version) => ` + + + Common Hosted Form Service - Documentation ${version} + + + + + + + + + + + + + `, +}; + +module.exports = docs; diff --git a/frontend/app/src/docs/v1.api-spec.yaml b/frontend/app/src/docs/v1.api-spec.yaml new file mode 100644 index 0000000..7713b84 --- /dev/null +++ b/frontend/app/src/docs/v1.api-spec.yaml @@ -0,0 +1,4276 @@ +--- +openapi: 3.0.3 +info: + version: 1.0.0 + title: Common Hosted Form Service (CHEFS) + description: >- + The API for an application for teams to create, manage and publish web + forms. These back-end operations can work for different form builder tools + that define the form as a json schema. Form management features include + role-based access for administrators, form versioning, submission review and + export, as well as notifications, document generation and reporting. + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + contact: + name: Forminators + email: submit.digital@gov.bc.ca +externalDocs: + description: Project Readmes + url: https://github.com/bcgov/common-hosted-form-service +servers: + - url: /api/v1 + description: This Server +security: + - BearerAuth: [] + OpenID: [] +tags: + - name: Form + description: >- + The API paths in this section are used to read and write data that make up + a web form, for example, the form schema object, metadata, and related + settings + - name: Form API + description: >- + This section supports the creation, management and removal of form scoped + API Key secrets. CHEFS endpoints which permit Basic Authentication use the + Form ID as username and the API Key as the password. + - name: Version + description: >- + The API supports versioning of forms. This allows a user to manage + multiple versions of a form design and, for example, publish a specific + version of a form. + - name: Draft + description: >- + This section of the API includes endpoints used to perform various + operations related to form drafts, for example create or publish a draft + from a specific version of a form. + - name: Submission + description: >- + These API endpoints handle the input data provided by a user that + completes the form, for example, writing the form data to the database, or + exporting form submissions created during a defined time period. + - name: Status + description: >- + These API endpoints handle operations to update and retrieve statuses and + notes on a submission, and status code management for a Form. + - name: Files + description: API endpoints to upload and retrieve files stored in CHEFS. + - name: User + description: >- + The section includes API endpoints for carrying out operations with data + related to users of the application. + - name: Role + description: >- + The API includes endpoints for managing roles assigned to users. A role, + for example, 'Form Designer' or 'Submission Reviewer' will often + correspond to the business functions of a user's job. Roles have a group + of related permissions that are used to control access to a defined set of + features of and application. + - name: Permission + description: >- + The API uses Permissions to control access to a defined set of features of + and application, for example, reading form submissions or updating the + design of a form. Permissions are assigned to roles. + - name: RBAC + description: >- + This section of the API documents the API endpoints related to Role-based + Access Control (RBAC). RBAC is a method of restricting access based on + roles. These endpoints handle a combination of user, role and permission + data as well as the access settings for a published form. + - name: Admin + description: >- + These API endpoints are used for elevated permission administrative calls. + All calls are secured by a role that operational team members will be + granted and allow fetching some details about forms without needing a + user->form permission. +paths: + /forms: + get: + summary: List all forms + operationId: listForms + tags: + - Form + security: + - BearerAuth: [] + OpenID: + - admin + parameters: + - in: query + name: active + schema: + type: boolean + description: filter forms by active status + example: true + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Form' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + post: + summary: Create a new form + operationId: createForm + tags: + - Form + requestBody: + required: true + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/FormBasic' + - $ref: '#/components/schemas/FormSchema' + responses: + '201': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/FormBasic' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /forms/{formId}: + get: + summary: Get details of a form (and metadata for versions) + operationId: readForm + security: + - BasicAuth: [] + - BearerAuth: [] + OpenID: [] + tags: + - Form + parameters: + - $ref: '#/components/parameters/formIdParam' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Form' + headers: + RateLimit: + $ref: '#/components/headers/RateLimit' + RateLimit-Policy: + $ref: '#/components/headers/RateLimit-Policy' + '401': + $ref: '#/components/responses/UnauthorizedError' + '403': + $ref: '#/components/responses/Forbidden' + '429': + $ref: '#/components/responses/TooManyRequests' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + put: + summary: Update a form + operationId: updateForm + security: + - BasicAuth: [] + - BearerAuth: [] + OpenID: [] + tags: + - Form + parameters: + - $ref: '#/components/parameters/formIdParam' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/FormBasic' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Form' + headers: + RateLimit: + $ref: '#/components/headers/RateLimit' + RateLimit-Policy: + $ref: '#/components/headers/RateLimit-Policy' + '401': + $ref: '#/components/responses/UnauthorizedError' + '403': + $ref: '#/components/responses/Forbidden' + '429': + $ref: '#/components/responses/TooManyRequests' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + delete: + summary: (Soft) Delete a form + operationId: deleteForm + security: + - BasicAuth: [] + - BearerAuth: [] + OpenID: [] + tags: + - Form + parameters: + - $ref: '#/components/parameters/formIdParam' + responses: + '204': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/FormBasic' + headers: + RateLimit: + $ref: '#/components/headers/RateLimit' + RateLimit-Policy: + $ref: '#/components/headers/RateLimit-Policy' + '401': + $ref: '#/components/responses/UnauthorizedError' + '403': + $ref: '#/components/responses/Forbidden' + '429': + $ref: '#/components/responses/TooManyRequests' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /forms/{formId}/apiKey: + get: + summary: Get current API Key + description: Get the active api key secret for a form + operationId: readApiKey + tags: + - Form API + parameters: + - $ref: '#/components/parameters/formIdParam' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/FormApiKey' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + put: + summary: Create/Replace API Key + description: Create or replace api key secret for a form + operationId: createReplaceApiKey + tags: + - Form API + parameters: + - $ref: '#/components/parameters/formIdParam' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/FormApiKey' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + delete: + summary: Delete API Key + description: Delete the api key secret for a form + operationId: deleteApiKey + tags: + - Form API + parameters: + - $ref: '#/components/parameters/formIdParam' + responses: + '204': + description: OK + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /forms/{formId}/export: + get: + summary: Export submissions for a form + operationId: export + security: + - BasicAuth: [] + - BearerAuth: [] + OpenID: [] + tags: + - Submission + parameters: + - $ref: '#/components/parameters/formIdParam' + - in: query + name: format + schema: + type: string + description: chosen format for the submission data exported + example: csv + required: true + - in: query + name: type + schema: + type: string + description: the category of data exported + example: submissions + required: true + - in: query + name: version + schema: + type: string + description: The form version number. If the export format is json and not csv, then setting this to 0 will export all versions. + example: 1 + required: true + - in: query + name: preference + schema: + type: object + example: '{ minDate=2020-12-17T08:00:00Z, maxDate=2020-12-17T08:00:00Z, updatedMinDate=2020-12-17T08:00:00Z, updatedMaxDate=2020-12-17T08:00:00Z }' + description: form submissions export preferences + - in: query + name: deleted + schema: + type: boolean + description: (optional) This optional parameter should be set to true if deleted records (submissions) need to be fetched + example: false + - in: query + name: drafts + schema: + type: boolean + description: (optional) This optional parameter should be set to true if draft records (submissions) need to be fetched + example: false + - in: query + name: columns + schema: + type: array + description: (optional) List of form level columns (Only Allowed draft, deleted, updatedAt columns) to be include. Other then allowed columns will be ignored + example: + - draft, + - deleted, + - updatedAt + - in: query + name: status + schema: + type: string + description: Submission status to be filtered based on + example: COMPLETED + required: false + responses: + '200': + description: Export file created for download + headers: + content-type: + description: Response header + schema: + type: object + example: text/json; charset=utf-8 + RateLimit: + $ref: '#/components/headers/RateLimit' + RateLimit-Policy: + $ref: '#/components/headers/RateLimit-Policy' + content: + text/csv: + schema: + type: string + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/FormSubmissionExport' + '401': + $ref: '#/components/responses/UnauthorizedError' + '403': + $ref: '#/components/responses/Forbidden' + '429': + $ref: '#/components/responses/TooManyRequests' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /forms/{formId}/export/fields: + post: + summary: Export submissions for a form with the ability to select fields to export if CSV is selected. + operationId: exportWithFields + security: + - BasicAuth: [] + - BearerAuth: [] + OpenID: [] + tags: + - Submission + parameters: + - $ref: '#/components/parameters/formIdParam' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/FormSubmissionExportWithFields' + responses: + '200': + description: Export file created for download + headers: + content-type: + description: Response header + schema: + type: object + example: text/json; charset=utf-8 + RateLimit: + $ref: '#/components/headers/RateLimit' + RateLimit-Policy: + $ref: '#/components/headers/RateLimit-Policy' + content: + text/csv: + schema: + type: string + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/FormSubmissionExport' + '401': + $ref: '#/components/responses/UnauthorizedError' + '403': + $ref: '#/components/responses/Forbidden' + '429': + $ref: '#/components/responses/TooManyRequests' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /forms/{formId}/options: + get: + summary: Get pre-flight details for a form + operationId: readFormOptions + tags: + - Form + parameters: + - $ref: '#/components/parameters/formIdParam' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/FormOptions' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /forms/{formId}/versions/{formVersionId}: + get: + summary: Get a single form version + operationId: readVersion + security: + - BasicAuth: [] + - BearerAuth: [] + OpenID: [] + tags: + - Version + parameters: + - $ref: '#/components/parameters/formIdParam' + - $ref: '#/components/parameters/formVersionIdParam' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/FormVersion' + headers: + RateLimit: + $ref: '#/components/headers/RateLimit' + RateLimit-Policy: + $ref: '#/components/headers/RateLimit-Policy' + '401': + $ref: '#/components/responses/UnauthorizedError' + '403': + $ref: '#/components/responses/Forbidden' + '429': + $ref: '#/components/responses/TooManyRequests' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /forms/{formId}/versions/{formVersionId}/fields: + get: + summary: Get a list of valid form fields in this form version + operationId: readVersionFields + security: + - BasicAuth: [] + - BearerAuth: [] + OpenID: [] + tags: + - Version + parameters: + - $ref: '#/components/parameters/formIdParam' + - $ref: '#/components/parameters/formVersionIdParam' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/FormVersionFields' + headers: + RateLimit: + $ref: '#/components/headers/RateLimit' + RateLimit-Policy: + $ref: '#/components/headers/RateLimit-Policy' + '401': + $ref: '#/components/responses/UnauthorizedError' + '403': + $ref: '#/components/responses/Forbidden' + '429': + $ref: '#/components/responses/TooManyRequests' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /forms/{formId}/version: + get: + summary: Get published version of a form + operationId: readPublishedForm + security: + - BasicAuth: [] + - BearerAuth: [] + OpenID: [] + tags: + - Version + parameters: + - $ref: '#/components/parameters/formIdParam' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Form' + headers: + RateLimit: + $ref: '#/components/headers/RateLimit' + RateLimit-Policy: + $ref: '#/components/headers/RateLimit-Policy' + '401': + $ref: '#/components/responses/UnauthorizedError' + '403': + $ref: '#/components/responses/Forbidden' + '429': + $ref: '#/components/responses/TooManyRequests' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /forms/{formId}/versions/{formVersionId}/publish: + post: + summary: Publish a version of a form + operationId: publishVersion + security: + - BasicAuth: [] + - BearerAuth: [] + OpenID: [] + tags: + - Version + parameters: + - $ref: '#/components/parameters/formIdParam' + - $ref: '#/components/parameters/formVersionIdParam' + - in: query + name: unpublish + schema: + type: boolean + example: true + required: false + description: Should this version of the form be unpublished + responses: + '201': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/FormVersionBasic' + headers: + RateLimit: + $ref: '#/components/headers/RateLimit' + RateLimit-Policy: + $ref: '#/components/headers/RateLimit-Policy' + '401': + $ref: '#/components/responses/UnauthorizedError' + '403': + $ref: '#/components/responses/Forbidden' + '429': + $ref: '#/components/responses/TooManyRequests' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /forms/{formId}/drafts: + get: + summary: List drafts for a form + operationId: listDrafts + security: + - BasicAuth: [] + - BearerAuth: [] + OpenID: [] + tags: + - Draft + parameters: + - $ref: '#/components/parameters/formIdParam' + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/FormDraft' + headers: + RateLimit: + $ref: '#/components/headers/RateLimit' + RateLimit-Policy: + $ref: '#/components/headers/RateLimit-Policy' + '401': + $ref: '#/components/responses/UnauthorizedError' + '403': + $ref: '#/components/responses/Forbidden' + '429': + $ref: '#/components/responses/TooManyRequests' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + post: + summary: Create a draft from a form version + operationId: createDraft + security: + - BasicAuth: [] + - BearerAuth: [] + OpenID: [] + tags: + - Draft + parameters: + - $ref: '#/components/parameters/formIdParam' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + formVersionId: + type: string + format: uuid + description: ID of the form version used for this draft + example: a675ab2a-1e88-4fb5-88f9-c7cb051a18b2 + schema: + $ref: '#/components/schemas/FormSchema' + responses: + '201': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/FormDraft' + headers: + RateLimit: + $ref: '#/components/headers/RateLimit' + RateLimit-Policy: + $ref: '#/components/headers/RateLimit-Policy' + '401': + $ref: '#/components/responses/UnauthorizedError' + '403': + $ref: '#/components/responses/Forbidden' + '429': + $ref: '#/components/responses/TooManyRequests' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /forms/{formId}/drafts/{formVersionDraftId}: + get: + summary: Get a form draft + operationId: readDraft + security: + - BasicAuth: [] + - BearerAuth: [] + OpenID: [] + tags: + - Draft + parameters: + - $ref: '#/components/parameters/formIdParam' + - $ref: '#/components/parameters/formVersionDraftIdParam' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/FormDraft' + headers: + RateLimit: + $ref: '#/components/headers/RateLimit' + RateLimit-Policy: + $ref: '#/components/headers/RateLimit-Policy' + '401': + $ref: '#/components/responses/UnauthorizedError' + '403': + $ref: '#/components/responses/Forbidden' + '429': + $ref: '#/components/responses/TooManyRequests' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + put: + summary: Update a form draft + operationId: updateDraft + security: + - BasicAuth: [] + - BearerAuth: [] + OpenID: [] + tags: + - Draft + parameters: + - $ref: '#/components/parameters/formIdParam' + - $ref: '#/components/parameters/formVersionDraftIdParam' + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + schema: + $ref: '#/components/schemas/FormSchema' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/FormDraft' + headers: + RateLimit: + $ref: '#/components/headers/RateLimit' + RateLimit-Policy: + $ref: '#/components/headers/RateLimit-Policy' + '401': + $ref: '#/components/responses/UnauthorizedError' + '403': + $ref: '#/components/responses/Forbidden' + '429': + $ref: '#/components/responses/TooManyRequests' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + delete: + summary: Delete a form draft + operationId: deleteDraft + security: + - BasicAuth: [] + - BearerAuth: [] + OpenID: [] + tags: + - Draft + parameters: + - $ref: '#/components/parameters/formIdParam' + - $ref: '#/components/parameters/formVersionDraftIdParam' + responses: + '204': + description: OK + headers: + RateLimit: + $ref: '#/components/headers/RateLimit' + RateLimit-Policy: + $ref: '#/components/headers/RateLimit-Policy' + '401': + $ref: '#/components/responses/UnauthorizedError' + '403': + $ref: '#/components/responses/Forbidden' + '429': + $ref: '#/components/responses/TooManyRequests' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /forms/{formId}/drafts/{formVersionDraftId}/publish: + post: + summary: Publish a form draft + operationId: publishDraft + security: + - BasicAuth: [] + - BearerAuth: [] + OpenID: [] + tags: + - Draft + parameters: + - $ref: '#/components/parameters/formIdParam' + - $ref: '#/components/parameters/formVersionDraftIdParam' + responses: + '201': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/FormVersionBasic' + headers: + RateLimit: + $ref: '#/components/headers/RateLimit' + RateLimit-Policy: + $ref: '#/components/headers/RateLimit-Policy' + '401': + $ref: '#/components/responses/UnauthorizedError' + '403': + $ref: '#/components/responses/Forbidden' + '429': + $ref: '#/components/responses/TooManyRequests' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /forms/{formId}/submissions: + get: + summary: List submissions for a form + operationId: listFormSubmissions + security: + - BasicAuth: [] + - BearerAuth: [] + OpenID: [] + tags: + - Submission + parameters: + - $ref: '#/components/parameters/formIdParam' + - in: query + name: fields + schema: + type: string + example: textField1,checkbox1,radioGroup1,email1 + description: >- + A list of form fields to search on. Refer to the related + `versions/{formVersionId}/fields` endpoint for a list of valid + values to query for. The list should be comma separated. + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/FormSubmissionSummary' + headers: + RateLimit: + $ref: '#/components/headers/RateLimit' + RateLimit-Policy: + $ref: '#/components/headers/RateLimit-Policy' + '401': + $ref: '#/components/responses/UnauthorizedError' + '403': + $ref: '#/components/responses/Forbidden' + '429': + $ref: '#/components/responses/TooManyRequests' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /forms/{formId}/versions/{formVersionId}/submissions: + get: + summary: List submissions from a form version + operationId: listSubmissions + security: + - BasicAuth: [] + - BearerAuth: [] + OpenID: [] + tags: + - Submission + parameters: + - $ref: '#/components/parameters/formIdParam' + - $ref: '#/components/parameters/formVersionIdParam' + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/FormSubmission' + headers: + RateLimit: + $ref: '#/components/headers/RateLimit' + RateLimit-Policy: + $ref: '#/components/headers/RateLimit-Policy' + '401': + $ref: '#/components/responses/UnauthorizedError' + '403': + $ref: '#/components/responses/Forbidden' + '429': + $ref: '#/components/responses/TooManyRequests' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + post: + summary: Create a new form submission + operationId: createSubmission + security: + - BasicAuth: [] + - BearerAuth: [] + OpenID: [] + tags: + - Submission + parameters: + - $ref: '#/components/parameters/formIdParam' + - $ref: '#/components/parameters/formVersionIdParam' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/FormSubmissionBasic' + responses: + '201': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/FormSubmission' + headers: + RateLimit: + $ref: '#/components/headers/RateLimit' + RateLimit-Policy: + $ref: '#/components/headers/RateLimit-Policy' + '401': + $ref: '#/components/responses/UnauthorizedError' + '403': + $ref: '#/components/responses/Forbidden' + '429': + $ref: '#/components/responses/TooManyRequests' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /forms/{formId}/versions/{formVersionId}/multiSubmission: + post: + summary: Upload multiple draft submissions + operationId: uploadMultipleDraft + security: + - BasicAuth: [] + - BearerAuth: [] + OpenID: [] + tags: + - Submission + parameters: + - $ref: '#/components/parameters/formIdParam' + - $ref: '#/components/parameters/formVersionIdParam' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/FormSubmissionMultiple' + responses: + '201': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/FormSubmissionResponseMultiple' + headers: + RateLimit: + $ref: '#/components/headers/RateLimit' + RateLimit-Policy: + $ref: '#/components/headers/RateLimit-Policy' + '401': + $ref: '#/components/responses/UnauthorizedError' + '403': + $ref: '#/components/responses/Forbidden' + '429': + $ref: '#/components/responses/TooManyRequests' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /forms/{formId}/versions/{formVersionId}/submissions/discover: + get: + summary: List field value submissions from a form version + description: >- + A queryable endpoint for acquiring a specific subset of data from the + submissions + operationId: listDiscoverSubmissions + security: + - BasicAuth: [] + - BearerAuth: [] + OpenID: [] + tags: + - Submission + parameters: + - $ref: '#/components/parameters/formIdParam' + - $ref: '#/components/parameters/formVersionIdParam' + - in: query + name: fields + schema: + type: string + example: textField1,checkbox1,radioGroup1,email1 + description: >- + A list of form fields to search on. Refer to the related `/fields` + endpoint for a list of valid values to query for. The list can be + comma separated or by repeating the same fields query multiple + times. + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/FormSubmissionDiscover' + headers: + RateLimit: + $ref: '#/components/headers/RateLimit' + RateLimit-Policy: + $ref: '#/components/headers/RateLimit-Policy' + '401': + $ref: '#/components/responses/UnauthorizedError' + '403': + $ref: '#/components/responses/Forbidden' + '429': + $ref: '#/components/responses/TooManyRequests' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /submissions/{formSubmissionId}: + get: + summary: Get a form submission + operationId: readSubmission + security: + - BasicAuth: [] + - BearerAuth: [] + OpenID: [] + tags: + - Submission + parameters: + - $ref: '#/components/parameters/formSubmissionIdParam' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/SubmissionFormVersion' + headers: + RateLimit: + $ref: '#/components/headers/RateLimit' + RateLimit-Policy: + $ref: '#/components/headers/RateLimit-Policy' + '401': + $ref: '#/components/responses/UnauthorizedError' + '403': + $ref: '#/components/responses/Forbidden' + '429': + $ref: '#/components/responses/TooManyRequests' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + put: + summary: Update a form submission + operationId: updateSubmission + tags: + - Submission + parameters: + - $ref: '#/components/parameters/formSubmissionIdParam' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/FormSubmissionBasic' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/FormSubmission' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + delete: + summary: (Soft) delete a form submission + operationId: deleteSubmission + security: + - BasicAuth: [] + - BearerAuth: [] + OpenID: [] + tags: + - Submission + parameters: + - $ref: '#/components/parameters/formSubmissionIdParam' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/SubmissionFormVersionDeleted' + headers: + RateLimit: + $ref: '#/components/headers/RateLimit' + RateLimit-Policy: + $ref: '#/components/headers/RateLimit-Policy' + '403': + $ref: '#/components/responses/Forbidden' + '429': + $ref: '#/components/responses/TooManyRequests' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /submissions/{formSubmissionId}/email: + post: + summary: Email a message with link to a submission + operationId: emailSubmission + tags: + - Submission + parameters: + - $ref: '#/components/parameters/formSubmissionIdParam' + - in: header + name: Referer + description: URL of webpage where email was requested + schema: + type: string + required: true + example: >- + https://submit.digital.gov.bc.ca/app/form/success?s=7d66664b-87c5-4df8-ba7c-a6fb7d62c379 + requestBody: + required: true + content: + application/json: + schema: + type: object + properties: + to: + type: string + example: jsmith@email.ca + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/EmailMessage' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /submissions/{formSubmissionId}/edits: + get: + summary: Get an audit list of edits to a submission + operationId: readSubmissionEdits + tags: + - Submission + parameters: + - $ref: '#/components/parameters/formSubmissionIdParam' + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/SubmissionEditMetadata' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /submissions/{formSubmissionId}/options: + get: + summary: Get pre-flight details for a form submission + operationId: readSubmissionOptions + tags: + - Submission + parameters: + - $ref: '#/components/parameters/formSubmissionIdParam' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/SubmissionFormVersionOptions' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /forms/{formId}/statusCodes: + get: + summary: List status codes for a form + operationId: getStatusCodes + tags: + - Status + parameters: + - $ref: '#/components/parameters/formIdParam' + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/StatusCodes' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /submissions/{formSubmissionId}/status: + get: + summary: Get the list of status history for a submission + operationId: readSubmissionStatus + security: + - BasicAuth: [] + - BearerAuth: [] + OpenID: [] + tags: + - Status + parameters: + - $ref: '#/components/parameters/formSubmissionIdParam' + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/SubmissionStatusHistory' + headers: + RateLimit: + $ref: '#/components/headers/RateLimit' + RateLimit-Policy: + $ref: '#/components/headers/RateLimit-Policy' + '401': + $ref: '#/components/responses/UnauthorizedError' + '403': + $ref: '#/components/responses/Forbidden' + '429': + $ref: '#/components/responses/TooManyRequests' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + post: + summary: Add a new status to a submission + description: |- + Adds a new status to a submission, and optionally provides email notification depending + on the status being assigned. + operationId: addSubmissionStatus + tags: + - Status + parameters: + - $ref: '#/components/parameters/formSubmissionIdParam' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/SubmissionStatus' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/SubmissionStatusHistory' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /submissions/{formSubmissionId}/template/render: + post: + summary: Generate document from inline Template + description: >- + This endpoint accepts a document template and a set (or multiple sets) + of substitution variables and merges them into the document. + operationId: uploadTemplateAndRenderReport + tags: + - Template + parameters: + - $ref: '#/components/parameters/formSubmissionIdParam' + requestBody: + description: Fields required to generate a document + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/TemplateRenderObject' + responses: + '200': + description: Returns the supplied document with variables merged in + content: + application/octet-stream: + schema: + type: string + format: binary + description: Raw binary-encoded response + headers: + Content-Disposition: + schema: + type: string + description: >- + Indicates if a browser should render this resource inline or + treat as an attachment for download + example: attachment; filename=file.pdf + Content-Type: + schema: + type: string + description: The MIME-type of the binary file payload + example: application/pdf + '400': + $ref: '#/components/responses/BadRequest' + '403': + $ref: '#/components/responses/Forbidden' + '422': + $ref: '#/components/responses/UnprocessableEntity' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /submissions/{formSubmissionId}/notes: + get: + summary: Get the list of notes for a submission + operationId: readSubmissioNotes + tags: + - Status + parameters: + - $ref: '#/components/parameters/formSubmissionIdParam' + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + allOf: + - $ref: '#/components/schemas/Note' + - $ref: '#/components/schemas/TimeStampUserData' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + post: + summary: Add a note to a submission + operationId: addSubmissionNote + tags: + - Status + parameters: + - $ref: '#/components/parameters/formSubmissionIdParam' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Note' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /files: + post: + summary: Upload a file + operationId: fileUpload + tags: + - Files + requestBody: + required: true + content: + multipart/form-data: + schema: + type: object + properties: + name: + type: string + example: file_name-5b26db5a-8388-4c01-b728-d0d098f815ba.pdf + description: The desired file name + files: + type: string + format: binary + description: The actual files to upload + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/FileUpload' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /files/{fileId}: + get: + summary: Get a file + operationId: fileGet + tags: + - Files + parameters: + - $ref: '#/components/parameters/fileIdParam' + responses: + '200': + description: The returned binary file + content: + application/: + schema: + type: string + format: binary + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + delete: + summary: Delete a file + operationId: fileDelete + tags: + - Files + parameters: + - $ref: '#/components/parameters/fileIdParam' + responses: + '202': + description: Accepted + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /permissions: + get: + summary: List all permissions + operationId: listPermissions + tags: + - Permission + security: + - BearerAuth: [] + OpenID: + - admin + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Permission' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + post: + summary: Create a new permission + operationId: createPermission + tags: + - Permission + security: + - BearerAuth: [] + OpenID: + - admin + requestBody: + required: true + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Permission' + responses: + '201': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Permission' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /permissions/{code}: + get: + summary: Get a permission + operationId: readPermission + tags: + - Permission + security: + - BearerAuth: [] + OpenID: + - admin + parameters: + - in: path + name: code + schema: + type: string + required: true + description: code of the permission to fetch + example: submission_read + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Permission' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + put: + summary: Update a permission + operationId: updatePermission + tags: + - Permission + security: + - BearerAuth: [] + OpenID: + - admin + parameters: + - in: path + name: code + schema: + type: string + required: true + example: submission_read + description: code of the permission to update + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Permission' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Permission' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /roles: + get: + summary: List all roles + operationId: listRoles + tags: + - Role + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Role' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + post: + summary: Create a new role + operationId: createRole + tags: + - Role + security: + - BearerAuth: [] + OpenID: + - admin + requestBody: + required: true + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Role' + responses: + '201': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Role' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /roles/{code}: + get: + summary: Get a role + operationId: getRole + tags: + - Role + parameters: + - in: path + name: code + schema: + type: string + required: true + description: code of the role to fetch + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Role' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + put: + summary: Update a role + operationId: updateRole + tags: + - Role + security: + - BearerAuth: [] + OpenID: + - admin + parameters: + - in: path + name: code + schema: + type: string + required: true + description: code of the role to update + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Role' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/Role' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /rbac/current: + get: + summary: Get forms/roles/permissions for current user + operationId: getCurrentUser + tags: + - RBAC + parameters: + - in: query + name: formId + schema: + type: string + format: uuid + example: c6455376-382c-439d-a811-0381a012d696 + description: form ID + - in: query + name: active + schema: + type: boolean + example: true + description: is the form active flag + - in: query + name: idps + schema: + type: string + - in: query + name: accessLevels + schema: + type: string + description: filter on the user access level for the form (public, idp, team) + responses: + '200': + description: OK + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/CurrentUser' + - type: array + items: + $ref: '#/components/schemas/UserForm' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /rbac/current/submissions: + get: + summary: Get submissions/roles/permissions for current user + operationId: getCurrentUserSubmissions + tags: + - RBAC + parameters: + - in: query + name: formId + schema: + type: string + format: uuid + example: c6455376-382c-439d-a811-0381a012d696 + description: form ID + - in: query + name: formSubmissionId + schema: + type: string + format: uuid + example: c6455376-382c-439d-a811-0381a012d696 + description: submission ID + - in: query + name: userId + schema: + type: string + format: uuid + example: c6455376-382c-439d-a811-0381a012d696 + description: user ID + - in: query + name: active + schema: + type: boolean + example: true + description: to include active or deleted submissions or not + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/UserSubmission' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /rbac/idps: + get: + summary: Get a list of identity providers + operationId: getIdentityProviders + tags: + - RBAC + parameters: + - in: query + name: active + schema: + type: boolean + example: true + description: is the identity provider active + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/IdentityProvider' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /rbac/forms: + get: + summary: Get a list of users and roles for a form + operationId: getFormUsers + tags: + - RBAC + parameters: + - in: query + name: formId + schema: + type: string + format: uuid + example: c6455376-382c-439d-a811-0381a012d696 + description: form ID + required: true + - in: query + name: userId + schema: + type: string + description: user ID + - in: query + name: idpUserId + schema: + type: string + description: user identity provider id + - in: query + name: username + schema: + type: string + description: user username + - in: query + name: fullName + schema: + type: string + description: user fullName + - in: query + name: firstName + schema: + type: string + description: user firstName + - in: query + name: lastName + schema: + type: string + description: user lastName + - in: query + name: email + schema: + type: string + description: user email + - in: query + name: formName + schema: + type: string + description: form name + - in: query + name: active + schema: + type: boolean + example: true + description: is the form active flag + - in: query + name: idps + schema: + type: string + description: identity provider (idp field) associated with form + - in: query + name: roles + schema: + type: string + description: roles (code field) user has on form + - in: query + name: permissions + schema: + type: string + description: permissions (code field) user has on form + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/UserAccess' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + put: + summary: Set user roles for a form + operationId: setFormUsers + tags: + - RBAC + parameters: + - in: query + name: formId + schema: + type: string + format: uuid + example: c6455376-382c-439d-a811-0381a012d696 + description: form id + required: true + - in: query + name: userId + schema: + type: string + format: uuid + example: d7455376-382c-439d-a811-0381a012d696 + description: user id + required: true + requestBody: + required: true + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/FormRoleUser' + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/UserAccess' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /rbac/submissions: + get: + summary: Get a list of users and permissions for a submission + operationId: getSubmissionUsers + tags: + - RBAC + parameters: + - in: query + name: formSubmissionId + schema: + type: string + format: uuid + example: c6455376-382c-439d-a811-0381a012d696 + description: submission ID + required: true + - in: query + name: userId + schema: + type: string + description: user ID + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/UserAccessSubmission' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + put: + summary: Set permissions for a user on a submission + operationId: setSubmissionUser + tags: + - RBAC + parameters: + - in: query + name: formSubmissionId + schema: + type: string + format: uuid + example: c6455376-382c-439d-a811-0381a012d696 + description: submission id + required: true + - in: query + name: userId + schema: + type: string + description: user ID + required: true + requestBody: + required: true + content: + application/json: + schema: + type: array + items: + type: string + example: SUBMISSION_UPDATE + description: >- + an array of the sumbission permissions to apply to this user. + Set an empty array to remove. + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/UserAccessSubmission' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /rbac/users: + get: + summary: Get a list of forms and roles for a user + operationId: getUserForms + tags: + - RBAC + security: + - BearerAuth: [] + OpenID: + - admin + parameters: + - in: query + name: userId + schema: + type: string + description: user id + - in: query + name: idpUserId + schema: + type: string + description: user identity provider id + - in: query + name: username + schema: + type: string + description: user username + - in: query + name: fullName + schema: + type: string + description: user fullName + - in: query + name: fullname + schema: + type: string + description: user username + - in: query + name: firstName + schema: + type: string + description: user firstName + - in: query + name: lastName + schema: + type: string + description: user lastName + - in: query + name: email + schema: + type: string + description: user email + - in: query + name: formId + schema: + type: string + format: uuid + example: c6455376-382c-439d-a811-0381a012d696 + description: form id + required: true + - in: query + name: formName + schema: + type: string + description: form name + - in: query + name: active + schema: + type: boolean + example: true + description: is the form active flag + - in: query + name: idps + schema: + type: string + description: identity provider (idp field) associated with form + - in: query + name: roles + schema: + type: string + description: roles (code field) user has on form + - in: query + name: permissions + schema: + type: string + description: permissions (code field) user has on form + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/UserAccess' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + put: + summary: Set form roles for a user + operationId: setUserForms + tags: + - RBAC + parameters: + - in: query + name: userId + schema: + type: string + description: user id + required: true + - in: query + name: formId + schema: + type: string + format: uuid + example: c6455376-382c-439d-a811-0381a012d696 + description: form id + required: true + requestBody: + required: true + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/FormRoleUser' + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/UserAccess' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /users: + get: + summary: Get a list of users and their roles + operationId: listUsers + tags: + - User + parameters: + - in: query + name: idpUserId + schema: + type: string + description: user identity provider id + - in: query + name: username + schema: + type: string + description: user username + - in: query + name: fullName + schema: + type: string + description: user fullName + - in: query + name: firstName + schema: + type: string + description: user firstName + - in: query + name: lastName + schema: + type: string + description: user lastName + - in: query + name: email + schema: + type: string + description: user email + - in: query + name: search + schema: + type: string + description: string to match against username, fullName and Email + - in: query + name: idpCode + schema: + type: string + description: Filter results to only users with specified idpCode + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/User' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /users/{userId}: + get: + summary: Get a user and their roles + operationId: readUser + tags: + - User + parameters: + - in: path + name: userId + schema: + type: string + example: bea3b705-1de5-4f4e-a4e6-0716b7674132 + description: user ID + required: true + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/User' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /users/preferences: + get: + summary: Get the preferences for current user + description: Fetches all known preferences for the current user + operationId: readUserPreferences + tags: + - User + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/UserPreferences' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + put: + summary: Update the preferences for current user + description: Updates all known preferences for the current user + operationId: updateUserPreferences + tags: + - User + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/UserPreferences' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/UserPreferences' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + delete: + summary: Delete all preferences for current user + description: Deletes all known preferences for the current user + operationId: deleteUserPreferences + tags: + - User + responses: + '204': + description: OK + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /users/preferences/forms/{formId}: + get: + summary: Get the form preferences for current user + description: Fetches preferences for the current user specific to this form + operationId: readUserFormPreferences + tags: + - User + parameters: + - $ref: '#/components/parameters/formIdParam' + responses: + '200': + description: OK + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/UserFormPreferences' + - $ref: '#/components/schemas/TimeStampUserData' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + put: + summary: Update the form preferences for current user + description: Updates preferences for the current user specific to this form + operationId: updateUserFormPreferences + tags: + - User + parameters: + - $ref: '#/components/parameters/formIdParam' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/FormPreferences' + responses: + '200': + description: OK + content: + application/json: + schema: + allOf: + - $ref: '#/components/schemas/UserFormPreferences' + - $ref: '#/components/schemas/TimeStampUserData' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + delete: + summary: Delete all form preferences for current user + description: Deletes preferences for the current user specific to this form + operationId: deleteUserFormPreferences + tags: + - User + parameters: + - $ref: '#/components/parameters/formIdParam' + responses: + '204': + description: OK + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /admin/forms: + get: + summary: List all forms in the system + operationId: adminListForms + tags: + - Admin + security: + - BearerAuth: [] + OpenID: + - admin + parameters: + - in: query + name: active + schema: + type: boolean + description: filter forms by active status + example: true + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Form' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /admin/forms/{formId}: + get: + summary: Get top level details of a form + operationId: adminReadForm + tags: + - Admin + security: + - BearerAuth: [] + OpenID: + - admin + parameters: + - $ref: '#/components/parameters/formIdParam' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/FormBasic' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /admin/forms/{formId}/apiKey: + get: + summary: Get Form API Key + description: Get the active api key details for a form + operationId: adminReadApiDetails + tags: + - Admin + security: + - BearerAuth: [] + OpenID: + - admin + parameters: + - $ref: '#/components/parameters/formIdParam' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/FormApiDetails' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + delete: + summary: Delete Form API Key + description: Delete the api key secret for a form + operationId: adminDeleteApiKey + tags: + - Admin + security: + - BearerAuth: [] + OpenID: + - admin + parameters: + - $ref: '#/components/parameters/formIdParam' + responses: + '204': + description: OK + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /admin/forms/{formId}/restore: + put: + summary: Un-delete a soft deleted form + operationId: adminRestoreForm + tags: + - Admin + security: + - BearerAuth: [] + OpenID: + - admin + parameters: + - $ref: '#/components/parameters/formIdParam' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/UserForm' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /admin/forms/{formId}/formUsers: + get: + summary: Get the list of users for the active forms in the system + operationId: adminReadFormUsers + tags: + - Admin + security: + - BearerAuth: [] + OpenID: + - admin + parameters: + - $ref: '#/components/parameters/formIdParam' + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/FormUserList' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /admin/forms/{formId}/addUser: + put: + summary: Add user permissions to a form + operationId: adminAddUser + tags: + - Admin + security: + - BearerAuth: [] + OpenID: + - admin + parameters: + - $ref: '#/components/parameters/formIdParam' + - in: query + name: userId + schema: + type: string + description: The user to add permissions to + required: true + requestBody: + required: true + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/FormRoleUser' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/UserAccess' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /admin/users: + get: + summary: Get the list of users + operationId: adminReadUsers + tags: + - Admin + security: + - BearerAuth: [] + OpenID: + - admin + responses: + '200': + description: OK + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/User' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + /admin/users/{userId}: + get: + summary: Get a user + operationId: adminReadUser + tags: + - Admin + security: + - BearerAuth: [] + OpenID: + - admin + parameters: + - in: path + name: userId + schema: + type: string + example: bea3b705-1de5-4f4e-a4e6-0716b7674132 + description: user ID + required: true + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/User' + '403': + $ref: '#/components/responses/Forbidden' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' +components: + headers: + RateLimit: + schema: + type: string + description: >- + Indicates the remaining number of allowed API calls within the + remaining window. In the example, 18 more requests are allowed + within the 45 seconds that remain in the window. When the window resets + after 45 seconds then the "remaining" will be reset to "limit". + example: limit=20, remaining=18, reset=45 + RateLimit-Policy: + schema: + type: string + description: >- + Indicates how many API calls can be made within a "window" of time. + Additional API calls within the window will result in HTTP 429 + responses. In the example, 20 requests are allowed within a 60 + second window. + example: 20;w=60 + retry-after: + schema: + type: integer + description: >- + Only returned when the rate limit is exceeded (HTTP 429). Indicates the + number of seconds before the window resets, after which API calls will + again be allowed. In the example, 13 seconds remain before the window is + reset. + example: 13 + securitySchemes: + BasicAuth: + type: http + scheme: basic + BearerAuth: + type: http + scheme: bearer + bearerFormat: JWT + OpenID: + type: openIdConnect + openIdConnectUrl: https://example.com/.well-known/openid-configuration + parameters: + fileIdParam: + in: path + name: fileId + schema: + type: string + format: uuid + example: 3cb9acc7-cfd8-4491-b091-1277bc0ec303 + required: true + description: ID of the File + formIdParam: + in: path + name: formId + schema: + type: string + format: uuid + description: ID of the form + required: true + example: c6455376-382c-439d-a811-0381a012d696 + formVersionIdParam: + in: path + name: formVersionId + schema: + type: string + format: uuid + example: a675ab2a-1e88-4fb5-88f9-c7cb051a18b2 + required: true + description: ID of the form version + formVersionDraftIdParam: + in: path + name: formVersionDraftId + schema: + type: string + format: uuid + example: b2e11d09-30fe-4c4c-9375-5a9de0dc2e9e + required: true + description: ID of the draft for form version + formSubmissionIdParam: + in: path + name: formSubmissionId + schema: + type: string + format: uuid + example: 3cb9acc7-cfd8-4491-b091-1277bc0ec303 + required: true + description: ID of the Submission + schemas: + BadRequest: + allOf: + - $ref: '#/components/schemas/Problem' + - type: object + properties: + status: + example: 400 + title: + example: Bad Request + type: + example: https://httpstatuses.com/400 + Conflict: + allOf: + - $ref: '#/components/schemas/Problem' + - type: object + properties: + status: + example: 409 + title: + example: Conflict + type: + example: https://httpstatuses.com/409 + CurrentUser: + type: object + properties: + id: + type: string + description: ID of the user + example: 5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987 + idpUserId: + type: string + description: ID of the user provided by the identity provider + example: ao9rsqw60nvf24pemkdik5e3fmo2kb6l + username: + type: string + description: Username of this user + example: jsmith + firstName: + type: string + example: Jane + fullName: + type: string + example: Jane Smith + lastName: + type: string + example: Smith + email: + type: string + example: jsmith@gov.bc.ca + public: + type: boolean + example: false + EmailMessage: + allOf: + - type: object + properties: + msgid: + type: string + format: uuid + description: ID of message. + example: 1223h78b-21d2-4128-b4e8-02ad3daipoi32 + to: + type: array + items: + type: string + example: jsmith@email.com + description: an array of the message recipients + txId: + type: string + format: uuid + description: Transaction ID returned by a messaging service + example: 7d13b78b-21d2-4128-b4e8-02ad3da17d22 + Error: + allOf: + - $ref: '#/components/schemas/Problem' + - type: object + properties: + status: + example: 500 + title: + example: Internal Server Error + type: + example: https://httpstatuses.com/500 + FileUpload: + type: object + properties: + createdAt: + type: string + example: '2020-06-04T18:49:20.672Z' + createdBy: + type: string + example: jsmith@idir + id: + type: string + format: uuid + example: aeb3b705-1de5-4f4e-a4e6-0716b7671034 + originalName: + type: string + example: hiring_approval_request_form_schema.json + size: + type: integer + description: Size in bytes of the file. + example: 27462 + Form: + allOf: + - $ref: '#/components/schemas/FormBasic' + - $ref: '#/components/schemas/FormWithoutVersions' + - type: object + properties: + versions: + type: array + items: + $ref: '#/components/schemas/FormVersionBasic' + - $ref: '#/components/schemas/TimeStampUserData' + FormApiKey: + allOf: + - type: object + properties: + id: + type: number + example: 4 + formId: + type: string + example: c6455376-382c-439d-a811-0381a012d696 + secret: + type: string + example: dd7d1699-61ec-4037-aa33-727f8aa79c0a + - $ref: '#/components/schemas/TimeStampUserData' + FormApiDetails: + allOf: + - type: object + properties: + id: + type: number + example: 4 + formId: + type: string + example: c6455376-382c-439d-a811-0381a012d696 + - $ref: '#/components/schemas/TimeStampUserData' + FormBasic: + allOf: + - $ref: '#/components/schemas/FormCore' + - type: object + properties: + identityProviders: + type: array + items: + $ref: '#/components/schemas/IdentityProvider' + showSubmissionConfirmation: + type: boolean + example: true + submissionReceivedEmails: + type: array + items: + type: string + example: + - me@email.com + - manager@email.com + enableStatusUpdates: + type: boolean + example: true + enableSubmitterDraft: + type: boolean + example: true + reminder_enabled: + type: boolean + example: true + description: Allow form to send reminder email to all submitters + schedule: + type: object + description: Contains schedule related data + properties: + enabled: + type: boolean + description: Used to indicate if schedule feature enabled or not + example: true + scheduleType: + type: string + description: Shows type of Schedule setting choose by form designed. Could be period,closingDate,manual + example: period + closingMessage: + type: string + description: This string contain custom closing message message set by form designer that shows on frontend when a form is expired for a particular period. + example: This Form is expired. + keepOpenForTerm: + type: string + description: This contain a value that can be used with combination to another key i.e. keepOpenForInterval to calculate a period. Thats tells a form to be keep open for particular period. 40 Days, 3 Weeks, 1 Years etc. + example: '15' + keepOpenForInterval: + type: string + description: This contain a value that can be used with combination to another key i.e. keepOpenForTerm to calculate a period. Thats tells a form to be keep open for particular period. 40 Days, 3 Weeks, 1 Years etc. + example: '15' + repeatSubmission: + type: object + properties: + enabled: + type: boolean + description: Used to indicate if repeatition of scheduling a form enabled or not + example: true + everyTerm: + type: string + description: This contain a value that can be used with combination to another key i.e. everyIntervalType to calculate a period. Thats tells a form to be schedule a form repetition after particular period. 40 Days, 3 Weeks, 1 Years etc. + example: '15' + repeatUntil: + type: string + description: Contains end date for repeatition of form schedule. + example: '2023-12-22' + everyIntervalType: + type: string + description: This contain a value that can be used with combination to another key i.e. everyTerm to calculate a period. Thats tells a form to be schedule a form repetition after particular period. 40 Days, 3 Weeks, 1 Years etc. + example: '15' + allowLateSubmissions: + type: object + properties: + enabled: + type: boolean + description: Used to indicate if late submission allowed on a form or not, Will be true if enabled + example: true + forNext: + type: object + properties: + term: + type: string + description: This contain a value that can be used with combination to another key i.e. intervalType to calculate a period. Thats tells a form to be allowed a late submission for particular period. 40 Days, 3 Weeks, 1 Years etc. + intervalType: + type: string + description: This contain a value that can be used with combination to another key i.e. term to calculate a period. Thats tells a form to be allowed a late submission for particular period. 40 Days, 3 Weeks, 1 Years etc. + closingMessageEnabled: + type: boolean + description: Set to true when custom closing message is enabled + example: true + openSubmissionDateTime: + type: string + description: Contains open date of form schedule system. + example: '2022-12-22' + closeSubmissionDateTime: + type: string + description: Contains closing date of form schedule system when type of ScheduleType set to closingDate. + example: '2022-12-22' + subscribe: + type: object + description: Contains subscription related data - future storage of subscribed events + properties: + enabled: + type: boolean + description: Used to indicate if subscribe feature enabled or not + example: true + enableCopyExistingSubmission: + type: boolean + example: false + FormCore: + type: object + properties: + name: + type: string + example: My Survey Form + description: + type: string + example: I built this survey form. It is amazing. + FormDraft: + allOf: + - type: object + properties: + id: + type: string + example: aeb3b705-1de5-4f4e-a4e6-0716b7671034 + formId: + type: string + format: uuid + description: ID of the form + example: aeb3b705-1de5-4f4e-a4e6-0716b7671034 + formVersionId: + type: string + format: uuid + description: ID of the FormVersion this submission is for. + example: a675ab2a-1e88-4fb5-88f9-c7cb051a18b2 + - $ref: '#/components/schemas/FormSchema' + - $ref: '#/components/schemas/TimeStampUserData' + FormWithoutVersions: + allOf: + - $ref: '#/components/schemas/FormBasic' + - type: object + properties: + id: + type: string + example: aeb3b705-1de5-4f4e-a4e6-0716b7671034 + active: + type: boolean + example: true + labels: + type: array + example: + - Survey + items: + type: string + snake: + type: string + example: my-survey-form + - $ref: '#/components/schemas/TimeStampUserData' + FormOptions: + allOf: + - $ref: '#/components/schemas/FormCore' + - type: object + properties: + id: + type: string + example: aeb3b705-1de5-4f4e-a4e6-0716b7671034 + idpHints: + type: array + example: + - idir + items: + type: string + snake: + type: string + example: my-survey-form + FormRoleUser: + type: object + properties: + formId: + type: string + format: uuid + description: ID of form + example: aeb3b705-1de5-4f4e-a4e6-0716b7671034 + role: + type: string + description: code of role + example: team_manager + userId: + type: string + description: ID of user + example: aeb3b705-1de5-4f4e-a4e6-0716b7671034 + FormSchema: + allOf: + - type: object + properties: + schema: + type: object + description: this is the json for the form design. + example: + display: form + type: form + components: + - type: textfield + key: firstName + label: First Name + placeholder: Enter your first name. + input: true + tooltip: Enter your First Name + description: Enter your First Name + - type: textfield + key: lastName + label: Last Name + placeholder: Enter your last name. + input: true + tooltip: Enter your Last Name + description: Enter your Last Name + FormSubmission: + allOf: + - $ref: '#/components/schemas/FormSubmissionBasic' + - $ref: '#/components/schemas/FormSubmissionCore' + - type: object + properties: + confirmationId: + type: string + description: shortend version of the id, useful for visual representation + example: AEB3B705 + deleted: + type: boolean + description: Used to indicate a soft delete. + example: false + FormSubmissionBasic: + allOf: + - type: object + properties: + draft: + type: boolean + description: >- + Used to indicate if submission came from a draft version of a + form. + example: false + submission: + type: object + description: this is the json for the form submission. + - $ref: '#/components/schemas/TimeStampUserData' + FormSubmissionObjectForMultipleUpload: + allOf: + - type: object + description: this is the json for the form submission. + FormSubmissionResponseMultiple: + allOf: + - type: array + items: + - type: object + properties: + draft: + type: boolean + description: >- + Used to indicate if submission came from a draft version of a + form. + example: false + submission: + type: object + description: this object should contain one property named data as an array. This array named data should store all the multiple drafts as object in this array. + properties: + data: + type: array + items: + $ref: '#/components/schemas/FormSubmissionObjectForMultipleUpload' + description: this is an array of multiple objects, each object contain data of single the form submissions. + FormSubmissionMultiple: + allOf: + - type: object + properties: + draft: + type: boolean + description: >- + Used to indicate if submission came from a draft version of a + form. + example: false + submission: + type: object + description: this object should contain one property named data as an array. This array named data should store all the multiple drafts as object in this array. + properties: + data: + type: array + items: + $ref: '#/components/schemas/FormSubmissionObjectForMultipleUpload' + description: this is an array of multiple objects, each object contain data of single the form submissions. + FormSubmissionCore: + type: object + properties: + id: + type: string + example: c0822716-01f5-43e6-b4d4-ffcacd13aae3 + formVersionId: + type: string + description: ID of the FormVersion this submission is for. + example: b6908dd4-2f01-4e08-831d-921edae99ca3 + FormSubmissionDeleted: + allOf: + - $ref: '#/components/schemas/FormSubmission' + - type: object + properties: + deleted: + type: boolean + description: Used to indicate a soft delete. + example: true + FormSubmissionDiscover: + type: object + properties: + id: + type: string + example: aeb3b705-1de5-4f4e-a4e6-0716b7671034 + example: + id: aeb3b705-1de5-4f4e-a4e6-0716b7671034 + textField1: foo + checkbox1: bar + radioGroup1: baz + email1: test@email.com + FormSubmissionExport: + allOf: + - type: object + properties: + form: + type: object + properties: + confirmationId: + type: string + description: shortend version of the id, useful for visual representation + example: AEB3B705 + formName: + type: string + description: The title of the form + example: My Survey Form + username: + type: string + description: Username of this user + example: jsmith + fullName: + type: string + example: Jane Smith + email: + type: string + example: jsmith@gov.bc.ca + version: + type: integer + description: The version number of the form for a submission + example: 1 + createdAt: + type: string + example: '2020-06-04T18:49:20.672Z' + formFieldA: + type: string + description: A field in the submission object + formFieldB: + type: string + description: A field in the submission object + FormSubmissionExportWithFields: + allOf: + - type: object + properties: + format: + type: string + description: Chosen file type for the submission data exported + example: csv + template: + type: string + description: Chosen CSV format for the submission data exported + example: multiRowEmptySpacesCSVExport + version: + type: integer + description: The version number of the form for the submission data exported + example: 1 + type: + type: string + description: default value is submissions and should be changed + example: submissions + preference: + type: object + description: form submissions export preferences + example: { minDate, maxDate } + fields: + type: array + description: List of form submission fields to be exported to CSV + example: + - form.confirmationId, + - form.formName, + - form.version, + - form.createdAt, + - form.fullName, + - form.username, + - form.email, + - form.status, + - form.assignee, + - form.assigneeEmail, + - fishermansName, + - email, + - forWhichBcLakeRegionAreYouCompletingTheseQuestions, + - didYouFishAnyBcLakesThisYear, + - oneRowPerLake, + - oneRowPerLake.lakeName, + - oneRowPerLake.closestTown, + - oneRowPerLake.numberOfDays, + - oneRowPerLake.dataGrid, + - oneRowPerLake.dataGrid.fishType, + - oneRowPerLake.dataGrid.numberCaught, + - oneRowPerLake.dataGrid.numberKept + emailExport: + type: boolean + description: This parameter should be set to true if the form submissions are large (e.g. above 500) or the form is big + example: false + FormSubmissionSummary: + allOf: + - type: object + properties: + textField1: + type: string + example: >- + the contents of the field called 'textField1' from the 'fields' + query param + submissionId: + type: string + example: aeb3b705-1de5-4f4e-a4e6-0716b7671034 + formId: + type: string + format: uuid + description: ID of the form this submission is for. + example: bea3b705-1de5-4f4e-a4e6-0716b7674132 + formName: + type: string + description: The title of the form + example: My Survey Form + formVersionId: + type: string + description: ID of the FormVersion this submission is for. + example: a675ab2a-1e88-4fb5-88f9-c7cb051a18b2 + confirmationId: + type: string + description: shortend version of the id, useful for visual representation + example: AEB3B705 + deleted: + type: boolean + description: Used to indicate a soft delete. + example: false + draft: + type: boolean + description: >- + Used to indicate if submission came from a draft version of a + form. + example: false + version: + type: integer + description: The version number of the form for a submission + example: 1 + - $ref: '#/components/schemas/TimeStampUserData' + FormUserList: + allOf: + - type: object + properties: + id: + type: string + example: aeb3b705-1de5-4f4e-a4e6-0716b7671034 + name: + type: string + example: My Survey Form. + users: + type: array + items: + $ref: '#/components/schemas/UserFormBasic' + FormVersion: + allOf: + - $ref: '#/components/schemas/FormVersionBasic' + - $ref: '#/components/schemas/FormSchema' + FormVersionBasic: + allOf: + - $ref: '#/components/schemas/FormVersionCore' + - type: object + properties: + version: + type: integer + example: 1 + published: + type: boolean + example: true + - $ref: '#/components/schemas/TimeStampUserData' + FormVersionCore: + type: object + properties: + id: + type: string + example: b6908dd4-2f01-4e08-831d-921edae99ca3 + formId: + type: string + format: uuid + description: ID of the form + example: aeb3b705-1de5-4f4e-a4e6-0716b7671034 + FormVersionFields: + type: array + example: + - textField1 + - checkbox1 + - radioGroup1 + - email1 + items: + type: string + IdentityProvider: + allOf: + - type: object + properties: + code: + type: string + example: idir + display: + type: string + example: IDIR + idp: + type: string + description: >- + The identity_provider a user logs in with. Allows us to + determine what source authenticated the user. + example: idir + active: + type: boolean + example: true + - $ref: '#/components/schemas/TimeStampUserData' + Note: + type: object + properties: + submissionId: + type: string + example: aeb3b705-1de5-4f4e-a4e6-0716b7671034 + submissionStatusId: + type: string + example: aeb3b705-1de5-4f4e-a4e6-0716b7671034 + note: + type: string + example: >- + 'This is a note that can be up to 4000 characters I add to the + submission and can link to an individual status id' + NotFound: + allOf: + - $ref: '#/components/schemas/Problem' + - type: object + properties: + status: + example: 404 + title: + example: Not Found + type: + example: https://httpstatuses.com/404 + PermissionBasic: + allOf: + - type: object + properties: + code: + type: string + example: design_update + display: + type: string + description: The permission name + example: Design Update + description: + type: string + example: Can edit/update the form design + active: + type: boolean + example: true + - $ref: '#/components/schemas/TimeStampUserData' + Permission: + allOf: + - $ref: '#/components/schemas/PermissionBasic' + - type: object + properties: + roles: + type: array + items: + $ref: '#/components/schemas/RoleBasic' + Problem: + required: + - type + - title + - status + - detail + properties: + type: + type: string + description: What type of problem, link to explanation of problem + title: + type: string + description: Title of problem, generally the Http Status Code description + status: + type: string + description: The Http Status code + detail: + type: string + description: short description of why this problem was raised. + Role: + allOf: + - $ref: '#/components/schemas/RoleBasic' + - type: object + properties: + permissions: + type: array + items: + $ref: '#/components/schemas/PermissionBasic' + RoleBasic: + allOf: + - type: object + properties: + code: + type: string + example: form_designer + display: + type: string + description: The role name + example: Form Designer + description: + type: string + example: Designs the form + active: + type: boolean + example: true + - $ref: '#/components/schemas/TimeStampUserData' + StatusCodes: + allOf: + - type: object + properties: + id: + type: string + example: aeb3b705-1de5-4f4e-a4e6-0716b7671034 + formId: + type: string + example: ccb5b715-1de5-4f4e-a4e6-0716b7671034 + code: + type: string + example: COMPLETED + statusCode: + type: object + properties: + code: + type: string + example: COMPLETED + display: + type: string + example: Completed + nextCodes: + type: array + example: + - ASSIGNED + - COMPLETED + items: + type: string + - $ref: '#/components/schemas/TimeStampUserData' + SubmissionEditMetadata: + type: object + properties: + id: + type: integer + example: 5 + updatedByUsername: + type: string + example: jsmith + actionTimestamp: + type: string + example: '2020-06-04T18:49:20.672Z' + action: + type: string + example: U + SubmissionFormVersion: + type: object + properties: + submission: + $ref: '#/components/schemas/FormSubmission' + version: + $ref: '#/components/schemas/FormVersion' + form: + $ref: '#/components/schemas/Form' + SubmissionFormVersionDeleted: + type: object + properties: + submission: + $ref: '#/components/schemas/FormSubmissionDeleted' + version: + $ref: '#/components/schemas/FormVersion' + form: + $ref: '#/components/schemas/FormWithoutVersions' + SubmissionFormVersionOptions: + type: object + properties: + submission: + $ref: '#/components/schemas/FormSubmissionCore' + version: + $ref: '#/components/schemas/FormVersionCore' + form: + $ref: '#/components/schemas/FormOptions' + SubmissionStatus: + type: object + required: + - code + properties: + code: + type: string + description: |- + Status code to assign. Check the `/forms/{formId}/statusCodes` endpoint for valid + codes. + example: ASSIGNED + assignedToUserId: + type: string + description: Optional UserID assignment. Only applicable when `code` is `ASSIGNED`. + example: ccb5b715-1de5-4f4e-a4e6-0716b7671034 + assignmentNotificationEmail: + type: string + description: |- + Optional email for dispatching assignment notifications. If this property is falsy, no notification will be sent. + example: jsmith@gov.bc.ca + actionDate: + type: string + description: |- + Optional time this status comes into effect. Defaults to now if unspecified. + example: '2020-06-04T18:49:20.672Z' + submissionUserEmail: + type: string + description: |- + Optional email address for dispatching an email notification to the submitter. If this property is falsy, no notification will be sent. + example: bsmith@gov.bc.ca + revisionNotificationEmailContent: + type: string + description: |- + Optional revision request email content. This plaintext string will be added to the revision requests email body contents. + example: foo bar + SubmissionStatusHistory: + allOf: + - type: object + properties: + id: + type: string + example: aeb3b705-1de5-4f4e-a4e6-0716b7671034 + submissionId: + type: string + example: ccb5b715-1de5-4f4e-a4e6-0716b7671034 + code: + type: string + example: COMPLETED + assignedToUserId: + type: string + example: dda7a123-1de5-4f4e-a4e6-0716b7671034 + actionDate: + type: string + example: '2020-06-04T18:49:20.672Z' + user: + $ref: '#/components/schemas/User' + - $ref: '#/components/schemas/TimeStampUserData' + TemplateRenderObject: + type: object + properties: + options: + type: object + description: Object containing processing options + properties: + convertTo: + type: string + description: >- + The desired file extension of the generated document, used for + converting to other types of document. If not supplied, will + just use the original contentFileType. + example: pdf + reportName: + type: string + description: >- + The desired file name of the generated document, can accept + template substitution fields from the contexts. If not supplied, + will use a random UUID. Extension will be from convertTo. + example: abc_123_{d.firstName}_{d.lastName} + TimeStampUserData: + type: object + properties: + createdBy: + type: string + example: bsmith@idir + createdAt: + type: string + example: '2020-06-04T18:49:20.672Z' + updatedBy: + type: string + example: jsmith@idir + updatedAt: + type: string + example: '2020-06-05T11:27:15.853Z' + User: + allOf: + - type: object + properties: + id: + type: string + description: ID of the user + example: 5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987 + idpUserId: + type: string + description: ID of the user in the external identity provider system + example: ao9rsqw60nvf24pemkdik5e3fmo2kb6l + username: + type: string + description: Username of this user + example: jsmith + firstName: + type: string + example: Jane + fullName: + type: string + example: Jane Smith + lastName: + type: string + example: Smith + email: + type: string + example: jsmith@gov.bc.ca + idpCode: + type: string + example: idir + - $ref: '#/components/schemas/TimeStampUserData' + UserAccess: + type: object + properties: + userId: + type: string + description: ID of the user + example: 5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987 + idpUserId: + type: string + description: ID of the user in the external identity provider system + example: ao9rsqw60nvf24pemkdik5e3fmo2kb6l + username: + type: string + description: Username of this user + example: jsmith + firstName: + type: string + example: Jane + fullName: + type: string + example: Jane Smith + lastName: + type: string + example: Smith + email: + type: string + example: jsmith@gov.bc.ca + formId: + type: string + format: uuid + description: ID of the form + example: 5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987 + formName: + type: string + example: jsmith@gov.bc.ca + labels: + type: array + example: + - Survey + items: + type: string + active: + type: boolean + example: true + identityProviders: + type: array + description: the Identity Provider code associated with this form + example: + - bceid + - idir + items: + type: string + idps: + type: array + description: the Identity Provider idps associated with this form + example: + - bceid + - idir + items: + type: string + formVersionId: + type: string + description: ID of the current form version + example: a675ab2a-1e88-4fb5-88f9-c7cb051a18b2 + version: + type: integer + description: Number of the current form version + example: 1 + published: + type: boolean + example: true + versionUpdatedAt: + type: string + description: when latest form version was last updated + example: '2020-06-04T18:49:20.672Z' + roles: + type: array + description: the role codes this user has on this form + example: + - owner + - team_manager + items: + type: string + permissions: + type: array + description: the permission codes this user has on this form + example: + - design_update + - submission_create + items: + type: string + UserAccessSubmission: + type: object + properties: + active: + type: boolean + example: true + confirmationId: + type: string + example: 5DAD1EC9 + createdAt: + type: string + example: '2020-06-04T18:49:20.672Z' + description: + type: string + example: A BC Hunting licence application + draft: + type: boolean + example: true + enableStatusUpdates: + type: boolean + example: true + enableSubmitterDraft: + type: boolean + example: true + formId: + type: string + example: 5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987 + formSubmissionId: + type: string + example: 6dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987 + name: + type: string + example: Licence Application + permissions: + type: array + description: the permission codes this user has on this form + example: + - submission_delete + - submission_create + items: + type: string + user: + $ref: '#/components/schemas/User' + userId: + type: string + example: 7dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987 + UserForm: + type: object + properties: + formId: + type: string + format: uuid + description: ID of the form + example: 5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987 + formName: + type: string + example: jsmith@gov.bc.ca + labels: + type: array + example: + - Form + items: + type: string + idps: + type: array + description: the Identity Provider code associated with this form + example: + - bceid + - idir + items: + type: string + active: + type: boolean + example: true + formVersionId: + type: string + description: ID of the current form version + example: a675ab2a-1e88-4fb5-88f9-c7cb051a18b2 + version: + type: integer + description: Number of the current form version + example: 1 + roles: + type: array + description: the role codes this user has on this form + example: + - owner + - team_manager + items: + type: string + permissions: + type: array + description: the permission codes this user has on this form + example: + - design_update + - submission_create + items: + type: string + UserFormBasic: + type: object + properties: + userId: + type: string + format: uuid + description: ID of the user + example: 5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987 + username: + type: string + example: jsmith + roles: + type: array + description: the role codes this user has on this form + example: + - owner + - team_manager + items: + type: string + FormPreferences: + type: object + description: Form level user preferences + properties: + columnList: + type: array + description: A list of desired columns to show + example: + - foo + - bar + items: + type: string + UserFormPreferences: + type: object + properties: + userId: + type: string + format: uuid + description: ID of the user + example: 5dad1ec9-d3c0-4b0f-8ead-cb4d9fa98987 + formId: + type: string + format: uuid + description: ID of the form + example: a675ab2a-1e88-4fb5-88f9-c7cb051a18b2 + preferences: + $ref: '#/components/schemas/FormPreferences' + UserPreferences: + type: object + properties: + forms: + type: array + description: A list of form specific preferences + items: + $ref: '#/components/schemas/UserFormPreferences' + preferences: + type: object + description: CHEFS app level user preferences + example: {} + UserSubmission: + type: object + properties: + active: + type: boolean + description: If the submission is active + example: true + confirmationId: + type: string + description: The submission's Confirmation ID + example: B6F3E0EB + createdAt: + type: string + example: '2020-06-04T18:49:20.672Z' + description: + type: string + description: The form description + example: A form that allows a user to fill out a survey + enableStatusUpdates: + type: boolean + description: If the form uses status flow + example: true + enableSubmitterDraft: + type: boolean + description: If the form's submissions can be saved as draft + example: true + formId: + type: string + format: uuid + description: ID of the form + example: d9249b52-d97c-4d28-90e3-a39a94c847ea + formSubmissionId: + type: string + format: uuid + description: ID of the submission + example: b6f3e0eb-52e5-4c02-833e-d514e4610d1f + name: + type: string + description: The form name + example: NR survey form + permissions: + type: array + description: the permission codes this user has on this submission + example: + - submission_create + - submission_read + - submission_delete + - submission_update + items: + type: string + submissionStatus: + type: array + description: the permission codes this user has on this submission + items: + $ref: '#/components/schemas/SubmissionStatus' + userId: + type: string + format: uuid + description: ID of the user + example: b6f3e0eb-52e5-4c02-833e-d514e4610d1f + version: + type: integer + description: The version number of the form for a submission + example: 1 + ValidationError: + allOf: + - $ref: '#/components/schemas/Problem' + - type: object + required: + - errors + properties: + errors: + type: array + items: + type: object + required: + - message + properties: + value: + type: object + description: Contents of the field that was in error. + example: utf-8x + message: + type: string + description: The error message for the field. + example: Invalid value `encoding`. + status: + example: 422 + title: + example: Unprocessable Entity + type: + example: https://httpstatuses.com/422 + responses: + Accepted: + description: Accepted + BadRequest: + description: Request is missing content or is malformed + content: + application/json: + schema: + $ref: '#/components/schemas/BadRequest' + Conflict: + description: Request conflicts with server state + content: + application/json: + schema: + $ref: '#/components/schemas/Conflict' + Error: + description: Unexpected error + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + Forbidden: + description: Lack required role to perform action + NoContent: + description: Accepted and no content + NotFound: + description: Not found + content: + application/json: + schema: + $ref: '#/components/schemas/NotFound' + TooManyRequests: + description: BasicAuth request exceeds rate limiting + headers: + RateLimit: + $ref: '#/components/headers/RateLimit' + RateLimit-Policy: + $ref: '#/components/headers/RateLimit-Policy' + retry-after: + $ref: '#/components/headers/retry-after' + UnauthorizedError: + description: Invalid authorization credentials + UnprocessableEntity: + description: >- + The server was unable to process the contained instructions. Generally + validation error(s). + content: + application/json: + schema: + $ref: '#/components/schemas/ValidationError' diff --git a/frontend/app/src/forms/admin/controller.js b/frontend/app/src/forms/admin/controller.js new file mode 100644 index 0000000..eb529c6 --- /dev/null +++ b/frontend/app/src/forms/admin/controller.js @@ -0,0 +1,144 @@ +const Problem = require('api-problem'); +const service = require('./service'); +const formService = require('../form/service'); +const rbacService = require('../rbac/service'); + +module.exports = { + // + // Forms + // + deleteApiKey: async (req, res, next) => { + try { + const response = await formService.deleteApiKey(req.params.formId); + res.status(204).json(response); + } catch (error) { + next(error); + } + }, + listForms: async (req, res, next) => { + try { + const response = await service.listForms(req.query); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + readDraft: async (req, res, next) => { + try { + const response = await service.readDraft(req.params.formVersionDraftId); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + readForm: async (req, res, next) => { + try { + const response = await service.readForm(req.params.formId); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + readVersion: async (req, res, next) => { + try { + const response = await service.readVersion(req.params.formVersionId); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + readApiDetails: async (req, res, next) => { + try { + const response = await formService.readApiKey(req.params.formId); + if (response) { + delete response.secret; + } + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + restoreForm: async (req, res, next) => { + try { + const response = await service.restoreForm(req.params.formId); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + + // + // Users + // + getUsers: async (req, res, next) => { + try { + const response = await service.getUsers(req.query); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + getFormUserRoles: async (req, res, next) => { + try { + const response = await service.getFormUserRoles(req.params.formId); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + + // + // Form Components Help Information + // + createFormComponentsProactiveHelp: async (req, res, next) => { + try { + const response = await service.createFormComponentsProactiveHelp(req.body); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + + updateFormComponentsProactiveHelp: async (req, res, next) => { + try { + const response = await service.updateFormComponentsProactiveHelp(req.params); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + + getFCProactiveHelpImageUrl: async (req, res, next) => { + try { + const response = await service.getFCProactiveHelpImageUrl(req.params.componentId); + res.status(200).send(response); + } catch (error) { + next(error); + } + }, + setFormUserRoles: async (req, res, next) => { + try { + // Safety guard that this admin call isn't ever used without a form or user id + if (!req.params.formId || !req.query.userId) { + return next( + new Problem(422, { + detail: 'Must supply userId and formId', + }) + ); + } + const response = await rbacService.setFormUsers(req.params.formId, req.query.userId, req.body, req.currentUser); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + + listFormComponentsProactiveHelp: async (req, res, next) => { + try { + const response = await service.listFormComponentsProactiveHelp(); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, +}; diff --git a/frontend/app/src/forms/admin/fileService.js b/frontend/app/src/forms/admin/fileService.js new file mode 100644 index 0000000..bf9b189 --- /dev/null +++ b/frontend/app/src/forms/admin/fileService.js @@ -0,0 +1,13 @@ +const storageService = require('../file/storage/storageService'); + +const fileService = { + create: async (imageData) => { + return await storageService.uploadImage(imageData); + }, + + signedUrl: async (param) => { + return await storageService.readSignedUrl(param.imageName); + }, +}; + +module.exports = fileService; diff --git a/frontend/app/src/forms/admin/index.js b/frontend/app/src/forms/admin/index.js new file mode 100644 index 0000000..3d69372 --- /dev/null +++ b/frontend/app/src/forms/admin/index.js @@ -0,0 +1,7 @@ +const dataErrors = require('../common/middleware').dataErrors; +const routes = require('./routes'); +const setupMount = require('../common/utils').setupMount; + +module.exports.mount = (app) => { + return setupMount('admin', app, routes, dataErrors); +}; diff --git a/frontend/app/src/forms/admin/routes.js b/frontend/app/src/forms/admin/routes.js new file mode 100644 index 0000000..735a7f5 --- /dev/null +++ b/frontend/app/src/forms/admin/routes.js @@ -0,0 +1,84 @@ +const config = require('config'); +const routes = require('express').Router(); + +const currentUser = require('../auth/middleware/userAccess').currentUser; + +const controller = require('./controller'); +const userController = require('../user/controller'); +const keycloak = require('../../components/keycloak'); + +// Always have this applied to all routes here +routes.use(keycloak.protect(`${config.get('server.keycloak.clientId')}:admin`)); +routes.use(currentUser); + +// Routes under the /admin pathing will fetch data without doing Form permission checks in the database +// As such, this should ALWAYS remain under the :admin role check and that KC role should not be given out +// other than to people who have permission to read all data + +// +// Forms +// +routes.get('/forms', async (req, res, next) => { + await controller.listForms(req, res, next); +}); + +routes.get('/forms/:formId', async (req, res, next) => { + await controller.readForm(req, res, next); +}); + +routes.delete('/forms/:formId/apiKey', async (req, res, next) => { + await controller.deleteApiKey(req, res, next); +}); + +routes.get('/forms/:formId/apiKey', async (req, res, next) => { + await controller.readApiDetails(req, res, next); +}); + +routes.put('/forms/:formId/restore', async (req, res, next) => { + await controller.restoreForm(req, res, next); +}); + +routes.get('/forms/:formId/versions/:formVersionId', async (req, res, next) => { + await controller.readVersion(req, res, next); +}); + +routes.get('/forms/:formId/formUsers', async (req, res, next) => { + await controller.getFormUserRoles(req, res, next); +}); + +routes.put('/forms/:formId/addUser', async (req, res, next) => { + await controller.setFormUserRoles(req, res, next); +}); + +// +// Users +// +routes.get('/users', async (req, res, next) => { + await controller.getUsers(req, res, next); +}); + +routes.get('/users/:userId', async (req, res, next) => { + await userController.read(req, res, next); +}); + +// +//Form componets help info +// + +routes.post('/formcomponents/proactivehelp/object', async (req, res, next) => { + await controller.createFormComponentsProactiveHelp(req, res, next); +}); + +routes.put('/formcomponents/proactivehelp/:publishStatus/:componentId', async (req, res, next) => { + await controller.updateFormComponentsProactiveHelp(req, res, next); +}); + +routes.get('/formcomponents/proactivehelp/imageUrl/:componentId', async (req, res, next) => { + await controller.getFCProactiveHelpImageUrl(req, res, next); +}); + +routes.get('/formcomponents/proactivehelp/list', async (req, res, next) => { + await controller.listFormComponentsProactiveHelp(req, res, next); +}); + +module.exports = routes; diff --git a/frontend/app/src/forms/admin/service.js b/frontend/app/src/forms/admin/service.js new file mode 100644 index 0000000..9047e64 --- /dev/null +++ b/frontend/app/src/forms/admin/service.js @@ -0,0 +1,274 @@ +const { Form, FormVersion, User, UserFormAccess, FormComponentsProactiveHelp } = require('../common/models'); +const { queryUtils } = require('../common/utils'); +const { v4: uuidv4 } = require('uuid'); + +const service = { + // + // Forms + // + + /** + * @function listForms + * List all the forms in CHEFS + * @param {Object} params The query params. Specify 'active' bool to control active/deleted + * @returns {Promise} An objection query promise + */ + listForms: async (params) => { + params = queryUtils.defaultActiveOnly(params); + return Form.query() + .modify('filterActive', params.active) + .allowGraph('[identityProviders,versions]') + .withGraphFetched('identityProviders(orderDefault)') + .withGraphFetched('versions(selectWithoutSchema, orderVersionDescending)') + .modify('orderNameAscending'); + }, + + /** + * @function readVersion + * Find a form version entry + * @param {String} formVersionId The version Id + * @returns {Promise} An objection query promise + */ + readVersion: (formVersionId) => { + return FormVersion.query().findById(formVersionId).throwIfNotFound(); + }, + + /** + * @function readForm + * Find a form entry + * @param {String} formId The form Id + * @returns {Promise} An objection query promise + */ + readForm: async (formId) => { + return Form.query() + .findById(formId) + .withGraphFetched('identityProviders(orderDefault)') + .withGraphFetched('versions(selectWithoutSchema, orderVersionDescending)') + .throwIfNotFound(); + }, + + /** + * @function restoreForm + * Reactivate a soft-deleted form + * @param {String} formId The form Id + * @returns {Object} The form entry after the restore + */ + restoreForm: async (formId) => { + let trx; + try { + const obj = await service.readForm(formId); + trx = await Form.startTransaction(); + const upd = { + active: true, + updatedBy: 'ADMIN', + }; + + await Form.query(trx).patchAndFetchById(formId, upd); + + await trx.commit(); + const result = await service.readForm(obj.id); + return result; + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, + + // + // Users + // + + /** + * @function getUsers + * Search for users + * @param {Object} params The query parameters + * @returns {Promise} An objection query promise + */ + getUsers: async (params) => { + return User.query() + .modify('filterUsername', params.username) + .modify('filterFirstName', params.firstName) + .modify('filterLastName', params.lastName) + .modify('filterEmail', params.email) + .modify('orderLastFirstAscending'); + }, + + /** + * @function getFormUserRoles + * For the given form, return users that have roles for that form + * @param {String} formId The form ID + * @returns {Promise} An objection query promise + */ + getFormUserRoles: async (formId) => { + const formAccess = await UserFormAccess.query().modify('filterFormId', formId).modify('orderDefault'); + return ( + formAccess + // grab all users that have roles on this form + .filter((fa) => fa.roles.length) + // do a quick transform into a simple structure. + .map((fa) => ({ + userId: fa.userId, + idpUserId: fa.idpUserId, + username: fa.username, + email: fa.email, + roles: fa.roles, + })) + ); + }, + + /** + * @function createFormComponentsProactiveHelp + * insert each Form Component Help Info + * @param {Object} data Form Component Help Info object + * @returns {Promise} An objection query promise + */ + createFormComponentsProactiveHelp: async (data) => { + let trx; + try { + trx = await FormComponentsProactiveHelp.startTransaction(); + + let id = data && data.componentId; + + let buf, imageType; + if (data.image !== '') { + buf = data.image.split(',')[1]; + imageType = data.image.split(';')[0].split(':')[1]; + } + + if (id) { + await FormComponentsProactiveHelp.query(trx).patchAndFetchById(data.componentId, { + componentName: data && data.componentName, + externalLink: data && data.externalLink, + image: buf, + imageType: imageType, + componentImageName: data && data.imageName, + groupName: data && data.groupName, + isLinkEnabled: data && data.isLinkEnabled, + description: data && data.description, + publishStatus: data && data.status, + createdBy: 'ADMIN', + }); + } else { + const obj = {}; + id = uuidv4(); + obj.id = id; + obj.componentName = data && data.componentName; + obj.externalLink = data && data.externalLink; + obj.image = buf; + obj.componentImageName = data && data.imageName; + (obj.imageType = imageType), (obj.groupName = data && data.groupName); + obj.isLinkEnabled = data && data.isLinkEnabled; + obj.description = data && data.description; + obj.publishStatus = data && data.status; + obj.createdBy = 'ADMIN'; + await FormComponentsProactiveHelp.query(trx).insert(obj); + } + await trx.commit(); + return service.readFormComponentsProactiveHelp(id); + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, + + /** + * @function readFormComponentsProactiveHelp + * fetch all Components proactive/Help Info + * @returns {Promise} An objection query promise + */ + + readFormComponentsProactiveHelp: async () => { + const result = await FormComponentsProactiveHelp.query().modify('selectWithoutImages'); + if (result.length > 0) { + let filterResult = result.map((item) => { + return { + id: item.id, + status: item.publishStatus, + componentName: item.componentName, + externalLink: item.externalLink, + version: item.version, + groupName: item.groupName, + description: item.description, + isLinkEnabled: item.isLinkEnabled, + imageName: item.componentImageName, + }; + }); + + return filterResult.reduce(function (r, a) { + r[a.groupName] = r[a.groupName] || []; + r[a.groupName].push(a); + return r; + }, Object.create(null)); + } + return {}; + }, + + /** + * @function getFCProactiveHelpImageUrl + * get form component proactive help image + * @param {Object} param consist of publishStatus and componentId. + * @returns {Promise} An objection query promise + */ + getFCProactiveHelpImageUrl: async (componentId) => { + let result = []; + result = await FormComponentsProactiveHelp.query().modify('findByComponentId', componentId); + let item = result.length > 0 ? result[0] : null; + let imageUrl = item !== null ? 'data:' + item.imageType + ';' + 'base64' + ',' + item.image : ''; + return { url: imageUrl }; + }, + + /** + * @function updateFormComponentsProactiveHelp + * update the publish status of each form component information help information + * @param {Object} param consist of publishStatus and componentId. + * @returns {Promise} An objection query promise + */ + updateFormComponentsProactiveHelp: async (param) => { + let trx; + try { + trx = await FormComponentsProactiveHelp.startTransaction(); + await FormComponentsProactiveHelp.query(trx).patchAndFetchById(param.componentId, { + publishStatus: JSON.parse(param.publishStatus), + updatedBy: 'ADMIN', + }); + await trx.commit(); + return await service.readFormComponentsProactiveHelp(param.componentId); + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, + + /** + * @function listFormComponentsProactiveHelp + * Search for all form components help information + * @returns {Promise} An objection query promise + */ + listFormComponentsProactiveHelp: async () => { + let result = []; + result = await FormComponentsProactiveHelp.query().modify('selectWithoutImages'); + if (result.length > 0) { + let filterResult = result.map((item) => { + return { + id: item.id, + status: item.publishStatus, + componentName: item.componentName, + externalLink: item.externalLink, + version: item.version, + groupName: item.groupName, + description: item.description, + isLinkEnabled: item.isLinkEnabled, + imageName: item.componentImageName, + }; + }); + return await filterResult.reduce(function (r, a) { + r[a.groupName] = r[a.groupName] || []; + r[a.groupName].push(a); + return r; + }, Object.create(null)); + } + return {}; + }, +}; + +module.exports = service; diff --git a/frontend/app/src/forms/auth/middleware/apiAccess.js b/frontend/app/src/forms/auth/middleware/apiAccess.js new file mode 100644 index 0000000..cd2623a --- /dev/null +++ b/frontend/app/src/forms/auth/middleware/apiAccess.js @@ -0,0 +1,54 @@ +const Problem = require('api-problem'); +const basicAuth = require('express-basic-auth'); +const { validate: uuidValidate } = require('uuid'); + +const formService = require('../../form/service'); +const submissionService = require('../../submission/service'); + +module.exports = async (req, res, next) => { + try { + // Check if authorization header is basic auth + if (req.headers && req.headers.authorization && req.headers.authorization.startsWith('Basic ')) { + // URL params should override query string params of the same attribute + const params = { ...req.query, ...req.params }; + + // Basic auth is currently only used for form and submission endpoints. Use + // the formId if it exists, otherwise fetch the formId from the submission's + // form. + let formId; + if (params.formId) { + formId = params.formId; + } else if (params.formSubmissionId && uuidValidate(params.formSubmissionId)) { + const result = await submissionService.read(params.formSubmissionId); + formId = result?.form?.id; + } + + let secret = ''; // Must be initialized as a string + + if (formId && uuidValidate(formId)) { + const result = await formService.readApiKey(formId); + secret = result && result.secret ? result.secret : ''; + } + + const checkCredentials = basicAuth({ + // Must be a synchronous function + authorizer: (username, password) => { + const userMatch = formId && basicAuth.safeCompare(username, formId); + const pwMatch = secret && basicAuth.safeCompare(password, secret); + + req.apiUser = userMatch & pwMatch; // Flag current request as an API entity + return req.apiUser; + }, + unauthorizedResponse: () => { + return new Problem(401, { detail: 'Invalid authorization credentials.' }); + }, + }); + + return checkCredentials(req, res, next); + } else { + next(); + } + } catch (error) { + next(error); + } +}; diff --git a/frontend/app/src/forms/auth/middleware/userAccess.js b/frontend/app/src/forms/auth/middleware/userAccess.js new file mode 100644 index 0000000..9e3c01c --- /dev/null +++ b/frontend/app/src/forms/auth/middleware/userAccess.js @@ -0,0 +1,338 @@ +const Problem = require('api-problem'); +const { validate } = require('uuid'); + +const keycloak = require('../../../components/keycloak'); +const Permissions = require('../../common/constants').Permissions; +const Roles = require('../../common/constants').Roles; +const service = require('../service'); +const rbacService = require('../../rbac/service'); + +const getToken = (req) => { + try { + return req.kauth.grant.access_token; + } catch (err) { + return null; + } +}; + +const setUser = async (req, _res, next) => { + try { + const token = getToken(req); + // we can limit the form list from query string or url params. Url params override query params + // ex. /forms/:formId=ABC/version?formId=123 + // the ABC in the url will be used... so don't do that. + const params = { ...req.query, ...req.params }; + req.currentUser = await service.login(token, params); + next(); + } catch (error) { + next(error); + } +}; + +const currentUser = async (req, res, next) => { + // Check if authorization header is a bearer token + if (req.headers && req.headers.authorization && req.headers.authorization.startsWith('Bearer ')) { + // need to check keycloak, ensure the bearer token is valid + const token = req.headers.authorization.substring(7); + const ok = await keycloak.grantManager.validateAccessToken(token); + if (!ok) { + return new Problem(403, { detail: 'Authorization token is invalid.' }).send(res); + } + } + + return setUser(req, res, next); +}; + +const hasFormPermissions = (permissions) => { + return (req, res, next) => { + // Skip permission checks if requesting as API entity + if (req.apiUser) { + return next(); + } + + if (!req.currentUser) { + // cannot find the currentUser... guess we don't have access... FAIL! + return new Problem(401, { detail: 'Current user not found on request.' }).send(res); + } + // If we invoke this middleware and the caller is acting on a specific formId, whether in a param or query (precedence to param) + const formId = req.params.formId || req.query.formId; + if (!formId) { + // No form provided to this route that secures based on form... that's a problem! + return new Problem(401, { detail: 'Form Id not found on request.' }).send(res); + } + let form = req.currentUser.forms.find((f) => f.formId === formId); + if (!form) { + // check deleted... (this allows 404 on other queries later) + if (req.currentUser.deletedForms) { + form = req.currentUser.deletedForms.find((f) => f.formId === formId); + } + if (!form) { + // cannot find the form... guess we don't have access... FAIL! + return new Problem(401, { detail: 'Current user has no access to form.' }).send(res); + } + } + + if (!Array.isArray(permissions)) { + permissions = [permissions]; + } + + const intersection = permissions.filter((p) => { + return form.permissions.includes(p); + }); + + if (intersection.length !== permissions.length) { + return new Problem(401, { detail: 'Current user does not have required permission(s) on form' }).send(res); + } else { + return next(); + } + }; +}; + +const hasSubmissionPermissions = (permissions) => { + return async (req, _res, next) => { + try { + // Skip permission checks if requesting as API entity + if (req.apiUser) { + return next(); + } + + if (!Array.isArray(permissions)) { + permissions = [permissions]; + } + + // Get the provided submission ID whether in a param or query (precedence to param) + const submissionId = req.params.formSubmissionId || req.query.formSubmissionId; + if (!submissionId) { + // No submission provided to this route that secures based on form... that's a problem! + return next(new Problem(401, { detail: 'Submission Id not found on request.' })); + } + + // Get the submission results so we know what form this submission is for + const submissionForm = await service.getSubmissionForm(submissionId); + + // Does the user have permissions for this submission due to their FORM permissions + if (req.currentUser) { + let formFromCurrentUser = req.currentUser.forms.find((f) => f.formId === submissionForm.form.id); + if (formFromCurrentUser) { + // Do they have the submission permissions being requested on this FORM + const intersection = permissions.filter((p) => { + return formFromCurrentUser.permissions.includes(p); + }); + if (intersection.length === permissions.length) { + req.formIdWithDeletePermission = submissionForm.form.id; + return next(); + } + } + } + + // Deleted submissions are inaccessible + if (submissionForm.submission.deleted) { + return next(new Problem(401, { detail: 'You do not have access to this submission.' })); + } + + // TODO: consider whether DRAFT submissions are restricted as deleted above + + // Public (annonymous) forms are publicly viewable + const publicAllowed = submissionForm.form.identityProviders.find((p) => p.code === 'public') !== undefined; + if (permissions.length === 1 && permissions.includes(Permissions.SUBMISSION_READ) && publicAllowed) { + return next(); + } + + // check against the submission level permissions assigned to the user... + const submissionPermission = await service.checkSubmissionPermission(req.currentUser, submissionId, permissions); + if (submissionPermission) return next(); + + // no access to this submission... + return next(new Problem(401, { detail: 'You do not have access to this submission.' })); + } catch (error) { + next(error); + } + }; +}; + +const filterMultipleSubmissions = () => { + return async (req, _res, next) => { + try { + // Get the provided list of submissions Id whether in a req body + const submissionIds = req.body && req.body.submissionIds; + if (!Array.isArray(submissionIds)) { + // No submission provided to this route that secures based on form... that's a problem! + return next(new Problem(401, { detail: 'SubmissionIds not found on request.' })); + } + + let formIdWithDeletePermission = req.formIdWithDeletePermission; + + // Get the provided form ID whether in a param or query (precedence to param) + const formId = req.params.formId || req.query.formId; + if (!formId) { + // No submission provided to this route that secures based on form... that's a problem! + return next(new Problem(401, { detail: 'Form Id not found on request.' })); + } + + //validate form id + if (!validate(formId)) { + return next(new Problem(401, { detail: 'Not a valid form id' })); + } + + //validate all submission ids + const isValidSubmissionId = submissionIds.every((submissionId) => validate(submissionId)); + if (!isValidSubmissionId) { + return next(new Problem(401, { detail: 'Invalid submissionId(s) in the submissionIds list.' })); + } + + if (formIdWithDeletePermission === formId) { + // check if users has not injected submission id that does not belong to this form + const metaData = await service.getMultipleSubmission(submissionIds); + + const isForeignSubmissionId = metaData.every((SubmissionMetadata) => SubmissionMetadata.formId === formId); + if (!isForeignSubmissionId || metaData.length !== submissionIds.length) { + return next(new Problem(401, { detail: 'Current user does not have required permission(s) for some submissions in the submissionIds list.' })); + } + return next(); + } + return next(new Problem(401, { detail: 'Current user does not have required permission(s) for to delete submissions' })); + } catch (error) { + next(error); + } + }; +}; + +const hasFormRole = (formId, user, role) => { + let hasRole = false; + form_loop: for (let i = 0; i < user.forms.length; i++) { + if (user.forms[i].formId === formId) { + for (let j = 0; j < user.forms[i].roles.length; j++) { + if (user.forms[i].roles[j] === role) { + hasRole = true; + break form_loop; + } + } + } + } + + return hasRole; +}; + +const hasFormRoles = (formRoles, hasAll = false) => { + return async (req, res, next) => { + // If we invoke this middleware and the caller is acting on a specific formId, whether in a param or query (precedence to param) + const formId = req.params.formId || req.query.formId; + if (!formId) { + // No form provided to this route that secures based on form... that's a problem! + return new Problem(401, { detail: 'Form Id not found on request.' }).send(res); + } + + // Iterate all the forms the current user has access to + form_loop: for (let formIndex = 0; formIndex < req.currentUser.forms.length; formIndex++) { + // If the indexed form is the form we're checking role access + if (req.query.formId === req.currentUser.forms[formIndex].formId) { + // Iterate all the roles for this form + for (let roleIndex = 0; roleIndex < req.currentUser.forms[formIndex].roles.length; roleIndex++) { + let index = formRoles.indexOf(req.currentUser.forms[formIndex].roles[roleIndex]); + // If the user has the indexed role requested by the route + if (index > -1) { + // If the route specifies all roles must exist for the form + if (hasAll) + // Remove that role from the search + formRoles.splice(index, 1); + // The user has at least one of the roles + else return next(); + } + + // The user has all of the required roles + if (formRoles.length == 0) break form_loop; + } + } + } + + if (hasAll) { + if (formRoles.length > 0) return next(new Problem(401, { detail: 'You do not have permission to update this role.' })); + else return next(); + } + return next(new Problem(401, { detail: 'You do not have permission to update this role.' })); + }; +}; + +const hasRolePermissions = (removingUsers = false) => { + return async (req, res, next) => { + try { + // If we invoke this middleware and the caller is acting on a specific formId, whether in a param or query (precedence to param) + const formId = req.params.formId || req.query.formId; + if (!formId) { + // No form provided to this route that secures based on form... that's a problem! + return new Problem(401, { detail: 'Form Id not found on request.' }).send(res); + } + + const currentUser = req.currentUser; + const data = req.body; + + const isOwner = hasFormRole(formId, currentUser, Roles.OWNER); + + if (removingUsers) { + if (data.includes(currentUser.id)) return next(new Problem(401, { detail: "You can't remove yourself from this form." })); + + if (!isOwner) { + for (let i = 0; i < data.length; i++) { + let userId = data[i]; + + const userRoles = await rbacService.readUserRole(userId, formId); + + // Can't update another user's roles if they are an owner + if (userRoles.some((fru) => fru.role === Roles.OWNER) && userId !== currentUser.id) { + return next(new Problem(401, { detail: "You can not update an owner's roles." })); + } + + // If the user is trying to remove the designer role + if (userRoles.some((fru) => fru.role === Roles.FORM_DESIGNER)) { + return next(new Problem(401, { detail: "You can't remove a form designer role." })); + } + } + } + } else { + const userId = req.params.userId || req.query.userId; + if (!userId || (userId && userId.length === 0)) { + return new Problem(401, { detail: 'User Id not found on request.' }); + } + + if (!isOwner) { + const userRoles = await rbacService.readUserRole(userId, formId); + + // If the user is trying to remove the team manager role for their own userid + if (userRoles.some((fru) => fru.role === Roles.TEAM_MANAGER) && !data.some((role) => role.role === Roles.TEAM_MANAGER) && userId == currentUser.id) { + return next(new Problem(401, { detail: "You can't remove your own team manager role." })); + } + + // Can't update another user's roles if they are an owner + if (userRoles.some((fru) => fru.role === Roles.OWNER) && userId !== currentUser.id) { + return next(new Problem(401, { detail: "You can't update an owner's roles." })); + } + if (!userRoles.some((fru) => fru.role === Roles.OWNER) && data.some((role) => role.role === Roles.OWNER)) { + return next(new Problem(401, { detail: "You can't add an owner role." })); + } + + // If the user is trying to remove the designer role for another userid + if (userRoles.some((fru) => fru.role === Roles.FORM_DESIGNER) && !data.some((role) => role.role === Roles.FORM_DESIGNER)) { + return next(new Problem(401, { detail: "You can't remove a form designer role." })); + } + if (!userRoles.some((fru) => fru.role === Roles.FORM_DESIGNER) && data.some((role) => role.role === Roles.FORM_DESIGNER)) { + return next(new Problem(401, { detail: "You can't add a form designer role." })); + } + } + } + + return next(); + } catch (error) { + next(error); + } + }; +}; + +module.exports = { + currentUser, + hasFormPermissions, + hasSubmissionPermissions, + hasFormRoles, + hasFormRole, + hasRolePermissions, + filterMultipleSubmissions, +}; diff --git a/frontend/app/src/forms/auth/service.js b/frontend/app/src/forms/auth/service.js new file mode 100644 index 0000000..8dae491 --- /dev/null +++ b/frontend/app/src/forms/auth/service.js @@ -0,0 +1,245 @@ +const { v4: uuidv4 } = require('uuid'); + +const { Form, FormSubmissionUserPermissions, PublicFormAccess, SubmissionMetadata, User, UserFormAccess } = require('../common/models'); +const { queryUtils } = require('../common/utils'); + +const FORM_SUBMITTER = require('../common/constants').Permissions.FORM_SUBMITTER; + +const service = { + createUser: async (data) => { + let trx; + try { + trx = await User.startTransaction(); + + const obj = { + id: uuidv4(), + idpUserId: data.idpUserId, + keycloakId: data.keycloakId, + username: data.username, + fullName: data.fullName, + email: data.email, + firstName: data.firstName, + lastName: data.lastName, + idpCode: data.idp, + }; + + await User.query(trx).insert(obj).onConflict('keycloakId').ignore(); + await trx.commit(); + const result = await service.readUser(obj.keycloakId); + return result; + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, + + readUser: async (keycloakId) => { + return User.query().modify('filterKeycloakId', keycloakId).first().throwIfNotFound(); + }, + + updateUser: async (id, data) => { + let trx; + try { + trx = await User.startTransaction(); + + const update = { + idpUserId: data.idpUserId, + keycloakId: data.keycloakId, + username: data.username, + fullName: data.fullName, + email: data.email, + firstName: data.firstName, + lastName: data.lastName, + idpCode: data.idp, + }; + + await User.query(trx).patchAndFetchById(id, update); + await trx.commit(); + const result = await service.readUser(update.keycloakId); + return result; + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, + + parseToken: (token) => { + try { + // identity_provider_* will be undefined if user login is to local keycloak (userid/password) + const { + idp_userid: idpUserId, + idp_username: identity, + identity_provider: idp, + preferred_username: username, + given_name: firstName, + family_name: lastName, + sub: keycloakId, + name: fullName, + email, + } = token.content; + + return { + idpUserId: idpUserId, + keycloakId: keycloakId, + username: identity ? identity : username, + firstName: firstName, + lastName: lastName, + fullName: fullName, + email: email, + idp: idp ? idp : '', + public: false, + }; + } catch (e) { + // any issues parsing the token, or if token doesn't exist, return a default "public" user + return { + idpUserId: undefined, + keycloakId: undefined, + username: 'public', + firstName: undefined, + lastName: undefined, + fullName: 'public', + email: undefined, + idp: 'public', + public: true, + }; + } + }, + + getUserId: async (userInfo) => { + if (userInfo.public) { + return { id: 'public', ...userInfo }; + } + + const obj = { ...userInfo }; + + // if this user does not exists, add... + let user = await User.query().first().where('idpUserId', obj.idpUserId); + + if (!user) { + // add to the system. + user = await service.createUser(obj); + } else { + // what if name or email changed? + user = await service.updateUser(user.id, obj); + } + + // return with the db id... + return { id: user.id, usernameIdp: user.idpCode ? `${user.username}@${user.idpCode}` : user.username, ...userInfo }; + }, + + getUserForms: async (userInfo, params = {}) => { + params = queryUtils.defaultActiveOnly(params); + let items = []; + if (userInfo && userInfo.public) { + // if the user is 'public', then we can only fetch public accessible forms... + items = await PublicFormAccess.query().modify('filterFormId', params.formId).modify('filterActive', params.active).modify('orderDefault'); + // ignore any passed in accessLevel params, only return public + return service.filterForms(userInfo, items, ['public']); + } else { + // if user has an id, then we fetch whatever forms match the query params + items = await UserFormAccess.query().modify('filterUserId', userInfo.id).modify('filterFormId', params.formId).modify('filterActive', params.active).modify('orderDefault'); + return service.filterForms(userInfo, items, params.accessLevels); + } + }, + + filterForms: (userInfo, items, accessLevels = []) => { + // note that the user form access query returns submitter roles for everyone + // we need to filter out the true access level here. + // so we need a role, or a valid idp from login, or form needs to be public. + let forms = []; + + let filtered = items.filter((x) => { + // include if user has idp, or form is public, or user has an explicit role. + if (x.idps.includes(userInfo.idp) || x.idps.includes('public')) { + // always give submitter permissions to launch by idp and public + x.permissions = Array.from(new Set([...x.permissions, ...FORM_SUBMITTER])); + return true; + } + // user has permissions solely through their assigned roles... + return x.roles.length; + }); + + if (accessLevels && accessLevels.length) { + filtered.forEach((item) => { + let hasPublic = false; + let hasIdp = false; + let hasTeam = false; + if (accessLevels.includes('public')) { + // must have public in form idps... + hasPublic = item.idps.includes('public'); + } else if (accessLevels.includes('idp')) { + // must have user's idp in idps... + hasIdp = item.idps.includes(userInfo.idp); + } else if (accessLevels.includes('team')) { + // must have a role... + hasTeam = item.roles.length; + } + if (hasPublic || hasIdp || hasTeam) { + forms.push(service.formAccessToForm(item)); + } + }); + } else { + forms = filtered.map((item) => service.formAccessToForm(item)); + } + return forms; + }, + + formAccessToForm: (item) => { + return { + formId: item.formId, + formName: item.formName, + formDescription: item.formDescription, + labels: item.labels, + idps: item.idps, + active: item.active, + formVersionId: item.formVersionId, + version: item.version, + published: item.published, + versionUpdatedAt: item.versionUpdatedAt, + roles: item.roles, + permissions: item.permissions, + }; + }, + + login: async (token, params = {}) => { + const userInfo = service.parseToken(token); + const user = await service.getUserId(userInfo); + const forms = await service.getUserForms(user, params); // get forms for user (filtered by params)... + params.active = false; + const deletedForms = await service.getUserForms(user, params); // get forms for user (filtered by params)... + return { ...user, forms: forms, deletedForms: deletedForms }; + }, + + // ------------------------------------------------------------------------------------------------------------- + // Submission Data + // ------------------------------------------------------------------------------------------------------------- + checkSubmissionPermission: async (currentUser, submissionId, permissions) => { + if (currentUser.public) return false; + return FormSubmissionUserPermissions.query() + .modify('filterSubmissionId', submissionId) + .modify('filterUserId', currentUser.id) + .modify('filterByPermissions', permissions) + .first(); + }, + + getSubmissionForm: async (submissionId) => { + // Get this submission data for the form Id + const meta = await SubmissionMetadata.query().where('submissionId', submissionId).first().throwIfNotFound(); + + // Get the form with IDP info + const form = await Form.query().findById(meta.formId).allowGraph('identityProviders').withGraphFetched('identityProviders(orderDefault)').throwIfNotFound(); + + return { + submission: meta, + form: form, + }; + }, + + getMultipleSubmission: async (submissionIds) => { + return await SubmissionMetadata.query().whereIn('submissionId', submissionIds); + }, + + // ---------------------------------------------------------------------------------------------/Submission Data +}; + +module.exports = service; diff --git a/frontend/app/src/forms/bcgeoaddress/controller.js b/frontend/app/src/forms/bcgeoaddress/controller.js new file mode 100644 index 0000000..60987ed --- /dev/null +++ b/frontend/app/src/forms/bcgeoaddress/controller.js @@ -0,0 +1,22 @@ +const service = require('./service'); + +module.exports = { + searchBCGeoAddress: async (req, res, next) => { + try { + const { query } = req; + const response = await service.searchBCGeoAddress(query); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + advanceSearchBCGeoAddress: async (req, res, next) => { + try { + const { query } = req; + const response = await service.advanceSearchBCGeoAddress(query); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, +}; diff --git a/frontend/app/src/forms/bcgeoaddress/index.js b/frontend/app/src/forms/bcgeoaddress/index.js new file mode 100644 index 0000000..4b3451e --- /dev/null +++ b/frontend/app/src/forms/bcgeoaddress/index.js @@ -0,0 +1,7 @@ +const dataErrors = require('../common/middleware').dataErrors; +const routes = require('./routes'); +const setupMount = require('../common/utils').setupMount; + +module.exports.mount = (app) => { + return setupMount('bcgeoaddress', app, routes, dataErrors); +}; diff --git a/frontend/app/src/forms/bcgeoaddress/routes.js b/frontend/app/src/forms/bcgeoaddress/routes.js new file mode 100644 index 0000000..10f2d1f --- /dev/null +++ b/frontend/app/src/forms/bcgeoaddress/routes.js @@ -0,0 +1,13 @@ +const routes = require('express').Router(); + +const controller = require('./controller'); + +routes.get('/address', async (req, res, next) => { + await controller.searchBCGeoAddress(req, res, next); +}); + +routes.get('/advance/address', async (req, res, next) => { + await controller.advanceSearchBCGeoAddress(req, res, next); +}); + +module.exports = routes; diff --git a/frontend/app/src/forms/bcgeoaddress/service.js b/frontend/app/src/forms/bcgeoaddress/service.js new file mode 100644 index 0000000..87f4e7e --- /dev/null +++ b/frontend/app/src/forms/bcgeoaddress/service.js @@ -0,0 +1,24 @@ +const geoAddressService = require('../../components/geoAddressService'); + +const service = { + searchBCGeoAddress: async (query) => { + let addresses = { features: [] }; + + let searchAddresses = await geoAddressService.addressQuerySearch(query); + + if (searchAddresses?.features && Array.isArray(searchAddresses.features)) { + searchAddresses.features.forEach((element) => { + if (element?.properties?.fullAddress) { + addresses.features.push({ geometry: { coordinates: element.geometry.coordinates }, properties: { fullAddress: element.properties.fullAddress } }); + } + }); + } + return addresses; + }, + + advanceSearchBCGeoAddress: async (query) => { + return await geoAddressService.addressQuerySearch(query); + }, +}; + +module.exports = service; diff --git a/frontend/app/src/forms/common/constants.js b/frontend/app/src/forms/common/constants.js new file mode 100644 index 0000000..278df00 --- /dev/null +++ b/frontend/app/src/forms/common/constants.js @@ -0,0 +1,93 @@ +module.exports = Object.freeze({ + EmailProperties: { + FROM_EMAIL: 'donotreplyCHEFS@gov.bc.ca', + }, + EmailTypes: { + SUBMISSION_ASSIGNED: 'submissionAssigned', + SUBMISSION_UNASSIGNED: 'submissionUnassigned', + STATUS_ASSIGNED: 'statusAssigned', + STATUS_REVISING: 'statusRevising', + SUBMISSION_RECEIVED: 'submissionReceived', + SUBMISSION_CONFIRMATION: 'submissionConfirmation', + REMINDER_FORM_OPEN: 'formOpen', + REMINDER_FORM_WILL_CLOSE: 'formWillClose', + REMINDER_FORM_NOT_FILL: 'formNotFill', + }, + Permissions: { + EMAIL_TEMPLATE_READ: 'email_template_read', + EMAIL_TEMPLATE_UPDATE: 'email_template_update', + FORM_API_CREATE: 'form_api_create', + FORM_API_READ: 'form_api_read', + FORM_API_UPDATE: 'form_api_update', + FORM_API_DELETE: 'form_api_delete', + FORM_READ: 'form_read', + FORM_UPDATE: 'form_update', + FORM_DELETE: 'form_delete', + SUBMISSION_CREATE: 'submission_create', + SUBMISSION_READ: 'submission_read', + SUBMISSION_UPDATE: 'submission_update', + SUBMISSION_DELETE: 'submission_delete', + DESIGN_CREATE: 'design_create', + DESIGN_READ: 'design_read', + DESIGN_UPDATE: 'design_update', + DESIGN_DELETE: 'design_delete', + TEAM_READ: 'team_read', + TEAM_UPDATE: 'team_update', + FORM_SUBMITTER: ['form_read', 'submission_create'], + }, + Roles: { + OWNER: 'owner', + TEAM_MANAGER: 'team_manager', + FORM_DESIGNER: 'form_designer', + SUBMISSION_REVIEWER: 'submission_reviewer', + FORM_SUBMITTER: 'form_submitter', + }, + Regex: { + CONFIRMATION_ID: '^[0-9A-Fa-f]{8}$', + UUID: '^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-4[0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$', + // From ajv-formats + EMAIL: "^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$", + }, + Statuses: { + SUBMITTED: 'SUBMITTED', + ASSIGNED: 'ASSIGNED', + COMPLETED: 'COMPLETED', + REVISING: 'REVISING', + }, + SubscriptionEvent: { + FORM_SUBMITTED: 'eventSubmission', + FORM_STATUS_CHANGE: 'eventStatusChange', + FORM_ASSIGNMENT: 'eventAssignment', + }, + StorageTypes: { + UPLOADS: 'uploads', + LOCAL_STORAGE: 'localStorage', + OBJECT_STORAGE: 'objectStorage', + LOCAL_STORES: ['uploads', 'localStorage', 'exports'], + }, + Restricted: { + IDP: { + BCEID_BASIC: 'bceid-basic', + BCEID_BUSINESS: 'bceid-business', + }, + }, + ScheduleType: { + MANUAL: 'manual', + CLOSINGDATE: 'closingDate', + PERIOD: 'period', + }, + IdentityProviders: { + BCEIDBASIC: 'bceid-basic', // Basic BCeID + BCEIDBUSINESS: 'bceid-business', // Business BCeID + IDIR: 'idir', // IDIR + }, + EXPORT_TYPES: { + submissions: 'submissions', + default: 'submissions', + }, + EXPORT_FORMATS: { + csv: 'csv', + json: 'json', + default: 'csv', + }, +}); diff --git a/frontend/app/src/forms/common/middleware/dataErrors.js b/frontend/app/src/forms/common/middleware/dataErrors.js new file mode 100644 index 0000000..d0ff88a --- /dev/null +++ b/frontend/app/src/forms/common/middleware/dataErrors.js @@ -0,0 +1,21 @@ +const Problem = require('api-problem'); +const Objection = require('objection'); + +module.exports.dataErrors = async (err, req, res, next) => { + let error = err; + if (err instanceof Objection.NotFoundError) { + error = new Problem(404, { + detail: "Sorry... we still haven't found what you're looking for :(", + }); + } else if (err instanceof Objection.ValidationError) { + error = new Problem(422, { + detail: 'Validation Error', + errors: err.data, + }); + } else if (err instanceof Objection.DataError) { + error = new Problem(422, { + detail: 'Sorry... the database does not like the data you provided :(', + }); + } + next(error); +}; diff --git a/frontend/app/src/forms/common/middleware/index.js b/frontend/app/src/forms/common/middleware/index.js new file mode 100644 index 0000000..7cb497c --- /dev/null +++ b/frontend/app/src/forms/common/middleware/index.js @@ -0,0 +1,4 @@ +module.exports = { + ...require('./dataErrors'), + ...require('./rateLimiter'), +}; diff --git a/frontend/app/src/forms/common/middleware/rateLimiter.js b/frontend/app/src/forms/common/middleware/rateLimiter.js new file mode 100644 index 0000000..ed67391 --- /dev/null +++ b/frontend/app/src/forms/common/middleware/rateLimiter.js @@ -0,0 +1,19 @@ +const config = require('config'); +const rateLimit = require('express-rate-limit'); + +const apiKeyRateLimiter = rateLimit({ + // Instead of legacy headers use the standardHeaders version defined below. + legacyHeaders: false, + + limit: config.get('server.rateLimit.public.max'), + + // Skip Bearer token auth so that CHEFS app users are not limited. + skip: (req) => req.headers && req.headers.authorization && !req.headers.authorization.startsWith('Basic '), + + // Use the latest draft of the IETF standard for rate limiting headers. + standardHeaders: 'draft-7', + + windowMs: parseInt(config.get('server.rateLimit.public.windowMs')), +}); + +module.exports.apiKeyRateLimiter = apiKeyRateLimiter; diff --git a/frontend/app/src/forms/common/models/index.js b/frontend/app/src/forms/common/models/index.js new file mode 100644 index 0000000..ebd53d2 --- /dev/null +++ b/frontend/app/src/forms/common/models/index.js @@ -0,0 +1,33 @@ +module.exports = { + // Tables + FileStorage: require('./tables/fileStorage'), + Form: require('./tables/form'), + FormApiKey: require('./tables/formApiKey'), + FormEmailTemplate: require('./tables/formEmailTemplate'), + FormIdentityProvider: require('./tables/formIdentityProvider'), + FormSubmission: require('./tables/formSubmission'), + FormStatusCode: require('./tables/formStatusCode'), + FormSubmissionStatus: require('./tables/formSubmissionStatus'), + FormSubmissionUser: require('./tables/formSubmissionUser'), + FormRoleUser: require('./tables/formRoleUser'), + FormVersion: require('./tables/formVersion'), + FormVersionDraft: require('./tables/formVersionDraft'), + IdentityProvider: require('./tables/identityProvider'), + Note: require('./tables/note'), + Permission: require('./tables/permission'), + Role: require('./tables/role'), + StatusCode: require('./tables/statusCode'), + SubmissionAudit: require('./tables/submissionAudit'), + User: require('./tables/user'), + UserFormPreferences: require('./tables/userFormPreferences'), + FormComponentsProactiveHelp: require('./tables/formComponentsProactiveHelp'), + FormSubscription: require('./tables/formSubscription'), + + // Views + FormSubmissionUserPermissions: require('./views/formSubmissionUserPermissions'), + PublicFormAccess: require('./views/publicFormAccess'), + SubmissionData: require('./views/submissionData'), + SubmissionMetadata: require('./views/submissionMetadata'), + UserFormAccess: require('./views/userFormAccess'), + UserSubmissions: require('./views/userSubmissions'), +}; diff --git a/frontend/app/src/forms/common/models/jsonSchema.js b/frontend/app/src/forms/common/models/jsonSchema.js new file mode 100644 index 0000000..27b405c --- /dev/null +++ b/frontend/app/src/forms/common/models/jsonSchema.js @@ -0,0 +1,6 @@ +module.exports.stamps = { + createdBy: { type: ['string', 'null'] }, + createdAt: { type: ['string', 'null'] }, + updatedBy: { type: ['string', 'null'] }, + updatedAt: { type: ['string', 'null'] }, +}; diff --git a/frontend/app/src/forms/common/models/mixins.js b/frontend/app/src/forms/common/models/mixins.js new file mode 100644 index 0000000..bf8b7b0 --- /dev/null +++ b/frontend/app/src/forms/common/models/mixins.js @@ -0,0 +1,29 @@ +const moment = require('moment'); + +/** Timestamps Objection Model Plugin + * Add handlers to an Objection Model + * + * In order to use JSON Schema Validation, we need to treat Timestamps as strings. + * They still get stored as dates/timestamps, but in/out of the database they need to be strings. + * + * This class will set the createdAt timestamp/string before insert and updatedAt before update. + * The JSON Schema validation will pass as it goes through the marshalling, expecting createdAt and updateAt as strings. + * + * @see module:knex + * @see module:objection + */ + +const Timestamps = (Model) => { + return class extends Model { + async $beforeInsert(queryContext) { + await super.$beforeInsert(queryContext); + this.createdAt = moment().toISOString(); + } + async $beforeUpdate(opt, queryContext) { + await super.$beforeUpdate(opt, queryContext); + this.updatedAt = moment().toISOString(); + } + }; +}; + +module.exports.Timestamps = Timestamps; diff --git a/frontend/app/src/forms/common/models/tables/fileStorage.js b/frontend/app/src/forms/common/models/tables/fileStorage.js new file mode 100644 index 0000000..887d24d --- /dev/null +++ b/frontend/app/src/forms/common/models/tables/fileStorage.js @@ -0,0 +1,45 @@ +const { Model } = require('objection'); +const { Timestamps } = require('../mixins'); +const { Regex } = require('../../constants'); +const stamps = require('../jsonSchema').stamps; + +class FileStorage extends Timestamps(Model) { + static get tableName() { + return 'file_storage'; + } + + static get relationMappings() { + const FormSubmission = require('./formSubmission'); + + return { + submission: { + relation: Model.HasOneRelation, + modelClass: FormSubmission, + join: { + from: 'file_storage.formSubmissionId', + to: 'form_submission.id', + }, + }, + }; + } + + static get jsonSchema() { + return { + type: 'object', + required: ['id', 'originalName', 'mimeType', 'size', 'storage', 'path'], + properties: { + id: { type: 'string', pattern: Regex.UUID }, + originalName: { type: 'string', minLength: 1, maxLength: 1024 }, + mimeType: { type: 'string' }, + size: { type: 'integer' }, + storage: { type: 'string' }, + path: { type: 'string', minLength: 1, maxLength: 1024 }, + formSubmissionId: { type: ['string', 'null'], pattern: Regex.UUID }, + ...stamps, + }, + additionalProperties: false, + }; + } +} + +module.exports = FileStorage; diff --git a/frontend/app/src/forms/common/models/tables/form.js b/frontend/app/src/forms/common/models/tables/form.js new file mode 100644 index 0000000..8300bb3 --- /dev/null +++ b/frontend/app/src/forms/common/models/tables/form.js @@ -0,0 +1,159 @@ +const { Model } = require('objection'); +const { Timestamps } = require('../mixins'); +const { Regex } = require('../../constants'); +const stamps = require('../jsonSchema').stamps; + +class Form extends Timestamps(Model) { + static get tableName() { + return 'form'; + } + + $parseDatabaseJson(json) { + json = super.$parseDatabaseJson(json); + // Need to make sure that name is a string (could be a number) + if (json.name !== undefined) { + json.name = json.name.toString(); + } + return json; + } + + snake() { + // like a slug, but not guaranteed to be unique (as names are not unique). + // use this for file names or any other instances we want a standardized name without punctuation etc. + return this.name + .replace(/\s+/g, '_') + .replace(/[^-_0-9a-z]/gi, '') + .toLowerCase(); + } + + static get virtualAttributes() { + return ['snake']; + } + + static get relationMappings() { + const FormIdentityProvider = require('./formIdentityProvider'); + const FormVersion = require('./formVersion'); + const FormVersionDraft = require('./formVersionDraft'); + const IdentityProvider = require('./identityProvider'); + return { + drafts: { + relation: Model.HasManyRelation, + modelClass: FormVersionDraft, + join: { + from: 'form.id', + to: 'form_version_draft.formId', + }, + }, + idpHints: { + relation: Model.HasManyRelation, + modelClass: FormIdentityProvider, + filter: (query) => query.select('code'), + join: { + from: 'form.id', + to: 'form_identity_provider.formId', + }, + }, + identityProviders: { + relation: Model.ManyToManyRelation, + modelClass: IdentityProvider, + join: { + from: 'form.id', + through: { + from: 'form_identity_provider.formId', + to: 'form_identity_provider.code', + }, + to: 'identity_provider.code', + }, + }, + versions: { + relation: Model.HasManyRelation, + modelClass: FormVersion, + join: { + from: 'form.id', + to: 'form_version.formId', + }, + }, + }; + } + + static get modifiers() { + return { + filterName(query, value) { + if (value) { + // ilike is postgres case insensitive like + query.where('name', 'ilike', `%${value}%`); + } + }, + filterDescription(query, value) { + if (value) { + // ilike is postgres case insensitive like + query.where('description', 'ilike', `%${value}%`); + } + }, + filterActive(query, value) { + if (value !== undefined) { + query.where('active', value); + } + }, + filterLabels(query, value) { + if (value) { + query.whereRaw(`'${value}' = ANY (labels)`); + } + }, + orderNameAscending(builder) { + builder.orderByRaw('lower("name")'); + }, + reminderEnabled(query) { + query.where('reminder_enabled', true); + }, + }; + } + + // exclude labels and submissionReceivedEmails arrays from explicit JSON conversion + // encounter malformed array literal + static get jsonAttributes() { + return [ + 'id', + 'name', + 'description', + 'active', + 'allowSubmitterToUploadFile', + 'showSubmissionConfirmation', + 'enableStatusUpdates', + 'schedule', + 'subscribe', + 'reminder_enabled', + 'createdBy', + 'createdAt', + 'updatedBy', + 'updatedAt', + ]; + } + + static get jsonSchema() { + return { + type: 'object', + required: ['name'], + properties: { + id: { type: 'string', pattern: Regex.UUID }, + name: { type: 'string', minLength: 1, maxLength: 255 }, + description: { type: ['string', 'null'], maxLength: 255 }, + active: { type: 'boolean' }, + allowSubmitterToUploadFile: { type: 'boolean' }, + labels: { type: ['array', 'null'], items: { type: 'string' } }, + showSubmissionConfirmation: { type: 'boolean' }, + submissionReceivedEmails: { type: ['array', 'null'], items: { type: 'string', pattern: Regex.EMAIL } }, + enableStatusUpdates: { type: 'boolean' }, + enableSubmitterDraft: { type: 'boolean' }, + schedule: { type: 'object' }, + subscribe: { type: 'object' }, + reminder_enabled: { type: 'boolean' }, + enableCopyExistingSubmission: { type: 'boolean' }, + ...stamps, + }, + additionalProperties: false, + }; + } +} + +module.exports = Form; diff --git a/frontend/app/src/forms/common/models/tables/formApiKey.js b/frontend/app/src/forms/common/models/tables/formApiKey.js new file mode 100644 index 0000000..f7a3b72 --- /dev/null +++ b/frontend/app/src/forms/common/models/tables/formApiKey.js @@ -0,0 +1,36 @@ +const { Model } = require('objection'); +const { Timestamps } = require('../mixins'); +const { Regex } = require('../../constants'); +const stamps = require('../jsonSchema').stamps; + +class FormApiKey extends Timestamps(Model) { + static get tableName() { + return 'form_api_key'; + } + + static get modifiers() { + return { + filterFormId(query, value) { + if (value) { + query.where('formId', value); + } + }, + }; + } + + static get jsonSchema() { + return { + type: 'object', + required: ['formId'], + properties: { + id: { type: 'integer' }, + formId: { type: 'string', pattern: Regex.UUID }, + secret: { type: 'string', pattern: Regex.UUID }, + ...stamps, + }, + additionalProperties: false, + }; + } +} + +module.exports = FormApiKey; diff --git a/frontend/app/src/forms/common/models/tables/formComponentsProactiveHelp.js b/frontend/app/src/forms/common/models/tables/formComponentsProactiveHelp.js new file mode 100644 index 0000000..b5f1fd6 --- /dev/null +++ b/frontend/app/src/forms/common/models/tables/formComponentsProactiveHelp.js @@ -0,0 +1,62 @@ +const { Model } = require('objection'); +const { Timestamps } = require('../mixins'); +const { Regex } = require('../../constants'); +const stamps = require('../jsonSchema').stamps; + +class FormComponentsProactiveHelp extends Timestamps(Model) { + static get tableName() { + return 'form_components_proactive_help'; + } + static get modifiers() { + return { + findByComponentName(query, value) { + if (value !== undefined) { + query.where('componentName', value); + } + }, + findByComponentNameAndGroup(query, componentName, groupName) { + if (componentName !== undefined && groupName !== undefined) { + query.where('componentName', componentName).where('groupName', groupName); + } + }, + distinctOnComponentNameAndGroupName(builder) { + builder.distinctOn(['componentName', 'groupName']); + }, + selectWithoutImages(query) { + query.select('id', 'componentName', 'externalLink', 'imageType', 'groupName', 'publishStatus', 'isLinkEnabled', 'description', 'componentImageName'); + }, + selectImageUrl(query, id) { + query.select('image').where('id', id); + }, + + findByComponentId(query, value) { + if (value !== undefined) { + query.where('id', value); + } + }, + }; + } + + static get jsonSchema() { + return { + type: 'object', + required: ['id', 'componentName', 'groupName'], + properties: { + id: { type: 'string', pattern: Regex.UUID }, + componentName: { type: 'string', minLength: 1, maxLength: 255 }, + externalLink: { type: 'string' }, + image: { type: 'string' }, + componentImageName: { type: 'string' }, + imageType: { type: 'string' }, + groupName: { type: 'string', minLength: 1, maxLength: 255 }, + publishStatus: { type: 'boolean' }, + isLinkEnabled: { type: 'boolean' }, + description: { type: 'string' }, + ...stamps, + }, + additionalProperties: false, + }; + } +} + +module.exports = FormComponentsProactiveHelp; diff --git a/frontend/app/src/forms/common/models/tables/formEmailTemplate.js b/frontend/app/src/forms/common/models/tables/formEmailTemplate.js new file mode 100644 index 0000000..ac4399c --- /dev/null +++ b/frontend/app/src/forms/common/models/tables/formEmailTemplate.js @@ -0,0 +1,49 @@ +const { Model } = require('objection'); +const { Timestamps } = require('../mixins'); +const { Regex } = require('../../constants'); +const stamps = require('../jsonSchema').stamps; + +class FormEmailTemplate extends Timestamps(Model) { + static get tableName() { + return 'form_email_template'; + } + + static get modifiers() { + return { + filterId(query, value) { + if (value) { + query.where('id', value); + } + }, + filterFormId(query, value) { + if (value) { + query.where('formId', value); + } + }, + filterType(query, value) { + if (value) { + query.where('type', value); + } + }, + }; + } + + static get jsonSchema() { + return { + type: 'object', + required: ['body', 'formId', 'subject', 'title', 'type'], + properties: { + id: { type: 'string', pattern: Regex.UUID }, + formId: { type: 'string', pattern: Regex.UUID }, + type: { type: 'string' }, + subject: { type: 'string' }, + title: { type: 'string' }, + body: { type: 'string' }, + ...stamps, + }, + additionalProperties: false, + }; + } +} + +module.exports = FormEmailTemplate; diff --git a/frontend/app/src/forms/common/models/tables/formIdentityProvider.js b/frontend/app/src/forms/common/models/tables/formIdentityProvider.js new file mode 100644 index 0000000..6d7243a --- /dev/null +++ b/frontend/app/src/forms/common/models/tables/formIdentityProvider.js @@ -0,0 +1,26 @@ +const { Model } = require('objection'); +const { Timestamps } = require('../mixins'); +const { Regex } = require('../../constants'); +const stamps = require('../jsonSchema').stamps; + +class FormIdentityProvider extends Timestamps(Model) { + static get tableName() { + return 'form_identity_provider'; + } + + static get jsonSchema() { + return { + type: 'object', + required: ['formId'], + properties: { + id: { type: 'string', pattern: Regex.UUID }, + formId: { type: 'string', pattern: Regex.UUID }, + code: { type: 'string', maxLength: 255 }, + ...stamps, + }, + additionalProperties: false, + }; + } +} + +module.exports = FormIdentityProvider; diff --git a/frontend/app/src/forms/common/models/tables/formRoleUser.js b/frontend/app/src/forms/common/models/tables/formRoleUser.js new file mode 100644 index 0000000..33b3b1c --- /dev/null +++ b/frontend/app/src/forms/common/models/tables/formRoleUser.js @@ -0,0 +1,86 @@ +const { Model } = require('objection'); +const { Timestamps } = require('../mixins'); +const { Regex } = require('../../constants'); +const stamps = require('../jsonSchema').stamps; + +class FormRoleUser extends Timestamps(Model) { + static get tableName() { + return 'form_role_user'; + } + + static get relationMappings() { + const Form = require('./form'); + const Role = require('./role'); + const User = require('./user'); + + return { + form: { + relation: Model.HasOneRelation, + modelClass: Form, + join: { + from: 'form_role_user.formId', + to: 'form.id', + }, + }, + userRole: { + relation: Model.HasOneRelation, + modelClass: Role, + join: { + from: 'form_role_user.role', + to: 'role.code', + }, + }, + user: { + relation: Model.HasOneRelation, + modelClass: User, + join: { + from: 'form_role_user.userId', + to: 'user.id', + }, + }, + }; + } + + static get modifiers() { + return { + filterUserId(query, value) { + if (value) { + query.where('userId', value); + } + }, + filterFormId(query, value) { + if (value) { + query.where('formId', value); + } + }, + filterRole(query, value) { + if (value) { + query.where('role', value); + } + }, + orderCreatedAtDescending(builder) { + builder.orderBy('createdAt', 'desc'); + }, + orderUpdatedAtDescending(builder) { + builder.orderBy('updatedAt', 'desc'); + }, + }; + } + + static get jsonSchema() { + return { + type: 'object', + required: ['role', 'formId', 'userId'], + properties: { + id: { type: 'string', pattern: Regex.UUID }, + formId: { type: 'string', pattern: Regex.UUID }, + userId: { type: 'string', pattern: Regex.UUID }, + role: { type: 'string', minLength: 1, maxLength: 255 }, + ...stamps, + }, + additionalProperties: false, + }; + } +} + +module.exports = FormRoleUser; diff --git a/frontend/app/src/forms/common/models/tables/formStatusCode.js b/frontend/app/src/forms/common/models/tables/formStatusCode.js new file mode 100644 index 0000000..a0d1056 --- /dev/null +++ b/frontend/app/src/forms/common/models/tables/formStatusCode.js @@ -0,0 +1,51 @@ +const { Model } = require('objection'); +const { Timestamps } = require('../mixins'); +const { Regex } = require('../../constants'); +const stamps = require('../jsonSchema').stamps; + +class FormStatusCode extends Timestamps(Model) { + static get tableName() { + return 'form_status_code'; + } + + static get relationMappings() { + const StatusCode = require('./statusCode'); + + return { + statusCode: { + relation: Model.HasOneRelation, + modelClass: StatusCode, + join: { + from: 'form_status_code.code', + to: 'status_code.code', + }, + }, + }; + } + + static get modifiers() { + return { + filterFormId(query, value) { + if (value !== undefined) { + query.where('formId', value); + } + }, + }; + } + + static get jsonSchema() { + return { + type: 'object', + required: ['formId', 'code'], + properties: { + id: { type: 'string', pattern: Regex.UUID }, + formId: { type: 'string', pattern: Regex.UUID }, + code: { type: 'string' }, + ...stamps, + }, + additionalProperties: false, + }; + } +} + +module.exports = FormStatusCode; diff --git a/frontend/app/src/forms/common/models/tables/formSubmission.js b/frontend/app/src/forms/common/models/tables/formSubmission.js new file mode 100644 index 0000000..fced6cb --- /dev/null +++ b/frontend/app/src/forms/common/models/tables/formSubmission.js @@ -0,0 +1,47 @@ +const { Model } = require('objection'); +const { Timestamps } = require('../mixins'); +const { Regex } = require('../../constants'); +const stamps = require('../jsonSchema').stamps; + +class FormSubmission extends Timestamps(Model) { + static get tableName() { + return 'form_submission'; + } + + static get modifiers() { + return { + filterCreatedBy(query, value) { + if (value) { + query.where('createdBy', 'ilike', `%${value}%`); + } + }, + filterFormVersionId(query, value) { + if (value !== undefined) { + query.where('formVersionId', value); + } + }, + orderDescending(builder) { + builder.orderBy('createdAt', 'desc'); + }, + }; + } + + static get jsonSchema() { + return { + type: 'object', + required: ['formVersionId', 'confirmationId', 'submission'], + properties: { + id: { type: 'string', pattern: Regex.UUID }, + formVersionId: { type: 'string', pattern: Regex.UUID }, + confirmationId: { type: 'string', pattern: Regex.CONFIRMATION_ID }, + draft: { type: 'boolean' }, + deleted: { type: 'boolean' }, + submission: { type: 'object' }, + ...stamps, + }, + additionalProperties: false, + }; + } +} + +module.exports = FormSubmission; diff --git a/frontend/app/src/forms/common/models/tables/formSubmissionStatus.js b/frontend/app/src/forms/common/models/tables/formSubmissionStatus.js new file mode 100644 index 0000000..04b3376 --- /dev/null +++ b/frontend/app/src/forms/common/models/tables/formSubmissionStatus.js @@ -0,0 +1,56 @@ +const { Model } = require('objection'); +const { Timestamps } = require('../mixins'); +const { Regex } = require('../../constants'); +const stamps = require('../jsonSchema').stamps; + +class FormSubmissionStatus extends Timestamps(Model) { + static get tableName() { + return 'form_submission_status'; + } + + static get relationMappings() { + const User = require('./user'); + + return { + user: { + relation: Model.HasOneRelation, + modelClass: User, + join: { + from: 'form_submission_status.assignedToUserId', + to: 'user.id', + }, + }, + }; + } + + static get modifiers() { + return { + filterSubmissionId(query, value) { + if (value !== undefined) { + query.where('submissionId', value); + } + }, + orderDescending(builder) { + builder.orderBy('createdAt', 'desc'); + }, + }; + } + + static get jsonSchema() { + return { + type: 'object', + required: ['submissionId', 'code'], + properties: { + id: { type: 'string', pattern: Regex.UUID }, + submissionId: { type: 'string', pattern: Regex.UUID }, + code: { type: 'string' }, + assignedToUserId: { type: 'string', pattern: Regex.UUID }, + actionDate: { type: 'string' }, + ...stamps, + }, + additionalProperties: false, + }; + } +} + +module.exports = FormSubmissionStatus; diff --git a/frontend/app/src/forms/common/models/tables/formSubmissionUser.js b/frontend/app/src/forms/common/models/tables/formSubmissionUser.js new file mode 100644 index 0000000..8b20704 --- /dev/null +++ b/frontend/app/src/forms/common/models/tables/formSubmissionUser.js @@ -0,0 +1,71 @@ +const { Model } = require('objection'); +const { Timestamps } = require('../mixins'); +const { Regex } = require('../../constants'); +const stamps = require('../jsonSchema').stamps; + +class FormSubmissionUser extends Timestamps(Model) { + static get tableName() { + return 'form_submission_user'; + } + + static get relationMappings() { + const FormSubmission = require('./formSubmission'); + const Permission = require('./permission'); + const User = require('./user'); + + return { + submission: { + relation: Model.HasOneRelation, + modelClass: FormSubmission, + join: { + from: 'form_submission_user.submissionId', + to: 'form_submission.id', + }, + }, + userPermission: { + relation: Model.HasOneRelation, + modelClass: Permission, + join: { + from: 'form_submission_user.permission', + to: 'permission.code', + }, + }, + user: { + relation: Model.HasOneRelation, + modelClass: User, + join: { + from: 'form_submission_user.userId', + to: 'user.id', + }, + }, + }; + } + + static get modifiers() { + return { + orderCreatedAtDescending(builder) { + builder.orderBy('createdAt', 'desc'); + }, + orderUpdatedAtDescending(builder) { + builder.orderBy('updatedAt', 'desc'); + }, + }; + } + + static get jsonSchema() { + return { + type: 'object', + required: ['permission', 'formSubmissionId', 'userId'], + properties: { + id: { type: 'string', pattern: Regex.UUID }, + formSubmissionId: { type: 'string', pattern: Regex.UUID }, + userId: { type: 'string', pattern: Regex.UUID }, + permission: { type: 'string', minLength: 1, maxLength: 255 }, + ...stamps, + }, + additionalProperties: false, + }; + } +} + +module.exports = FormSubmissionUser; diff --git a/frontend/app/src/forms/common/models/tables/formSubscription.js b/frontend/app/src/forms/common/models/tables/formSubscription.js new file mode 100644 index 0000000..947eeeb --- /dev/null +++ b/frontend/app/src/forms/common/models/tables/formSubscription.js @@ -0,0 +1,39 @@ +const { Model } = require('objection'); +const { Timestamps } = require('../mixins'); +const { Regex } = require('../../constants'); +const stamps = require('../jsonSchema').stamps; + +class FormSubscription extends Timestamps(Model) { + static get tableName() { + return 'form_subscription'; + } + + static get modifiers() { + return { + filterFormId(query, value) { + if (value) { + query.where('formId', value); + } + }, + }; + } + + static get jsonSchema() { + return { + type: 'object', + required: ['formId', 'endpointUrl', 'endpointToken'], + properties: { + id: { type: 'string', pattern: Regex.UUID }, + formId: { type: 'string', pattern: Regex.UUID }, + subscribeEvent: { type: 'string' }, + endpointUrl: { type: 'string' }, + endpointToken: { type: 'string' }, + key: { type: 'string' }, + ...stamps, + }, + additionalProperties: false, + }; + } +} + +module.exports = FormSubscription; diff --git a/frontend/app/src/forms/common/models/tables/formVersion.js b/frontend/app/src/forms/common/models/tables/formVersion.js new file mode 100644 index 0000000..4a1a540 --- /dev/null +++ b/frontend/app/src/forms/common/models/tables/formVersion.js @@ -0,0 +1,72 @@ +const { Model } = require('objection'); +const { Timestamps } = require('../mixins'); +const { Regex } = require('../../constants'); +const stamps = require('../jsonSchema').stamps; + +class FormVersion extends Timestamps(Model) { + static get tableName() { + return 'form_version'; + } + + static get relationMappings() { + const FormSubmission = require('./formSubmission'); + + return { + submissions: { + relation: Model.HasManyRelation, + modelClass: FormSubmission, + join: { + from: 'form_version.id', + to: 'form_submission.formVersionId', + }, + }, + }; + } + + static get modifiers() { + return { + selectWithoutSchema(builder) { + builder.select('id', 'formId', 'version', 'published', 'createdBy', 'createdAt', 'updatedBy', 'updatedAt'); + }, + filterVersion(query, value) { + if (value && value > 0) { + query.where('version', value); + } + }, + filterFormId(query, value) { + if (value !== undefined) { + query.where('formId', value); + } + }, + filterPublished(query, value) { + if (value !== undefined) { + query.where('published', value); + } + }, + onlyPublished(query) { + query.where('published', true); + }, + orderVersionDescending(builder) { + builder.orderBy('version', 'desc'); + }, + }; + } + + static get jsonSchema() { + return { + type: 'object', + required: ['formId', 'version', 'schema'], + properties: { + id: { type: 'string', pattern: Regex.UUID }, + formId: { type: 'string', pattern: Regex.UUID }, + version: { type: 'integer' }, + schema: { type: 'object' }, + published: { type: 'boolean' }, + ...stamps, + }, + additionalProperties: false, + }; + } +} + +module.exports = FormVersion; diff --git a/frontend/app/src/forms/common/models/tables/formVersionDraft.js b/frontend/app/src/forms/common/models/tables/formVersionDraft.js new file mode 100644 index 0000000..34598de --- /dev/null +++ b/frontend/app/src/forms/common/models/tables/formVersionDraft.js @@ -0,0 +1,60 @@ +const { Model } = require('objection'); +const { Timestamps } = require('../mixins'); +const { Regex } = require('../../constants'); +const stamps = require('../jsonSchema').stamps; + +class FormVersionDraft extends Timestamps(Model) { + static get tableName() { + return 'form_version_draft'; + } + + static get relationMappings() { + const FormVersion = require('./formVersion'); + + return { + version: { + relation: Model.HasManyRelation, + modelClass: FormVersion, + join: { + from: 'form_version_draft.formVersionId', + to: 'form_version.id', + }, + }, + }; + } + + static get modifiers() { + return { + filterFormId(query, value) { + if (value !== undefined) { + query.where('formId', value); + } + }, + filterFormVersionId(query, value) { + if (value !== undefined) { + query.where('formVersionId', value); + } + }, + orderDescending(builder) { + builder.orderBy('updatedAt', 'desc'); + }, + }; + } + + static get jsonSchema() { + return { + type: 'object', + required: ['formId', 'schema'], + properties: { + id: { type: 'string', pattern: Regex.UUID }, + formId: { type: 'string', pattern: Regex.UUID }, + formVersionId: { type: ['string', 'null'], pattern: Regex.UUID }, + schema: { type: 'object' }, + ...stamps, + }, + additionalProperties: false, + }; + } +} + +module.exports = FormVersionDraft; diff --git a/frontend/app/src/forms/common/models/tables/identityProvider.js b/frontend/app/src/forms/common/models/tables/identityProvider.js new file mode 100644 index 0000000..cebd481 --- /dev/null +++ b/frontend/app/src/forms/common/models/tables/identityProvider.js @@ -0,0 +1,43 @@ +const { Model } = require('objection'); +const { Timestamps } = require('../mixins'); +const stamps = require('../jsonSchema').stamps; + +class IdentityProvider extends Timestamps(Model) { + static get tableName() { + return 'identity_provider'; + } + + static get idColumn() { + return 'code'; + } + + static get modifiers() { + return { + filterActive(query, value) { + if (value !== undefined) { + query.where('active', value); + } + }, + orderDefault(builder) { + builder.orderByRaw('lower("identity_provider"."code")'); + }, + }; + } + + static get jsonSchema() { + return { + type: 'object', + required: ['code', 'display', 'idp'], + properties: { + code: { type: 'string', minLength: 1, maxLength: 255 }, + display: { type: 'string', minLength: 1, maxLength: 255 }, + idp: { type: 'string', minLength: 1, maxLength: 255 }, + active: { type: 'boolean' }, + ...stamps, + }, + additionalProperties: false, + }; + } +} + +module.exports = IdentityProvider; diff --git a/frontend/app/src/forms/common/models/tables/note.js b/frontend/app/src/forms/common/models/tables/note.js new file mode 100644 index 0000000..affa803 --- /dev/null +++ b/frontend/app/src/forms/common/models/tables/note.js @@ -0,0 +1,66 @@ +const { Model } = require('objection'); +const { Timestamps } = require('../mixins'); +const { Regex } = require('../../constants'); +const stamps = require('../jsonSchema').stamps; + +class Note extends Timestamps(Model) { + static get tableName() { + return 'note'; + } + + static get relationMappings() { + const User = require('./user'); + + return { + user: { + relation: Model.HasOneRelation, + modelClass: User, + join: { + from: 'note.userId', + to: 'user.id', + }, + }, + }; + } + + static get modifiers() { + return { + filterId(query, value) { + if (value) { + query.where('id', value); + } + }, + filterSubmissionId(query, value) { + if (value) { + query.where('submissionId', value); + } + }, + filterSubmissionStatusId(query, value) { + if (value) { + query.where('submissionId', value); + } + }, + orderDefault(builder) { + builder.orderBy('createdAt', 'DESC'); + }, + }; + } + + static get jsonSchema() { + return { + type: 'object', + required: ['submissionId'], + properties: { + id: { type: 'string', pattern: Regex.UUID }, + submissionId: { type: 'string', pattern: Regex.UUID }, + submissionStatusId: { type: 'string', pattern: Regex.UUID }, + note: { type: ['string', 'null'], maxLength: 4000 }, + userId: { type: 'string', pattern: Regex.UUID }, + ...stamps, + }, + additionalProperties: false, + }; + } +} + +module.exports = Note; diff --git a/frontend/app/src/forms/common/models/tables/permission.js b/frontend/app/src/forms/common/models/tables/permission.js new file mode 100644 index 0000000..9ba46af --- /dev/null +++ b/frontend/app/src/forms/common/models/tables/permission.js @@ -0,0 +1,69 @@ +const { Model } = require('objection'); +const { Timestamps } = require('../mixins'); +const stamps = require('../jsonSchema').stamps; + +class Permission extends Timestamps(Model) { + static get tableName() { + return 'permission'; + } + + static get relationMappings() { + const Role = require('./role'); + + return { + roles: { + relation: Model.ManyToManyRelation, + modelClass: Role, + join: { + from: 'permission.code', + through: { + from: 'role_permission.permission', + to: 'role_permission.role', + }, + to: 'role.code', + }, + }, + }; + } + + static get modifiers() { + return { + filterCode(query, value) { + if (value) { + // ilike is postgres case insensitive like + query.where('code', 'ilike', `%${value}%`); + } + }, + filterDisplay(query, value) { + if (value) { + // ilike is postgres case insensitive like + query.where('display', 'ilike', `%${value}%`); + } + }, + filterActive(query, value) { + if (value !== undefined) { + query.where('active', value); + } + }, + orderDefault(builder) { + builder.orderByRaw('lower("display")'); + }, + }; + } + + static get jsonSchema() { + return { + type: 'object', + required: ['code', 'display'], + properties: { + code: { type: 'string', minLength: 1, maxLength: 255 }, + display: { type: 'string', minLength: 1, maxLength: 255 }, + active: { type: 'boolean' }, + ...stamps, + }, + additionalProperties: false, + }; + } +} + +module.exports = Permission; diff --git a/frontend/app/src/forms/common/models/tables/role.js b/frontend/app/src/forms/common/models/tables/role.js new file mode 100644 index 0000000..9198fb6 --- /dev/null +++ b/frontend/app/src/forms/common/models/tables/role.js @@ -0,0 +1,69 @@ +const { Model } = require('objection'); +const { Timestamps } = require('../mixins'); +const stamps = require('../jsonSchema').stamps; + +class Role extends Timestamps(Model) { + static get tableName() { + return 'role'; + } + + static get relationMappings() { + const Permission = require('./permission'); + + return { + permissions: { + relation: Model.ManyToManyRelation, + modelClass: Permission, + join: { + from: 'role.code', + through: { + from: 'role_permission.role', + to: 'role_permission.permission', + }, + to: 'permission.code', + }, + }, + }; + } + + static get modifiers() { + return { + filterCode(query, value) { + if (value) { + // ilike is postgres case insensitive like + query.where('code', 'ilike', `%${value}%`); + } + }, + filterDisplay(query, value) { + if (value) { + // ilike is postgres case insensitive like + query.where('display', 'ilike', `%${value}%`); + } + }, + filterActive(query, value) { + if (value !== undefined) { + query.where('active', value); + } + }, + orderDefault(builder) { + builder.orderByRaw('lower("display")'); + }, + }; + } + + static get jsonSchema() { + return { + type: 'object', + required: ['code', 'display'], + properties: { + code: { type: 'string', minLength: 1, maxLength: 255 }, + display: { type: 'string', minLength: 1, maxLength: 255 }, + active: { type: 'boolean' }, + ...stamps, + }, + additionalProperties: false, + }; + } +} + +module.exports = Role; diff --git a/frontend/app/src/forms/common/models/tables/statusCode.js b/frontend/app/src/forms/common/models/tables/statusCode.js new file mode 100644 index 0000000..3aaa7d7 --- /dev/null +++ b/frontend/app/src/forms/common/models/tables/statusCode.js @@ -0,0 +1,26 @@ +const { Model } = require('objection'); +const { Timestamps } = require('../mixins'); +const { Regex } = require('../../constants'); +const stamps = require('../jsonSchema').stamps; + +class StatusCode extends Timestamps(Model) { + static get tableName() { + return 'status_code'; + } + + static get jsonSchema() { + return { + type: 'object', + required: ['code'], + properties: { + code: { type: 'string' }, + display: { type: 'string' }, + nextCodes: { type: ['array', 'null'], items: { type: 'string', pattern: Regex.EMAIL } }, + ...stamps, + }, + additionalProperties: false, + }; + } +} + +module.exports = StatusCode; diff --git a/frontend/app/src/forms/common/models/tables/submissionAudit.js b/frontend/app/src/forms/common/models/tables/submissionAudit.js new file mode 100644 index 0000000..9ca6e51 --- /dev/null +++ b/frontend/app/src/forms/common/models/tables/submissionAudit.js @@ -0,0 +1,48 @@ +const { Model } = require('objection'); +const { Regex } = require('../../constants'); + +class SubmissionAudit extends Model { + static get tableName() { + return 'form_submission_audit'; + } + + static get modifiers() { + return { + filterId(query, value) { + if (value) { + query.where('id', value); + } + }, + filterSubmissionId(query, value) { + if (value) { + query.where('submissionId', value); + } + }, + filterDraft(query, value) { + query.whereRaw('("originalData"->>\'draft\')::boolean = ?', value); + }, + orderDefault(builder) { + builder.orderBy('actionTimestamp', 'DESC'); + }, + }; + } + + static get jsonSchema() { + return { + type: 'object', + required: ['submissionId'], + properties: { + id: { type: 'integer' }, + submissionId: { type: 'string', pattern: Regex.UUID }, + dbUser: { type: 'string', maxLength: 255 }, + updatedByUsername: { type: ['string', 'null'], maxLength: 255 }, + actionTimestamp: { type: ['string', 'null'] }, + action: { type: 'string', maxLength: 255 }, + originalData: { type: 'object' }, + }, + additionalProperties: false, + }; + } +} + +module.exports = SubmissionAudit; diff --git a/frontend/app/src/forms/common/models/tables/user.js b/frontend/app/src/forms/common/models/tables/user.js new file mode 100644 index 0000000..6124e4f --- /dev/null +++ b/frontend/app/src/forms/common/models/tables/user.js @@ -0,0 +1,117 @@ +const { Model } = require('objection'); +const { Timestamps } = require('../mixins'); +const { Regex, Restricted } = require('../../constants'); +const stamps = require('../jsonSchema').stamps; + +class User extends Timestamps(Model) { + static get tableName() { + return 'user'; + } + + static get relationMappings() { + const IdentityProvider = require('./identityProvider'); + + return { + identityProvider: { + relation: Model.BelongsToOneRelation, + modelClass: IdentityProvider, + join: { + from: 'user.idpCode', + to: 'identity_provider.code', + }, + }, + }; + } + + static get modifiers() { + return { + filterIdpUserId(query, value) { + if (value) { + query.where('idpUserId', value); + } + }, + filterKeycloakId(query, value) { + if (value) { + query.where('keycloakId', value); + } + }, + filterIdpCode(query, value) { + if (value) { + query.where('idpCode', value); + } + }, + filterRestricted(query) { + query.whereNotIn('idpCode', Object.values(Restricted.IDP)); + }, + filterUsername(query, value, exact = false) { + if (value) { + if (exact) query.where('username', value); + // ilike is postgres case insensitive like + else query.where('username', 'ilike', `%${value}%`); + } + }, + filterFirstName(query, value) { + if (value) { + // ilike is postgres case insensitive like + query.where('firstName', 'ilike', `%${value}%`); + } + }, + filterLastName(query, value) { + if (value) { + // ilike is postgres case insensitive like + query.where('lastName', 'ilike', `%${value}%`); + } + }, + filterFullName(query, value) { + if (value) { + // ilike is postgres case insensitive like + query.where('fullName', 'ilike', `%${value}%`); + } + }, + filterEmail(query, value, exact = false) { + if (value) { + if (exact) query.where('email', value); + // ilike is postgres case insensitive like + else query.where('email', 'ilike', `%${value}%`); + } + }, + filterSearch(query, value) { + // use this field 'search' to OR across many fields + // must be written as subquery function to force parentheses grouping + if (value) { + query.where((subquery) => { + subquery.where('username', 'ilike', `%${value}%`).orWhere('fullName', 'ilike', `%${value}%`).orWhere('email', 'ilike', `%${value}%`); + }); + } + }, + safeSelect(query) { + query.select('id', 'idpUserId', 'keycloakId', 'idpCode'); + }, + orderLastFirstAscending(builder) { + builder.orderByRaw('lower("lastName"), lower("firstName")'); + }, + }; + } + + static get jsonSchema() { + return { + type: 'object', + required: ['keycloakId'], + properties: { + id: { type: 'string', pattern: Regex.UUID }, + idpUserId: { type: 'string', maxLength: 255 }, + keycloakId: { type: 'string', pattern: Regex.UUID }, + username: { type: ['string', 'null'], maxLength: 255 }, + firstName: { type: ['string', 'null'], maxLength: 255 }, + lastName: { type: ['string', 'null'], maxLength: 255 }, + fullName: { type: ['string', 'null'], maxLength: 255 }, + email: { type: ['string', 'null'], maxLength: 255 }, + idpCode: { type: ['string', 'null'], maxLength: 255 }, + ...stamps, + }, + additionalProperties: false, + }; + } +} + +module.exports = User; diff --git a/frontend/app/src/forms/common/models/tables/userFormPreferences.js b/frontend/app/src/forms/common/models/tables/userFormPreferences.js new file mode 100644 index 0000000..cbc8a55 --- /dev/null +++ b/frontend/app/src/forms/common/models/tables/userFormPreferences.js @@ -0,0 +1,31 @@ +const { Model } = require('objection'); +const { Timestamps } = require('../mixins'); +const { Regex } = require('../../constants'); +const stamps = require('../jsonSchema').stamps; + +class UserFormPreferences extends Timestamps(Model) { + static get tableName() { + return 'user_form_preferences'; + } + + // This is a composite key - order of attributes is important + static get idColumn() { + return ['userId', 'formId']; + } + + static get jsonSchema() { + return { + type: 'object', + required: ['formId', 'userId'], + properties: { + userId: { type: 'string', pattern: Regex.UUID }, + formId: { type: 'string', pattern: Regex.UUID }, + preferences: { type: 'object' }, + ...stamps, + }, + additionalProperties: false, + }; + } +} + +module.exports = UserFormPreferences; diff --git a/frontend/app/src/forms/common/models/utils.js b/frontend/app/src/forms/common/models/utils.js new file mode 100644 index 0000000..78bf3c9 --- /dev/null +++ b/frontend/app/src/forms/common/models/utils.js @@ -0,0 +1,25 @@ +const toArray = (values) => { + if (values) { + return Array.isArray(values) ? values.filter((p) => p && p.trim().length > 0) : [values].filter((p) => p && p.trim().length > 0); + } + return []; +}; +const inArrayClause = (column, values) => { + return values.map((p) => `'${p}' = ANY("${column}")`).join(' or '); +}; + +const inArrayFilter = (column, values) => { + const clause = inArrayClause(column, values); + return `(array_length("${column}", 1) > 0 and (${clause}))`; +}; + +const tableNames = (models) => { + return Object.values(models).map((model) => model.tableName); +}; + +module.exports = { + toArray, + inArrayClause, + inArrayFilter, + tableNames, +}; diff --git a/frontend/app/src/forms/common/models/views/formSubmissionUserPermissions.js b/frontend/app/src/forms/common/models/views/formSubmissionUserPermissions.js new file mode 100644 index 0000000..bd4adac --- /dev/null +++ b/frontend/app/src/forms/common/models/views/formSubmissionUserPermissions.js @@ -0,0 +1,40 @@ +const { Model } = require('objection'); + +const utils = require('../utils'); + +class FormSubmissionUserPermissions extends Model { + static get tableName() { + return 'form_submission_users_vw'; + } + + static get modifiers() { + return { + filterSubmissionId(query, value) { + if (value) { + query.where('formSubmissionId', value); + } + }, + filterUserId(query, value) { + if (value) { + query.where('userId', value); + } + }, + filterByPermissions(query, permissions) { + if (permissions) { + const _permissions = utils.toArray(permissions); + let clauses = []; + + if (_permissions.length) { + clauses.push(utils.inArrayFilter('permissions', _permissions)); + } + + if (clauses.length) { + query.whereRaw(`(${clauses.join(' or ')})`); + } + } + }, + }; + } +} + +module.exports = FormSubmissionUserPermissions; diff --git a/frontend/app/src/forms/common/models/views/publicFormAccess.js b/frontend/app/src/forms/common/models/views/publicFormAccess.js new file mode 100644 index 0000000..4663059 --- /dev/null +++ b/frontend/app/src/forms/common/models/views/publicFormAccess.js @@ -0,0 +1,27 @@ +const { Model } = require('objection'); + +class PublicFormAccess extends Model { + static get tableName() { + return 'public_form_access_vw'; + } + + static get modifiers() { + return { + filterActive(query, value) { + if (value !== undefined) { + query.where('active', value); + } + }, + filterFormId(query, value) { + if (value) { + query.where('formId', value); + } + }, + orderDefault(builder) { + builder.orderByRaw('lower("formName")'); + }, + }; + } +} + +module.exports = PublicFormAccess; diff --git a/frontend/app/src/forms/common/models/views/submissionData.js b/frontend/app/src/forms/common/models/views/submissionData.js new file mode 100644 index 0000000..d3728e5 --- /dev/null +++ b/frontend/app/src/forms/common/models/views/submissionData.js @@ -0,0 +1,55 @@ +const { Model } = require('objection'); + +class SubmissionData extends Model { + static get tableName() { + return 'submissions_data_vw'; + } + + static get modifiers() { + return { + filterVersion(query, value) { + if (value) { + query.where('version', value); + } + }, + filterCreatedAt(query, minDate, maxDate) { + if (minDate && maxDate) { + query.whereBetween('createdAt', [minDate, maxDate]); + } else if (minDate) { + query.where('createdAt', '>=', minDate); + } else if (maxDate) { + query.where('createdAt', '<=', maxDate); + } + }, + filterUpdatedAt(query, minDate, maxDate) { + if (minDate && maxDate) { + query.whereBetween('updatedAt', [minDate, maxDate]); + } else if (minDate) { + query.where('updatedAt', '>=', minDate); + } else if (maxDate) { + query.where('updatedAt', '<=', maxDate); + } + }, + filterStatus(query, value) { + if (value) { + query.where('status', value); + } + }, + filterDeleted(query, value) { + if (!value) { + query.where('deleted', false); + } + }, + filterDrafts(query, value) { + if (!value) { + query.where('draft', false); + } + }, + orderDefault(builder) { + builder.orderBy('createdAt', 'DESC'); + }, + }; + } +} + +module.exports = SubmissionData; diff --git a/frontend/app/src/forms/common/models/views/submissionMetadata.js b/frontend/app/src/forms/common/models/views/submissionMetadata.js new file mode 100644 index 0000000..68585de --- /dev/null +++ b/frontend/app/src/forms/common/models/views/submissionMetadata.js @@ -0,0 +1,85 @@ +const { Model } = require('objection'); + +class SubmissionMetadata extends Model { + static get tableName() { + return 'submissions_vw'; + } + + static get modifiers() { + return { + filterSubmissionId(query, value) { + if (value) { + query.where('submissionId', value); + } + }, + filterConfirmationId(query, value) { + if (value) { + query.where('confirmationId', value); + } + }, + filterformSubmissionStatusCode(query, value) { + if (value) { + query.whereNot('formSubmissionStatusCode', null); + } + }, + + filterDraft(query, value) { + if (value !== undefined) { + query.where('draft', value); + } + }, + filterDeleted(query, value) { + if (value !== undefined) { + query.where('deleted', value); + } + }, + filterCreatedBy(query, value) { + if (value) { + query.where('createdBy', 'ilike', `%${value}%`); + } + }, + filterFormId(query, value) { + if (value) { + query.where('formId', value); + } + }, + filterFormName(query, value) { + if (value) { + query.where('formName', 'ilike', `%${value}%`); + } + }, + filterFormVersionId(query, value) { + if (value) { + query.where('formVersionId', value); + } + }, + filterVersion(query, value) { + if (value) { + query.where('version', value); + } + }, + orderDefault(builder, pagination, params) { + if (!pagination) { + builder.orderBy('createdAt', 'DESC'); + } else { + let orderBy = params?.sortBy.column; + let orderDirection = params?.sortBy.order; + if (orderBy && orderDirection) { + builder.orderBy(orderBy, orderDirection); + } + } + }, + filterCreatedAt(query, minDate, maxDate) { + if (minDate && maxDate) { + query.whereBetween('createdAt', [minDate, maxDate]); + } else if (minDate) { + query.where('createdAt', '>=', minDate); + } else if (maxDate) { + query.where('createdAt', '<=', maxDate); + } + }, + }; + } +} + +module.exports = SubmissionMetadata; diff --git a/frontend/app/src/forms/common/models/views/userFormAccess.js b/frontend/app/src/forms/common/models/views/userFormAccess.js new file mode 100644 index 0000000..37cab93 --- /dev/null +++ b/frontend/app/src/forms/common/models/views/userFormAccess.js @@ -0,0 +1,111 @@ +const { Model } = require('objection'); + +const utils = require('../utils'); + +class UserFormAccess extends Model { + static get tableName() { + return 'user_form_access_vw'; + } + + static get modifiers() { + return { + filterUserId(query, value) { + if (value) { + query.where('userId', value); + } + }, + filterIdpUserId(query, value) { + if (value) { + query.where('idpUserId', value); + } + }, + filterUsername(query, value) { + if (value) { + query.where('username', 'ilike', `%${value}%`); + } + }, + filterFullName(query, value) { + if (value) { + query.where('fullName', 'ilike', `%${value}%`); + } + }, + filterFirstName(query, value) { + if (value) { + query.where('firstName', 'ilike', `%${value}%`); + } + }, + filterLastName(query, value) { + if (value) { + query.where('lastName', 'ilike', `%${value}%`); + } + }, + filterEmail(query, value) { + if (value) { + query.where('email', 'ilike', `%${value}%`); + } + }, + filterFormId(query, value) { + if (value) { + query.where('formId', value); + } + }, + filterFormName(query, value) { + if (value) { + query.where('formName', 'ilike', `%${value}%`); + } + }, + filterActive(query, value) { + if (value !== undefined) { + query.where('active', value); + } + }, + filterByAccess(query, idps, roles, permissions) { + if (idps || roles || permissions) { + const _idps = utils.toArray(idps); + const _roles = utils.toArray(roles); + const _permissions = utils.toArray(permissions); + let clauses = []; + + if (_idps.length) { + if (_idps.length === 1 && _idps[0] === '*') { + clauses.push('(\'{}\'::varchar[] = "roles" and array_length("idps", 1) > 0)'); + } else { + clauses.push(`('{}'::varchar[] = "roles" and (${utils.inArrayClause('idps', _idps)}))`); + } + } + + if (_roles.length) { + if (_roles.length === 1 && _roles[0] === '*') { + clauses.push('array_length("roles", 1) > 0'); + } else { + clauses.push(utils.inArrayFilter('roles', _roles)); + } + } + + if (_permissions.length) { + if (_permissions.length === 1 && _permissions[0] === '*') { + clauses.push('array_length("permissions", 1) > 0'); + } else { + clauses.push(utils.inArrayFilter('permissions', _permissions)); + } + } + + if (clauses.length) { + query.whereRaw(`(${clauses.join(' or ')})`); + } + } + }, + orderFormNameAscending(builder) { + builder.orderByRaw('lower("formName")'); + }, + orderLastFirstAscending(builder) { + builder.orderByRaw('lower("lastName"), lower("firstName")'); + }, + orderDefault(builder) { + builder.orderByRaw('lower("lastName"), lower("firstName"), lower("formName")'); + }, + }; + } +} + +module.exports = UserFormAccess; diff --git a/frontend/app/src/forms/common/models/views/userSubmissions.js b/frontend/app/src/forms/common/models/views/userSubmissions.js new file mode 100644 index 0000000..9e9766a --- /dev/null +++ b/frontend/app/src/forms/common/models/views/userSubmissions.js @@ -0,0 +1,70 @@ +const { Model } = require('objection'); + +class UserSubmissions extends Model { + static get tableName() { + return 'submissions_submitters_vw'; + } + + static get relationMappings() { + const FormSubmission = require('../tables/formSubmission'); + const FormSubmissionStatus = require('../tables/formSubmissionStatus'); + const User = require('../tables/user'); + + return { + submission: { + relation: Model.HasOneRelation, + modelClass: FormSubmission, + join: { + from: 'submissions_submitters_vw.formSubmissionId', + to: 'form_submission.id', + }, + }, + submissionStatus: { + relation: Model.HasManyRelation, + modelClass: FormSubmissionStatus, + join: { + from: 'submissions_submitters_vw.formSubmissionId', + to: 'form_submission_status.submissionId', + }, + }, + user: { + relation: Model.HasOneRelation, + modelClass: User, + join: { + from: 'submissions_submitters_vw.userId', + to: 'user.id', + }, + }, + }; + } + + static get modifiers() { + return { + filterFormId(query, value) { + if (value) { + query.where('formId', value); + } + }, + filterFormSubmissionId(query, value) { + if (value) { + query.where('formSubmissionId', value); + } + }, + filterUserId(query, value) { + if (value) { + query.where('userId', value); + } + }, + filterActive(query, value) { + if (value !== undefined) { + query.where('deleted', !value); + } + }, + orderDefault(builder) { + builder.orderBy('createdAt', 'DESC'); + }, + }; + } +} + +module.exports = UserSubmissions; diff --git a/frontend/app/src/forms/common/utils.js b/frontend/app/src/forms/common/utils.js new file mode 100644 index 0000000..afdd740 --- /dev/null +++ b/frontend/app/src/forms/common/utils.js @@ -0,0 +1,746 @@ +const falsey = require('falsey'); +const moment = require('moment'); +const clone = require('lodash/clone'); +const _ = require('lodash'); +const setupMount = (type, app, routes, dataErrors) => { + const p = `/${type}`; + app.use(p, routes); + app.use(dataErrors); + return p; +}; + +const typeUtils = { + isInt: (x) => { + if (isNaN(x)) { + return false; + } + const num = parseFloat(x); + // use modulus to determine if it is an int + return num % 1 === 0; + }, + isNumeric: (x) => { + return Object.prototype.toString.call(x) === '[object Number]'; + }, + isString: (x) => { + return Object.prototype.toString.call(x) === '[object String]'; + }, + isBoolean: (x) => { + return Object.prototype.toString.call(x) === '[object Boolean]'; + }, + isObject: (x) => { + return Object.prototype.toString.call(x) === '[object Object]'; + }, + isNil: (x) => { + return x == null; + }, + isDate: (x) => { + var d = new Date(x); + return !isNaN(d.valueOf()); + }, +}; + +const queryUtils = { + defaultActiveOnly: (params) => { + if (!params) { + params = {}; + } + let active = true; + if (!typeUtils.isNil(params.active)) { + // if caller hasn't explicitly set active, then force to active = true, do not return "deleted" forms. + active = !falsey(params.active); + } + params.active = active; + return params; + }, +}; + +/** + * @function isFormExpired + * Returns true for a form's schedule object if this form schedule available for that period + * @param {Object} form Schedule data + * @returns {boolean} TRUE if form not expired and Available to submission + * + */ +const isFormExpired = (formSchedule = {}) => { + let result = { + allowLateSubmissions: false, + expire: false, + message: 'Form Submission is not available.', + }; + + if (formSchedule && formSchedule.enabled) { + //Check if Form open date is in past or Is form already started for submission + if (formSchedule.openSubmissionDateTime) { + let startDate = moment(formSchedule.openSubmissionDateTime).format('YYYY-MM-DD HH:MM:SS'); + let isFormStartedAlready = moment().diff(startDate, 'seconds'); //If a positive number it means form get started + if (isFormStartedAlready >= 0) { + //Form have valid past open date for scheduling so lets check for the next conditions + if (isFormStartedAlready && formSchedule.enabled) { + if (formSchedule.closingMessage) { + result = { ...result, message: formSchedule.closingMessage }; + } + let closeDate = getCalculatedCloseSubmissionDate( + startDate, + formSchedule.keepOpenForTerm, + formSchedule.keepOpenForInterval, + formSchedule.allowLateSubmissions.enabled ? formSchedule.allowLateSubmissions.forNext.term : 0, + formSchedule.allowLateSubmissions.forNext.intervalType, + formSchedule.repeatSubmission.everyTerm, + formSchedule.repeatSubmission.everyIntervalType, + formSchedule.repeatSubmission.repeatUntil + ); //moment(formSchedule.closeSubmissionDateTime).format('YYYY-MM-DD HH:MM:SS'); + let isBetweenStartAndCloseDate = moment().isBetween(startDate, closeDate); + + if (isBetweenStartAndCloseDate) { + /** Check if form is Repeat enabled - start */ + /** Check if form is Repeat enabled and alow late submition - start */ + if (formSchedule.repeatSubmission.enabled) { + let availableDates = getAvailableDates( + formSchedule.keepOpenForTerm, + formSchedule.keepOpenForInterval, + startDate, + formSchedule.repeatSubmission.everyTerm, + formSchedule.repeatSubmission.everyIntervalType, + formSchedule.allowLateSubmissions.enabled ? formSchedule.allowLateSubmissions.forNext.term : 0, + formSchedule.allowLateSubmissions.forNext.intervalType, + formSchedule.repeatSubmission.repeatUntil + ); + for (let i = 0; i < availableDates.length; i++) { + //Check if today is the day when a submitter can submit the form for given period of repeat submission + let repeatIsBetweenStartAndCloseDate = moment().isBetween(availableDates[i].startDate, availableDates[i].closeDate); + + if (repeatIsBetweenStartAndCloseDate) { + result = { ...result, expire: false }; //Form is available for given period to be submit. + break; + } else if (formSchedule.allowLateSubmissions.enabled) { + result = { ...result, expire: true }; + /** Check if form is alow late submition - start */ + let isallowLateSubmissions = moment().isBetween(availableDates[i].startDate, availableDates[i].graceDate); + + if (isallowLateSubmissions) { + //If late submission is allowed for the given repeat submission period then stop checking for other dates + result = { + ...result, + expire: true, + allowLateSubmissions: isallowLateSubmissions, + }; + break; + } + /** Check if form is alow late submition - end */ + } else { + result = { ...result, expire: true, allowLateSubmissions: false }; + } + } + } + /** Check if form is Repeat enabled and alow late submition - end */ + /** Check if form is Repeat enabled - end */ + } else { + //if close date not valid or not-in future OR close date not in between start and Today then block formSubmission but check the late submission if allowed + + if (formSchedule.allowLateSubmissions.enabled) { + /** Check if form is alow late submition - start */ + result = { + ...result, + expire: true, + allowLateSubmissions: isEligibleLateSubmission(closeDate, formSchedule.allowLateSubmissions.forNext.term, formSchedule.allowLateSubmissions.forNext.intervalType), + }; + /** Check if form is alow late submition - end */ + } else { + result = { ...result, expire: true, allowLateSubmissions: false }; + } + } + } + } else { + //Form schedule open date is in the future so form will not be available for submission + result = { ...result, expire: true, allowLateSubmissions: false, message: 'This form is not yet available for submission.' }; + } + } + } + return result; +}; + +/** + * @function checkIsFormExpired + * @param {Object} form Schedule data + * @returns {Object} {allowLateSubmissions:Boolean,expire:Boolean,message:String} + * + */ +const checkIsFormExpired = (formSchedule = {}) => { + let result = { + allowLateSubmissions: false, + expire: false, + message: '', + }; + + if (formSchedule && formSchedule.enabled) { + //Check if Form open date is in past or Is form already started for submission + if (formSchedule.openSubmissionDateTime) { + let startDate = moment(formSchedule.openSubmissionDateTime).format('YYYY-MM-DD HH:MM:SS'); + let closingDate = null; + if (formSchedule.scheduleType === 'closingDate' && formSchedule.closeSubmissionDateTime) { + closingDate = moment(formSchedule.closeSubmissionDateTime).format('YYYY-MM-DD HH:MM:SS'); + } + let isFormStartedAlready = moment().diff(startDate, 'seconds'); //If a positive number it means form get started + if (isFormStartedAlready >= 0) { + //Form have valid past open date for scheduling so lets check for the next conditions + if (isFormStartedAlready && formSchedule.enabled && formSchedule.scheduleType !== 'manual') { + if (formSchedule.closingMessageEnabled) { + if (formSchedule.closingMessage) { + result = { ...result, message: formSchedule.closingMessage }; + } else { + result = { ...result, message: 'Something went wrong.' }; + } + } else { + result = { ...result, message: 'The form submission period has expired.' }; + } + + let closeDate = + formSchedule.scheduleType === 'period' + ? getCalculatedCloseSubmissionDate( + startDate, + formSchedule.keepOpenForTerm, + formSchedule.keepOpenForInterval, + formSchedule.allowLateSubmissions.enabled ? formSchedule.allowLateSubmissions.forNext.term : 0, + formSchedule.allowLateSubmissions.forNext.intervalType, + formSchedule.repeatSubmission.everyTerm, + formSchedule.repeatSubmission.everyIntervalType, + formSchedule.repeatSubmission.repeatUntil, + formSchedule.scheduleType, + formSchedule.closeSubmissionDateTime + ) + : closingDate; //moment(formSchedule.closeSubmissionDateTime).format('YYYY-MM-DD HH:MM:SS'); + let isBetweenStartAndCloseDate = moment().isBetween(startDate, closeDate); + + if (isBetweenStartAndCloseDate) { + /** Check if form is Repeat enabled - start */ + /** Check if form is Repeat enabled and alow late submition - start */ + if (formSchedule.repeatSubmission.enabled) { + let availableDates = getAvailableDates( + formSchedule.keepOpenForTerm, + formSchedule.keepOpenForInterval, + startDate, + formSchedule.repeatSubmission.everyTerm, + formSchedule.repeatSubmission.everyIntervalType, + formSchedule.allowLateSubmissions.enabled ? formSchedule.allowLateSubmissions.forNext.term : 0, + formSchedule.allowLateSubmissions.forNext.intervalType, + formSchedule.repeatSubmission.repeatUntil, + formSchedule.scheduleType, + formSchedule.closeSubmissionDateTime + ); + for (let i = 0; i < availableDates.length; i++) { + //Check if today is the day when a submitter can submit the form for given period of repeat submission + let repeatIsBetweenStartAndCloseDate = moment().isBetween(availableDates[i].startDate, availableDates[i].closeDate); + + if (repeatIsBetweenStartAndCloseDate) { + result = { ...result, expire: false }; //Form is available for given period to be submit. + break; + } else if (formSchedule.allowLateSubmissions.enabled) { + result = { ...result, expire: true }; + /** Check if form is alow late submition - start */ + let isallowLateSubmissions = moment().isBetween(availableDates[i].startDate, availableDates[i].graceDate); + if (isallowLateSubmissions) { + //If late submission is allowed for the given repeat submission period then stop checking for other dates + result = { + ...result, + expire: true, + allowLateSubmissions: isallowLateSubmissions, + }; + break; + } + /** Check if form is alow late submition - end */ + } else { + result = { ...result, expire: true, allowLateSubmissions: false }; + } + } + } + /** Check if form is Repeat enabled and alow late submition - end */ + /** Check if form is Repeat enabled - end */ + } else { + //if close date not valid or not-in future OR close date not in between start and Today then block formSubmission but check the late submission if allowed + + if (formSchedule.allowLateSubmissions.enabled) { + /** Check if form is alow late submition - start */ + result = { + ...result, + expire: true, + allowLateSubmissions: isEligibleLateSubmission(closeDate, formSchedule.allowLateSubmissions.forNext.term, formSchedule.allowLateSubmissions.forNext.intervalType), + }; + /** Check if form is alow late submition - end */ + } else { + result = { ...result, expire: true, allowLateSubmissions: false }; + } + } + } + } else { + //Form schedule open date is in the future so form will not be available for submission + result = { ...result, expire: true, allowLateSubmissions: false, message: 'This form is not yet available for submission.' }; + } + } + } + return result; +}; + +/** + * @function isEligibleLateSubmission + * Get All possible dates in given period with Term and Interval + * + * @param {Object[]} date An object of Moment JS date + * @param {Integer} term An integer of number of Days/Weeks OR Years + * @param {String} interval A string of days,Weeks,months + * @returns {Boolean} Return true if form is available for late submission + */ +const isEligibleLateSubmission = (date, term, interval) => { + let gracePeriodDate = moment(date, 'YYYY-MM-DD HH:mm:ss').add(term, interval).format('YYYY-MM-DD HH:mm:ss'); + let isBetweenCloseAndGraceDate = moment().isBetween(date, gracePeriodDate); + return isBetweenCloseAndGraceDate; +}; + +/** + * @function getAvailableDates + * Get All possible dates in given period with Term and Interval + * + * @param {Integer} keepAliveFor An integer for number of days + * @param {String} keepAliveForInterval A string of days,Weeks,months + * @param {Object[]} subStartDate An object of Moment JS date + * @param {Integer} term An integer of number of Days/Weeks OR Years + * @param {String} interval A string of days,Weeks,months + * @param {Integer} allowLateTerm An integer of number of Days/Weeks OR Years + * @param {String} allowLateInterval A string of days,Weeks,months + * @param {Object[]} repeatUntil An object of Moment JS date + * @param {String} scheduleType A string one of Manual, ClosingDate OR Period + * @param {Object[]} closeDate An object of Moment JS date + * @returns {Object[]} An object array of Available dates in given period + */ +const getAvailableDates = ( + keepAliveFor = 0, + keepAliveForInterval = 'days', + subStartDate, + term = null, + interval = null, + allowLateTerm = null, + allowLateInterval = null, + repeatUntil, + scheduleType, + closeDate = null +) => { + let substartDate = moment(subStartDate); + repeatUntil = moment(repeatUntil); + let calculatedsubcloseDate = getCalculatedCloseSubmissionDate( + substartDate, + keepAliveFor, + keepAliveForInterval, + allowLateTerm, + allowLateInterval, + term, + interval, + repeatUntil, + scheduleType, + closeDate + ); + let availableDates = []; + if (calculatedsubcloseDate && term && interval) { + while (substartDate.isBefore(calculatedsubcloseDate)) { + let newDate = substartDate.clone(); + if (substartDate.isBefore(repeatUntil)) { + availableDates.push( + Object({ + startDate: substartDate.format('YYYY-MM-DD HH:MM:SS'), + closeDate: newDate.add(keepAliveFor, keepAliveForInterval).format('YYYY-MM-DD HH:MM:SS'), + graceDate: newDate.add(allowLateTerm, allowLateInterval).format('YYYY-MM-DD HH:MM:SS'), + }) + ); + } + substartDate.add(term, interval); + } + } + + if (term == null && interval == null && keepAliveFor && keepAliveForInterval) { + let newDates = substartDate.clone(); + availableDates.push( + Object({ + startDate: substartDate.format('YYYY-MM-DD HH:MM:SS'), + closeDate: newDates.add(keepAliveFor, keepAliveForInterval).format('YYYY-MM-DD HH:MM:SS'), + graceDate: allowLateTerm && allowLateInterval ? newDates.add(allowLateTerm, allowLateInterval).format('YYYY-MM-DD HH:MM:SS') : null, + }) + ); + } + return availableDates; +}; + +/** + * @function getCalculatedCloseSubmissionDate + * Get calculated Close date for a Form schedule setting with the given scenario + * + * @param {Object[]} openDate An object of Moment JS date + * keepOpenForTerm + * keepOpenForInterval + * @param {Integer} term An integer of number of Days/Weeks OR Years + * @param {String} interval A string of days,Weeks,months + * @param {Integer} allowLateTerm An integer of number of Days/Weeks OR Years + * @param {String} allowLateInterval A string of days,Weeks,months + * @param {Integer} repeatSubmissionTerm An integer of number of Days/Weeks OR Years + * @param {String} repeatSubmissionInterval A string of days,Weeks,months + * @param {Object[]} repeatUntil An object of Moment JS date + * @param {Object[]} closeDate and object of moment JS date + * @returns {Object[]} An object of Moment JS date + */ +const getCalculatedCloseSubmissionDate = ( + openedDate = moment(), + keepOpenForTerm = 0, + keepOpenForInterval = 'days', + allowLateTerm = 0, + allowLateInterval = 'days', + repeatSubmissionTerm = 0, + repeatSubmissionInterval = 'days', + repeatSubmissionUntil = moment() +) => { + const openDate = moment(openedDate).clone(); + let calculatedCloseDate = moment(openDate); + repeatSubmissionUntil = moment(repeatSubmissionUntil); + + if (!allowLateTerm && !repeatSubmissionTerm) { + calculatedCloseDate = openDate.add(keepOpenForTerm, keepOpenForInterval).format('YYYY-MM-DD HH:MM:SS'); + } else { + if (repeatSubmissionTerm && repeatSubmissionInterval && repeatSubmissionUntil) { + calculatedCloseDate = repeatSubmissionUntil; + } + if (allowLateTerm && allowLateInterval) { + calculatedCloseDate = calculatedCloseDate.add(keepOpenForTerm, keepOpenForInterval).add(allowLateTerm, allowLateInterval).format('YYYY-MM-DD HH:MM:SS'); + } + } + + return calculatedCloseDate; +}; + +const periodType = { + Daily: { name: 'Daily', value: 1, regex: 'days' }, + Weekly: { name: 'Weekly', value: 7, regex: 'days' }, + BiWeekly: { name: 'Bi-weekly', value: 14, regex: 'days' }, + Monthly: { name: 'Monthly', value: 1, regex: 'months' }, + Quaterly: { name: 'Quaterly', value: 3, regex: 'months' }, + SemiAnnually: { name: 'Semi-Annually', value: 6, regex: 'months' }, + Annually: { name: 'Annually', value: 1, regex: 'years' }, +}; + +const flattenComponents = (components, includeAll) => { + const flattened = []; + eachComponent( + components, + (component, path) => { + flattened.push(path); + }, + includeAll + ); + return flattened.flatMap((path) => path); +}; + +const eachComponent = (components, fn, includeAll, path, parent, inRecursion) => { + if (!components) return; + path = path || ''; + if (inRecursion) { + if (components.noRecurse) { + delete components.noRecurse; + return; + } + components.noRecurse = true; + } + components.forEach((component) => { + if (!component) { + return; + } + + const hasColumns = component.columns && Array.isArray(component.columns); + const hasRows = component.rows && Array.isArray(component.rows); + const hasComps = component.components && Array.isArray(component.components); + let noRecurse = false; + const newPath = component.key ? (path ? `${path}.${component.key}` : component.key) : ''; + + // Keep track of parent references. + if (parent) { + // Ensure we don't create infinite JSON structures. + component.parent = clone(parent); + delete component.parent.components; + delete component.parent.componentMap; + delete component.parent.columns; + delete component.parent.rows; + } + + // there's no need to add other layout components here because we expect that those would either have columns, rows or components + const layoutTypes = ['htmlelement', 'content', 'simplecontent', 'button']; + const isLayoutComponent = hasColumns || hasRows || (hasComps && !component.input) || layoutTypes.indexOf(component.type) > -1; + if (includeAll || component.tree || !isLayoutComponent) { + let keyPath = []; + const componentsWithSubValues = ['simplecheckboxes', 'selectboxes', 'survey', 'tree']; + if (component.type && componentsWithSubValues.includes(component.type)) { + // for survey component, get field name from obj.questions.value + if (component.type === 'survey') { + component.questions.forEach((e) => keyPath.push(path ? `${path}.${component.key}.${e.value}` : `${component.key}.${e.value}`)); + } + // for checkboxes and selectboxes, get field name from obj.values.value + else if (component.values) component.values.forEach((e) => keyPath.push(path ? `${path}.${component.key}.${e.value}` : `${component.key}.${e.value}`)); + // else push the parent field + else { + keyPath.push(component.key); + } + + noRecurse = fn(component, keyPath, components); + } else { + noRecurse = fn(component, newPath, components); + } + } + + const subPath = () => { + if ( + component.key && + !['panel', 'table', 'well', 'columns', 'fieldset', 'tabs', 'form'].includes(component.type) && + (['datagrid', 'container', 'editgrid', 'address', 'dynamicWizard', 'datatable', 'tagpad'].includes(component.type) || component.tree) + ) { + return newPath; + } else if (component.key && component.type === 'form') { + return `${newPath}.data`; + } + return path; + }; + + if (!noRecurse) { + if (hasColumns) { + component.columns.forEach((column) => eachComponent(column.components, fn, includeAll, subPath(), parent ? component : null), true); + } else if (hasRows) { + component.rows.forEach((row) => { + if (Array.isArray(row)) { + row.forEach((column) => eachComponent(column.components, fn, includeAll, subPath(), parent ? component : null), true); + } + }); + } else if (hasComps) { + eachComponent(component.components, fn, includeAll, subPath(), parent ? component : null, true); + } + } + }); + if (components.noRecurse) { + delete components.noRecurse; + } +}; + +const unwindPath = (schema) => { + let path = []; + for (let obj of schema) { + const findField = (obj, keyPath) => { + let keys = keyPath; + if (!_.isUndefined(obj) && !_.isNull(obj)) { + Object.keys(obj).forEach((key) => { + if (Array.isArray(obj[key]) && !key.includes('address')) { + path.push(keys !== undefined ? keys + '.' + key : key); + for (let value of obj[key]) { + findField(value, keys !== undefined ? keys + '.' + key : key); + } + } + if (obj[key] instanceof Object && !key.includes('address')) { + findField(obj[key], keys !== undefined ? keys + '.' + key : key); + } + }); + } + }; + findField(obj, undefined); + } + return path; +}; + +const submissionHeaders = (obj) => { + let objectMap = new Set(); + + const findField = (obj, keyPath) => { + if (_.isUndefined(obj) || _.isNull(obj)) { + objectMap.add(keyPath); + } else { + Object.keys(obj).forEach((key) => { + if (_.isString(obj[key]) || _.isNumber(obj[key]) || _.isDate(obj[key])) { + if (key !== 'submit') { + objectMap.add(keyPath ? keyPath + '.' + key : key); + } + } else if (Array.isArray(obj[key])) { + for (let value of obj[key]) { + findField(value, keyPath ? keyPath + '.' + key : key); + } + } else if (_.isPlainObject(obj[key])) { + findField(obj[key], keyPath ? keyPath + '.' + key : key); + } + }); + } + }; + + findField(obj, undefined); + + return objectMap; +}; + +const encodeURI = (unsafe) => { + let textDelimiter = '_'; + let textDelimiterRegex = new RegExp('\\' + ',', 'g'); + return unsafe.replace(textDelimiterRegex, textDelimiter); +}; + +const validateScheduleObject = (schedule = {}) => { + let result = { + message: '', + status: 'success', + }; + + if (schedule.enabled) { + let schType = schedule.scheduleType; + let openSubmissionDateTime = schedule.openSubmissionDateTime; + if (isDateValid(openSubmissionDateTime)) { + if (schType === 'closingDate') { + if (!isDateValid(schedule.closeSubmissionDateTime)) { + result = { + message: 'Invalid closed submission date.', + status: 'error', + }; + return result; + } + + if (!isLateSubmissionObjValid(schedule)) { + result = { + message: 'Invalid late submission data.', + status: 'error', + }; + return result; + } + + if (!isClosingMessageValid(schedule)) { + result = { + message: 'Invalid Closing message.', + status: 'error', + }; + return result; + } + } else if (schType === 'period') { + if (!isLateSubmissionObjValid(schedule)) { + result = { + message: 'Invalid late submission data.', + status: 'error', + }; + return result; + } + + if (!isClosingMessageValid(schedule)) { + result = { + message: 'Invalid Closing message.', + status: 'error', + }; + return result; + } + + //Check keep open for + if (!isKeepOpenForValid(schedule)) { + result = { + message: 'Invalid keep open submission data.', + status: 'error', + }; + return result; + } + + //Check repeat + if (!isRepeatDataValid(schedule)) { + result = { + message: 'Invalid repeat submission data.', + status: 'error', + }; + return result; + } + } else { + if (schType !== 'manual') { + result = { + message: 'Invalid schedule type.', + status: 'error', + }; + return result; + } + } + } else { + result = { + message: 'Invalid open submission date.', + status: 'error', + }; + return result; + } + } else { + result = { + message: '', + status: 'success', + }; + return result; + } + + return result; +}; + +const isKeepOpenForValid = (schedule) => { + let keepOpenForInterval = schedule.keepOpenForInterval; + let keepOpenForTerm = schedule.keepOpenForTerm; + if (!keepOpenForInterval || keepOpenForInterval === null || !keepOpenForTerm || keepOpenForTerm === null) { + return false; + } + return true; +}; + +const isRepeatDataValid = (schedule) => { + let isRepeatSubmissionEnabled = schedule && schedule.repeatSubmission && schedule.repeatSubmission.enabled; + if (isRepeatSubmissionEnabled) { + if ( + !schedule.repeatSubmission.everyTerm || + schedule.repeatSubmission.everyTerm === null || + !schedule.repeatSubmission.repeatUntil || + schedule.repeatSubmission.repeatUntil === null || + !schedule.repeatSubmission.everyIntervalType || + schedule.repeatSubmission.everyIntervalType === null + ) { + return false; + } + } + return true; +}; + +const isLateSubmissionObjValid = (schedule) => { + let allowLateSubmissions = schedule && schedule.allowLateSubmissions && schedule.allowLateSubmissions.enabled; + let allowLateSubmissionsForNextTerm = schedule && schedule.allowLateSubmissions && schedule.allowLateSubmissions.forNext && schedule.allowLateSubmissions.forNext.term; + let allowLateSubmissionsForNextInterval = + schedule && schedule.allowLateSubmissions && schedule.allowLateSubmissions.forNext && schedule.allowLateSubmissions.forNext.intervalType; + + if (allowLateSubmissions) { + if (!allowLateSubmissionsForNextTerm || allowLateSubmissionsForNextInterval === null || !allowLateSubmissionsForNextInterval || allowLateSubmissionsForNextInterval === null) { + return false; + } + } + return true; +}; + +const isDateValid = (date) => { + return Date.parse(date); +}; + +const isClosingMessageValid = (schedule) => { + if (schedule.closingMessageEnabled) { + if (!schedule.closingMessage || schedule.closingMessage === null) { + return false; + } + } + return true; +}; + +module.exports = { + falsey, + setupMount, + queryUtils, + typeUtils, + isFormExpired, + getCalculatedCloseSubmissionDate, + getAvailableDates, + isEligibleLateSubmission, + periodType, + checkIsFormExpired, + flattenComponents, + unwindPath, + submissionHeaders, + encodeURI, + validateScheduleObject, +}; diff --git a/frontend/app/src/forms/email/assets/bodies/file-download-ready.html b/frontend/app/src/forms/email/assets/bodies/file-download-ready.html new file mode 100644 index 0000000..4ba2891 --- /dev/null +++ b/frontend/app/src/forms/email/assets/bodies/file-download-ready.html @@ -0,0 +1,12 @@ + + + + +
+
+

+ {{ messageLinkText }}
+ Download file +

+
+
diff --git a/frontend/app/src/forms/email/assets/bodies/reminder-form-not-fill.html b/frontend/app/src/forms/email/assets/bodies/reminder-form-not-fill.html new file mode 100644 index 0000000..00a88a8 --- /dev/null +++ b/frontend/app/src/forms/email/assets/bodies/reminder-form-not-fill.html @@ -0,0 +1,27 @@ + + + + +
+
+

+ {{ messageLinkText }} +

+ +

+ + View this Form + +

+ +
+
diff --git a/frontend/app/src/forms/email/assets/bodies/reminder-form-open.html b/frontend/app/src/forms/email/assets/bodies/reminder-form-open.html new file mode 100644 index 0000000..fd3fcff --- /dev/null +++ b/frontend/app/src/forms/email/assets/bodies/reminder-form-open.html @@ -0,0 +1,23 @@ + + + + +
+
+

+ {{ messageLinkText }} +

+ +

+ + View this Form + +

+ +
+
diff --git a/frontend/app/src/forms/email/assets/bodies/reminder-form-will-close.html b/frontend/app/src/forms/email/assets/bodies/reminder-form-will-close.html new file mode 100644 index 0000000..446ad9e --- /dev/null +++ b/frontend/app/src/forms/email/assets/bodies/reminder-form-will-close.html @@ -0,0 +1,25 @@ + + + + +
+
+

+ {{ messageLinkText }} +

+

+ + View this Form + +

+
+
diff --git a/frontend/app/src/forms/email/assets/bodies/send-status-assigned-email-body.html b/frontend/app/src/forms/email/assets/bodies/send-status-assigned-email-body.html new file mode 100644 index 0000000..777f2c2 --- /dev/null +++ b/frontend/app/src/forms/email/assets/bodies/send-status-assigned-email-body.html @@ -0,0 +1,38 @@ + + + + +
+
+ Confirmation Number: + + {{ confirmationNumber }} + +

+ {{ messageLinkText }} +

+ {% if emailContent %} + + Comments: + +

+ {{ emailContent }} +

+ {% endif %} +

+ + View this submission + +

+
+
diff --git a/frontend/app/src/forms/email/assets/bodies/send-status-revising-email-body.html b/frontend/app/src/forms/email/assets/bodies/send-status-revising-email-body.html new file mode 100644 index 0000000..777f2c2 --- /dev/null +++ b/frontend/app/src/forms/email/assets/bodies/send-status-revising-email-body.html @@ -0,0 +1,38 @@ + + + + +
+
+ Confirmation Number: + + {{ confirmationNumber }} + +

+ {{ messageLinkText }} +

+ {% if emailContent %} + + Comments: + +

+ {{ emailContent }} +

+ {% endif %} +

+ + View this submission + +

+
+
diff --git a/frontend/app/src/forms/email/assets/bodies/submission-assigned.html b/frontend/app/src/forms/email/assets/bodies/submission-assigned.html new file mode 100644 index 0000000..910a4aa --- /dev/null +++ b/frontend/app/src/forms/email/assets/bodies/submission-assigned.html @@ -0,0 +1,30 @@ + + + + +
+ +
diff --git a/frontend/app/src/forms/email/assets/bodies/submission-completed.html b/frontend/app/src/forms/email/assets/bodies/submission-completed.html new file mode 100644 index 0000000..777f2c2 --- /dev/null +++ b/frontend/app/src/forms/email/assets/bodies/submission-completed.html @@ -0,0 +1,38 @@ + + + + +
+
+ Confirmation Number: + + {{ confirmationNumber }} + +

+ {{ messageLinkText }} +

+ {% if emailContent %} + + Comments: + +

+ {{ emailContent }} +

+ {% endif %} +

+ + View this submission + +

+
+
diff --git a/frontend/app/src/forms/email/assets/bodies/submission-confirmation.html b/frontend/app/src/forms/email/assets/bodies/submission-confirmation.html new file mode 100644 index 0000000..5d3dc5d --- /dev/null +++ b/frontend/app/src/forms/email/assets/bodies/submission-confirmation.html @@ -0,0 +1,30 @@ + + + + +
+
+ Confirmation Number: + + {{ confirmationNumber }} + +

+ {{ messageLinkText }} +

+

+ + View this submission + +

+
+
diff --git a/frontend/app/src/forms/email/assets/bodies/submission-received-confirmation-login.html b/frontend/app/src/forms/email/assets/bodies/submission-received-confirmation-login.html new file mode 100644 index 0000000..4bc30e7 --- /dev/null +++ b/frontend/app/src/forms/email/assets/bodies/submission-received-confirmation-login.html @@ -0,0 +1,35 @@ + + + + +
+
+ Confirmation Number: + + {{ confirmationNumber }} + +

+ {{ messageLinkText }} +

+

+ + View this submission + +

+

+ + View your {{ form.name }} submissions + +

+
+
diff --git a/frontend/app/src/forms/email/assets/bodies/submission-received-confirmation-public.html b/frontend/app/src/forms/email/assets/bodies/submission-received-confirmation-public.html new file mode 100644 index 0000000..5d3dc5d --- /dev/null +++ b/frontend/app/src/forms/email/assets/bodies/submission-received-confirmation-public.html @@ -0,0 +1,30 @@ + + + + +
+
+ Confirmation Number: + + {{ confirmationNumber }} + +

+ {{ messageLinkText }} +

+

+ + View this submission + +

+
+
diff --git a/frontend/app/src/forms/email/assets/bodies/submission-unassigned.html b/frontend/app/src/forms/email/assets/bodies/submission-unassigned.html new file mode 100644 index 0000000..fec3f21 --- /dev/null +++ b/frontend/app/src/forms/email/assets/bodies/submission-unassigned.html @@ -0,0 +1,20 @@ + + + + +
+
+

+ {{ messageLinkText }} +

+
+
diff --git a/frontend/app/src/forms/email/assets/triggered-notification-email-template.html b/frontend/app/src/forms/email/assets/triggered-notification-email-template.html new file mode 100644 index 0000000..e55db55 --- /dev/null +++ b/frontend/app/src/forms/email/assets/triggered-notification-email-template.html @@ -0,0 +1,197 @@ + +
+ + + + + + +
+ + + + + + +
+
+ + + + + + +
+
+ + + + + + +
+ +
+ {{ title }} +
+
+
+
+
+
+ + + + + + + +
+
+ + + + + + +
+
+ + + + + +
+ +
+
+
+
+ +
+ + + + + + + +
+
+ + + + + + +
+ +
+
+
+

 

+

{{ bottomText }}

+
+ diff --git a/frontend/app/src/forms/email/emailService.js b/frontend/app/src/forms/email/emailService.js new file mode 100644 index 0000000..a3e1bc0 --- /dev/null +++ b/frontend/app/src/forms/email/emailService.js @@ -0,0 +1,515 @@ +const fs = require('fs'); +const Handlebars = require('handlebars'); +const path = require('path'); + +const chesService = require('../../components/chesService'); +const log = require('../../components/log')(module.filename); +const { EmailProperties, EmailTypes } = require('../common/constants'); +const formService = require('../form/service'); +const moment = require('moment'); + +/** + * Replace the {{ handlebar }} expressions in a string with the values from a + * context object. + * @param {string} format the string that is to have handlebars replaced + * @param {object} context the values used to replace the handlebar items + * @returns the format string with the handlebar items replaced + */ +const _replaceHandlebars = (format, context) => { + const template = Handlebars.compile(format); + + return template(context); +}; + +/** Helper function used to build the email template based on email type and contents */ +const buildEmailTemplate = async (formId, formSubmissionId, emailType, referer, additionalProperties = 0) => { + const form = await formService.readForm(formId); + const submission = await formService.readSubmission(formSubmissionId); + let configData = {}; + let contextToVal = []; + let userTypePath = ''; + + if (emailType === EmailTypes.SUBMISSION_ASSIGNED) { + contextToVal = [additionalProperties.assignmentNotificationEmail]; + userTypePath = 'user/view'; + configData = { + bodyTemplate: 'submission-assigned.html', + title: `Invited to ${form.name} Draft`, + subject: 'Invited to Submission Draft', + messageLinkText: `You have been invited to a ${form.name} submission draft. You can review your submission draft details by visiting the following links:`, + priority: 'normal', + form, + }; + } else if (emailType === EmailTypes.STATUS_COMPLETED) { + contextToVal = [additionalProperties.submissionUserEmail]; + userTypePath = 'user/view'; + configData = { + bodyTemplate: 'submission-completed.html', + title: `${form.name} Has Been Completed`, + subject: 'Form Has Been Completed', + messageLinkText: `Your submission from ${form.name} has been Completed.`, + priority: 'normal', + form, + }; + } else if (emailType === EmailTypes.SUBMISSION_UNASSIGNED) { + contextToVal = [additionalProperties.assignmentNotificationEmail]; + userTypePath = 'user/view'; + configData = { + bodyTemplate: 'submission-unassigned.html', + title: `Uninvited From ${form.name} Draft`, + subject: 'Uninvited From Submission Draft', + messageLinkText: `You have been uninvited from ${form.name} submission draft.`, + priority: 'normal', + form, + }; + } else if (emailType === EmailTypes.STATUS_ASSIGNED) { + contextToVal = [additionalProperties.assignmentNotificationEmail]; + userTypePath = 'form/view'; + configData = { + bodyTemplate: 'send-status-assigned-email-body.html', + title: `${form.name} Submission Assignment`, + subject: 'Form Submission Assignment', + messageLinkText: `You have been assigned to a ${form.name} submission. Please login to review it.`, + priority: 'normal', + form, + }; + } else if (emailType === EmailTypes.STATUS_REVISING) { + contextToVal = [additionalProperties.submissionUserEmail]; + userTypePath = 'user/view'; + configData = { + bodyTemplate: 'send-status-revising-email-body.html', + title: `${form.name} Submission Revision Requested`, + subject: 'Form Submission Revision Request', + messageLinkText: `You have been asked to revise a ${form.name} submission. Please login to review it.`, + priority: 'normal', + form, + }; + } else if (emailType === EmailTypes.SUBMISSION_RECEIVED) { + contextToVal = form.submissionReceivedEmails; + userTypePath = 'form/view'; + configData = { + body: additionalProperties.body, + bodyTemplate: 'submission-confirmation.html', + title: `${form.name} Submission`, + subject: `${form.name} Submission`, + messageLinkText: `There is a new ${form.name} submission. Please login to review it.`, + priority: 'normal', + form, + }; + } else if (emailType === EmailTypes.SUBMISSION_CONFIRMATION) { + contextToVal = [additionalProperties.body.to]; + userTypePath = 'form/success'; + const bodyTemplate = + form.identityProviders.length > 0 && form.identityProviders[0].idp === 'public' + ? 'submission-received-confirmation-public.html' + : 'submission-received-confirmation-login.html'; + const emailTemplate = await formService.readEmailTemplate(form.id, emailType); + + // The data that is allowed to be used in the templates. This is currently + // very restrictive due to PII concerns and keeping within the PIA allowable + // uses of data. + const handlebarsData = { form: { description: form.description, name: form.name } }; + + configData = { + bodyTemplate: bodyTemplate, + title: _replaceHandlebars(emailTemplate.title, handlebarsData), + subject: _replaceHandlebars(emailTemplate.subject, handlebarsData), + priority: additionalProperties.body.priority, + messageLinkText: _replaceHandlebars(emailTemplate.body, handlebarsData), + form, + }; + } + + return { + configData, + contexts: [ + { + context: { + allFormSubmissionUrl: `${service._appUrl(referer)}/user/submissions?f=${configData.form.id}`, + confirmationNumber: submission.confirmationId, + form: configData.form, + messageLinkText: configData.messageLinkText, + messageLinkUrl: `${service._appUrl(referer)}/${userTypePath}?s=${submission.id}`, + emailContent: additionalProperties.emailContent, + title: configData.title, + }, + to: contextToVal, + }, + ], + }; +}; + +/** Helper function used to build the email template based on email type and contents for reminder */ +const buildEmailTemplateFormForReminder = async (form, emailType, users, report, referer) => { + let configData = {}; + const closeDate = report.dates.closeDate ? moment(report.dates.closeDate).format('MMM. D, YYYY') : undefined; + const subject = 'CHEFS Submission Reminder'; + + const formatEmailTextMessage = (name, closeDate) => { + const messageValue = closeDate + ? `This email is to inform you that the ${name} form is now open for submission and will stay open until ${closeDate}. Please complete your submission before the submission period is closed.` + : `This email is to inform you that the ${name} form is now open for submission.`; + return 'Hi,\n' + messageValue + '\nThank you'; + }; + const message = formatEmailTextMessage(form.name, closeDate); + const contextToVal = users; + if (emailType === EmailTypes.REMINDER_FORM_OPEN) { + configData = { + bodyTemplate: 'reminder-form-open.html', + title: `Submission Start for ${form.name} `, + subject: subject, + messageLinkText: `${message} + `, + priority: 'normal', + form, + }; + } else if (emailType === EmailTypes.REMINDER_FORM_NOT_FILL) { + configData = { + bodyTemplate: 'reminder-form-not-fill.html', + title: `Submission Reminder for ${form.name}`, + subject: subject, + messageLinkText: `${message}`, + priority: 'normal', + form, + }; + } else if (emailType === EmailTypes.REMINDER_FORM_WILL_CLOSE) { + configData = { + bodyTemplate: 'reminder-form-will-close.html', + title: `Submission Closing for ${form.name}`, + subject: subject, + messageLinkText: `${message}`, + priority: 'normal', + form, + }; + } + + return { + configData, + contexts: [ + { + context: { + allFormSubmissionUrl: '', + form: configData.form, + report: report, + messageLinkText: configData.messageLinkText, + messageLinkUrl: `${referer}/form/submit?f=${configData.form.id}`, + title: configData.title, + }, + to: contextToVal, + }, + ], + }; +}; + +const service = { + /** + * @function _appUrl + * Attempts to parse out the base application url + * @param {string} referer + * @returns base url for the application + */ + _appUrl: (referer) => { + try { + const url = new URL(referer); + const p = url.pathname.split('/')[1]; + const u = url.href.substring(0, url.href.indexOf(`/${p}`)); + return `${u}/${p}`; + } catch (err) { + log.error(err.message, { + function: '_appUrl', + referer: referer, + }); + throw err; + } + }, + + /** + * @function _mergeEmailTemplate + * Merges the template and body HTML files to allow dynamic content in the emails + * @param {*} bodyTemplate + * @returns joined template files + */ + _mergeEmailTemplate: (bodyTemplate) => { + const template = fs.readFileSync(`${path.join(__dirname, 'assets')}/triggered-notification-email-template.html`, 'utf8'); + const body = fs.readFileSync(`${path.join(__dirname, 'assets', 'bodies')}/${bodyTemplate}`, 'utf8'); + const bodyInsertIndex = template.search(''); + const result = [template.substring(0, bodyInsertIndex), body, template.substring(bodyInsertIndex, template.length)].join(''); + return result; + }, + + /** + * @function _sendEmailTemplate + * Sends email using chesService.merge + * @param {string} configData + * @param {string} contexts + * @returns The result of the email merge operation + */ + _sendEmailTemplate: (configData, contexts) => { + try { + const mergedHtml = service._mergeEmailTemplate(configData.bodyTemplate); + const data = { + body: mergedHtml, + bodyType: 'html', + contexts: contexts, + from: EmailProperties.FROM_EMAIL, + subject: configData.subject, + title: configData.title, + priority: configData.priority, + messageLinkText: configData.messageLinkText, + }; + return chesService.merge(data); + } catch (err) { + log.error(err.message, { function: '_sendEmailTemplate' }); + throw err; + } + }, + + /** + * @function submissionAssigned + * Assigning user to Submission Draft + * @param {string} formId + * @param {string} currentStatus + * @param {string} assignmentNotificationEmail + * @param {string} referer + * @returns The result of the email merge operation + */ + submissionAssigned: async (formId, currentStatus, assignmentNotificationEmail, referer) => { + try { + const { configData, contexts } = await buildEmailTemplate(formId, currentStatus.formSubmissionId, EmailTypes.SUBMISSION_ASSIGNED, referer, { assignmentNotificationEmail }); + + return service._sendEmailTemplate(configData, contexts); + } catch (e) { + log.error(e.message, { + function: EmailTypes.SUBMISSION_ASSIGNED, + status: currentStatus, + referer: referer, + }); + throw e; + } + }, + + /** + * @function submissionUnassigned + * Unassigning user from Submission Draft + * @param {string} formId + * @param {string} currentStatus + * @param {string} assignmentNotificationEmail + * @param {string} referer + * @returns The result of the email merge operation + */ + submissionUnassigned: async (formId, currentStatus, assignmentNotificationEmail, referer) => { + try { + const { configData, contexts } = await buildEmailTemplate(formId, currentStatus.formSubmissionId, EmailTypes.SUBMISSION_UNASSIGNED, referer, { assignmentNotificationEmail }); + + return service._sendEmailTemplate(configData, contexts); + } catch (e) { + log.error(e.message, { + function: EmailTypes.SUBMISSION_UNASSIGNED, + status: currentStatus, + referer: referer, + }); + throw e; + } + }, + + /** + * @function statusAssigned + * Setting Assigned status to user on Submission + * @param {string} formId + * @param {string} currentStatus + * @param {string} assignmentNotificationEmail + * @param {string} emailContent + * @param {string} referer + * @returns The result of the email merge operation + */ + statusAssigned: async (formId, currentStatus, assignmentNotificationEmail, emailContent, referer) => { + try { + const { configData, contexts } = await buildEmailTemplate(formId, currentStatus.submissionId, EmailTypes.STATUS_ASSIGNED, referer, { + assignmentNotificationEmail, + emailContent, + }); + + return service._sendEmailTemplate(configData, contexts); + } catch (e) { + log.error(e.message, { + function: EmailTypes.STATUS_ASSIGNED, + status: currentStatus, + referer: referer, + }); + throw e; + } + }, + + /** + * @function statusCompleted + * Setting Completed status to user on Submission + * @param {string} formId + * @param {string} currentStatus + * @param {string} submissionUserEmail The email address to send to + * @param {string} emailContent + * @param {string} referer + * @returns {object} The result of the email merged from operation + */ + statusCompleted: async (formId, currentStatus, submissionUserEmail, emailContent, referer) => { + try { + const { configData, contexts } = await buildEmailTemplate(formId, currentStatus.submissionId, EmailTypes.STATUS_COMPLETED, referer, { submissionUserEmail, emailContent }); + return service._sendEmailTemplate(configData, contexts); + } catch (e) { + log.error(e.message, { + function: EmailTypes.STATUS_COMPLETED, + status: currentStatus, + referer: referer, + }); + throw e; + } + }, + + /** + * @function statusRevising + * Revising status to submission form owner + * @param {string} formId The form id + * @param {string} currentStatus The current status + * @param {string} submissionUserEmail The email address to send to + * @param {string} emailContent The optional content to send as a comment + * @param {string} referer The currently logged in user + * @returns The result of the email merge operation + */ + statusRevising: async (formId, currentStatus, submissionUserEmail, emailContent, referer) => { + try { + const { configData, contexts } = await buildEmailTemplate(formId, currentStatus.submissionId, EmailTypes.STATUS_REVISING, referer, { submissionUserEmail, emailContent }); + + return service._sendEmailTemplate(configData, contexts); + } catch (e) { + log.error(e.message, e, { + function: EmailTypes.STATUS_REVISING, + status: currentStatus, + referer: referer, + }); + throw e; + } + }, + + /** + * @function submissionReceived + * Completing submission of a form + * @param {string} formId + * @param {string} submissionId + * @param {string} body + * @param {string} referer + * @returns The result of the email merge operation + */ + submissionReceived: async (formId, submissionId, body, referer) => { + try { + const { configData, contexts } = await buildEmailTemplate(formId, submissionId, EmailTypes.SUBMISSION_RECEIVED, referer, { body }); + if (contexts[0].to.length) { + return service._sendEmailTemplate(configData, contexts); + } else { + return {}; + } + } catch (e) { + log.error(e.message, { + function: EmailTypes.SUBMISSION_RECEIVED, + formId: formId, + submissionId: submissionId, + body: body, + referer: referer, + }); + throw e; + } + }, + + /** + * @function submissionConfirmation + * Manual email confirmation after form has been submitted + * @param {string} formId + * @param {string} submissionId + * @param {string} body + * @param {string} referer + * @returns The result of the email merge operation + */ + submissionConfirmation: async (formId, submissionId, body, referer) => { + try { + const { configData, contexts } = await buildEmailTemplate(formId, submissionId, EmailTypes.SUBMISSION_CONFIRMATION, referer, { body: body }); + + return service._sendEmailTemplate(configData, contexts); + } catch (e) { + log.error(e.message, { + function: EmailTypes.SUBMISSION_CONFIRMATION, + formId: formId, + submissionId: submissionId, + body: body, + referer: referer, + }); + throw e; + } + }, + + /** + * @function formOpen + * Manual email confirmation after form has been submitted + * @param {object} information about the submitter and the form + * @returns The result of the email merge operation + */ + initReminder: async (obj) => { + try { + const { configData, contexts } = await buildEmailTemplateFormForReminder(obj.form, obj.state, obj.users, obj.report, obj.referer); + return service._sendEmailTemplate(configData, contexts); + } catch (e) { + log.error(e.message, { + function: obj.state, + formId: obj.form.id, + }); + throw e; + } + }, + + /** + * @function submissionExportLink + * Email with the link to the Form submissions export file + * @param {string} formId + * @param {string} submissionId + * @param {object} body + * @param {string} referer + * @param {string} fileId + * @returns The result of the email merge operation + */ + submissionExportLink: async (formId, submissionId, body, referer, fileId) => { + try { + const form = await formService.readForm(formId); + const contextToVal = [body.to]; + const userTypePath = 'file/download'; + const bodyTemplate = 'file-download-ready.html'; + const configData = { + bodyTemplate: bodyTemplate, + title: 'CHEFS Data Export', + subject: `CHEFS: ${form.name} submissions export`, + priority: 'normal', + messageLinkText: `Your data export for ${form.name} is ready`, + form, + }; + const contexts = [ + { + context: { + form: configData.form, + messageLinkText: configData.messageLinkText, + messageLinkUrl: `${service._appUrl(referer)}/${userTypePath}?id=${fileId}`, + title: configData.title, + }, + to: contextToVal, + }, + ]; + + return service._sendEmailTemplate(configData, contexts); + } catch (e) { + log.error(e.message, { + function: EmailTypes.SUBMISSION_EXPORT, + formId: formId, + body: body, + referer: referer, + }); + throw e; + } + }, +}; + +module.exports = service; diff --git a/frontend/app/src/forms/email/reminderService.js b/frontend/app/src/forms/email/reminderService.js new file mode 100644 index 0000000..bc66e5c --- /dev/null +++ b/frontend/app/src/forms/email/reminderService.js @@ -0,0 +1,290 @@ +const { getAvailableDates } = require('../common/utils'); +const emailService = require('./emailService'); +const moment = require('moment'); +const { EmailTypes, ScheduleType } = require('../common/constants'); +const config = require('config'); +const log = require('../../components/log')(module.filename); +const { SubmissionData, UserFormAccess, Form } = require('../common/models'); +const { Roles } = require('../common/constants'); + +const service = { + _init: async () => { + const forms = await service._getForms(); + + const q = await service._getReminders(forms); + + const referer = service._getReferer(); + const resolve = []; + const errors = []; + let mail = 0; + + if (q.length !== 0) { + for (let i = 0; i < q.length; i++) { + if (!q[i].error) { + const obj = await service._runQueries(q[i].statement); + let result = await service._initStatement(obj); + let chesResponses = service._initMailSender(result, referer); + resolve.push({ + formId: result.form.id, + formName: result.form.name, + type_mail: result.state, + number_mail: result.submitters.length, + period_type: q[i].periodType, + chesResponses, + }); + // eslint-disable-next-line no-unused-vars + mail += result.submitters.length; + } else { + errors.push(q[i].message); + } + } + return { + message: `${q.length} forms found, ${mail} emails sent.`, + errors, + resolve, + }; + } else { + return { + message: '0 emails sent.', + data: q, + }; + } + }, + getCurrentPeriod(dates, toDay, late) { + // if send and empty date + if (dates == null || dates == undefined) return null; + + // list periods is null + if (dates.length == 0) return null; + + // if period has no closed date + if (dates.length == 1 && dates[0].endDate == null) { + return Object({ + state: 1, + index: 0, + dates: dates[0], + old_dates: null, + late: 0, + }); + } + + // check for the current period + for (let i = 0; i < dates.length; i++) { + let startDate = moment(dates[i].startDate).format('YYYY-MM-DD'); + let graceDate = late ? moment(dates[i].graceDate).format('YYYY-MM-DD') : moment(dates[i].closeDate).format('YYYY-MM-DD'); + if (toDay.isBetween(startDate, graceDate)) { + return Object({ + state: 1, + index: i, + dates: dates[i], + old_dates: i == 0 ? null : dates[i - 1], + late: toDay.isBetween(dates[i].closeDate, dates[i].graceDate) ? 1 : 0, + }); + } + } + + let first = dates[0]; + return Object({ + state: toDay.isBefore(first.startDate) ? -1 : 0, + index: -1, + dates: false, + old_dates: false, + late: -1, + }); + }, + _listDates: (schedule) => { + if (schedule.scheduleType == ScheduleType.PERIOD) { + return getAvailableDates( + schedule.keepOpenForTerm, + schedule.keepOpenForInterval, + schedule.openSubmissionDateTime, + schedule.repeatSubmission.everyTerm, + schedule.repeatSubmission.everyIntervalType, + schedule.allowLateSubmissions.forNext.term, + schedule.allowLateSubmissions.forNext.intervalType, + schedule.repeatSubmission.repeatUntil, + schedule.scheduleType, + schedule.closeSubmissionDateTime + ); + } + if (schedule.scheduleType == ScheduleType.MANUAL) { + return [ + Object({ + startDate: schedule.openSubmissionDateTime, + closeDate: null, + graceDate: null, + }), + ]; + } + + if (schedule.scheduleType == ScheduleType.CLOSINGDATE) { + return [ + Object({ + startDate: schedule.openSubmissionDateTime, + closeDate: schedule.closeSubmissionDateTime, + graceDate: service._getGraceDate(schedule), + }), + ]; + } + }, + _getGraceDate: (schedule) => { + let substartDate = moment(schedule.openSubmissionDateTime); + let newDate = substartDate.clone(); + return schedule.allowLateSubmissions.enabled + ? newDate.add(schedule.allowLateSubmissions.forNext.term, schedule.allowLateSubmissions.forNext.intervalType).format('YYYY-MM-DD HH:MM:SS') + : null; + }, + _getForms: async () => { + let fs = []; + await Form.query() + .modify('reminderEnabled') + .modify('filterActive', true) + .then((forms) => { + fs = forms; + }); + return fs; + }, + _getReminders: async (forms) => { + let reminder = []; + let toDay = moment(); + for (let i = 0; i < forms.length; i++) { + let obj = {}; + + obj.availableDate = service._listDates(forms[i].schedule); + + if (obj.availableDate.length == 0) { + reminder.push({ error: true, message: `Form ${forms[i].name} has no available date.` }); + continue; + } + + obj.report = service.getCurrentPeriod(obj.availableDate, toDay, forms[i].schedule.allowLateSubmissions.enabled); + + obj.form = forms[i]; + + obj.state = service._getMailType(obj.report, forms[i].schedule.allowLateSubmissions.enabled); + + if (obj.state == undefined) { + reminder.push({ error: true, message: `Form ${forms[i].name} has no valid date` }); + continue; + } + + reminder.push({ + error: false, + statement: obj, + periodType: forms[i].schedule.scheduleType, + }); + } + + return reminder; + }, + _getMailType: (report, late) => { + let state = undefined; + + const now = moment().format('YYYY-MM-DD'); + const start_date = moment(report.dates.startDate).format('YYYY-MM-DD'); + const end_date = late ? moment(report.dates.graceDate).format('YYYY-MM-DD') : moment(report.dates.closeDate).format('YYYY-MM-DD'); + const days_diff = moment(end_date).diff(start_date, 'days'); + + if (moment(now).isSame(start_date)) { + return EmailTypes.REMINDER_FORM_OPEN; + } + + if (report.dates.closeDate == null || days_diff <= 3) return state; + + if (service.checkIfInMiddleOfThePeriod(now, start_date, days_diff)) { + return EmailTypes.REMINDER_FORM_NOT_FILL; + } + + const yend_date = moment(end_date).subtract(1, 'day'); + + if (moment(now).isSame(yend_date)) { + return EmailTypes.REMINDER_FORM_WILL_CLOSE; + } + + return state; + }, + checkIfInMiddleOfThePeriod: (now, start_date, days_diff) => { + if (days_diff < 6) return false; + let interval = Math.floor(days_diff / 2); + // eslint-disable-next-line no-console + let mail_date = moment(start_date).add(interval, 'days').format('YYYY-MM-DD'); + return moment(now).isSame(mail_date); + }, + _runQueries: async (obj) => { + obj.fillers = []; + await UserFormAccess.query() + .select('formVersionId', 'formName', 'userId', 'firstName', 'lastName', 'email') + .where('formId', obj.form.id) + .modify('filterActive', true) + .modify('filterByAccess', undefined, Roles.FORM_SUBMITTER, undefined) + .modify('orderDefault') + .then(function (data) { + obj.submitters = data; + }); + + if (obj.submitters && obj.submitters.length > 0) { + await SubmissionData.query() + .select('confirmationId', 'createdAt', 'submissionId', 'formVersionId', 'userId', 'firstName', 'lastName', 'email') + .where('formId', obj.form.id) + .modify('filterDrafts', false) + .modify('filterDeleted', false) + .modify('filterCreatedAt', obj.report.dates.startDate, obj.report.dates.graceDate) + .modify('orderDefault') + .then(function (data2) { + obj.fillers = data2 ? data2 : []; + }); + } + + return obj; + }, + getDifference: async (array1, array2) => { + return array1.filter((object1) => { + return !array2.some((object2) => { + return object1.userId === object2.userId; + }); + }); + }, + _initStatement: async (obj) => { + const statement = {}; + statement.form = obj.form; + statement.report = obj.report; + statement.state = obj.state; + statement.submitters = []; + + if (!obj.submitters || obj.submitters.length == 0) return statement; + + if (statement.state != EmailTypes.REMINDER_FORM_OPEN) { + if (obj.fillers && obj.fillers.length != 0) { + statement.submitters = await service.getDifference(obj.submitters, obj.fillers); + } else { + statement.submitters = obj.submitters; + } + } else { + statement.submitters = obj.submitters; + } + return statement; + }, + _getReferer: () => { + // We create this function because in the header we cant get the real referer but + // this function allow us to generate the referer dynamicly + try { + const protocol = 'https://'; + const basePath = config.get('frontend.basePath'); + const host = process.env.SERVER_HOST; + return `${protocol}${host}${basePath}`; + } catch (error) { + log.error(error.message, { + function: '_getReferer', + }); + throw error; + } + }, + _initMailSender: async (statement, referer) => { + const chesResponse = []; + const users = statement.submitters.map((user) => user.email); + const data = { form: statement.form, report: statement.report, users, state: statement.state, referer }; + chesResponse.push(emailService.initReminder(data)); + return chesResponse; + }, +}; +module.exports = service; diff --git a/frontend/app/src/forms/file/controller.js b/frontend/app/src/forms/file/controller.js new file mode 100644 index 0000000..38eedc8 --- /dev/null +++ b/frontend/app/src/forms/file/controller.js @@ -0,0 +1,64 @@ +const service = require('./service'); +const storageService = require('./storage/storageService'); + +const { encodeURI } = require('../common/utils'); + +const _trim = (r) => { + if (r) { + // don't want storage information going over the wire... + return { + id: r.id, + originalName: r.originalName, + size: r.size, + createdBy: r.createdBy, + createdAt: r.createdAt, + }; + } + return r; +}; + +module.exports = { + create: async (req, res, next) => { + try { + const response = await service.create(req.file, req.currentUser); + res.status(201).json(_trim(response)); + } catch (error) { + next(error); + } + }, + read: async (req, res, next) => { + try { + // Permissions checked on this at the route level with middleware + // On the request from the middleware + const fileStorage = req.currentFileRecord; + + // ok, let's go get the binary... + const stream = await storageService.read(fileStorage); + + stream.on('error', function error(err) { + throw err; + }); + + res.setHeader('Content-Disposition', `attachment; filename=${encodeURI(fileStorage.originalName)}`); + res.set('Content-Type', fileStorage.mimeType); + res.set('Content-Length', fileStorage.size); + res.set('Last-Modified', fileStorage.updatedAt); + + // and stream it out... + stream.pipe(res); + } catch (error) { + next(error); + } + }, + + delete: async (req, res, next) => { + try { + // Permissions checked on this at the route level with middleware + // ok, let's remove the file... + await service.delete(req.params.id); + res.sendStatus(202); + } catch (error) { + next(error); + } + }, +}; diff --git a/frontend/app/src/forms/file/index.js b/frontend/app/src/forms/file/index.js new file mode 100644 index 0000000..e06618a --- /dev/null +++ b/frontend/app/src/forms/file/index.js @@ -0,0 +1,21 @@ +const config = require('config'); +const dataErrors = require('../common/middleware').dataErrors; +const routes = require('./routes'); + +const _PATH = config.get('files.uploads.path') || 'files'; + +const fileUpload = require('./middleware/upload').fileUpload; + +fileUpload.init({ + dir: config.has('files.uploads.dir') ? config.get('files.uploads.dir') : undefined, + fieldName: config.has('files.uploads.fileKey') ? config.get('files.uploads.fileKey') : undefined, + maxFileCount: config.has('files.uploads.fileCount') ? config.get('files.uploads.fileCount') : undefined, + maxFileSize: config.has('files.uploads.fileMaxSize') ? config.get('files.uploads.fileMaxSize') : undefined, +}); + +module.exports.mount = (app) => { + const p = `/${_PATH}`; + app.use(p, routes); + app.use(dataErrors); + return p; +}; diff --git a/frontend/app/src/forms/file/middleware/filePermissions.js b/frontend/app/src/forms/file/middleware/filePermissions.js new file mode 100644 index 0000000..48e7b90 --- /dev/null +++ b/frontend/app/src/forms/file/middleware/filePermissions.js @@ -0,0 +1,81 @@ +const Problem = require('api-problem'); + +const userAccess = require('../../auth/middleware/userAccess'); +const log = require('../../../components/log')(module.filename); +const service = require('../service'); + +/** + * @function currentFileRecord + * Get the DB record for this file being accessed and store in request for use further down the chain + * @returns {Function} a middleware function + */ +const currentFileRecord = async (req, res, next) => { + let fileRecord = undefined; + try { + // Check if authed, can expand for API key access if needed + if (req.params.id && req.currentUser) { + fileRecord = await service.read(req.params.id); + } + } catch (error) { + log.error(`Failed to find file record for id ${req.params.id}. Error ${error}`); + } + + if (!fileRecord) { + // 403 on no auth or file not found (don't 404 for id discovery) + return next(new Problem(403, { detail: 'File access to this ID is unauthorized.' })); + } + + req.currentFileRecord = fileRecord; + next(); +}; + +/** + * @function hasFileCreate + * Middleware to determine if this user can upload a file to the system + * @returns {Function} a middleware function + */ +const hasFileCreate = (req, res, next) => { + // You can't do this if you are not authenticated as a USER (not a public user) + // Can expand on this for API key access if ever needed + if (!req.currentUser || !req.currentUser.idpUserId) { + return next(new Problem(403, { detail: 'Invalid authorization credentials.' })); + } + next(); +}; + +/** + * @function hasFilePermissions + * Middleware to determine if the current user can do a specific permission on a file + * This is generally based on the SUBMISSION permissions that the file is attached to + * but has to handle management for files that are added before submit + * @param {string} permissions the permission to require on this route + * @returns {Function} a middleware function + */ +const hasFilePermissions = (permissions) => { + return (req, res, next) => { + // Guard against unauthed (or public) users + if (!req.currentUser || !req.currentUser.idpUserId) { + return next(new Problem(403, { detail: 'Unauthorized to read file' })); + } + + // Check to see if this has been associated with a submission... + // like prior implementations, if a submission has not been posted, there's not + // anything we can check permissions on so can only check authed + if (req.currentFileRecord.formSubmissionId) { + // For the existing middleware to interface as designed, add the sub ID to the req + req.query.formSubmissionId = req.currentFileRecord.formSubmissionId; + + // Trigger submission permission checker + const subPermCheck = userAccess.hasSubmissionPermissions(permissions); + return subPermCheck(req, res, next); + } + + next(); + }; +}; + +module.exports = { + currentFileRecord, + hasFileCreate, + hasFilePermissions, +}; diff --git a/frontend/app/src/forms/file/middleware/upload.js b/frontend/app/src/forms/file/middleware/upload.js new file mode 100644 index 0000000..ee13382 --- /dev/null +++ b/frontend/app/src/forms/file/middleware/upload.js @@ -0,0 +1,108 @@ +const bytes = require('bytes'); +const fs = require('fs-extra'); +const multer = require('multer'); +const os = require('os'); + +const Problem = require('api-problem'); + +let uploader = undefined; +let storage = undefined; +let maxFileSize = bytes.parse('25MB'); +let maxFileCount = 1; + +const fileSetup = (options) => { + const fileUploadsDir = (options && options.dir) || process.env.FILE_UPLOADS_DIR || fs.realpathSync(os.tmpdir()); + try { + fs.ensureDirSync(fileUploadsDir); + } catch (e) { + throw new Error(`Could not create file uploads directory '${fileUploadsDir}'.`); + } + + maxFileSize = (options && options.maxFileSize) || process.env.FILE_UPLOADS_MAX_FILE_SIZE || '25MB'; + try { + maxFileSize = bytes.parse(maxFileSize); + } catch (e) { + throw new Error('Could not determine max file size (bytes) for file uploads.'); + } + + maxFileCount = (options && options.maxFileCount) || process.env.FILE_UPLOADS_MAX_FILE_COUNT || '1'; + try { + maxFileCount = parseInt(maxFileCount); + } catch (e) { + maxFileCount = 1; + } + + return { fileUploadsDir, maxFileSize, maxFileCount }; +}; + +module.exports.fileUpload = { + init(options) { + let { fileUploadsDir, maxFileSize, maxFileCount } = fileSetup(options); + + const formFieldName = (options && options.fieldName) || process.env.FILE_UPLOADS_FIELD_NAME || 'files'; + + storage = multer.diskStorage({ + destination: function (req, file, cb) { + cb(null, fileUploadsDir); + }, + }); + + // set up the multer + if (maxFileCount > 1) { + uploader = multer({ + storage: storage, + limits: { fileSize: maxFileSize, files: maxFileCount }, + }).array(formFieldName); + } else { + // just in case we set a negative number... + maxFileCount = 1; + uploader = multer({ + storage: storage, + limits: { fileSize: maxFileSize, files: maxFileCount }, + }).single(formFieldName); + } + }, + + async upload(req, res, next) { + if (!uploader) { + return next(new Problem(500, 'File Upload middleware has not been configured.')); + } + uploader(req, res, (err) => { + // detect multer errors, send back nicer through the middleware stack... + if (err instanceof multer.MulterError) { + switch (err.code) { + case 'LIMIT_FILE_SIZE': + next(new Problem(400, 'Upload file error', { detail: `Upload file size is limited to ${maxFileSize} bytes` })); + break; + case 'LIMIT_FILE_COUNT': + next(new Problem(400, 'Upload file error', { detail: `Upload is limited to ${maxFileCount} files` })); + break; + case 'LIMIT_UNEXPECTED_FILE': + next(new Problem(400, 'Upload file error', { detail: 'Upload encountered an unexpected file' })); + break; + // we don't expect that we will encounter these in our api/app, but here for completeness + case 'LIMIT_PART_COUNT': + next(new Problem(400, 'Upload file error', { detail: 'Upload rejected: upload form has too many parts' })); + break; + case 'LIMIT_FIELD_KEY': + next(new Problem(400, 'Upload file error', { detail: 'Upload rejected: upload field name for the files is too long' })); + break; + case 'LIMIT_FIELD_VALUE': + next(new Problem(400, 'Upload file error', { detail: 'Upload rejected: upload field is too long' })); + break; + case 'LIMIT_FIELD_COUNT': + next(new Problem(400, 'Upload file error', { detail: 'Upload rejected: too many fields' })); + break; + default: + next(new Problem(400, 'Upload file error', { detail: `Upload failed with the following error: ${err.message}` })); + } + } else if (err) { + // send this error to express... + next(new Problem(400, 'Unknown upload file error', { detail: err.message })); + } else { + // all good, carry on. + next(); + } + }); + }, +}; diff --git a/frontend/app/src/forms/file/routes.js b/frontend/app/src/forms/file/routes.js new file mode 100644 index 0000000..3e6f912 --- /dev/null +++ b/frontend/app/src/forms/file/routes.js @@ -0,0 +1,23 @@ +const routes = require('express').Router(); +const controller = require('./controller'); + +const P = require('../common/constants').Permissions; +const { currentFileRecord, hasFileCreate, hasFilePermissions } = require('./middleware/filePermissions'); +const fileUpload = require('./middleware/upload').fileUpload; +const { currentUser } = require('../auth/middleware/userAccess'); + +routes.use(currentUser); + +routes.post('/', hasFileCreate, fileUpload.upload, async (req, res, next) => { + await controller.create(req, res, next); +}); + +routes.get('/:id', currentFileRecord, hasFilePermissions(P.SUBMISSION_READ), async (req, res, next) => { + await controller.read(req, res, next); +}); + +routes.delete('/:id', currentFileRecord, hasFilePermissions(P.SUBMISSION_UPDATE), async (req, res, next) => { + await controller.delete(req, res, next); +}); + +module.exports = routes; diff --git a/frontend/app/src/forms/file/service.js b/frontend/app/src/forms/file/service.js new file mode 100644 index 0000000..a7c0a83 --- /dev/null +++ b/frontend/app/src/forms/file/service.js @@ -0,0 +1,93 @@ +const config = require('config'); +const { v4: uuidv4 } = require('uuid'); + +const { FileStorage } = require('../common/models'); +const storageService = require('./storage/storageService'); + +const PERMANENT_STORAGE = config.get('files.permanent'); + +const service = { + create: async (data, currentUser, folder = 'uploads') => { + let trx; + try { + trx = await FileStorage.startTransaction(); + + const obj = {}; + obj.id = uuidv4(); + obj.storage = folder; + obj.originalName = data.originalname; + obj.mimeType = data.mimetype; + obj.size = data.size; + obj.path = data.path; + obj.createdBy = currentUser.usernameIdp; + + const uploadResult = await storageService.upload(obj); + obj.path = uploadResult.path; + obj.storage = uploadResult.storage; + + await FileStorage.query(trx).insert(obj); + + await trx.commit(); + const result = await service.read(obj.id); + return result; + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, + + read: async (id) => { + return FileStorage.query().findById(id).throwIfNotFound(); + }, + + delete: async (id) => { + let trx; + try { + trx = await FileStorage.startTransaction(); + const obj = await service.read(id); + + await FileStorage.query(trx).deleteById(id).throwIfNotFound(); + + const result = await storageService.delete(obj); + if (!result) { + // error? + } + await trx.commit(); + return result; + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, + + moveSubmissionFiles: async (submissionId, currentUser) => { + let trx; + try { + trx = await FileStorage.startTransaction(); + + // fetch all the File Storage records for a submission id + // move them to permanent storage + // update their new paths. + const items = await FileStorage.query(trx).where('formSubmissionId', submissionId); + + for (const item of items) { + // move the files under a sub directory for this submission + const newPath = await storageService.move(item, 'submissions', submissionId); + if (!newPath) { + throw new Error('Error moving files for submission'); + } + await FileStorage.query(trx).patchAndFetchById(item.id, { + storage: PERMANENT_STORAGE, + path: newPath, + updatedBy: currentUser.usernameIdp, + }); + } + await trx.commit(); + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, +}; + +module.exports = service; diff --git a/frontend/app/src/forms/file/storage/localStorageService.js b/frontend/app/src/forms/file/storage/localStorageService.js new file mode 100644 index 0000000..cb7fa6a --- /dev/null +++ b/frontend/app/src/forms/file/storage/localStorageService.js @@ -0,0 +1,67 @@ +const config = require('config'); +const fs = require('fs-extra'); +const os = require('os'); +const path = require('path'); + +const _remLastSep = (x) => (x && x.endsWith(path.sep) ? x.slice(0, -1) : x); + +const _path = config.get('files.localStorage.path') ? config.get('files.localStorage.path') : fs.realpathSync(os.tmpdir()); +const BASE_PATH = _remLastSep(_path); + +try { + fs.ensureDirSync(BASE_PATH); +} catch (e) { + throw new Error(`Could not access local storage directory '${BASE_PATH}'.`); +} + +const service = { + delete: async (fileStorage) => { + if (fs.existsSync(fileStorage.path)) { + fs.unlinkSync(fileStorage.path); + return !fs.existsSync(fileStorage.path); + } else { + return false; + } + }, + + move: async (fileStorage, ...subdirs) => { + // by default, just move the file to the storage location, we use the id as the filename + if (fs.existsSync(fileStorage.path)) { + let bp = `${BASE_PATH}`; + + try { + // are we supposed to move this to some sub directory structure? + if (subdirs && subdirs.length) { + bp = `${bp}${path.sep}${subdirs.join(path.sep)}`; + } + // will need to make sure the subdirs are ok... + fs.ensureDirSync(bp); + } catch (e) { + bp = `${BASE_PATH}`; + } + + const newPath = `${bp}${path.sep}${fileStorage.id}`; + fs.renameSync(fileStorage.path, newPath); + if (fs.existsSync(newPath) && !fs.existsSync(fileStorage.path)) { + return newPath; + } + } + }, + + read: async (fileStorage) => { + // just return a stream... + if (fs.existsSync(fileStorage.path)) { + return fs.createReadStream(fileStorage.path); + } + }, + + uploadFile: async (fileStorage) => { + // we do not upload, so return current state. + return { + path: fileStorage.path, + storage: fileStorage.storage, + }; + }, +}; + +module.exports = service; diff --git a/frontend/app/src/forms/file/storage/objectStorageService.js b/frontend/app/src/forms/file/storage/objectStorageService.js new file mode 100644 index 0000000..b294fde --- /dev/null +++ b/frontend/app/src/forms/file/storage/objectStorageService.js @@ -0,0 +1,216 @@ +const config = require('config'); +const fs = require('fs-extra'); +const mime = require('mime-types'); +const path = require('path'); +const Problem = require('api-problem'); +const S3 = require('aws-sdk/clients/s3'); + +const StorageTypes = require('../../common/constants').StorageTypes; +const errorToProblem = require('../../../components/errorToProblem'); +const log = require('../../../components/log')(module.filename); + +const SERVICE = 'ObjectStorage'; +const TEMP_DIR = 'uploads'; +const Delimiter = '/'; + +class ObjectStorageService { + constructor({ endpoint, bucket, key, accessKeyId, secretAccessKey }) { + log.debug(`Constructed with ${endpoint}, ${bucket}, ${key}, ${accessKeyId}, secretAccessKey`, { function: 'constructor' }); + if (!endpoint || !bucket || !key || !accessKeyId || !secretAccessKey) { + log.error('Invalid configuration.', { function: 'constructor' }); + throw new Error('ObjectStorageService is not configured. Check configuration.'); + } + this._endpoint = endpoint; + this._bucket = bucket; + this._key = this._delimit(key); + this._accessKeyId = accessKeyId; + this._secretAccessKey = secretAccessKey; + this._s3 = new S3({ + endpoint: this._endpoint, + accessKeyId: this._accessKeyId, + secretAccessKey: this._secretAccessKey, + s3ForcePathStyle: true, + params: { + Bucket: this._bucket, + }, + }); + } + + _join(...items) { + if (items && items.length) { + const parts = []; + items.map((p) => { + if (p) { + p.split('/').map((x) => { + if (x && x.trim().length) parts.push(x); + }); + } + }); + return parts.join(Delimiter); + } + return ''; + } + + _delimit(s) { + if (s) { + return s.endsWith(Delimiter) ? s : `${s}${Delimiter}`; + } + return ''; + } + + async uploadFile(fileStorage) { + try { + const fileContent = fs.readFileSync(fileStorage.path); + + // uploads can go to a 'holding' area, we can shuffle it later if we want to. + const key = this._join(this._key, TEMP_DIR, fileStorage.id); + + const params = { + Bucket: this._bucket, + Key: key, + Body: fileContent, + Metadata: { + name: fileStorage.originalName, + id: fileStorage.id, + }, + }; + + if (mime.contentType(path.extname(fileStorage.originalName))) { + params.ContentType = mime.contentType(path.extname(fileStorage.originalName)); + } + + return new Promise((resolve, reject) => { + // eslint-disable-next-line no-unused-vars + this._s3.upload(params, (err, data) => { + if (err) { + reject(err); + } else { + resolve({ + path: data.Key, + storage: StorageTypes.OBJECT_STORAGE, + }); + } + }); + }); + } catch (e) { + errorToProblem(SERVICE, e); + } + } + + async delete(fileStorage) { + try { + const params = { + Bucket: this._bucket, + Key: fileStorage.path, + }; + return new Promise((resolve, reject) => { + this._s3.deleteObject(params, (err, data) => { + if (err) { + // doesn't throw a 404 when given a bad key + reject(err); + } else { + resolve(data); + } + }); + }); + } catch (e) { + errorToProblem(SERVICE, e); + } + } + + async read(fileStorage) { + try { + const params = { + Bucket: this._bucket, + Key: fileStorage.path, + }; + return new Promise((resolve, reject) => { + const _local_s3 = this._s3; + // eslint-disable-next-line + _local_s3.headObject(params, function (err, data) { + if (err) { + if (404 === err.statusCode) { + reject(new Problem(404, 'File not found')); + } else { + reject(err); + } + } else { + // want to return the stream... + resolve(_local_s3.getObject(params).createReadStream()); + } + }); + }); + } catch (e) { + errorToProblem(SERVICE, e); + } + } + + async move(fileStorage, ...subdirs) { + try { + const sourcePath = fileStorage.path; + const file = await this.copyFile(fileStorage, ...subdirs); + if (file) { + // this doesn't return the new key/path, but we can build it + const newPath = this._join(this._key, ...subdirs, fileStorage.id); + // now delete original... + const params = { + Bucket: this._bucket, + Key: sourcePath, + }; + + return new Promise((resolve, reject) => { + // eslint-disable-next-line no-unused-vars + this._s3.deleteObject(params, (err, data) => { + if (err) { + reject(err); + } else { + resolve(newPath); + } + }); + }); + } + } catch (e) { + errorToProblem(SERVICE, e); + } + } + + async copyFile(fileStorage, ...subdirs) { + try { + const destPath = this._join(...subdirs); + + const params = { + Bucket: `${this._bucket}/${this._key}${destPath}`, + CopySource: `${this._bucket}/${fileStorage.path}`, + Key: fileStorage.id, + }; + + return new Promise((resolve, reject) => { + // eslint-disable-next-line no-unused-vars + this._s3.copyObject(params, (err, data) => { + if (err) { + reject(err); + } else { + resolve(data); + } + }); + }); + } catch (e) { + errorToProblem(SERVICE, e); + } + } +} + +const endpoint = config.get('files.objectStorage.endpoint'); +const bucket = config.get('files.objectStorage.bucket'); +const key = config.get('files.objectStorage.key'); +const accessKeyId = config.get('files.objectStorage.accessKeyId'); +const secretAccessKey = config.get('files.objectStorage.secretAccessKey'); + +let objectStorageService = new ObjectStorageService({ + accessKeyId: accessKeyId, + secretAccessKey: secretAccessKey, + endpoint: endpoint, + bucket: bucket, + key: key, +}); +module.exports = objectStorageService; diff --git a/frontend/app/src/forms/file/storage/storageService.js b/frontend/app/src/forms/file/storage/storageService.js new file mode 100644 index 0000000..74bfc90 --- /dev/null +++ b/frontend/app/src/forms/file/storage/storageService.js @@ -0,0 +1,61 @@ +const config = require('config'); + +const StorageTypes = require('../../common/constants').StorageTypes; +const _isLocal = (x) => StorageTypes.LOCAL_STORES.includes(x.storage); + +const PERMANENT_STORAGE = config.get('files.permanent'); +const localStorageService = require('./localStorageService'); +const objectStorageService = require('./objectStorageService'); + +const service = { + _deleteFile: async (fileStorage) => { + if (_isLocal(fileStorage)) { + return localStorageService.delete(fileStorage); + } else if (StorageTypes.OBJECT_STORAGE === fileStorage.storage) { + return objectStorageService.delete(fileStorage); + } + }, + + _readFile: async (fileStorage) => { + if (_isLocal(fileStorage)) { + return localStorageService.read(fileStorage); + } else if (StorageTypes.OBJECT_STORAGE === fileStorage.storage) { + return objectStorageService.read(fileStorage); + } + }, + + _moveFile: async (fileStorage, ...subdirs) => { + // move file only works on the same storage system + if (_isLocal(fileStorage)) { + return localStorageService.move(fileStorage, ...subdirs); + } else if (StorageTypes.OBJECT_STORAGE === fileStorage.storage) { + return objectStorageService.move(fileStorage, ...subdirs); + } + }, + + _uploadFile: async (fileStorage) => { + if (PERMANENT_STORAGE === StorageTypes.LOCAL_STORAGE) { + return localStorageService.uploadFile(fileStorage); + } else if (PERMANENT_STORAGE === StorageTypes.OBJECT_STORAGE) { + return objectStorageService.uploadFile(fileStorage); + } + }, + + delete: async (fileStorage) => { + return service._deleteFile(fileStorage); + }, + + move: async (fileStorage, ...subdirs) => { + return service._moveFile(fileStorage, ...subdirs); + }, + + read: async (fileStorage) => { + return service._readFile(fileStorage); + }, + + upload: async (fileStorage) => { + return service._uploadFile(fileStorage); + }, +}; + +module.exports = service; diff --git a/frontend/app/src/forms/form/controller.js b/frontend/app/src/forms/form/controller.js new file mode 100644 index 0000000..53eec1b --- /dev/null +++ b/frontend/app/src/forms/form/controller.js @@ -0,0 +1,305 @@ +const emailService = require('../email/emailService'); +const exportService = require('./exportService'); +const service = require('./service'); +const fileService = require('../file/service'); + +module.exports = { + export: async (req, res, next) => { + try { + const result = await exportService.export(req.params.formId, req.query, req.currentUser, req.headers.referer); + ['Content-Disposition', 'Content-Type'].forEach((h) => { + res.setHeader(h, result.headers[h.toLowerCase()]); + }); + return res.send(result.data); + } catch (error) { + next(error); + } + }, + + exportWithFields: async (req, res, next) => { + try { + const result = await exportService.export(req.params.formId, req.body, req.currentUser, req.headers.referer); + ['Content-Disposition', 'Content-Type'].forEach((h) => { + res.setHeader(h, result.headers[h.toLowerCase()]); + }); + return res.send(result.data); + } catch (error) { + next(error); + } + }, + listForms: async (req, res, next) => { + try { + const response = await service.listForms(req.query); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + createForm: async (req, res, next) => { + try { + const response = await service.createForm(req.body, req.currentUser); + res.status(201).json(response); + } catch (error) { + next(error); + } + }, + readForm: async (req, res, next) => { + try { + const response = await service.readForm(req.params.formId, req.query); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + readFormOptions: async (req, res, next) => { + try { + const response = await service.readFormOptions(req.params.formId, req.query); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + readPublishedForm: async (req, res, next) => { + try { + const response = await service.readPublishedForm(req.params.formId, req.query); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + updateForm: async (req, res, next) => { + try { + const response = await service.updateForm(req.params.formId, req.body, req.currentUser); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + deleteForm: async (req, res, next) => { + try { + const response = await service.deleteForm(req.params.formId, req.query, req.currentUser); + res.status(204).json(response); + } catch (error) { + next(error); + } + }, + listFormSubmissions: async (req, res, next) => { + try { + const response = await service.listFormSubmissions(req.params.formId, req.query); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + readVersion: async (req, res, next) => { + try { + const response = await service.readVersion(req.params.formVersionId); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + readVersionFields: async (req, res, next) => { + try { + const response = await service.readVersionFields(req.params.formVersionId); + res.status(200).json(response.filter((f) => f !== 'submit')); + } catch (error) { + next(error); + } + }, + publishVersion: async (req, res, next) => { + try { + const response = await service.publishVersion(req.params.formId, req.params.formVersionId, req.query, req.currentUser); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + listSubmissions: async (req, res, next) => { + try { + const response = await service.listSubmissions(req.params.formVersionId, req.query); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + createSubmission: async (req, res, next) => { + try { + const response = await service.createSubmission(req.params.formVersionId, req.body, req.currentUser); + if (!req.body.draft) { + emailService.submissionReceived(req.params.formId, response.id, req.body, req.headers.referer).catch(() => {}); + } + // do we want to await this? could take a while, but it could fail... maybe make an explicit api call? + fileService.moveSubmissionFiles(response.id, req.currentUser).catch(() => {}); + res.status(201).json(response); + } catch (error) { + next(error); + } + }, + createMultiSubmission: async (req, res, next) => { + try { + const response = await service.createMultiSubmission(req.params.formVersionId, req.body, req.currentUser); + res.status(201).json(response); + } catch (error) { + next(error); + } + }, + listSubmissionFields: async (req, res, next) => { + try { + let fields = []; + if (req.query.fields) { + let splitFields = []; + if (Array.isArray(req.query.fields)) { + splitFields = req.query.fields.flatMap((f) => f.split(',').map((s) => s.trim())); + } else { + splitFields = req.query.fields.split(',').map((s) => s.trim()); + } + + // Drop invalid fields + const validFields = await service.readVersionFields(req.params.formVersionId); + fields = splitFields.filter((f) => validFields.includes(f)); + } + + const response = await service.listSubmissionFields(req.params.formVersionId, fields); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + listDrafts: async (req, res, next) => { + try { + const response = await service.listDrafts(req.params.formId, req.query); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + createDraft: async (req, res, next) => { + try { + const response = await service.createDraft(req.params.formId, req.body, req.currentUser); + res.status(201).json(response); + } catch (error) { + next(error); + } + }, + readDraft: async (req, res, next) => { + try { + const response = await service.readDraft(req.params.formVersionDraftId); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + updateDraft: async (req, res, next) => { + try { + const response = await service.updateDraft(req.params.formVersionDraftId, req.body, req.currentUser); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + deleteDraft: async (req, res, next) => { + try { + const response = await service.deleteDraft(req.params.formVersionDraftId); + res.status(204).json(response); + } catch (error) { + next(error); + } + }, + publishDraft: async (req, res, next) => { + try { + const response = await service.publishDraft(req.params.formId, req.params.formVersionDraftId, req.currentUser); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + getStatusCodes: async (req, res, next) => { + try { + const response = await service.getStatusCodes(req.params.formId); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + readApiKey: async (req, res, next) => { + try { + const response = await service.readApiKey(req.params.formId); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + createOrReplaceApiKey: async (req, res, next) => { + try { + const response = await service.createOrReplaceApiKey(req.params.formId, req.currentUser); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + deleteApiKey: async (req, res, next) => { + try { + const response = await service.deleteApiKey(req.params.formId); + res.status(204).json(response); + } catch (error) { + next(error); + } + }, + getFCProactiveHelpImageUrl: async (req, res, next) => { + try { + const response = await service.getFCProactiveHelpImageUrl(req.params.componentId); + res.status(200).send(response); + } catch (error) { + next(error); + } + }, + readFieldsForCSVExport: async (req, res, next) => { + try { + const response = await exportService.fieldsForCSVExport(req.params.formId, req.query); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + listFormComponentsProactiveHelp: async (req, res, next) => { + try { + const response = await service.listFormComponentsProactiveHelp(); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + readFormSubscriptionDetails: async (req, res, next) => { + try { + const response = await service.readFormSubscriptionDetails(req.params.formId, req.query); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + createOrUpdateSubscriptionDetails: async (req, res, next) => { + try { + const response = await service.createOrUpdateSubscriptionDetails(req.params.formId, req.body, req.currentUser); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + readEmailTemplates: async (req, res, next) => { + try { + const response = await service.readEmailTemplates(req.params.formId); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + createOrUpdateEmailTemplate: async (req, res, next) => { + try { + const response = await service.createOrUpdateEmailTemplate(req.params.formId, req.body, req.currentUser); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, +}; diff --git a/frontend/app/src/forms/form/exportService.js b/frontend/app/src/forms/form/exportService.js new file mode 100644 index 0000000..849c572 --- /dev/null +++ b/frontend/app/src/forms/form/exportService.js @@ -0,0 +1,455 @@ +const Problem = require('api-problem'); +const { flattenComponents, unwindPath, submissionHeaders } = require('../common/utils'); +const { EXPORT_FORMATS, EXPORT_TYPES } = require('../common/constants'); +const { Form, FormVersion, SubmissionData } = require('../common/models'); +const _ = require('lodash'); +const { Readable } = require('stream'); +const { unwind, flatten } = require('@json2csv/transforms'); +const { Transform } = require('@json2csv/node'); +const fs = require('fs-extra'); +const os = require('os'); +const config = require('config'); +const fileService = require('../file/service'); +const emailService = require('../email/emailService'); +const { v4: uuidv4 } = require('uuid'); +const nestedObjectsUtil = require('nested-objects-util'); + +const service = { + /** + * @function _readSchemaFields + * Returns a flattened, ordered array of relevant content field names with topology + * @param {Object} schema A form.io schema + * @returns {String[]} An array of strings + */ + _readSchemaFieldsV2: (schema) => { + /** + * @function findFields + * Recursively traverses the form.io schema to extract all relevant content field names + * @param {Object} obj A form.io schema or subset of it + * @returns {String[]} An array of strings + */ + const findFields = (obj) => { + const fields = []; + const fieldsDefinedInSubmission = ['datamap', 'tree']; + + // if an input component (not hidden or a button) + if (obj.key && obj.input && !obj.hidden && obj.type !== 'button') { + // if the fieldname we want is defined in component's sub-values + const componentsWithSubValues = ['simplecheckboxes', 'selectboxes', 'survey', 'address']; + if (obj.type && componentsWithSubValues.includes(obj.type)) { + // for survey component, get field name from obj.questions.value + if (obj.type === 'survey') { + obj.questions.forEach((e) => fields.push(`${obj.key}.${e.value}`)); + } + // for checkboxes and selectboxes, get field name from obj.values.value + else if (obj.values) obj.values.forEach((e) => fields.push(`${obj.key}.${e.value}`)); + // else push the parent field + else { + fields.push(obj.key); + } + } + + // get these sub-vales so they appear in ordered columns + else if (obj.type === 'simplefile') { + fields.push(`${obj.key}.url`, `${obj.key}.url`, `${obj.key}.data.id`, `${obj.key}.size`, `${obj.key}.storage`, `${obj.key}.originalName`); + } else if (!obj.tree && !fieldsDefinedInSubmission.includes(obj.type)) { + /** + * component's 'tree' property is true for input components with child inputs, + * which we get recursively. + * also exclude fieldnames defined in submission + * eg datagrid, container, tree + */ + // Add current field key + fields.push(obj.key); + } + } + + // Recursively traverse children array levels + Object.entries(obj).forEach(([k, v]) => { + if (Array.isArray(v) && v.length) { + // Enumerate children fields + const children = obj[k].flatMap((e) => { + const cFields = findFields(e); + // Prepend current key to field name if component's 'tree' property is true + // eg: datagrid1.textFieldInDataGrid1 + // TODO: find fields in 'table' component + return obj.tree && !fieldsDefinedInSubmission.includes(obj.type) ? cFields.flatMap((c) => `${obj.key}.${c}`) : cFields; + }); + if (children.length) { + Array.prototype.push.apply(fields, children); // concat into first argument + } + } + }); + + return fields; + }; + + return findFields(schema); + }, + _readSchemaFields: async (schema) => { + return await flattenComponents(schema.components); + }, + + /** + * Help function to make header column order same as it goes in form + */ + mapOrder: (array, order) => { + let result = []; + let helpMap = {}; + array.map((ar) => { + if (ar.search(/\.\d*\./) !== -1 || ar.search(/\.\d*$/) !== -1) { + if (helpMap[ar.replace(/\.\d*\./gi, '.')] && Array.isArray(helpMap[ar.replace(/\.\d*\./gi, '.')])) { + helpMap[ar.replace(/\.\d*\./gi, '.')].push(ar); + Object.assign(helpMap, { [ar.replace(/\.\d*\./gi, '.')]: helpMap[ar.replace(/\.\d*\./gi, '.')] }); + } else if (helpMap[ar.replace(/\.\d*$/gi, '')] && Array.isArray(helpMap[ar.replace(/\.\d*$/gi, '')])) { + helpMap[ar.replace(/\.\d*$/gi, '')].push(ar); + Object.assign(helpMap, { [ar.replace(/\.\d*$/gi, '')]: helpMap[ar.replace(/\.\d*$/gi, '')] }); + } else { + if (ar.search(/\.\d*\./) !== -1) { + Object.assign(helpMap, { [ar.replace(/\.\d*\./gi, '.')]: [ar] }); + } else if (ar.search(/\.\d*$/) !== -1) { + Object.assign(helpMap, { [ar.replace(/\.\d*$/gi, '')]: [ar] }); + } + } + } + }); + array.map((ar) => { + if (ar.substring(0, 5) === 'form.') { + result.push(ar); + } + }); + order.map((ord) => { + if (array.includes(ord) && !helpMap[ord]) { + result.push(ord); + } else if (helpMap[ord]) { + helpMap[ord].map((h) => result.push(h)); + } else { + // if non of those single fields or datagrids with multi children + // then work with possible fields with external sources as an object/json + array.map((ar) => { + if (ar.includes(ord)) { + result.push(ar); + } + }); + } + }); + // removing all possible duplicates + result = [...new Set(result)]; + return result; + }, + + _buildCsvHeaders: async (form, data, version, fields, singleRow = false) => { + /** + * get column order to match field order in form design + * object key order is not preserved when submission JSON is saved to jsonb field type in postgres. + */ + + // get correctly ordered field names (keys) from latest form version + const latestFormDesign = await service._readLatestFormSchema(form.id, version); + + const fieldNames = await service._readSchemaFields(latestFormDesign, data); + // get meta properties in 'form.' string format + const metaKeys = Object.keys(data.length > 0 && data[0].form); + const metaHeaders = metaKeys.map((x) => 'form.' + x); + /** + * make other changes to headers here if required + * eg: use field labels as headers + * see: https://github.com/kaue/jsonexport + */ + let formSchemaheaders = Array.isArray(data) && data.length > 0 && !singleRow ? metaHeaders.concat(fieldNames) : metaHeaders; + if (Array.isArray(data) && data.length > 0) { + let flattenSubmissionHeaders = []; + // if we generate single row headers we need to keep in mind of possible multi children nested data thus do flattening + if (singleRow) { + flattenSubmissionHeaders = Object.keys(nestedObjectsUtil.flatten(data)); + // '0**.field_name' removing starting digits from flaten object properies to get unique fields after + flattenSubmissionHeaders = flattenSubmissionHeaders.map((header) => header.replace(/^\d*\./gi, '')); + // getting unique values + flattenSubmissionHeaders = [...new Set(flattenSubmissionHeaders)]; + } else { + flattenSubmissionHeaders = Array.from(submissionHeaders(data[0])); + } + // apply help function to make header column order same as it goes in form + const flattenSubmissionHeadersOrdered = service.mapOrder(flattenSubmissionHeaders, fieldNames); + formSchemaheaders = formSchemaheaders.concat(flattenSubmissionHeadersOrdered.filter((item) => formSchemaheaders.indexOf(item) < 0)); + } + + if (fields) { + return formSchemaheaders.filter((header) => { + if (Array.isArray(fields) && fields.includes(header)) { + return header; + } + }); + } + return formSchemaheaders; + }, + + _exportType: (params = {}) => { + let result = EXPORT_TYPES[params.type]; + return result ? result : EXPORT_TYPES.default; + }, + + _exportFormat: (params = {}) => { + let result = EXPORT_FORMATS[params.format]; + return result ? result : EXPORT_FORMATS.default; + }, + + _exportFilename: (form, type, format) => { + return `${form.snake()}_${type}.${format}`.toLowerCase(); + }, + + _submissionsColumns: (form, params) => { + // Custom columns not defined - return default column selection behavior + let columns = ['submissionId', 'confirmationId', 'formName', 'version', 'createdAt', 'fullName', 'username', 'email']; + // if form has 'status updates' enabled in the form settings include these in export + if (form.enableStatusUpdates) { + columns = columns.concat(['status', 'assignee', 'assigneeEmail']); + } + // Let's add form level columns like deleted or draft + if (params?.columns?.length) { + let optionalAcceptedColumns = ['draft', 'deleted', 'updatedAt']; //'draft', 'deleted', 'updatedAt' columns needed for ETL process at this moment + columns = columns.concat((Array.isArray(params.columns) ? [...params.columns] : [params.columns]).filter((column) => optionalAcceptedColumns.includes(column))); + } + // and join the submission data + return columns.concat(['submission']); + }, + + _getForm: (formId) => { + return Form.query().findById(formId).throwIfNotFound(); + }, + + _getData: async (exportType, formVersion, form, params = {}) => { + if (EXPORT_TYPES.submissions === exportType) { + let subs = await service._getSubmissions(form, params, formVersion); + return subs; + } + return {}; + }, + _formatData: async (exportFormat, exportType, exportTemplate, form, data = {}, columns, version, emailExport, currentUser, referer) => { + // inverting content structure nesting to prioritize submission content clarity + const formatted = data.map((obj) => { + const { submission, ...form } = obj; + return Object.assign({ form: form }, submission); + }); + + if (EXPORT_TYPES.submissions === exportType) { + if (EXPORT_FORMATS.csv === exportFormat) { + let formVersion = version ? parseInt(version) : 1; + return await service._formatSubmissionsCsv(form, formatted, exportTemplate, columns, formVersion, emailExport, currentUser, referer); + } + if (EXPORT_FORMATS.json === exportFormat) { + return await service._formatSubmissionsJson(form, formatted); + } + } + throw new Problem(422, { + detail: 'Could not create an export for this form. Invalid options provided', + }); + }, + + _getSubmissions: async (form, params, version) => { + //let preference = params.preference ? JSON.parse(params.preference) : undefined; + let preference; + if (params.preference && _.isString(params.preference)) { + preference = JSON.parse(params.preference); + } else { + preference = params.preference; + } + // let submissionData; + // params for this export include minDate and maxDate (full timestamp dates). + return SubmissionData.query() + .select(service._submissionsColumns(form, params)) + .where('formId', form.id) + .modify('filterVersion', version) + .modify('filterCreatedAt', preference && preference.minDate, preference && preference.maxDate) + .modify('filterUpdatedAt', preference && preference.updatedMinDate, preference && preference.updatedMaxDate) + .modify('filterStatus', params.status) + .modify('filterDeleted', params.deleted) + .modify('filterDrafts', params.drafts) + .modify('orderDefault') + .then((submissionData) => { + if (submissionData == undefined || submissionData == null || submissionData.length == 0) return []; + return service._submissionFilterByUnsubmit(submissionData); + }); + }, + + _submissionFilterByUnsubmit: (submissionData) => { + for (let index in submissionData) { + let keys = Object.keys(submissionData[index].submission); + for (let key of keys) { + if (key === 'submit') { + delete submissionData[index].submission[key]; + } + } + } + return submissionData; + }, + _formatSubmissionsJson: (form, data) => { + return { + data: data, + headers: { + 'content-disposition': `attachment; filename="${service._exportFilename(form, EXPORT_TYPES.submissions, EXPORT_FORMATS.json)}"`, + 'content-type': 'text/json', + }, + }; + }, + _formatSubmissionsCsv: async (form, data, exportTemplate, fields, version, emailExport, currentUser, referer) => { + try { + switch (exportTemplate) { + case 'multiRowEmptySpacesCSVExport': + return service._multiRowsCSVExport(form, data, version, true, fields, emailExport, currentUser, referer); + case 'multiRowBackFilledCSVExport': + return service._multiRowsCSVExport(form, data, version, false, fields, emailExport, currentUser, referer); + case 'singleRowCSVExport': + return service._singleRowCSVExport(form, data, version, fields, currentUser, emailExport, referer); + case 'unFormattedCSVExport': + return service._unFormattedCSVExport(form, data, emailExport, currentUser, referer); + default: + // code block + } + } catch (e) { + throw new Problem(500, { + detail: `Could not make a csv export of submissions for this form. ${e.message}`, + }); + } + }, + _multiRowsCSVExport: async (form, data, version, blankout, fields, emailExport, currentUser, referer) => { + const pathToUnwind = await unwindPath(data); + let headers = await service._buildCsvHeaders(form, data, version, fields); + + const opts = { + transforms: [unwind({ paths: pathToUnwind, blankOut: blankout }), flatten({ object: true, array: true, separator: '.' })], + fields: headers, + }; + + return service._submissionCSVExport(opts, form, data, emailExport, currentUser, referer); + }, + _singleRowCSVExport: async (form, data, version, fields, currentUser, emailExport, referer) => { + const headers = await service._buildCsvHeaders(form, data, version, fields, true); + const opts = { + transforms: [flatten({ objects: true, arrays: true, separator: '.' })], + fields: headers, + }; + + return service._submissionCSVExport(opts, form, data, emailExport, currentUser, referer); + }, + _unFormattedCSVExport: async (form, data, emailExport, currentUser, referer) => { + return service._submissionCSVExport({}, form, data, emailExport, currentUser, referer); + }, + + _submissionCSVExport(opts, form, data, emailExport, currentUser, referer) { + // to work with object chunk in pipe instead of Buffer + const transformOpts = { + objectMode: true, + }; + + const dataStream = Readable.from(data); + const json2csvParser = new Transform(opts, transformOpts); + + let csv = []; + + if (emailExport !== 'false' && emailExport !== false) { + // If submission count is big we're start streams parsed chunks into the temp file + // using Nodejs fs internal library, then upload the outcome CSV file to Filestorage + // (/myfiles folder for local machines / to Object cloud storage for other env) gathering the file storage ID + // to use it in email for link generation for downloading... + const path = config.get('files.localStorage.path') ? config.get('files.localStorage.path') : fs.realpathSync(os.tmpdir()); + const pathToTmpFile = `${path}/${uuidv4()}.csv`; + const outputStream = fs.createWriteStream(pathToTmpFile); + dataStream.pipe(json2csvParser).pipe(outputStream); + + // Creating FileStorage instance and uploading it, so we can download it later + outputStream.on('finish', () => { + // Read file stats to get fie size + fs.stat(pathToTmpFile, async (err, stats) => { + if (err) { + throw new Problem(400, { + detail: `Error while trying to fetch file stats: ${err}`, + }); + } else { + const fileData = { + originalname: service._exportFilename(form, EXPORT_TYPES.submissions, EXPORT_FORMATS.csv), + mimetype: 'text/csv', + size: stats.size, + path: pathToTmpFile, + }; + const fileCurrentUser = { + usernameIdp: currentUser.usernameIdp, + }; + // Uploading to Object storage + const fileResult = await fileService.create(fileData, fileCurrentUser, 'exports'); + // Sending the email with link to uploaded export + emailService.submissionExportLink(form.id, null, { to: currentUser.email }, referer, fileResult.id); + } + }); + }); + return new Promise((resolve) => + resolve({ + data: null, + headers: { + 'content-disposition': `attachment; filename="${service._exportFilename(form, EXPORT_TYPES.submissions, EXPORT_FORMATS.csv)}"`, + 'content-type': 'text/csv', + }, + }) + ); + } + // If we're working with not too many submissions, we can process parsing right away without + // any memory constrains + return new Promise((resolve, reject) => { + dataStream + .pipe(json2csvParser) + .on('data', (chunk) => { + csv.push(chunk.toString()); + }) + .on('finish', () => { + resolve({ + data: csv.join(''), + headers: { + 'content-disposition': `attachment; filename="${service._exportFilename(form, EXPORT_TYPES.submissions, EXPORT_FORMATS.csv)}"`, + 'content-type': 'text/csv', + }, + }); + }) + .on('error', (err) => { + reject({ + detail: `Error while parsing json chunk: ${err}`, + }); + }); + }); + }, + + _readLatestFormSchema: (formId, version) => { + return FormVersion.query() + .select('schema') + .where('formId', formId) + .where('version', version) + .modify('filterVersion', version) + .modify('orderVersionDescending') + .first() + .then((row) => row?.schema); + }, + fieldsForCSVExport: async (formId, params = {}) => { + const form = await service._getForm(formId); + const data = await service._getData(params.type, params.version, form, params); + const formatted = data.map((obj) => { + const { submission, ...form } = obj; + return Object.assign({ form: form }, submission); + }); + + return await service._buildCsvHeaders(form, formatted, params.version, undefined, params.singleRow === 'true'); + }, + + export: async (formId, params = {}, currentUser = null, referer) => { + // ok, let's determine what we are exporting and do it!!!! + // what operation? + // what output format? + const exportType = service._exportType(params); + const exportFormat = service._exportFormat(params); + const exportTemplate = params.template ? params.template : 'multiRowEmptySpacesCSVExport'; + const form = await service._getForm(formId); + const data = await service._getData(exportType, params.version, form, params); + const result = await service._formatData(exportFormat, exportType, exportTemplate, form, data, params.fields, params.version, params.emailExport, currentUser, referer); + return { data: result.data, headers: result.headers }; + }, +}; + +module.exports = service; diff --git a/frontend/app/src/forms/form/index.js b/frontend/app/src/forms/form/index.js new file mode 100644 index 0000000..d4afe96 --- /dev/null +++ b/frontend/app/src/forms/form/index.js @@ -0,0 +1,7 @@ +const dataErrors = require('../common/middleware').dataErrors; +const routes = require('./routes'); +const setupMount = require('../common/utils').setupMount; + +module.exports.mount = (app) => { + return setupMount('forms', app, routes, dataErrors); +}; diff --git a/frontend/app/src/forms/form/routes.js b/frontend/app/src/forms/form/routes.js new file mode 100644 index 0000000..af62c75 --- /dev/null +++ b/frontend/app/src/forms/form/routes.js @@ -0,0 +1,149 @@ +const config = require('config'); +const routes = require('express').Router(); +const apiAccess = require('../auth/middleware/apiAccess'); +const { currentUser, hasFormPermissions } = require('../auth/middleware/userAccess'); +const P = require('../common/constants').Permissions; +const rateLimiter = require('../common/middleware').apiKeyRateLimiter; + +const keycloak = require('../../components/keycloak'); +const controller = require('./controller'); + +routes.use(currentUser); + +routes.get('/', keycloak.protect(`${config.get('server.keycloak.clientId')}:admin`), async (req, res, next) => { + await controller.listForms(req, res, next); +}); + +routes.post('/', async (req, res, next) => { + await controller.createForm(req, res, next); +}); + +routes.get('/:formId', rateLimiter, apiAccess, hasFormPermissions(P.FORM_READ), async (req, res, next) => { + await controller.readForm(req, res, next); +}); + +routes.get('/:formId/export', rateLimiter, apiAccess, hasFormPermissions([P.FORM_READ, P.SUBMISSION_READ]), async (req, res, next) => { + await controller.export(req, res, next); +}); + +routes.post('/:formId/export/fields', rateLimiter, apiAccess, hasFormPermissions([P.FORM_READ, P.SUBMISSION_READ]), async (req, res, next) => { + await controller.exportWithFields(req, res, next); +}); + +routes.get('/:formId/emailTemplates', hasFormPermissions(P.EMAIL_TEMPLATE_READ), async (req, res, next) => { + await controller.readEmailTemplates(req, res, next); +}); + +routes.put('/:formId/emailTemplate', hasFormPermissions([P.EMAIL_TEMPLATE_READ, P.EMAIL_TEMPLATE_UPDATE]), async (req, res, next) => { + await controller.createOrUpdateEmailTemplate(req, res, next); +}); + +routes.get('/:formId/options', async (req, res, next) => { + await controller.readFormOptions(req, res, next); +}); + +routes.get('/:formId/version', rateLimiter, apiAccess, hasFormPermissions(P.FORM_READ), async (req, res, next) => { + await controller.readPublishedForm(req, res, next); +}); + +routes.put('/:formId', rateLimiter, apiAccess, hasFormPermissions([P.FORM_READ, P.FORM_UPDATE]), async (req, res, next) => { + await controller.updateForm(req, res, next); +}); + +routes.delete('/:formId', rateLimiter, apiAccess, hasFormPermissions([P.FORM_READ, P.FORM_DELETE]), async (req, res, next) => { + await controller.deleteForm(req, res, next); +}); + +routes.get('/:formId/submissions', rateLimiter, apiAccess, hasFormPermissions([P.FORM_READ, P.SUBMISSION_READ]), async (req, res, next) => { + await controller.listFormSubmissions(req, res, next); +}); + +routes.get('/:formId/versions/:formVersionId', rateLimiter, apiAccess, hasFormPermissions([P.FORM_READ]), async (req, res, next) => { + await controller.readVersion(req, res, next); +}); + +routes.get('/:formId/versions/:formVersionId/fields', rateLimiter, apiAccess, hasFormPermissions([P.FORM_READ]), async (req, res, next) => { + await controller.readVersionFields(req, res, next); +}); + +routes.post('/:formId/versions/:formVersionId/publish', rateLimiter, apiAccess, hasFormPermissions([P.FORM_READ, P.DESIGN_CREATE]), async (req, res, next) => { + await controller.publishVersion(req, res, next); +}); + +routes.get('/:formId/versions/:formVersionId/submissions', rateLimiter, apiAccess, hasFormPermissions([P.FORM_READ, P.SUBMISSION_READ]), async (req, res, next) => { + await controller.listSubmissions(req, res, next); +}); + +routes.post('/:formId/versions/:formVersionId/submissions', rateLimiter, apiAccess, hasFormPermissions([P.FORM_READ, P.SUBMISSION_CREATE]), async (req, res, next) => { + await controller.createSubmission(req, res, next); +}); + +routes.post('/:formId/versions/:formVersionId/multiSubmission', rateLimiter, apiAccess, hasFormPermissions([P.FORM_READ, P.SUBMISSION_CREATE]), async (req, res, next) => { + await controller.createMultiSubmission(req, res, next); +}); + +routes.get('/:formId/versions/:formVersionId/submissions/discover', rateLimiter, apiAccess, hasFormPermissions([P.FORM_READ, P.SUBMISSION_READ]), (req, res, next) => { + controller.listSubmissionFields(req, res, next); +}); + +routes.get('/:formId/drafts', rateLimiter, apiAccess, hasFormPermissions([P.FORM_READ, P.DESIGN_READ]), async (req, res, next) => { + await controller.listDrafts(req, res, next); +}); + +routes.post('/:formId/drafts', rateLimiter, apiAccess, hasFormPermissions([P.FORM_READ, P.DESIGN_CREATE]), async (req, res, next) => { + await controller.createDraft(req, res, next); +}); + +routes.get('/:formId/drafts/:formVersionDraftId', rateLimiter, apiAccess, hasFormPermissions([P.FORM_READ, P.DESIGN_READ]), async (req, res, next) => { + await controller.readDraft(req, res, next); +}); + +routes.put('/:formId/drafts/:formVersionDraftId', rateLimiter, apiAccess, hasFormPermissions([P.FORM_READ, P.DESIGN_UPDATE]), async (req, res, next) => { + await controller.updateDraft(req, res, next); +}); + +routes.delete('/:formId/drafts/:formVersionDraftId', rateLimiter, apiAccess, hasFormPermissions([P.FORM_READ, P.DESIGN_DELETE]), async (req, res, next) => { + await controller.deleteDraft(req, res, next); +}); + +routes.post('/:formId/drafts/:formVersionDraftId/publish', rateLimiter, apiAccess, hasFormPermissions([P.FORM_READ, P.DESIGN_CREATE]), async (req, res, next) => { + await controller.publishDraft(req, res, next); +}); + +routes.get('/:formId/statusCodes', rateLimiter, apiAccess, hasFormPermissions([P.FORM_READ]), async (req, res, next) => { + await controller.getStatusCodes(req, res, next); +}); + +routes.get('/:formId/apiKey', hasFormPermissions(P.FORM_API_READ), async (req, res, next) => { + await controller.readApiKey(req, res, next); +}); + +routes.put('/:formId/apiKey', hasFormPermissions(P.FORM_API_CREATE), async (req, res, next) => { + await controller.createOrReplaceApiKey(req, res, next); +}); + +routes.delete('/:formId/apiKey', hasFormPermissions(P.FORM_API_DELETE), async (req, res, next) => { + await controller.deleteApiKey(req, res, next); +}); + +routes.get('/formcomponents/proactivehelp/list', async (req, res, next) => { + await controller.listFormComponentsProactiveHelp(req, res, next); +}); + +routes.get('/:formId/csvexport/fields', rateLimiter, apiAccess, hasFormPermissions([P.FORM_READ]), async (req, res, next) => { + await controller.readFieldsForCSVExport(req, res, next); +}); + +routes.get('/formcomponents/proactivehelp/imageUrl/:componentId', async (req, res, next) => { + await controller.getFCProactiveHelpImageUrl(req, res, next); +}); + +routes.get('/:formId/subscriptions', hasFormPermissions([P.FORM_READ, P.FORM_UPDATE]), async (req, res, next) => { + await controller.readFormSubscriptionDetails(req, res, next); +}); + +routes.put('/:formId/subscriptions', hasFormPermissions([P.FORM_READ, P.FORM_UPDATE]), async (req, res, next) => { + await controller.createOrUpdateSubscriptionDetails(req, res, next); +}); + +module.exports = routes; diff --git a/frontend/app/src/forms/form/service.js b/frontend/app/src/forms/form/service.js new file mode 100644 index 0000000..b8a9639 --- /dev/null +++ b/frontend/app/src/forms/form/service.js @@ -0,0 +1,927 @@ +const Problem = require('api-problem'); +const { ref } = require('objection'); +const { v4: uuidv4 } = require('uuid'); +const { EmailTypes, SubscriptionEvent } = require('../common/constants'); +const axios = require('axios'); +const log = require('../../components/log')(module.filename); +const moment = require('moment'); +const { + FileStorage, + Form, + FormApiKey, + FormEmailTemplate, + FormIdentityProvider, + FormRoleUser, + FormVersion, + FormVersionDraft, + FormStatusCode, + FormSubmission, + FormSubmissionStatus, + FormSubmissionUser, + IdentityProvider, + SubmissionMetadata, + FormComponentsProactiveHelp, + FormSubscription, +} = require('../common/models'); +const { falsey, queryUtils, checkIsFormExpired, validateScheduleObject, typeUtils } = require('../common/utils'); +const { Permissions, Roles, Statuses } = require('../common/constants'); +const Rolenames = [Roles.OWNER, Roles.TEAM_MANAGER, Roles.FORM_DESIGNER, Roles.SUBMISSION_REVIEWER, Roles.FORM_SUBMITTER]; + +const service = { + // Get the list of file IDs from the submission + _findFileIds: (schema, data) => { + return ( + schema.components + // Get the file controls + .filter((x) => x.type === 'simplefile') + // for the file controls, get their respective data element (skip if it's not in data) + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flatMap#for_adding_and_removing_items_during_a_map + .flatMap((x) => (data.submission.data[x.key] ? data.submission.data[x.key] : [])) + // get the id from the data + .map((x) => x.data.id) + ); + }, + + listForms: async (params) => { + params = queryUtils.defaultActiveOnly(params); + return Form.query() + .modify('filterActive', params.active) + .allowGraph('[identityProviders,versions]') + .withGraphFetched('identityProviders(orderDefault)') + .withGraphFetched('versions(selectWithoutSchema, orderVersionDescending)') + .modify('orderNameAscending'); + }, + + createForm: async (data, currentUser) => { + let trx; + const scheduleData = validateScheduleObject(data.schedule); + if (scheduleData.status !== 'success') { + throw new Problem(422, `${scheduleData.message}`); + } + + try { + trx = await Form.startTransaction(); + const obj = {}; + obj.id = uuidv4(); + obj.name = data.name; + obj.description = data.description; + obj.active = true; + obj.labels = data.labels; + obj.showSubmissionConfirmation = data.showSubmissionConfirmation; + obj.submissionReceivedEmails = data.submissionReceivedEmails; + obj.enableStatusUpdates = data.enableStatusUpdates; + obj.enableSubmitterDraft = data.enableSubmitterDraft; + obj.createdBy = currentUser.usernameIdp; + obj.allowSubmitterToUploadFile = data.allowSubmitterToUploadFile; + obj.schedule = data.schedule; + obj.subscribe = data.subscribe; + obj.reminder_enabled = data.reminder_enabled; + obj.enableCopyExistingSubmission = data.enableCopyExistingSubmission; + + await Form.query(trx).insert(obj); + if (data.identityProviders && Array.isArray(data.identityProviders) && data.identityProviders.length) { + const fips = []; + for (const p of data.identityProviders) { + const exists = await IdentityProvider.query(trx).where('code', p.code).where('active', true).first(); + if (!exists) { + throw new Problem(422, `${p.code} is not a valid Identity Provider code`); + } + fips.push({ id: uuidv4(), formId: obj.id, code: p.code, createdBy: currentUser.usernameIdp }); + } + await FormIdentityProvider.query(trx).insert(fips); + } + // make this user have ALL the roles... + const userRoles = Rolenames.map((r) => { + return { id: uuidv4(), createdBy: currentUser.usernameIdp, userId: currentUser.id, formId: obj.id, role: r }; + }); + await FormRoleUser.query(trx).insert(userRoles); + + // create a unpublished draft + const draft = { + id: uuidv4(), + formId: obj.id, + createdBy: currentUser.usernameIdp, + schema: data.schema, + }; + await FormVersionDraft.query(trx).insert(draft); + + // Map all status codes to the form - hardcoded to include all states + // TODO: Could make this more dynamic and settable by the user if that feature is required + const defaultStatuses = Object.values(Statuses).map((status) => ({ + id: uuidv4(), + formId: obj.id, + code: status, + createdBy: currentUser.usernameIdp, + })); + await FormStatusCode.query(trx).insert(defaultStatuses); + + await trx.commit(); + const result = await service.readForm(obj.id); + result.draft = draft; + return result; + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, + + updateForm: async (formId, data, currentUser) => { + let trx; + try { + const obj = await service.readForm(formId); + trx = await Form.startTransaction(); + // do not update the active flag, that should be done via DELETE + const scheduleData = validateScheduleObject(data.schedule); + if (scheduleData.status !== 'success') { + throw new Problem(422, `${scheduleData.message}`); + } + const upd = { + name: data.name, + description: data.description, + labels: data.labels ? data.labels : [], + showSubmissionConfirmation: data.showSubmissionConfirmation, + submissionReceivedEmails: data.submissionReceivedEmails ? data.submissionReceivedEmails : [], + enableStatusUpdates: data.enableStatusUpdates, + enableSubmitterDraft: data.enableSubmitterDraft, + updatedBy: currentUser.usernameIdp, + allowSubmitterToUploadFile: data.allowSubmitterToUploadFile, + schedule: data.schedule, + subscribe: data.subscribe, + reminder_enabled: data.reminder_enabled, + enableCopyExistingSubmission: data.enableCopyExistingSubmission, + }; + + await Form.query(trx).patchAndFetchById(formId, upd); + + // remove any existing links to identity providers, and the updated ones + await FormIdentityProvider.query(trx).delete().where('formId', obj.id); + + // insert any new identity providers + const fIdps = data.identityProviders.map((p) => ({ + id: uuidv4(), + formId: obj.id, + code: p.code, + createdBy: currentUser.usernameIdp, + })); + if (fIdps && fIdps.length) await FormIdentityProvider.query(trx).insert(fIdps); + + await trx.commit(); + const result = await service.readForm(obj.id); + return result; + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, + + deleteForm: async (formId, params, currentUser) => { + let trx; + try { + const obj = await service.readForm(formId); + trx = await Form.startTransaction(); + // for now, only handle a soft delete, we could pass in a param to do a hard delete later + await Form.query(trx).patchAndFetchById(formId, { active: false, updatedBy: currentUser.usernameIdp }); + + // If there's a current API key, hard delete that + if (await service.readApiKey(formId)) { + await service.deleteApiKey(formId); + } + + await trx.commit(); + return await service.readForm(obj.id, { active: false }); + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, + + readForm: (formId, params = {}) => { + params = queryUtils.defaultActiveOnly(params); + return Form.query() + .findById(formId) + .modify('filterActive', params.active) + .allowGraph('[identityProviders,versions]') + .withGraphFetched('identityProviders(orderDefault)') + .withGraphFetched('versions(selectWithoutSchema, orderVersionDescending)') + .throwIfNotFound(); + }, + + readFormOptions: (formId, params = {}) => { + params = queryUtils.defaultActiveOnly(params); + return Form.query() + .findById(formId) + .modify('filterActive', params.active) + .select(['id', 'name', 'description']) + .allowGraph('[idpHints]') + .withGraphFetched('idpHints') + .throwIfNotFound() + .then((form) => { + form.idpHints = form.idpHints.map((idp) => idp.code); + return form; + }); + }, + + readPublishedForm: (formId, params = {}) => { + params = queryUtils.defaultActiveOnly(params); + return Form.query() + .findById(formId) + .modify('filterActive', params.active) + .allowGraph('[identityProviders,versions]') + .withGraphFetched('identityProviders(orderDefault)') + .withGraphFetched('versions(onlyPublished)') + .throwIfNotFound() + .then((form) => { + // there are some configs that we don't want returned here... + delete form.submissionReceivedEmails; + //Lets Replace the original schedule Object as it should not expose schedule data to FE users. + form.schedule = checkIsFormExpired(form.schedule); + return form; + }); + }, + + listFormSubmissions: async (formId, params) => { + const query = SubmissionMetadata.query() + .where('formId', formId) + .modify('filterSubmissionId', params.submissionId) + .modify('filterConfirmationId', params.confirmationId) + .modify('filterDraft', params.draft) + .modify('filterDeleted', params.deleted) + .modify('filterCreatedBy', params.createdBy) + .modify('filterFormVersionId', params.formVersionId) + .modify('filterVersion', params.version) + .modify('filterformSubmissionStatusCode', params.filterformSubmissionStatusCode) + .modify('orderDefault', params.sortBy && params.page ? true : false, params); + if (params.createdAt && Array.isArray(params.createdAt) && params.createdAt.length == 2) { + query.modify('filterCreatedAt', params.createdAt[0], params.createdAt[1]); + } + const selection = ['confirmationId', 'createdAt', 'formId', 'formSubmissionStatusCode', 'submissionId', 'deleted', 'createdBy', 'formVersionId']; + + if (params.fields && params.fields.length) { + let fields = []; + if (typeof params.fields !== 'string' && params.fields.includes('updatedAt')) { + selection.push('updatedAt'); + } + if (typeof params.fields !== 'string' && params.fields.includes('updatedBy')) { + selection.push('updatedBy'); + } + if (Array.isArray(params.fields)) { + fields = params.fields.flatMap((f) => f.split(',').map((s) => s.trim())); + } else { + fields = params.fields.split(',').map((s) => s.trim()); + } + // remove updatedAt and updatedBy from custom selected field so they won't be pulled from submission columns + fields = fields.filter((f) => f !== 'updatedAt' && f !== 'updatedBy'); + + fields.push('lateEntry'); + query.select( + selection, + fields.map((f) => ref(`submission:data.${f}`).as(f.split('.').slice(-1))) + ); + } else { + query.select( + selection, + ['lateEntry'].map((f) => ref(`submission:data.${f}`).as(f.split('.').slice(-1))) + ); + } + if (params.paginationEnabled) { + return await service.processPaginationData(query, parseInt(params.page), parseInt(params.itemsPerPage), params.totalSubmissions, params.search, params.searchEnabled); + } + return query; + }, + + async processPaginationData(query, page, itemsPerPage, totalSubmissions, search, searchEnabled) { + let isSearchAble = typeUtils.isBoolean(searchEnabled) ? searchEnabled : searchEnabled !== undefined ? JSON.parse(searchEnabled) : false; + if (isSearchAble) { + let submissionsData = await query; + let result = { + results: [], + total: 0, + }; + let searchedData = submissionsData.filter((data) => { + return Object.keys(data).some((key) => { + if (key !== 'submissionId' && key !== 'formVersionId' && key !== 'formId') { + if (!Array.isArray(data[key]) && !typeUtils.isObject(data[key])) { + if ( + !typeUtils.isBoolean(data[key]) && + !typeUtils.isNil(data[key]) && + typeUtils.isDate(data[key]) && + moment(new Date(data[key])).format('YYYY-MM-DD hh:mm:ss a').toString().includes(search) + ) { + result.total = result.total + 1; + return true; + } + if (typeUtils.isString(data[key]) && data[key].toLowerCase().includes(search.toLowerCase())) { + result.total = result.total + 1; + return true; + } else if ( + (typeUtils.isNil(data[key]) || typeUtils.isBoolean(data[key]) || (typeUtils.isNumeric(data[key]) && typeUtils.isNumeric(search))) && + parseFloat(data[key]) === parseFloat(search) + ) { + result.total = result.total + 1; + return true; + } + } + return false; + } + return false; + }); + }); + let start = page * itemsPerPage; + let end = page * itemsPerPage + itemsPerPage; + result.results = searchedData.slice(start, end); + return result; + } else { + if (itemsPerPage && parseInt(itemsPerPage) === -1) { + return await query.page(parseInt(page), parseInt(totalSubmissions || 0)); + } else if (itemsPerPage && parseInt(page) >= 0) { + return await query.page(parseInt(page), parseInt(itemsPerPage)); + } + } + }, + + publishVersion: async (formId, formVersionId, params = {}, currentUser) => { + let trx; + try { + // allow an unpublish if they pass in unpublish parameter with an affirmative + const publish = params.unpublish ? falsey(params.unpublish) : true; + const form = await service.readForm(formId); + trx = await FormVersion.startTransaction(); + + await FormVersion.query(trx) + .patch({ + published: false, + updatedBy: currentUser.usernameIdp, + }) + .where('formId', form.id) + .where('published', publish); + + await FormVersion.query(trx).findById(formVersionId).patch({ + published: publish, + updatedBy: currentUser.usernameIdp, + }); + + await trx.commit(); + + // return the published form/version... + return await service.readPublishedForm(formId); + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, + + readVersion: (formVersionId) => { + return FormVersion.query().findById(formVersionId).throwIfNotFound(); + }, + + readVersionFields: async (formVersionId) => { + // Recursively find all field key names + // TODO: Consider if this should be a form utils function instead? + const findFields = (obj) => { + const fields = []; + if (!obj.hidden) { + // Only add key if it is an input and visible + if (obj.input) { + fields.push(obj.key); + } else if (Array.isArray(obj) && obj.length) { + // Handle table layouts, where it's an array without keys. + fields.push(obj.flatMap((o) => findFields(o))); + } else { + // Recursively check all children attributes that are arrays + Object.keys(obj).forEach((key) => { + if (Array.isArray(obj[key]) && obj[key].length) { + fields.push(obj[key].flatMap((o) => findFields(o))); + } + }); + } + } + return fields.flat(); + }; + + const { schema } = await service.readVersion(formVersionId); + return schema.components.flatMap((c) => findFields(c)); + }, + listSubmissions: async (formVersionId, params) => { + return FormSubmission.query().where('formVersionId', formVersionId).modify('filterCreatedBy', params.createdBy).modify('orderDescending'); + }, + createSubmission: async (formVersionId, data, currentUser) => { + let trx; + try { + const formVersion = await service.readVersion(formVersionId); + const { identityProviders, subscribe } = await service.readForm(formVersion.formId); + + trx = await FormSubmission.startTransaction(); + + // Ensure we only record the user if the form is not public facing + const isPublicForm = identityProviders.some((idp) => idp.code === 'public'); + const createdBy = isPublicForm ? 'public' : currentUser.usernameIdp; + + const submissionId = uuidv4(); + const obj = Object.assign( + { + id: submissionId, + formVersionId: formVersion.id, + confirmationId: submissionId.substring(0, 8).toUpperCase(), + createdBy: createdBy, + }, + data + ); + + await FormSubmission.query(trx).insert(obj); + + if (!isPublicForm && !currentUser.public) { + // Provide the submission creator appropriate CRUD permissions if this is a non-public form + // we decided that submitter cannot delete or update their own submission unless it's a draft + // We know this is the submission creator when we see the SUBMISSION_CREATE permission + // These are adjusted at the update point if going from draft to submitted, or when adding + // team submitters to a draft + const perms = [Permissions.SUBMISSION_CREATE, Permissions.SUBMISSION_READ]; + if (data.draft) { + perms.push(Permissions.SUBMISSION_DELETE, Permissions.SUBMISSION_UPDATE); + } + + const itemsToInsert = perms.map((perm) => ({ + id: uuidv4(), + userId: currentUser.id, + formSubmissionId: submissionId, + permission: perm, + createdBy: createdBy, + })); + + await FormSubmissionUser.query(trx).insert(itemsToInsert); + } + + if (!data.draft) { + // Add a SUBMITTED status if it's not a draft + const stObj = { + id: uuidv4(), + submissionId: submissionId, + code: Statuses.SUBMITTED, + createdBy: createdBy, + }; + + await FormSubmissionStatus.query(trx).insert(stObj); + } + if (subscribe && subscribe.enabled) { + const subscribeConfig = await service.readFormSubscriptionDetails(formVersion.formId); + const config = Object.assign({}, subscribe, subscribeConfig); + service.postSubscriptionEvent(config, formVersion, submissionId, SubscriptionEvent.FORM_SUBMITTED); + } + + // does this submission contain any file uploads? + // if so, we need to update the file storage records. + // use the schema to determine if there are uploads, fetch the ids from the submission data... + const fileIds = service._findFileIds(formVersion.schema, data); + for (const fileId of fileIds) { + await FileStorage.query(trx).patchAndFetchById(fileId, { formSubmissionId: obj.id, updatedBy: currentUser.usernameIdp }); + } + + await trx.commit(); + const result = await service.readSubmission(obj.id); + + return result; + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, + createMultiSubmission: async (formVersionId, data, currentUser) => { + let trx; + try { + const formVersion = await service.readVersion(formVersionId); + + const { identityProviders, enableSubmitterDraft, allowSubmitterToUploadFile } = await service.readForm(formVersion.formId); + + if (!enableSubmitterDraft) throw new Problem(401, `This form is not allowed to save draft.`); + + if (!allowSubmitterToUploadFile) throw new Problem(401, `This form is not allowed for multi draft upload.`); + // Ensure we only record the user if the form is not public facing + const isPublicForm = identityProviders.some((idp) => idp.code === 'public'); + + if (!isPublicForm && !currentUser.public) { + // Provide the submission creator appropriate CRUD permissions if this is a non-public form + // we decided that subitter cannot delete or update their own submission unless it's a draft + // We know this is the submission creator when we see the SUBMISSION_CREATE permission + // These are adjusted at the update point if going from draft to submitted, or when adding + // team submitters to a draft + trx = await FormSubmission.startTransaction(); + const createdBy = currentUser.usernameIdp; + const submissionDataArray = data.submission.data; + const recordWithoutData = data; + delete recordWithoutData.submission.data; + let recordsToInsert = []; + let submissionId; + // let's create multiple submissions with same metadata + service.popFormLevelInfo(submissionDataArray).map((singleData) => { + submissionId = uuidv4(); + recordsToInsert.push({ + ...recordWithoutData, + id: submissionId, + formVersionId: formVersion.id, + confirmationId: submissionId.substring(0, 8).toUpperCase(), + createdBy: createdBy, + submission: { + ...recordWithoutData.submission, + data: singleData, + }, + }); + }); + const result = await FormSubmission.query(trx).insert(recordsToInsert); + const perms = [Permissions.SUBMISSION_CREATE, Permissions.SUBMISSION_READ]; + if (data.draft) { + perms.push(Permissions.SUBMISSION_DELETE, Permissions.SUBMISSION_UPDATE); + } + let itemsToInsert = []; + result.map((singleSubmission) => { + itemsToInsert.push( + ...perms.map((perm) => ({ + id: uuidv4(), + userId: currentUser.id, + formSubmissionId: singleSubmission.id, + permission: perm, + createdBy: createdBy, + })) + ); + }); + await FormSubmissionUser.query(trx).insert(itemsToInsert); + await trx.commit(); + return result; + } else { + throw new Problem(401, `This operation is not allowed to public.`); + } + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, + listSubmissionFields: (formVersionId, fields) => { + return FormSubmission.query() + .select( + 'id', + fields.map((f) => ref(`submission:data.${f}`).as(f.split('.').slice(-1))) + ) + .where('formVersionId', formVersionId) + .modify('orderDescending'); + }, + + readSubmission: (id) => { + return FormSubmission.query().findById(id).throwIfNotFound(); + }, + + listDrafts: async (formId, params) => { + await service.readForm(formId, queryUtils.defaultActiveOnly(params)); + return FormVersionDraft.query() + .select('id', 'formId', 'formVersionId', 'createdBy', 'createdAt', 'updatedBy', 'updatedAt') + .where('formId', formId) + .modify('filterFormVersionId', params.formVersionId) + .modify('orderDescending'); + }, + createDraft: async (formId, data, currentUser) => { + let trx; + try { + const form = await service.readForm(formId); + trx = await FormVersionDraft.startTransaction(); + + // data.schema, maybe data.formVersionId + const obj = Object.assign({}, data); + obj.id = uuidv4(); + obj.formId = form.id; + obj.createdBy = currentUser.usernameIdp; + + await FormVersionDraft.query(trx).insert(obj); + await trx.commit(); + const result = await service.readDraft(obj.id); + return result; + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, + + updateDraft: async (formVersionDraftId, data, currentUser) => { + let trx; + try { + const obj = await service.readDraft(formVersionDraftId); + trx = await FormVersionDraft.startTransaction(); + await FormVersionDraft.query(trx).patchAndFetchById(formVersionDraftId, { + schema: data.schema, + formVersionId: data.formVersionId, + updatedBy: currentUser.usernameIdp, + }); + await trx.commit(); + return await service.readDraft(obj.id); + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, + readDraft: async (formVersionDraftId) => { + return FormVersionDraft.query().findById(formVersionDraftId).throwIfNotFound(); + }, + deleteDraft: async (formVersionDraftId) => { + return FormVersionDraft.query().deleteById(formVersionDraftId).throwIfNotFound(); + }, + publishDraft: async (formId, formVersionDraftId, currentUser) => { + let trx; + try { + const form = await service.readForm(formId); + const draft = await service.readDraft(formVersionDraftId); + trx = await FormVersionDraft.startTransaction(); + + const version = { + id: uuidv4(), + formId: form.id, + version: form.versions.length ? form.versions[0].version + 1 : 1, + createdBy: currentUser.usernameIdp, + schema: draft.schema, + published: true, + }; + + // this is where we create change the version data. + // mark all published as not published. + await FormVersion.query(trx).patch({ published: false }).where('formId', form.id); + + // add a record using this schema, mark as published and increment the version number + await FormVersion.query(trx).insert(version); + + // delete the draft... + await FormVersionDraft.query().deleteById(formVersionDraftId); + await trx.commit(); + + // return the published version... + return await service.readVersion(version.id); + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, + getStatusCodes: async (formId) => { + return FormStatusCode.query().withGraphFetched('statusCode').where('formId', formId); + }, + + // ----------------------------------------------------------------------------- + // API Key + // ----------------------------------------------------------------------------- + // Modification actions are audited in form_api_key_audit via a trigger + + // Get the current key for a form + readApiKey: (formId) => { + return FormApiKey.query().modify('filterFormId', formId).first(); + }, + + // Add an API key to the form, delete any existing key + createOrReplaceApiKey: async (formId, currentUser) => { + let trx; + try { + const currentKey = await service.readApiKey(formId); + trx = await FormApiKey.startTransaction(); + + if (currentKey) { + // Replace API key for the form + await FormApiKey.query(trx).modify('filterFormId', formId).update({ + formId: formId, + secret: uuidv4(), + updatedBy: currentUser.usernameIdp, + }); + } else { + // Add new API key for the form + await FormApiKey.query(trx).insert({ + formId: formId, + secret: uuidv4(), + createdBy: currentUser.usernameIdp, + }); + } + + await trx.commit(); + return service.readApiKey(formId); + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, + + // Hard delete the current key for a form + deleteApiKey: async (formId) => { + const currentKey = await service.readApiKey(formId); + return FormApiKey.query().deleteById(currentKey.id).throwIfNotFound(); + }, + + /** + * @function getFCProactiveHelpImageUrl + * get form component proactive help image + * @param {Object} param consist of publishStatus and componentId. + * @returns {Promise} An objection query promise + */ + getFCProactiveHelpImageUrl: async (componentId) => { + let result = []; + result = await FormComponentsProactiveHelp.query().modify('findByComponentId', componentId); + let item = result.length > 0 ? result[0] : null; + let imageUrl = item !== null ? 'data:' + item.imageType + ';' + 'base64' + ',' + item.image : ''; + return { url: imageUrl }; + }, + + postSubscriptionEvent: async (subscribe, formVersion, submissionId, subscriptionEvent) => { + try { + // Check if there are endpoints subscribed for form submission event + if (subscribe && subscribe.endpointUrl) { + const axiosOptions = { timeout: 10000 }; + const axiosInstance = axios.create(axiosOptions); + const jsonData = { formId: formVersion.formId, formVersion: formVersion.id, submissionId: submissionId, subscriptionEvent: subscriptionEvent }; + + axiosInstance.interceptors.request.use( + (cfg) => { + cfg.headers = { [subscribe.key]: `${subscribe.endpointToken}` }; + return Promise.resolve(cfg); + }, + (error) => { + return Promise.reject(error); + } + ); + + axiosInstance.post(subscribe.endpointUrl, jsonData); + } + } catch (err) { + log.error(err.message, err, { + function: 'postSubscriptionEvent', + }); + } + }, + + /** + * @function listFormComponentsProactiveHelp + * Search for all form components help information + * @returns {Promise} An objection query promise + */ + listFormComponentsProactiveHelp: async () => { + let result = []; + result = await FormComponentsProactiveHelp.query().modify('selectWithoutImages'); + if (result.length > 0) { + let filterResult = result.map((item) => { + return { + id: item.id, + status: item.publishStatus, + componentName: item.componentName, + externalLink: item.externalLink, + version: item.version, + groupName: item.groupName, + description: item.description, + isLinkEnabled: item.isLinkEnabled, + imageName: item.componentImageName, + }; + }); + return await filterResult.reduce(function (r, a) { + r[a.groupName] = r[a.groupName] || []; + r[a.groupName].push(a); + return r; + }, Object.create(null)); + } + return {}; + }, + // Get the current subscription settings for a form + readFormSubscriptionDetails: (formId) => { + return FormSubscription.query().modify('filterFormId', formId).first(); + }, + // Update subscription settings for a form + createOrUpdateSubscriptionDetails: async (formId, subscriptionData, currentUser) => { + let trx; + try { + const subscriptionDetails = await service.readFormSubscriptionDetails(formId); + trx = await FormSubscription.startTransaction(); + + if (subscriptionDetails) { + // Update new subscription settings for a form + await FormSubscription.query(trx) + .modify('filterFormId', formId) + .update({ + ...subscriptionData, + updatedBy: currentUser.usernameIdp, + }); + } else { + // Add new subscription settings for the form + await FormSubscription.query(trx).insert({ + id: uuidv4(), + ...subscriptionData, + createdBy: currentUser.usernameIdp, + }); + } + + await trx.commit(); + return service.readFormSubscriptionDetails(formId); + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, + + popFormLevelInfo: (jsonPayload = []) => { + /** This function is purely made to remove un-necessery information + * from the json payload of submissions. It will also help to remove crucial data + * to be removed from the payload that should not be going to DB like confirmationId, + * formName,version,createdAt,fullName,username,email,status,assignee,assigneeEmail and + * lateEntry + * Example: Sometime end user use the export json file as a bulk + * upload payload that contains formId, confirmationId and User + * details as well so we need to remove those details from the payload. + * + */ + if (jsonPayload.length) { + jsonPayload.forEach(function (submission) { + delete submission.submit; + delete submission.lateEntry; + if (Object.prototype.hasOwnProperty.call(submission, 'form')) { + const propsToRemove = ['confirmationId', 'formName', 'version', 'createdAt', 'fullName', 'username', 'email', 'status', 'assignee', 'assigneeEmail']; + + propsToRemove.forEach((key) => delete submission.form[key]); + } + }); + } + return jsonPayload; + }, + + // ----------------------------------------------------------------------------- + // Email Templates + // ----------------------------------------------------------------------------- + + _getDefaultEmailTemplate: (formId, type) => { + let template; + + switch (type) { + case EmailTypes.SUBMISSION_CONFIRMATION: + template = { + body: 'Thank you for your {{ form.name }} submission. You can view your submission details by visiting the following links:', + formId: formId, + subject: '{{ form.name }} Accepted', + title: '{{ form.name }} Accepted', + type: type, + }; + break; + } + + return template; + }, + + // Get a specific email template for a form. + readEmailTemplate: async (formId, type) => { + let result = await FormEmailTemplate.query().modify('filterFormId', formId).modify('filterType', type).first(); + + if (result === undefined) { + result = service._getDefaultEmailTemplate(formId, type); + } + + return result; + }, + + // Get all the email templates for a form + readEmailTemplates: async (formId) => { + const hasEmailTemplate = (emailTemplates, type) => { + return emailTemplates.find((t) => t.type === type) !== undefined; + }; + + let result = await FormEmailTemplate.query().modify('filterFormId', formId); + + // In the case that there is no email template in the database, use the + // default values. + if (!hasEmailTemplate(result, EmailTypes.SUBMISSION_CONFIRMATION)) { + result.push(service._getDefaultEmailTemplate(formId, EmailTypes.SUBMISSION_CONFIRMATION)); + } + + return result; + }, + + createOrUpdateEmailTemplate: async (formId, data, currentUser) => { + let transaction; + try { + const emailTemplate = await service.readEmailTemplate(formId, data.type); + transaction = await FormEmailTemplate.startTransaction(); + + if (emailTemplate.id) { + // Update new email template settings for a form + await FormEmailTemplate.query(transaction) + .modify('filterId', emailTemplate.id) + .update({ + ...data, + updatedBy: currentUser.usernameIdp, + }); + } else { + // Add new email template settings for the form + await FormEmailTemplate.query(transaction).insert({ + id: uuidv4(), + ...data, + createdBy: currentUser.usernameIdp, + }); + } + + await transaction.commit(); + + return service.readEmailTemplates(formId); + } catch (error) { + if (transaction) { + await transaction.rollback(); + } + + throw error; + } + }, +}; + +module.exports = service; diff --git a/frontend/app/src/forms/permission/controller.js b/frontend/app/src/forms/permission/controller.js new file mode 100644 index 0000000..d516209 --- /dev/null +++ b/frontend/app/src/forms/permission/controller.js @@ -0,0 +1,36 @@ +const service = require('./service'); + +module.exports = { + list: async (req, res, next) => { + try { + const response = await service.list(); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + create: async (req, res, next) => { + try { + const response = await service.create(req.body, req.currentUser); + res.status(201).json(response); + } catch (error) { + next(error); + } + }, + read: async (req, res, next) => { + try { + const response = await service.read(req.params.code); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + update: async (req, res, next) => { + try { + const response = await service.update(req.params.code, req.body, req.currentUser); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, +}; diff --git a/frontend/app/src/forms/permission/index.js b/frontend/app/src/forms/permission/index.js new file mode 100644 index 0000000..f2f1511 --- /dev/null +++ b/frontend/app/src/forms/permission/index.js @@ -0,0 +1,7 @@ +const dataErrors = require('../common/middleware').dataErrors; +const routes = require('./routes'); +const setupMount = require('../common/utils').setupMount; + +module.exports.mount = (app) => { + return setupMount('permissions', app, routes, dataErrors); +}; diff --git a/frontend/app/src/forms/permission/routes.js b/frontend/app/src/forms/permission/routes.js new file mode 100644 index 0000000..bd9ad9b --- /dev/null +++ b/frontend/app/src/forms/permission/routes.js @@ -0,0 +1,28 @@ +const config = require('config'); +const routes = require('express').Router(); + +const currentUser = require('../auth/middleware/userAccess').currentUser; + +const controller = require('./controller'); +const keycloak = require('../../components/keycloak'); + +routes.use(keycloak.protect(`${config.get('server.keycloak.clientId')}:admin`)); +routes.use(currentUser); + +routes.get('/', async (req, res, next) => { + await controller.list(req, res, next); +}); + +routes.post('/', async (req, res, next) => { + await controller.create(req, res, next); +}); + +routes.get('/:code', async (req, res, next) => { + await controller.read(req, res, next); +}); + +routes.put('/:code', async (req, res, next) => { + await controller.update(req, res, next); +}); + +module.exports = routes; diff --git a/frontend/app/src/forms/permission/service.js b/frontend/app/src/forms/permission/service.js new file mode 100644 index 0000000..153408c --- /dev/null +++ b/frontend/app/src/forms/permission/service.js @@ -0,0 +1,128 @@ +const { v4: uuidv4 } = require('uuid'); + +const { Permissions } = require('../common/constants'); +const { FormSubmissionUser, Permission } = require('../common/models'); + +const service = { + list: async () => { + return Permission.query().allowGraph('[roles]').withGraphFetched('roles(orderDefault)').modify('orderDefault'); + }, + + create: async (data, currentUser) => { + let trx; + try { + trx = await Permission.startTransaction(); + + // TODO: validate permission code is unique + data.createdBy = currentUser.usernameIdp; + + await Permission.query(trx).insert(data); + await trx.commit(); + const result = await service.read(data.code); + return result; + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, + + read: async (code) => { + return Permission.query().findOne('code', code).allowGraph('[roles]').withGraphFetched('roles(orderDefault)').throwIfNotFound(); + }, + + update: async (code, data, currentUser) => { + let trx; + try { + const obj = await service.read(code); + trx = await Permission.startTransaction(); + if (obj.display !== data.display || obj.description != data.description || obj.active != obj.active) { + // update name/description... + await Permission.query(trx).patchAndFetchById(obj.code, { + display: data.display, + description: data.description, + active: data.active, + updatedBy: currentUser.usernameIdp, + }); + } + // clean out existing roles... + await trx.raw(`delete from role_permission where "permission" = '${obj.code}'`); + // set to specified roles... + for (const r of data.roles) { + await trx.raw(`insert into role_permission (id, "role", "permission", "createdBy") values ('${uuidv4()}', '${r.code}', '${obj.code}', '${currentUser.usernameIdp}');`); + } + await trx.commit(); + + return await service.read(obj.code); + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, + + /** + * @function setUserEditable + * Adds editing permissions for all existing submitter users + * @param {string} submissionId The submission uuid + * @param {object} currentUser The currently logged in user metadata + * @param {object} [etrx=undefined] An optional Objection Transaction object + * @returns {object} The result of running the insert operation + * @throws The error encountered upon db transaction failure + */ + setUserEditable: async (submissionId, currentUser, etrx = undefined) => { + let trx; + try { + trx = etrx ? etrx : await FormSubmissionUser.startTransaction(); + + // DANGER - do not mess up the where clauses! + // ALWAYS ensure submissionid is enforced and you know what KNEX is doing about chaining the where clauses as to if it's making an AND or an OR + const users = await FormSubmissionUser.query().select('userId').where('formSubmissionId', submissionId).whereIn('permission', [Permissions.SUBMISSION_READ]); + + const itemsToInsert = users.map((user) => ({ + id: uuidv4(), + userId: user.userId, + formSubmissionId: submissionId, + permission: Permissions.SUBMISSION_UPDATE, + createdBy: currentUser.usernameIdp, + })); + + let result = undefined; + if (itemsToInsert && itemsToInsert.length) result = await FormSubmissionUser.query(trx).insert(itemsToInsert); + + if (!etrx) await trx.commit(); + return result; + } catch (err) { + if (!etrx && trx) await trx.rollback(); + throw err; + } + }, + + /** + * @function setUserReadOnly + * Drops editing and deletion permissions for all submitter users + * @param {string} submissionId The submission id + * @param {object} [etrx=undefined] An optional Objection Transaction object + * @returns {object} The result of running the delete operation + * @throws The error encountered upon db transaction failure + */ + setUserReadOnly: async (submissionId, etrx = undefined) => { + let trx; + try { + trx = etrx ? etrx : await FormSubmissionUser.startTransaction(); + + // DANGER - do not mess up the where clauses! + // ALWAYS ensure submissionid is enforced and you know what KNEX is doing about chaining the where clauses as to if it's making an AND or an OR + const result = await FormSubmissionUser.query(trx) + .delete() + .where('formSubmissionId', submissionId) + .whereIn('permission', [Permissions.SUBMISSION_DELETE, Permissions.SUBMISSION_UPDATE]); + + if (!etrx) await trx.commit(); + return result; + } catch (err) { + if (!etrx && trx) await trx.rollback(); + throw err; + } + }, +}; + +module.exports = service; diff --git a/frontend/app/src/forms/public/controller.js b/frontend/app/src/forms/public/controller.js new file mode 100644 index 0000000..056241a --- /dev/null +++ b/frontend/app/src/forms/public/controller.js @@ -0,0 +1,11 @@ +const service = require('./service'); +module.exports = { + sendReminderToSubmitter: async (req, res, next) => { + try { + const response = await service.sendReminderToSubmitter(); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, +}; diff --git a/frontend/app/src/forms/public/index.js b/frontend/app/src/forms/public/index.js new file mode 100644 index 0000000..f63cbef --- /dev/null +++ b/frontend/app/src/forms/public/index.js @@ -0,0 +1,7 @@ +const dataErrors = require('../common/middleware').dataErrors; +const routes = require('./routes'); +const setupMount = require('../common/utils').setupMount; + +module.exports.mount = (app) => { + return setupMount('public', app, routes, dataErrors); +}; diff --git a/frontend/app/src/forms/public/routes.js b/frontend/app/src/forms/public/routes.js new file mode 100644 index 0000000..c72618a --- /dev/null +++ b/frontend/app/src/forms/public/routes.js @@ -0,0 +1,28 @@ +const routes = require('express').Router(); +const controller = require('./controller'); + +routes.use('/reminder', (req, res, next) => { + // eslint-disable-next-line no-empty + try { + if (req.method == 'GET') { + const apikeyEnv = process.env.APITOKEN; + const apikeyIncome = req.headers.apikey; + if (apikeyEnv == apikeyIncome && (apikeyIncome == undefined || apikeyIncome == '')) return res.status(401).json({ message: 'No API key provided' }); + if (apikeyIncome === apikeyEnv) { + next(); + } else { + return res.status(401).json({ message: 'Invalid API key' }); + } + } else { + return res.status(404).json({ message: 'Only GET request is accepted' }); + } + } catch (err) { + return res.status(500).json({ message: err.message }); + } +}); + +routes.get('/reminder', async (req, res, next) => { + await controller.sendReminderToSubmitter(req, res, next); +}); + +module.exports = routes; diff --git a/frontend/app/src/forms/public/service.js b/frontend/app/src/forms/public/service.js new file mode 100644 index 0000000..dbe0f41 --- /dev/null +++ b/frontend/app/src/forms/public/service.js @@ -0,0 +1,8 @@ +const reminderService = require('../email/reminderService'); +const service = { + sendReminderToSubmitter: async () => { + return await reminderService._init(); + }, +}; + +module.exports = service; diff --git a/frontend/app/src/forms/rbac/controller.js b/frontend/app/src/forms/rbac/controller.js new file mode 100644 index 0000000..b8e6506 --- /dev/null +++ b/frontend/app/src/forms/rbac/controller.js @@ -0,0 +1,137 @@ +const emailService = require('../email/emailService'); +const formService = require('../submission/service'); +const service = require('./service'); +module.exports = { + list: async (req, res, next) => { + try { + const response = await service.list(); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + create: async (req, res, next) => { + try { + const response = await service.create(req.body); + res.status(201).json(response); + } catch (error) { + next(error); + } + }, + read: async (req, res, next) => { + try { + const response = await service.read(req.params.id); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + update: async (req, res, next) => { + try { + const response = await service.update(req.params.id, req.body); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + delete: async (req, res, next) => { + try { + const response = await service.delete(req.params.id); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + getCurrentUser: async (req, res, next) => { + try { + const response = await service.getCurrentUser(req.currentUser, req.query); + // don't want this going out, only need deleted forms on current user in middleware. + delete response.deletedForms; + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + getCurrentUserSubmissions: async (req, res, next) => { + try { + const response = await service.getCurrentUserSubmissions(req.currentUser, req.query); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + getFormUsers: async (req, res, next) => { + try { + const response = await service.getFormUsers(req.query); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + setFormUsers: async (req, res, next) => { + try { + const response = await service.setFormUsers(req.query.formId, req.query.userId, req.body, req.currentUser); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + removeMultiUsers: async (req, res, next) => { + try { + const response = await service.removeMultiUsers(req.query.formId, req.body); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + getSubmissionUsers: async (req, res, next) => { + try { + const response = await service.getSubmissionUsers(req.query); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + setSubmissionUserPermissions: async (req, res, next) => { + try { + const submission = await formService.read(req.query.formSubmissionId, req.currentUser); + const response = await service.modifySubmissionUser(req.query.formSubmissionId, req.query.userId, req.body, req.currentUser); + if (req.body && Array.isArray(req.body.permissions) && req.query.selectedUserEmail) { + // Check if we are adding or removing a user from the draft invite list. empty permissions signifies that we are removing permissions from a user. + if (req.body.permissions.length) { + emailService.submissionAssigned(submission.form.id, response[0], req.query.selectedUserEmail, req.headers.referer); + } else { + emailService.submissionUnassigned(submission.form.id, response[0], req.query.selectedUserEmail, req.headers.referer); + } + } + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + getUserForms: async (req, res, next) => { + try { + const response = await service.getUserForms(req.query); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + setUserForms: async (req, res, next) => { + try { + const response = await service.setUserForms(req.query.userId, req.query.formId, req.body, req.currentUser); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + + getIdentityProviders: async (req, res, next) => { + try { + const response = await service.getIdentityProviders(req.query); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, +}; diff --git a/frontend/app/src/forms/rbac/index.js b/frontend/app/src/forms/rbac/index.js new file mode 100644 index 0000000..111514e --- /dev/null +++ b/frontend/app/src/forms/rbac/index.js @@ -0,0 +1,7 @@ +const dataErrors = require('../common/middleware').dataErrors; +const routes = require('./routes'); +const setupMount = require('../common/utils').setupMount; + +module.exports.mount = (app) => { + return setupMount('rbac', app, routes, dataErrors); +}; diff --git a/frontend/app/src/forms/rbac/routes.js b/frontend/app/src/forms/rbac/routes.js new file mode 100644 index 0000000..35c463f --- /dev/null +++ b/frontend/app/src/forms/rbac/routes.js @@ -0,0 +1,52 @@ +const config = require('config'); +const routes = require('express').Router(); + +const controller = require('./controller'); +const keycloak = require('../../components/keycloak'); +const P = require('../common/constants').Permissions; +const R = require('../common/constants').Roles; +const { currentUser, hasFormPermissions, hasSubmissionPermissions, hasFormRoles, hasRolePermissions } = require('../auth/middleware/userAccess'); + +routes.use(currentUser); + +routes.get('/current', keycloak.protect(), async (req, res, next) => { + await controller.getCurrentUser(req, res, next); +}); + +routes.get('/current/submissions', keycloak.protect(), async (req, res, next) => { + await controller.getCurrentUserSubmissions(req, res, next); +}); + +routes.get('/idps', async (req, res, next) => { + await controller.getIdentityProviders(req, res, next); +}); + +routes.get('/forms', hasFormPermissions(P.TEAM_READ), async (req, res, next) => { + await controller.getFormUsers(req, res, next); +}); + +routes.put('/forms', hasFormPermissions(P.TEAM_UPDATE), async (req, res, next) => { + await controller.setFormUsers(req, res, next); +}); + +routes.get('/submissions', hasSubmissionPermissions(P.SUBMISSION_READ), async (req, res, next) => { + await controller.getSubmissionUsers(req, res, next); +}); + +routes.put('/submissions', hasSubmissionPermissions(P.SUBMISSION_UPDATE), async (req, res, next) => { + await controller.setSubmissionUserPermissions(req, res, next); +}); + +routes.get('/users', keycloak.protect(`${config.get('server.keycloak.clientId')}:admin`), async (req, res, next) => { + await controller.getUserForms(req, res, next); +}); + +routes.put('/users', hasFormPermissions(P.TEAM_UPDATE), hasFormRoles([R.OWNER, R.TEAM_MANAGER]), hasRolePermissions(false), async (req, res, next) => { + await controller.setUserForms(req, res, next); +}); + +routes.delete('/users', hasFormPermissions(P.TEAM_UPDATE), hasFormRoles([R.OWNER, R.TEAM_MANAGER]), hasRolePermissions(true), async (req, res, next) => { + await controller.removeMultiUsers(req, res, next); +}); + +module.exports = routes; diff --git a/frontend/app/src/forms/rbac/service.js b/frontend/app/src/forms/rbac/service.js new file mode 100644 index 0000000..11fb0fc --- /dev/null +++ b/frontend/app/src/forms/rbac/service.js @@ -0,0 +1,284 @@ +const Problem = require('api-problem'); +const { v4: uuidv4 } = require('uuid'); +const { FormRoleUser, FormSubmissionUser, IdentityProvider, User, UserFormAccess, UserSubmissions } = require('../common/models'); +const { Roles } = require('../common/constants'); +const { queryUtils } = require('../common/utils'); +const authService = require('../auth/service'); +const service = { + list: async () => { + return FormRoleUser.query().allowGraph('[form, userRole, user]').withGraphFetched('[form, userRole, user]').modify('orderCreatedAtDescending'); + }, + create: async (data) => { + let trx; + try { + trx = await FormRoleUser.startTransaction(); + + const obj = Object.assign({}, data); + obj.id = uuidv4(); + + await FormRoleUser.query(trx).insert(obj); + await trx.commit(); + const result = await service.read(obj.id); + return result; + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, + + update: async (id, data) => { + let trx; + try { + const obj = await service.read(id); + trx = await FormRoleUser.startTransaction(); + + const update = { + formId: data.formId, + role: data.role, + userId: data.userId, + }; + + await FormRoleUser.query(trx).patchAndFetchById(obj.id, update); + await trx.commit(); + const result = await service.read(obj.id); + return result; + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, + + read: async (id) => { + return FormRoleUser.query().findById(id).allowGraph('[form, userRole, user]').withGraphFetched('[form, userRole, user]').throwIfNotFound(); + }, + + readUserRole: async (userId, formId) => { + return FormRoleUser.query().modify('filterUserId', userId).modify('filterFormId', formId); + }, + + delete: async (id) => { + return FormRoleUser.query().deleteById(id).throwIfNotFound(); + }, + + readUser: async (id) => { + return User.query().findById(id).throwIfNotFound(); + }, + + getCurrentUser: async (currentUser, params) => { + const user = Object.assign({}, currentUser); + const accessLevels = []; + if (user.public) { + accessLevels.push('public'); + } else { + if (params.public) accessLevels.push('public'); + if (params.idp) accessLevels.push('idp'); + if (params.team) accessLevels.push('team'); + } + const filteredForms = authService.filterForms(user, user.forms, accessLevels); + user.forms = filteredForms; + return user; + }, + + getCurrentUserSubmissions: async (currentUser, params) => { + params = queryUtils.defaultActiveOnly(params); + return UserSubmissions.query() + .withGraphFetched('submissionStatus(orderDescending)') + .withGraphFetched('submission') + .modify('filterFormId', params.formId) + .modify('filterFormSubmissionId', params.formSubmissionId) + .modify('filterUserId', currentUser.id) + .modify('filterActive', params.active) + .modify('orderDefault'); + }, + + getFormUsers: async (params) => { + params = queryUtils.defaultActiveOnly(params); + const items = await UserFormAccess.query() + .modify('filterUserId', params.userId) + .modify('filterIdpUserId', params.idpUserId) + .modify('filterUsername', params.username) + .modify('filterFullName', params.fullName) + .modify('filterFirstName', params.firstName) + .modify('filterLastName', params.lastName) + .modify('filterEmail', params.email) + .modify('filterFormId', params.formId) + .modify('filterFormName', params.formName) + .modify('filterActive', params.active) + .modify('filterByAccess', params.idps, params.roles, params.permissions) + .modify('orderDefault'); + return items; + }, + + getSubmissionUsers: async (params) => { + params = queryUtils.defaultActiveOnly(params); + const items = await UserSubmissions.query() + .withGraphFetched('user') + .modify('filterFormSubmissionId', params.formSubmissionId) + .modify('filterUserId', params.userId) + .modify('filterActive', params.active) + .modify('orderDefault'); + return items; + }, + + getUserForms: async (params) => { + params = queryUtils.defaultActiveOnly(params); + const items = await UserFormAccess.query() + .modify('filterUserId', params.userId) + .modify('filterIdpUserId', params.idpUserId) + .modify('filterUsername', params.username) + .modify('filterFullName', params.fullName) + .modify('filterFirstName', params.firstName) + .modify('filterLastName', params.lastName) + .modify('filterEmail', params.email) + .modify('filterFormId', params.formId) + .modify('filterFormName', params.formName) + .modify('filterActive', params.active) + .modify('filterByAccess', params.idps, params.roles, params.permissions) + .modify('orderDefault'); + + return items; + }, + + setFormUsers: async (formId, userId, data, currentUser) => { + // check this in middleware? 422 in valid params + if (!formId || 0 === formId.length) { + throw new Error(); + } + + let trx; + try { + trx = await FormRoleUser.startTransaction(); + // remove existing mappings... + await FormRoleUser.query(trx).delete().where('formId', formId).where('userId', userId); + + // create the batch and insert... + if (!Array.isArray(data)) { + data = [data]; + } + // remove any data that isn't for this form... + data = data.filter((d) => d.formId === formId); + if (userId && userId.length) { + data = data.filter((d) => d.userId === userId); + } + // add an id and save them + const items = data.map((d) => { + return { id: uuidv4(), createdBy: currentUser.usernameIdp, ...d }; + }); + if (items && items.length) await FormRoleUser.query(trx).insert(items); + await trx.commit(); + return service.getFormUsers({ userId: userId, formId: formId }); + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, + + modifySubmissionUser: async (formSubmissionId, userId, body, currentUser) => { + if (!userId || !body.permissions) { + throw new Problem(422, 'User ID or permissions missing from request'); + } + + let trx; + try { + trx = await FormSubmissionUser.startTransaction(); + // remove existing mappings for the user... + await FormSubmissionUser.query(trx).delete().where('formSubmissionId', formSubmissionId).where('userId', userId); + + // create the batch and insert. So if permissions is empty it removes the user from the submission + if (Array.isArray(body.permissions) && body.permissions.length !== 0) { + // add ids and save them + const items = body.permissions.map((perm) => ({ + id: uuidv4(), + formSubmissionId: formSubmissionId, + userId: userId, + createdBy: currentUser.usernameIdp, + permission: perm, + })); + if (items && items.length) await FormSubmissionUser.query(trx).insert(items); + } + await trx.commit(); + return service.getSubmissionUsers({ formSubmissionId: formSubmissionId }); + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, + removeMultiUsers: async (formId, data) => { + // create the batch and insert... + if (Array.isArray(data) && data.length !== 0 && formId) { + // check if they're deleting the only owner + const userRoles = await FormRoleUser.query().where('formId', formId).where('role', Roles.OWNER); + if (userRoles.every((ur) => data.includes(ur.userId))) { + throw new Problem(400, { detail: "Can't remove all the owners." }); + } + let trx; + try { + trx = await FormRoleUser.startTransaction(); + // remove existing mappings... + await FormRoleUser.query(trx).delete().where('formId', formId).whereIn('userId', data); + + await trx.commit(); + return; + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + } + }, + /* + * + * @param data An array of roles being applied to a user id for a form id + * @param currentUser A user that contains an array of form objects and the roles + * that user has for that form. + */ + setUserForms: async (userId, formId, data, currentUser) => { + // check this in middleware? 422 in valid params + if (!userId || 0 === userId.length) { + throw new Error(); + } + + // check if they're deleting the only owner + const userRoles = await FormRoleUser.query().where('formId', formId).where('role', Roles.OWNER); + + // create the batch... + if (!Array.isArray(data)) { + data = [data]; + } + // remove any data that isn't for this userId... + data = data.filter((d) => d.userId === userId); + if (formId && formId.length) { + data = data.filter((d) => d.formId === formId); + } + + // If trying to remove the only owner + if (userRoles.length === 1 && userRoles.some((ur) => ur.role === Roles.OWNER) && userRoles.some((ur) => ur.userId === userId) && !data.some((d) => d.role === Roles.OWNER)) { + throw new Problem(400, { detail: "Can't remove the only owner." }); + } + + let trx; + try { + trx = await FormRoleUser.startTransaction(); + // remove existing mappings... + await FormRoleUser.query(trx).delete().where('userId', userId).where('formId', formId); + + // add an id and save them + const items = data.map((d) => { + return { id: uuidv4(), createdBy: currentUser.usernameIdp, ...d }; + }); + if (items && items.length) await FormRoleUser.query(trx).insert(items); + await trx.commit(); + // return the new mappings + const result = await service.getUserForms({ userId: userId, formId: formId }); + return result; + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, + + getIdentityProviders: (params) => { + return IdentityProvider.query().modify('filterActive', params.active).modify('orderDefault'); + }, +}; + +module.exports = service; diff --git a/frontend/app/src/forms/role/controller.js b/frontend/app/src/forms/role/controller.js new file mode 100644 index 0000000..d516209 --- /dev/null +++ b/frontend/app/src/forms/role/controller.js @@ -0,0 +1,36 @@ +const service = require('./service'); + +module.exports = { + list: async (req, res, next) => { + try { + const response = await service.list(); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + create: async (req, res, next) => { + try { + const response = await service.create(req.body, req.currentUser); + res.status(201).json(response); + } catch (error) { + next(error); + } + }, + read: async (req, res, next) => { + try { + const response = await service.read(req.params.code); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + update: async (req, res, next) => { + try { + const response = await service.update(req.params.code, req.body, req.currentUser); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, +}; diff --git a/frontend/app/src/forms/role/index.js b/frontend/app/src/forms/role/index.js new file mode 100644 index 0000000..3057103 --- /dev/null +++ b/frontend/app/src/forms/role/index.js @@ -0,0 +1,7 @@ +const dataErrors = require('../common/middleware').dataErrors; +const routes = require('./routes'); +const setupMount = require('../common/utils').setupMount; + +module.exports.mount = (app) => { + return setupMount('roles', app, routes, dataErrors); +}; diff --git a/frontend/app/src/forms/role/routes.js b/frontend/app/src/forms/role/routes.js new file mode 100644 index 0000000..4042f89 --- /dev/null +++ b/frontend/app/src/forms/role/routes.js @@ -0,0 +1,27 @@ +const config = require('config'); +const routes = require('express').Router(); + +const currentUser = require('../auth/middleware/userAccess').currentUser; + +const controller = require('./controller'); +const keycloak = require('../../components/keycloak'); + +routes.use(currentUser); + +routes.get('/', keycloak.protect(), async (req, res, next) => { + await controller.list(req, res, next); +}); + +routes.post('/', keycloak.protect(`${config.get('server.keycloak.clientId')}:admin`), async (req, res, next) => { + await controller.create(req, res, next); +}); + +routes.get('/:code', keycloak.protect(), async (req, res, next) => { + await controller.read(req, res, next); +}); + +routes.put('/:code', keycloak.protect(`${config.get('server.keycloak.clientId')}:admin`), async (req, res, next) => { + await controller.update(req, res, next); +}); + +module.exports = routes; diff --git a/frontend/app/src/forms/role/service.js b/frontend/app/src/forms/role/service.js new file mode 100644 index 0000000..2e55606 --- /dev/null +++ b/frontend/app/src/forms/role/service.js @@ -0,0 +1,63 @@ +const { v4: uuidv4 } = require('uuid'); + +const { Role } = require('../common/models'); + +const service = { + list: async () => { + return Role.query().allowGraph('[permissions]').withGraphFetched('permissions(orderDefault)').modify('orderDefault'); + }, + + create: async (data, currentUser) => { + let trx; + try { + trx = await Role.startTransaction(); + + // TODO: validate role code is unique + data.createdBy = currentUser.usernameIdp; + + await Role.query(trx).insert(data); + await trx.commit(); + const result = await service.read(data.code); + return result; + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, + + read: async (code) => { + return Role.query().findOne('code', code).allowGraph('[permissions]').withGraphFetched('permissions(orderDefault)').throwIfNotFound(); + }, + + update: async (code, data, currentUser) => { + let trx; + try { + const obj = await service.read(code); + trx = await Role.startTransaction(); + + if (obj.display !== data.display || obj.description != data.description || obj.active != data.active) { + // update name/description... + await Role.query(trx).patchAndFetchById(obj.code, { + display: data.display, + description: data.description, + active: data.active, + updatedBy: currentUser.usernameIdp, + }); + } + // clean out existing permissions... + await trx.raw(`delete from role_permission where "role" = '${obj.code}'`); + // set to specified permissions... + for (const p of data.permissions) { + await trx.raw(`insert into role_permission (id, "role", "permission", "createdBy") values ('${uuidv4()}', '${obj.code}', '${p.code}', '${currentUser.usernameIdp}');`); + } + + await trx.commit(); + return await service.read(obj.code); + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, +}; + +module.exports = service; diff --git a/frontend/app/src/forms/submission/controller.js b/frontend/app/src/forms/submission/controller.js new file mode 100644 index 0000000..d91fb0b --- /dev/null +++ b/frontend/app/src/forms/submission/controller.js @@ -0,0 +1,165 @@ +const { Statuses } = require('../common/constants'); +const cdogsService = require('../../components/cdogsService'); +const emailService = require('../email/emailService'); +const service = require('./service'); + +module.exports = { + read: async (req, res, next) => { + try { + const response = await service.read(req.params.formSubmissionId); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + update: async (req, res, next) => { + try { + const response = await service.update(req.params.formSubmissionId, req.body, req.currentUser, req.headers.referer); + if (!response) { + // Return Bad request if we're trying to save draft on already submitted record + res.status(400).json({ detail: 'Incorrect Submission status.' }); + } else { + res.status(200).json(response); + } + } catch (error) { + next(error); + } + }, + delete: async (req, res, next) => { + try { + const response = await service.delete(req.params.formSubmissionId, req.currentUser); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + deleteMutipleSubmissions: async (req, res, next) => { + try { + let submissionIds = req.body && req.body.submissionIds ? req.body.submissionIds : []; + const response = await service.deleteMutipleSubmissions(submissionIds, req.currentUser); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + restoreMutipleSubmissions: async (req, res, next) => { + try { + let submissionIds = req.body && req.body.submissionIds ? req.body.submissionIds : []; + const response = await service.restoreMutipleSubmissions(submissionIds, req.currentUser); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + restore: async (req, res, next) => { + try { + const response = await service.restore(req.params.formSubmissionId, req.body, req.currentUser); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + readOptions: async (req, res, next) => { + try { + const response = await service.readOptions(req.params.formSubmissionId); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + getNotes: async (req, res, next) => { + try { + const response = await service.getNotes(req.params.formSubmissionId); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + addNote: async (req, res, next) => { + try { + const response = await service.addNote(req.params.formSubmissionId, req.body, req.currentUser); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + getStatus: async (req, res, next) => { + try { + const response = await service.getStatus(req.params.formSubmissionId); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + addStatus: async (req, res, next) => { + try { + const tasks = [service.changeStatusState(req.params.formSubmissionId, req.body, req.currentUser), service.read(req.params.formSubmissionId)]; + const [response, submission] = await Promise.all(tasks); + // send an email (async in the background) + if (req.body.code === Statuses.ASSIGNED && req.body.assignmentNotificationEmail) { + emailService + .statusAssigned(submission.form.id, response[0], req.body.assignmentNotificationEmail, req.body.revisionNotificationEmailContent, req.headers.referer) + .catch(() => {}); + } else if (req.body.code === Statuses.COMPLETED && req.body.submissionUserEmail) { + emailService.statusCompleted(submission.form.id, response[0], req.body.submissionUserEmail, req.body.revisionNotificationEmailContent, req.headers.referer).catch(() => {}); + } else if (req.body.code === Statuses.REVISING && req.body.submissionUserEmail) { + emailService.statusRevising(submission.form.id, response[0], req.body.submissionUserEmail, req.body.revisionNotificationEmailContent, req.headers.referer).catch(() => {}); + } + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + email: async (req, res, next) => { + try { + const submission = await service.read(req.params.formSubmissionId); + const response = await emailService.submissionConfirmation(submission.form.id, req.params.formSubmissionId, req.body, req.headers.referer); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + templateUploadAndRender: async (req, res, next) => { + try { + const submission = await service.read(req.params.formSubmissionId); + const templateBody = { ...req.body, data: submission.submission.submission.data }; + const { data, headers, status } = await cdogsService.templateUploadAndRender(templateBody); + const contentDisposition = headers['content-disposition']; + + res + .status(status) + .set({ + 'Content-Disposition': contentDisposition ? contentDisposition : 'attachment', + 'Content-Type': headers['content-type'], + }) + .send(data); + } catch (error) { + next(error); + } + }, + draftTemplateUploadAndRender: async (req, res, next) => { + try { + const templateBody = { ...req.body.template, data: req.body.submission.data }; + const { data, headers, status } = await cdogsService.templateUploadAndRender(templateBody); + const contentDisposition = headers['content-disposition']; + + res + .status(status) + .set({ + 'Content-Disposition': contentDisposition ? contentDisposition : 'attachment', + 'Content-Type': headers['content-type'], + }) + .send(data); + } catch (error) { + next(error); + } + }, + listEdits: async (req, res, next) => { + try { + const response = await service.listEdits(req.params.formSubmissionId); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, +}; diff --git a/frontend/app/src/forms/submission/index.js b/frontend/app/src/forms/submission/index.js new file mode 100644 index 0000000..c1b586e --- /dev/null +++ b/frontend/app/src/forms/submission/index.js @@ -0,0 +1,7 @@ +const dataErrors = require('../common/middleware').dataErrors; +const routes = require('./routes'); +const setupMount = require('../common/utils').setupMount; + +module.exports.mount = (app) => { + return setupMount('submissions', app, routes, dataErrors); +}; diff --git a/frontend/app/src/forms/submission/routes.js b/frontend/app/src/forms/submission/routes.js new file mode 100644 index 0000000..63d4aa1 --- /dev/null +++ b/frontend/app/src/forms/submission/routes.js @@ -0,0 +1,72 @@ +const apiAccess = require('../auth/middleware/apiAccess'); +const routes = require('express').Router(); + +const controller = require('./controller'); +const P = require('../common/constants').Permissions; +const { currentUser, hasSubmissionPermissions, filterMultipleSubmissions } = require('../auth/middleware/userAccess'); +const rateLimiter = require('../common/middleware').apiKeyRateLimiter; + +routes.use(currentUser); + +routes.get('/:formSubmissionId', rateLimiter, apiAccess, hasSubmissionPermissions(P.SUBMISSION_READ), async (req, res, next) => { + await controller.read(req, res, next); +}); + +routes.put('/:formSubmissionId', hasSubmissionPermissions(P.SUBMISSION_UPDATE), async (req, res, next) => { + await controller.update(req, res, next); +}); + +routes.delete('/:formSubmissionId', rateLimiter, apiAccess, hasSubmissionPermissions(P.SUBMISSION_DELETE), async (req, res, next) => { + await controller.delete(req, res, next); +}); + +routes.put('/:formSubmissionId/:formId/submissions/restore', hasSubmissionPermissions(P.SUBMISSION_DELETE), filterMultipleSubmissions(), async (req, res, next) => { + await controller.restoreMutipleSubmissions(req, res, next); +}); + +routes.put('/:formSubmissionId/restore', hasSubmissionPermissions(P.SUBMISSION_DELETE), async (req, res, next) => { + await controller.restore(req, res, next); +}); + +routes.get('/:formSubmissionId/options', async (req, res, next) => { + await controller.readOptions(req, res, next); +}); + +routes.get('/:formSubmissionId/notes', hasSubmissionPermissions(P.SUBMISSION_READ), async (req, res, next) => { + await controller.getNotes(req, res, next); +}); + +routes.post('/:formSubmissionId/notes', hasSubmissionPermissions(P.SUBMISSION_UPDATE), async (req, res, next) => { + await controller.addNote(req, res, next); +}); + +routes.get('/:formSubmissionId/status', rateLimiter, apiAccess, hasSubmissionPermissions(P.SUBMISSION_READ), async (req, res, next) => { + await controller.getStatus(req, res, next); +}); + +routes.post('/:formSubmissionId/status', hasSubmissionPermissions(P.SUBMISSION_UPDATE), async (req, res, next) => { + await controller.addStatus(req, res, next); +}); + +routes.post('/:formSubmissionId/email', hasSubmissionPermissions(P.SUBMISSION_READ), async (req, res, next) => { + await controller.email(req, res, next); +}); + +routes.get('/:formSubmissionId/edits', hasSubmissionPermissions(P.SUBMISSION_READ), async (req, res, next) => { + await controller.listEdits(req, res, next); +}); + +routes.post('/:formSubmissionId/template/render', hasSubmissionPermissions(P.SUBMISSION_READ), async (req, res, next) => { + await controller.templateUploadAndRender(req, res, next); +}); + +routes.delete('/:formSubmissionId/:formId/submissions', hasSubmissionPermissions(P.SUBMISSION_DELETE), filterMultipleSubmissions(), async (req, res, next) => { + await controller.deleteMutipleSubmissions(req, res, next); +}); + +// Implement this when we want to fetch a specific audit row including the whole old submission record +// routes.get('/:formSubmissionId/edits/:auditId', hasSubmissionPermissions(P.SUBMISSION_READ), async (req, res, next) => { +// await controller.listEdits(req, res, next); +// }); + +module.exports = routes; diff --git a/frontend/app/src/forms/submission/service.js b/frontend/app/src/forms/submission/service.js new file mode 100644 index 0000000..8c89239 --- /dev/null +++ b/frontend/app/src/forms/submission/service.js @@ -0,0 +1,348 @@ +const { v4: uuidv4 } = require('uuid'); + +const { Statuses } = require('../common/constants'); +const { Form, FormVersion, FormSubmission, FormSubmissionStatus, Note, SubmissionAudit, SubmissionMetadata } = require('../common/models'); +const emailService = require('../email/emailService'); +const formService = require('../form/service'); +const permissionService = require('../permission/service'); + +const service = { + // ------------------------------------------------------------------------------------------------------- + // Submissions + // ------------------------------------------------------------------------------------------------------- + _fetchSubmissionData: async (formSubmissionId) => { + const meta = await SubmissionMetadata.query().where('submissionId', formSubmissionId).first().throwIfNotFound(); + + return await Promise.all([ + FormSubmission.query().findById(meta.submissionId).throwIfNotFound(), + FormVersion.query().findById(meta.formVersionId).throwIfNotFound(), + Form.query().findById(meta.formId).allowGraph('identityProviders').withGraphFetched('identityProviders(orderDefault)').throwIfNotFound(), + ]).then((data) => { + return { + submission: data[0], + version: data[1], + form: data[2], + }; + }); + }, + + // ------------------------------------------------------------------------------------------------------- + // Submissions + // ------------------------------------------------------------------------------------------------------- + _fetchSpecificSubmissionData: async (formSubmissionIds) => { + const meta = await SubmissionMetadata.query().whereIn('submissionId', formSubmissionIds); + + if (meta.length > 0) { + let submissionIds = meta.map((SubmissionMetadata) => SubmissionMetadata.submissionId); + let formVersionId = [...new Set(meta.map((SubmissionMetadata) => SubmissionMetadata.formVersionId))].at(0); + let formId = [...new Set(meta.map((SubmissionMetadata) => SubmissionMetadata.formId))].at(0); + return await Promise.all([ + FormSubmission.query().findByIds(submissionIds).throwIfNotFound(), + FormVersion.query().findByIds(formVersionId).throwIfNotFound(), + Form.query().findByIds(formId).allowGraph('identityProviders').withGraphFetched('identityProviders(orderDefault)').throwIfNotFound(), + ]).then((data) => { + return { + submission: data[0], + version: data[1], + form: data[2], + }; + }); + } + return []; + }, + + read: (formSubmissionId) => service._fetchSubmissionData(formSubmissionId), + + readSubmissionData: (formSubmissionIds) => service._fetchSpecificSubmissionData(formSubmissionIds), + + update: async (formSubmissionId, data, currentUser, referrer, etrx = undefined) => { + let trx; + try { + trx = etrx ? etrx : await FormSubmission.startTransaction(); + + // If we're restoring a submission + if (data['deleted'] !== undefined && typeof data.deleted == 'boolean') { + await FormSubmission.query(trx).patchAndFetchById(formSubmissionId, { deleted: data.deleted, updatedBy: currentUser.usernameIdp }); + } else { + const statuses = await FormSubmissionStatus.query().modify('filterSubmissionId', formSubmissionId).modify('orderDescending'); + if (!data.draft) { + // Write a SUBMITTED status only if this is in REVISING state OR is a brand new submission + if (!statuses || !statuses.length || statuses[0].code === Statuses.REVISING) { + await service.changeStatusState(formSubmissionId, { code: Statuses.SUBMITTED }, currentUser, trx); + // If finalizing submission, send the submission email (quiet fail if anything goes wrong) + const submissionMetaData = await SubmissionMetadata.query().where('submissionId', formSubmissionId).first(); + emailService.submissionReceived(submissionMetaData.formId, formSubmissionId, data, referrer).catch(() => {}); + } + } else { + if (statuses && statuses.length > 0 && (statuses[0].code === Statuses.SUBMITTED || statuses[0].code === Statuses.COMPLETED)) { + return false; + } + } + + // Patch the submission record with the updated changes + await FormSubmission.query(trx).patchAndFetchById(formSubmissionId, { + draft: data.draft, + submission: data.submission, + updatedBy: currentUser.usernameIdp, + }); + } + + if (!etrx) await trx.commit(); + + return service.read(formSubmissionId); + } catch (err) { + if (!etrx && trx) await trx.rollback(); + throw err; + } + }, + + /** + * @function setDraftState + * Changes the draft state of this submission + * @param {string} submissionId The submission id + * @param {boolean} draft Mark submission id as a draft or not + * @param {object} currentUser The currently logged in user metadata + * @param {object} [etrx=undefined] An optional Objection Transaction object + * @returns The new form submission object + * @throws The error encountered upon db transaction failure + */ + setDraftState: async (submissionId, draft, currentUser, etrx = undefined) => { + let trx; + try { + trx = etrx ? etrx : await FormSubmission.startTransaction(); + + const result = await FormSubmission.query(trx).patchAndFetchById(submissionId, { + draft: draft, + updatedBy: currentUser.usernameIdp, + }); + + if (!etrx) await trx.commit(); + return result; + } catch (err) { + if (!etrx && trx) await trx.rollback(); + throw err; + } + }, + + delete: async (formSubmissionId, currentUser) => { + let trx; + try { + trx = await FormSubmission.startTransaction(); + await FormSubmission.query(trx).patchAndFetchById(formSubmissionId, { + deleted: true, + updatedBy: currentUser.usernameIdp, + }); + await trx.commit(); + return await service.read(formSubmissionId); + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, + + deleteMutipleSubmissions: async (submissionIds, currentUser) => { + let trx; + try { + trx = await FormSubmission.startTransaction(); + await FormSubmission.query(trx).patch({ deleted: true, updatedBy: currentUser.usernameIdp }).whereIn('id', submissionIds); + await trx.commit(); + return await service.readSubmissionData(submissionIds); + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, + + restoreMutipleSubmissions: async (submissionIds, currentUser) => { + let trx; + try { + trx = await FormSubmission.startTransaction(); + await FormSubmission.query(trx) + .patch({ + deleted: false, + updatedBy: currentUser.usernameIdp, + }) + .whereIn('id', submissionIds); + await trx.commit(); + return await service.readSubmissionData(submissionIds); + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, + + restore: async (formSubmissionId, data, currentUser) => { + let trx; + try { + trx = await FormSubmission.startTransaction(); + await FormSubmission.query(trx).patchAndFetchById(formSubmissionId, { + deleted: data.deleted, + updatedBy: currentUser.usernameIdp, + }); + await trx.commit(); + return await service.read(formSubmissionId); + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, + + readOptions: async (formSubmissionId) => { + const meta = await SubmissionMetadata.query().where('submissionId', formSubmissionId).first().throwIfNotFound(); + + const form = await formService.readFormOptions(meta.formId); + + return { + submission: { + id: meta.submissionId, + formVersionId: meta.formId, + }, + version: { + id: meta.formVersionId, + formId: meta.formId, + }, + form: form, + }; + }, + + /** get the audit history metadata (nothing that edited a draft for now) */ + listEdits: (submissionId) => { + return SubmissionAudit.query() + .select('id', 'updatedByUsername', 'actionTimestamp', 'action') + .modify('filterSubmissionId', submissionId) + .modify('filterDraft', false) + .modify('orderDefault'); + }, + // --------------------------------------------------------------------------------------------/Submissions + + // ------------------------------------------------------------------------------------------------------- + // Notes + // ------------------------------------------------------------------------------------------------------- + _createNote: async (submissionId, data, currentUser) => { + let trx; + try { + trx = await Note.startTransaction(); + const result = await Note.query(trx).insertAndFetch({ + id: uuidv4(), + submissionId: submissionId, + submissionStatusId: data.submissionStatusId, + note: data.note, + userId: data.userId, + createdBy: currentUser.usernameIdp, + }); + await trx.commit(); + + return result; + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, + + /** Add a note for a specific submission */ + addNote: (formSubmissionId, data, currentUser) => { + return service._createNote(formSubmissionId, data, currentUser); + }, + + /** Get notes for a specific submission */ + getNotes: (formSubmissionId) => { + return Note.query().modify('filterSubmissionId', formSubmissionId).modify('orderDefault'); + }, + + /** Get a specific note */ + getNote: (noteId) => { + return Note.query().modify('filterId', noteId); + }, + // -------------------------------------------------------------------------------------------------/Notes + + // ------------------------------------------------------------------------------------------------------- + // Status + // ------------------------------------------------------------------------------------------------------- + /** + * @function getStatus + * Get status history for a specific submission + * @param {string} The submission id + * @returns The current status object + */ + getStatus: (formSubmissionId) => { + return FormSubmissionStatus.query().modify('filterSubmissionId', formSubmissionId).withGraphFetched('user').modify('orderDescending'); + }, + + /** + * @function changeStatusState + * Changes the status state of this submission. This method serves as the 'state machine' for submission permissions. + * @param {string} submissionId The submission id + * @param {object} data The data to persist + * @param {object} currentUser The currently logged in user metadata + * @param {object} [etrx=undefined] An optional Objection Transaction object + * @returns The new current status object + * @throws The error encountered upon db transaction failure + */ + changeStatusState: async (submissionId, data, currentUser, etrx = undefined) => { + let trx; + try { + trx = etrx ? etrx : await FormSubmissionStatus.startTransaction(); + + // Create a new status entry + await service.createStatus(submissionId, data, currentUser, trx); + + // Determine draft flag state on submission - true if revising, false otherwise + const draft = data.code === Statuses.REVISING; + const formSubmission = await FormSubmission.query(trx).findById(submissionId); + + // Only change draft state and permissions if draft state is getting toggled + if (formSubmission.draft !== draft) { + await service.setDraftState(submissionId, draft, currentUser, trx); + + if (draft) { + // Allow submitter users to edit the draft again if Revising status + await permissionService.setUserEditable(submissionId, currentUser, trx); + } else { + // Prevent submitter users from editing the submission + await permissionService.setUserReadOnly(submissionId, trx); + } + } + + if (!etrx) await trx.commit(); + return service.getStatus(submissionId); + } catch (err) { + if (!etrx && trx) await trx.rollback(); + throw err; + } + }, + + /** + * @function createStatus + * Adds a status history for a specific submission + * @param {string} submissionId The submission id + * @param {object} data The data to persist + * @param {object} currentUser The currently logged in user metadata + * @param {object} [etrx=undefined] An optional Objection Transaction object + * @returns The current status object + * @throws The error encountered upon db transaction failure + */ + createStatus: async (submissionId, data, currentUser, etrx = undefined) => { + let trx; + try { + trx = etrx ? etrx : await FormSubmissionStatus.startTransaction(); + + await FormSubmissionStatus.query(trx).insert({ + id: uuidv4(), + submissionId: submissionId, + code: data.code, + assignedToUserId: data.assignedToUserId, + actionDate: data.actionDate, + createdBy: currentUser.usernameIdp, + }); + + if (!etrx) await trx.commit(); + return service.getStatus(submissionId); + } catch (err) { + if (!etrx && trx) await trx.rollback(); + throw err; + } + }, + // -------------------------------------------------------------------------------------------------/Notes +}; + +module.exports = service; diff --git a/frontend/app/src/forms/user/controller.js b/frontend/app/src/forms/user/controller.js new file mode 100644 index 0000000..aeb0b45 --- /dev/null +++ b/frontend/app/src/forms/user/controller.js @@ -0,0 +1,99 @@ +const service = require('./service'); + +module.exports = { + // + // User + // + list: async (req, res, next) => { + try { + const response = await service.list(req.query); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + + read: async (req, res, next) => { + try { + const response = await service.readSafe(req.params.userId); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + + update: async (req, res, next) => { + try { + const response = await service.update(req.params.userId, req.body, req.currentUser); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, + + // + // User Preferences + // + deleteUserPreferences: async (req, res, next) => { + try { + await service.deleteUserPreferences(req.currentUser); + res.status(204).send(); + } catch (error) { + next(error); + } + }, + + readUserPreferences: async (req, res, next) => { + try { + const response = await service.readUserPreferences(req.currentUser); + res.status(200).json({ + forms: response, + preferences: {}, + }); + } catch (error) { + next(error); + } + }, + + updateUserPreferences: async (req, res, next) => { + try { + const response = await service.updateUserPreferences(req.currentUser, req.body); + res.status(200).json({ + forms: response, + preferences: {}, + }); + } catch (error) { + next(error); + } + }, + + // + // User Form Preferences + // + deleteUserFormPreferences: async (req, res, next) => { + try { + await service.deleteUserFormPreferences(req.currentUser, req.params.formId); + res.status(204).send(); + } catch (error) { + next(error); + } + }, + + readUserFormPreferences: async (req, res, next) => { + try { + const response = await service.readUserFormPreferences(req.currentUser, req.params.formId); + res.status(200).json(response || {}); + } catch (error) { + next(error); + } + }, + + updateUserFormPreferences: async (req, res, next) => { + try { + const response = await service.updateUserFormPreferences(req.currentUser, req.params.formId, req.body); + res.status(200).json(response); + } catch (error) { + next(error); + } + }, +}; diff --git a/frontend/app/src/forms/user/index.js b/frontend/app/src/forms/user/index.js new file mode 100644 index 0000000..376cda2 --- /dev/null +++ b/frontend/app/src/forms/user/index.js @@ -0,0 +1,7 @@ +const dataErrors = require('../common/middleware').dataErrors; +const routes = require('./routes'); +const setupMount = require('../common/utils').setupMount; + +module.exports.mount = (app) => { + return setupMount('users', app, routes, dataErrors); +}; diff --git a/frontend/app/src/forms/user/routes.js b/frontend/app/src/forms/user/routes.js new file mode 100644 index 0000000..c185552 --- /dev/null +++ b/frontend/app/src/forms/user/routes.js @@ -0,0 +1,52 @@ +const routes = require('express').Router(); +const controller = require('./controller'); + +const currentUser = require('../auth/middleware/userAccess').currentUser; +const keycloak = require('../../components/keycloak'); + +routes.use(keycloak.protect()); +routes.use(currentUser); + +// +// User Preferences +// This must be defined before /:userId route to work as intended +// +routes.get('/preferences', async (req, res, next) => { + await controller.readUserPreferences(req, res, next); +}); + +routes.put('/preferences', async (req, res, next) => { + await controller.updateUserPreferences(req, res, next); +}); + +routes.delete('/preferences', async (req, res, next) => { + await controller.deleteUserPreferences(req, res, next); +}); + +// +// User +// +routes.get('/', async (req, res, next) => { + await controller.list(req, res, next); +}); + +routes.get('/:userId', async (req, res, next) => { + await controller.read(req, res, next); +}); + +// +// User Form Preferences +// +routes.get('/preferences/forms/:formId', async (req, res, next) => { + await controller.readUserFormPreferences(req, res, next); +}); + +routes.put('/preferences/forms/:formId', async (req, res, next) => { + await controller.updateUserFormPreferences(req, res, next); +}); + +routes.delete('/preferences/forms/:formId', async (req, res, next) => { + await controller.deleteUserFormPreferences(req, res, next); +}); + +module.exports = routes; diff --git a/frontend/app/src/forms/user/service.js b/frontend/app/src/forms/user/service.js new file mode 100644 index 0000000..e84ef26 --- /dev/null +++ b/frontend/app/src/forms/user/service.js @@ -0,0 +1,131 @@ +const Problem = require('api-problem'); + +const { User, UserFormPreferences } = require('../common/models'); +const { IdentityProviders } = require('../common/constants'); + +const service = { + // + // User + // + list: (params) => { + let exact = false; + if (params.idpCode && (params.idpCode === IdentityProviders.BCEIDBASIC || params.idpCode === IdentityProviders.BCEIDBUSINESS)) { + if (!params.email && !params.username) { + throw new Problem(422, { + detail: 'Could not retrieve BCeID users. Invalid options provided.', + }); + } + exact = true; + } + + return User.query() + .modify('filterIdpUserId', params.idpUserId) + .modify('filterIdpCode', params.idpCode) + .modify('filterUsername', params.username, exact) + .modify('filterFullName', params.fullName) + .modify('filterFirstName', params.firstName) + .modify('filterLastName', params.lastName) + .modify('filterEmail', params.email, exact) + .modify('filterSearch', params.search) + .modify('orderLastFirstAscending'); + }, + + read: (userId) => { + return User.query().findById(userId).throwIfNotFound(); + }, + + readSafe: (userId) => { + return User.query().modify('safeSelect').findById(userId).throwIfNotFound(); + }, + + // + // User Preferences + // + deleteUserPreferences: (currentUser) => { + return UserFormPreferences.query().delete().where('userId', currentUser.id).throwIfNotFound(); + }, + + readUserPreferences: (currentUser) => { + return UserFormPreferences.query().where('userId', currentUser.id); + }, + + updateUserPreferences: async (currentUser, body) => { + let trx; + try { + if (!body || !body.forms || !Array.isArray(body.forms)) { + throw new Problem(422, { + detail: 'Could not update user preferences. Invalid options provided', + }); + } + + trx = await UserFormPreferences.startTransaction(); + + body.forms.forEach(async (form) => { + const current = await service.readUserFormPreferences(currentUser, form.formId); + + if (current) { + await UserFormPreferences.query(trx).patchAndFetchById([currentUser.id, form.formId], { + preferences: form.preferences, + updatedBy: currentUser.usernameIdp, + }); + } else { + await UserFormPreferences.query(trx).insert({ + userId: currentUser.id, + formId: form.formId, + preferences: form.preferences, + createdBy: currentUser.usernameIdp, + }); + } + }); + + await trx.commit(); + return service.readUserPreferences(currentUser); + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, + + // + // User Form Preferences + // + deleteUserFormPreferences: (currentUser, formId) => { + return UserFormPreferences.query().deleteById([currentUser.id, formId]).throwIfNotFound(); + }, + + readUserFormPreferences: (currentUser, formId) => { + return UserFormPreferences.query().findById([currentUser.id, formId]).first(); + }, + + updateUserFormPreferences: async (currentUser, formId, preferences) => { + let trx; + try { + let result; + + const current = await service.readUserFormPreferences(currentUser, formId); + trx = await UserFormPreferences.startTransaction(); + + if (current) { + result = await UserFormPreferences.query(trx).patchAndFetchById([currentUser.id, formId], { + preferences: preferences, + updatedBy: currentUser.usernameIdp, + }); + } else { + result = await UserFormPreferences.query(trx).insertAndFetch({ + userId: currentUser.id, + formId: formId, + preferences: preferences, + createdBy: currentUser.usernameIdp, + }); + } + + await trx.commit(); + return result; + } catch (err) { + if (trx) await trx.rollback(); + throw err; + } + }, +}; + +module.exports = service; diff --git a/frontend/app/src/forms/utils/index.js b/frontend/app/src/forms/utils/index.js new file mode 100644 index 0000000..b29726c --- /dev/null +++ b/frontend/app/src/forms/utils/index.js @@ -0,0 +1,7 @@ +const dataErrors = require('../common/middleware').dataErrors; +const routes = require('./routes'); +const setupMount = require('../common/utils').setupMount; + +module.exports.mount = (app) => { + return setupMount('utils', app, routes, dataErrors); +}; diff --git a/frontend/app/src/forms/utils/routes.js b/frontend/app/src/forms/utils/routes.js new file mode 100644 index 0000000..df31217 --- /dev/null +++ b/frontend/app/src/forms/utils/routes.js @@ -0,0 +1,12 @@ +const routes = require('express').Router(); + +const controller = require('../submission/controller'); +const { currentUser } = require('../auth/middleware/userAccess'); + +routes.use(currentUser); + +routes.post('/template/render', async (req, res, next) => { + await controller.draftTemplateUploadAndRender(req, res, next); +}); + +module.exports = routes; diff --git a/frontend/app/src/routes/v1.js b/frontend/app/src/routes/v1.js new file mode 100644 index 0000000..097d545 --- /dev/null +++ b/frontend/app/src/routes/v1.js @@ -0,0 +1,64 @@ +const config = require('config'); +const fs = require('fs'); +const path = require('path'); +const router = require('express').Router(); +const yaml = require('js-yaml'); + +const admin = require('../forms/admin'); +const bcgeoaddress = require('../forms/bcgeoaddress'); +const file = require('../forms/file'); +const form = require('../forms/form'); +const permission = require('../forms/permission'); +const rbac = require('../forms/rbac'); +const role = require('../forms/role'); +const user = require('../forms/user'); +const submission = require('../forms/submission'); +const utils = require('../forms/utils'); +const index = require('../forms/public'); + +admin.mount(router); +const bcaddress = bcgeoaddress.mount(router); +const filePath = file.mount(router); +const formPath = form.mount(router); +const permissionPath = permission.mount(router); +const rbacPath = rbac.mount(router); +const rolePath = role.mount(router); +const userPath = user.mount(router); +const submissionPath = submission.mount(router); +const utilsPath = utils.mount(router); +const publicPath = index.mount(router); + +const getSpec = () => { + const rawSpec = fs.readFileSync(path.join(__dirname, '../docs/v1.api-spec.yaml'), 'utf8'); + const spec = yaml.load(rawSpec); + spec.servers[0].url = `${config.get('server.basePath')}/api/v1`; + spec.components.securitySchemes.OpenID.openIdConnectUrl = `${config.get('server.keycloak.serverUrl')}/realms/${config.get( + 'server.keycloak.realm' + )}/.well-known/openid-configuration`; + return spec; +}; + +// Base v1 Responder +router.get('/', (_req, res) => { + res.status(200).json({ + endpoints: ['/docs', filePath, formPath, permissionPath, rbacPath, rolePath, submissionPath, userPath, bcaddress, publicPath, utilsPath], + }); +}); + +/** OpenAPI Docs */ +router.get('/docs', (_req, res) => { + const docs = require('../docs/docs'); + res.send(docs.getDocHTML('v1')); +}); + +/** OpenAPI YAML Spec */ +router.get('/api-spec.yaml', (_req, res) => { + res.status(200).type('application/yaml').send(yaml.dump(getSpec())); +}); + +/** OpenAPI JSON Spec */ +router.get('/api-spec.json', (_req, res) => { + res.status(200).json(getSpec()); +}); + +module.exports = router; diff --git a/frontend/app/tests/common/dbHelper.js b/frontend/app/tests/common/dbHelper.js new file mode 100644 index 0000000..2d3d22d --- /dev/null +++ b/frontend/app/tests/common/dbHelper.js @@ -0,0 +1,84 @@ +let returnValue = undefined; + +const retFn = (value) => { + returnValue = value; +}; + +/** + * @class MockTransaction + * Mock Objection Transaction + */ +class MockTransaction {} + +// Mocked Objection Functions +MockTransaction.commit = jest.fn().mockReturnThis(); +MockTransaction.rollback = jest.fn().mockReturnThis(); + +// Utility Functions +MockTransaction.mockClear = () => { + Object.keys(MockTransaction).forEach((f) => { + if (jest.isMockFunction(f)) f.mockClear(); + }); +}; +MockTransaction.mockReset = () => { + Object.keys(MockTransaction).forEach((f) => { + if (jest.isMockFunction(f)) f.mockReset(); + }); +}; + +/** + * @class MockModel + * Mock Objection Model + */ +class MockModel {} + +// Mocked Objection Functions +MockModel.findById = jest.fn().mockReturnThis(); +MockModel.first = jest.fn().mockReturnThis(); +MockModel.delete = jest.fn().mockReturnThis(); +MockModel.deleteById = jest.fn().mockReturnThis(); +MockModel.insert = jest.fn().mockReturnThis(); +MockModel.insertAndFetch = jest.fn().mockReturnThis(); +MockModel.insertGraph = jest.fn().mockReturnThis(); +MockModel.insertGraphAndFetch = jest.fn().mockReturnThis(); +MockModel.findById = jest.fn().mockReturnThis(); +MockModel.modify = jest.fn().mockReturnThis(); +MockModel.modifiers = jest.fn().mockReturnThis(); +MockModel.orderBy = jest.fn().mockReturnThis(); +MockModel.patch = jest.fn().mockReturnThis(); +MockModel.patchAndFetchById = jest.fn().mockReturnThis(); +MockModel.query = jest.fn().mockReturnThis(); +MockModel.query.select = jest.fn().mockReturnThis(); +MockModel.query.column = jest.fn().mockReturnThis(); +MockModel.resolve = jest.fn().mockResolvedValue(returnValue); +MockModel.returning = jest.fn().mockReturnThis(); +(MockModel.skipUndefined = jest.fn(() => { + throw new Error('skipUndefined() is deprecated in Objection 3.0. Refactor to not use this method!'); +})), + (MockModel.startTransaction = jest.fn().mockResolvedValue(MockTransaction)); +MockModel.then = jest.fn((done) => { + done(returnValue); +}); +MockModel.throwIfNotFound = jest.fn().mockReturnThis(); +MockModel.update = jest.fn().mockReturnThis(); +MockModel.where = jest.fn().mockReturnThis(); +MockModel.whereIn = jest.fn().mockReturnThis(); +MockModel.withGraphFetched = jest.fn().mockReturnThis(); + +// Utility Functions +MockModel.mockClear = () => { + Object.keys(MockModel).forEach((f) => { + if (jest.isMockFunction(f)) f.mockClear(); + }); + returnValue = undefined; +}; +MockModel.mockReset = () => { + Object.keys(MockModel).forEach((f) => { + if (jest.isMockFunction(f)) f.mockReset(); + }); + returnValue = undefined; +}; +MockModel.mockResolvedValue = retFn; +MockModel.mockReturnValue = retFn; + +module.exports = { MockModel, MockTransaction }; diff --git a/frontend/app/tests/common/helper.js b/frontend/app/tests/common/helper.js new file mode 100644 index 0000000..6cd3926 --- /dev/null +++ b/frontend/app/tests/common/helper.js @@ -0,0 +1,48 @@ +const express = require('express'); +const Problem = require('api-problem'); + +/** + * @class helper + * Provides helper utilities that are commonly used in tests + */ +const helper = { + /** + * @function expressHelper + * Creates a stripped-down simple Express server object + * @param {string} basePath The path to mount the `router` on + * @param {object} router An express router object to mount + * @returns {object} A simple express server object with `router` mounted to `basePath` + */ + expressHelper: (basePath, router) => { + const app = express(); + + app.use(express.json()); + app.use( + express.urlencoded({ + extended: false, + }) + ); + app.use(basePath, router); + + // Handle 500 + // eslint-disable-next-line no-unused-vars + app.use((err, _req, res, _next) => { + if (err instanceof Problem) { + err.send(res); + } else { + new Problem(500, { + details: err.message ? err.message : err, + }).send(res); + } + }); + + // Handle 404 + app.use((_req, res) => { + new Problem(404).send(res); + }); + + return app; + }, +}; + +module.exports = helper; diff --git a/frontend/app/tests/fixtures/form/Kitchen_sink_form_schema_datagrid.json b/frontend/app/tests/fixtures/form/Kitchen_sink_form_schema_datagrid.json new file mode 100644 index 0000000..071303c --- /dev/null +++ b/frontend/app/tests/fixtures/form/Kitchen_sink_form_schema_datagrid.json @@ -0,0 +1,1529 @@ +{ + "type": "form", + "display": "form", + "components": [ + { + "id": "ei55j3d", + "key": "introduction", + "html": "

In order to gather data on fishing effort and catch, and to improve freshwater fishing in the West Coast Region, please complete the following survey of your freshwater fishing experiences in 2017.

", + "type": "simplecontent", + "input": false, + "label": "Text/Images", + "addons": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "e95ejh6", + "key": "columnsRegions", + "tree": false, + "type": "simplecols2", + "input": false, + "label": "Columns-regions", + "addons": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "columns": [ + { + "pull": 0, + "push": 0, + "size": "md", + "width": 6, + "offset": 0, + "components": [ + { + "id": "evc9l309", + "key": "lake-regions-map", + "html": "
", + "type": "simplecontent", + "input": false, + "label": "Text/Images", + "addons": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + } + ], + "currentWidth": 6 + }, + { + "pull": 0, + "push": 0, + "size": "md", + "width": 6, + "offset": 0, + "components": [ + { + "id": "eykrvv", + "key": "fishermansName", + "case": "", + "mask": false, + "tags": [], + "type": "textfield", + "input": true, + "label": "Fisherman's Name", + "logic": [], + "addons": [], + "errors": "", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "json": "", + "custom": "", + "unique": false, + "pattern": "", + "maxWords": "", + "minWords": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": true, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "displayMask": "", + "inputFormat": "plain", + "labelMargin": "", + "placeholder": "", + "autocomplete": "", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false, + "truncateMultipleSpaces": false + }, + { + "id": "e5armig", + "key": "email", + "case": "", + "mask": false, + "tags": [], + "type": "email", + "input": true, + "label": "Email", + "logic": [], + "addons": [], + "errors": "", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "kickbox": { + "enabled": false + }, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "json": "", + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "email", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": true, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "displayMask": "", + "inputFormat": "plain", + "labelMargin": "", + "placeholder": "", + "autocomplete": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false, + "truncateMultipleSpaces": false + }, + { + "id": "eqmjhnp", + "key": "forWhichBcLakeRegionAreYouCompletingTheseQuestions", + "tags": [], + "type": "radio", + "input": true, + "label": "For which BC Lake region are you completing these questions?", + "logic": [], + "addons": [], + "errors": "", + "hidden": false, + "inline": false, + "prefix": "", + "suffix": "", + "unique": false, + "values": [ + { + "label": "Vancouver Island", + "value": "1", + "shortcut": "" + }, + { + "label": "Lower Mainland", + "value": "2", + "shortcut": "" + }, + { + "label": "Thompson-Nicola", + "value": "3", + "shortcut": "" + }, + { + "label": "Kootenay", + "value": "4", + "shortcut": "" + }, + { + "label": "Cariboo", + "value": "5", + "shortcut": "" + }, + { + "label": "Skeena", + "value": "6", + "shortcut": "" + }, + { + "label": "Omineca", + "value": "7a", + "shortcut": "" + }, + { + "label": "Peace", + "value": "7b", + "shortcut": "" + }, + { + "label": "Okanagan", + "value": "8", + "shortcut": "" + } + ], + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "dataType": "", + "disabled": false, + "fieldSet": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "json": "", + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "onlyAvailableItems": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputType": "radio", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "labelMargin": "", + "placeholder": "", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "optionsLabelPosition": "right", + "allowCalculateOverride": false + }, + { + "id": "edv42r", + "key": "didYouFishAnyBcLakesThisYear", + "tags": [], + "type": "radio", + "input": true, + "label": "Did you fish any BC lakes this year?", + "logic": [], + "addons": [], + "errors": "", + "hidden": false, + "inline": false, + "prefix": "", + "suffix": "", + "unique": false, + "values": [ + { + "label": "yes", + "value": "yes", + "shortcut": "" + }, + { + "label": "no", + "value": "no", + "shortcut": "" + } + ], + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "dataType": "", + "disabled": false, + "fieldSet": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "json": "", + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "onlyAvailableItems": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputType": "radio", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "labelMargin": "", + "placeholder": "", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "optionsLabelPosition": "right", + "allowCalculateOverride": false + } + ], + "currentWidth": 6 + } + ], + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "lazyLoad": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "autoAdjust": false, + "errorLabel": "", + "labelWidth": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": false, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "labelMargin": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "hideOnChildrenHidden": false, + "allowCalculateOverride": false + }, + { + "id": "etsnkuq", + "key": "simplecontent", + "html": "

Please complete the table even if you fished lakes but did not catch any fish

", + "type": "simplecontent", + "input": false, + "label": "Text/Images", + "addons": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "emyhiiui", + "key": "oneRowPerLake", + "tree": true, + "type": "datagrid", + "input": true, + "label": "One row per lake", + "addons": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "reorder": false, + "tooltip": "", + "disabled": false, + "lazyLoad": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "initEmpty": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "components": [ + { + "id": "entqpot9000000000000000000000000", + "key": "lakeName", + "case": "", + "mask": false, + "tags": [], + "type": "textfield", + "input": true, + "label": "Lake name", + "logic": [], + "addons": [], + "errors": "", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "json": "", + "custom": "", + "unique": false, + "pattern": "", + "maxWords": "", + "minWords": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": true, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "displayMask": "", + "inputFormat": "plain", + "labelMargin": "", + "placeholder": "", + "autocomplete": "", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false, + "truncateMultipleSpaces": false + }, + { + "id": "ezfdklm0000000000000000000000", + "key": "closestTown", + "case": "", + "mask": false, + "tags": [], + "type": "textfield", + "input": true, + "label": "Closest Town", + "logic": [], + "addons": [], + "errors": "", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "json": "", + "custom": "", + "unique": false, + "pattern": "", + "maxWords": "", + "minWords": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": true, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "displayMask": "", + "inputFormat": "plain", + "labelMargin": "", + "placeholder": "", + "autocomplete": "", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false, + "truncateMultipleSpaces": false + }, + { + "id": "e1qiedv00000000000", + "key": "numberOfDays", + "mask": false, + "tags": [], + "type": "number", + "input": true, + "label": "Number of Days", + "logic": [], + "addons": [], + "errors": "", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "max": "", + "min": "", + "json": "", + "step": "any", + "custom": "", + "unique": false, + "integer": "", + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "delimiter": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "displayMask": "", + "inputFormat": "plain", + "labelMargin": "", + "placeholder": "", + "autocomplete": "", + "decimalLimit": "", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "requireDecimal": false, + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false, + "truncateMultipleSpaces": false + }, + { + "id": "ey63cje0000000000000000", + "key": "dataGrid", + "tags": [], + "tree": true, + "type": "datagrid", + "input": true, + "label": "One row per fish type", + "logic": [], + "addons": [], + "errors": "", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "reorder": false, + "tooltip": "", + "disabled": false, + "lazyLoad": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "json": "", + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "initEmpty": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "addAnother": "", + "attributes": {}, + "components": [ + { + "id": "eg8bi7r0000000000000000000000", + "key": "fishType", + "data": { + "url": "", + "json": "", + "custom": "", + "values": [ + { + "label": "Rainbow", + "value": "rainbow" + }, + { + "label": "Cutthroat", + "value": "cutthroat" + }, + { + "label": "Dolly Vardon", + "value": "dollyVardon" + }, + { + "label": "Smallmouth Bass", + "value": "smallmouthBass" + } + ], + "resource": "" + }, + "tags": [], + "type": "select", + "input": true, + "label": "Fish Type", + "limit": 100, + "logic": [], + "addons": [], + "errors": "", + "filter": "", + "hidden": false, + "idPath": "id", + "prefix": "", + "suffix": "", + "unique": false, + "widget": "choicesjs", + "dataSrc": "values", + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "dataType": "", + "disabled": false, + "lazyLoad": true, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "template": "{{ item.label }}", + "validate": { + "json": "", + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "onlyAvailableItems": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "indexeddb": { + "filter": {} + }, + "minSearch": 0, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": true, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "fuseOptions": { + "include": "score", + "threshold": 0.3 + }, + "ignoreCache": false, + "labelMargin": "", + "placeholder": "", + "searchField": "", + "authenticate": false, + "defaultValue": "", + "selectFields": "", + "customOptions": {}, + "dataGridLabel": false, + "labelPosition": "top", + "readOnlyValue": false, + "refreshOnBlur": "", + "searchEnabled": true, + "showCharCount": false, + "showWordCount": false, + "uniqueOptions": false, + "valueProperty": "", + "calculateValue": "", + "clearOnRefresh": false, + "searchDebounce": 0.3, + "useExactSearch": false, + "calculateServer": false, + "selectThreshold": 0.3, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "epgkbb900000000000000000000", + "key": "numberCaught", + "mask": false, + "tags": [], + "type": "number", + "input": true, + "label": "Number Caught", + "logic": [], + "addons": [], + "errors": "", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "max": "", + "min": "", + "json": "", + "step": "any", + "custom": "", + "unique": false, + "integer": "", + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "delimiter": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "displayMask": "", + "inputFormat": "plain", + "labelMargin": "", + "placeholder": "", + "autocomplete": "", + "decimalLimit": "", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "requireDecimal": false, + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false, + "truncateMultipleSpaces": false + }, + { + "id": "elufg6i000000000000000000", + "key": "numberKept", + "mask": false, + "tags": [], + "type": "number", + "input": true, + "label": "Number Kept", + "logic": [], + "addons": [], + "errors": "", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "max": "", + "min": "", + "json": "", + "step": "any", + "custom": "", + "unique": false, + "integer": "", + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "delimiter": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "displayMask": "", + "inputFormat": "plain", + "labelMargin": "", + "placeholder": "", + "autocomplete": "", + "decimalLimit": "", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "requireDecimal": false, + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false, + "truncateMultipleSpaces": false + } + ], + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "labelMargin": "", + "layoutFixed": false, + "placeholder": "", + "defaultValue": [ + {} + ], + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "enableRowGroups": false, + "customConditional": "", + "addAnotherPosition": "bottom", + "allowMultipleMasks": false, + "customDefaultValue": "", + "conditionalAddButton": "", + "allowCalculateOverride": false, + "disableAddingRemovingRows": false + } + ], + "errorLabel": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "yes", + "show": true, + "when": "didYouFishAnyBcLakesThisYear" + }, + "customClass": "", + "description": "", + "layoutFixed": false, + "placeholder": "", + "defaultValue": [ + {} + ], + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "enableRowGroups": false, + "addAnotherPosition": "bottom", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false, + "disableAddingRemovingRows": false + }, + { + "id": "eckbcz8", + "key": "submit", + "size": "md", + "type": "button", + "block": false, + "input": true, + "label": "Submit", + "theme": "primary", + "action": "submit", + "addons": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "leftIcon": "", + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "rightIcon": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": true, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "disableOnInvalid": true, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + } + ] +} \ No newline at end of file diff --git a/frontend/app/tests/fixtures/form/advanced_schema.json b/frontend/app/tests/fixtures/form/advanced_schema.json new file mode 100644 index 0000000..17d7d99 --- /dev/null +++ b/frontend/app/tests/fixtures/form/advanced_schema.json @@ -0,0 +1,4251 @@ +{ + "display": "form", + "type": "form", + "components": [ + { + "id": "eaoylvk", + "key": "panel1", + "tags": [], + "tree": false, + "type": "panel", + "input": false, + "label": "Advanced Layout and static content", + "logic": [], + "theme": "default", + "title": "Advanced Layout and static content", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "collapsed": true, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "breadcrumb": "default", + "components": [ + { + "id": "eh27zic", + "key": "layouthtml1", + "tag": "p", + "type": "htmlelement", + "attrs": [ + { + "attr": "", + "value": "" + } + ], + "input": false, + "label": "HTML", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "content": "

html content here

", + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "refreshOnChange": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "e23fi1i", + "key": "layoutcontent1", + "html": "

content here

", + "type": "content", + "input": false, + "label": "Content", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "refreshOnChange": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "estjjzi", + "key": "advancedColumns", + "tree": false, + "type": "columns", + "input": false, + "label": "advanced Columns", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "columns": [ + { + "pull": 0, + "push": 0, + "size": "md", + "width": 6, + "offset": 0, + "components": [ + { + "id": "e3t9v2", + "key": "textincolumn1", + "mask": false, + "type": "textfield", + "input": true, + "label": "Text Field", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": true, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "hideOnChildrenHidden": false, + "allowCalculateOverride": false + } + ] + }, + { + "pull": 0, + "push": 0, + "size": "md", + "width": 6, + "offset": 0, + "components": [ + { + "id": "e71mueb", + "key": "fieldset1", + "tree": false, + "type": "fieldset", + "input": false, + "label": "", + "hidden": false, + "legend": "Fieldset legend", + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "components": [ + { + "id": "euoj0jq", + "key": "textinfieldset", + "mask": false, + "type": "textfield", + "input": true, + "label": "Text Field", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": true, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + } + ], + "errorLabel": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "hideOnChildrenHidden": false, + "allowCalculateOverride": false + } + ] + } + ], + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "autoAdjust": false, + "errorLabel": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": false, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "hideOnChildrenHidden": false, + "allowCalculateOverride": false + }, + { + "id": "e1bwyr", + "key": "panel", + "tree": false, + "type": "panel", + "input": false, + "label": "Panel", + "theme": "default", + "title": "Panel", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "breadcrumb": "default", + "components": [ + { + "id": "et68jwo", + "key": "tabs2", + "tree": false, + "type": "tabs", + "input": false, + "label": "Tabs", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "components": [ + { + "key": "tab2", + "label": "Tab 1", + "components": [ + { + "id": "eouovr", + "key": "well1", + "tree": false, + "type": "well", + "input": false, + "label": "well", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "components": [ + { + "id": "e39k2fg", + "key": "table", + "rows": [ + [ + { + "components": [ + { + "id": "exl22p4", + "key": "numberintable1", + "mask": false, + "type": "number", + "input": true, + "label": "Number", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "max": "", + "min": "", + "step": "any", + "custom": "", + "unique": false, + "integer": "", + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "delimiter": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "defaultValue": 1, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "requireDecimal": false, + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + } + ] + }, + { + "components": [ + { + "id": "eaxn2bk", + "key": "numberintable2", + "mask": false, + "type": "number", + "input": true, + "label": "Number", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "max": "", + "min": "", + "step": "any", + "custom": "", + "unique": false, + "integer": "", + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "delimiter": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "defaultValue": 2, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "requireDecimal": false, + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + } + ] + } + ], + [ + { + "components": [ + { + "id": "ezj0opk", + "key": "numberintable3", + "mask": false, + "type": "number", + "input": true, + "label": "Number", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "max": "", + "min": "", + "step": "any", + "custom": "", + "unique": false, + "integer": "", + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "delimiter": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "defaultValue": 3, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "requireDecimal": false, + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + } + ] + }, + { + "components": [ + { + "id": "et5gqpc", + "key": "numberintable4", + "mask": false, + "type": "number", + "input": true, + "label": "Number", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "max": "", + "min": "", + "step": "any", + "custom": "", + "unique": false, + "integer": "", + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "delimiter": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "defaultValue": 4, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "requireDecimal": false, + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + } + ] + } + ] + ], + "tree": false, + "type": "table", + "hover": false, + "input": false, + "label": "Table", + "header": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "caption": "", + "dbIndex": false, + "numCols": 2, + "numRows": 2, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "striped": false, + "tooltip": "", + "bordered": false, + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "cloneRows": false, + "condensed": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "cellAlignment": "left", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + } + ], + "errorLabel": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + } + ] + }, + { + "key": "tab3", + "label": "Tab 2", + "components": [ + { + "id": "eutbxt8", + "key": "dataGridInPanel", + "tree": true, + "type": "datagrid", + "input": true, + "label": "Data Grid in panel", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "reorder": false, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "initEmpty": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "components": [ + { + "id": "e7qk4m00000000", + "key": "textInDatagridInPanel1", + "mask": false, + "type": "textfield", + "input": true, + "label": "Text Field", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": true, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "e62tb7j00000000", + "key": "textInDatagridInPanel2", + "mask": false, + "type": "textfield", + "input": true, + "label": "Text Field", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": true, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + } + ], + "errorLabel": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "layoutFixed": false, + "placeholder": "", + "defaultValue": [ + {} + ], + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "enableRowGroups": false, + "addAnotherPosition": "bottom", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false, + "disableAddingRemovingRows": false + } + ] + } + ], + "errorLabel": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + } + ], + "errorLabel": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": false, + "collapsible": false, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + } + ], + "errorLabel": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": false, + "collapsible": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "exdpqrf", + "key": "advancedFields", + "tags": [], + "tree": false, + "type": "panel", + "input": false, + "label": "Advanced fields", + "logic": [], + "theme": "default", + "title": "Advanced fields", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "collapsed": true, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "breadcrumb": "default", + "components": [ + { + "id": "eed6g9", + "key": "tags", + "type": "tags", + "input": true, + "label": "Tags", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "maxTags": 0, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "storeas": "string", + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "delimeter": ",", + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "evscjdw", + "key": "address", + "tree": true, + "type": "address", + "input": true, + "label": "Address", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "provider": "custom", + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "components": [ + { + "id": "ej8ak8", + "key": "address1", + "mask": false, + "type": "textfield", + "input": true, + "label": "Address 1", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "show = _.get(instance, 'parent.manualMode', false);", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "e7kocrl", + "key": "address2", + "mask": false, + "type": "textfield", + "input": true, + "label": "Address 2", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "show = _.get(instance, 'parent.manualMode', false);", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "e60e28h", + "key": "city", + "mask": false, + "type": "textfield", + "input": true, + "label": "City", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "show = _.get(instance, 'parent.manualMode', false);", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "etzr247", + "key": "state", + "mask": false, + "type": "textfield", + "input": true, + "label": "State", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "show = _.get(instance, 'parent.manualMode', false);", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "es3cgwa", + "key": "country", + "mask": false, + "type": "textfield", + "input": true, + "label": "Country", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "show = _.get(instance, 'parent.manualMode', false);", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "e6wl9z3", + "key": "zip", + "mask": false, + "type": "textfield", + "input": true, + "label": "Zip Code", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "show = _.get(instance, 'parent.manualMode', false);", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + } + ], + "errorLabel": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "providerOptions": { + "url": "http://example.com", + "params": {}, + "queryProperty": "query" + }, + "disableClearIcon": false, + "enableManualMode": false, + "allowMultipleMasks": false, + "customDefaultValue": "value = 'my address';", + "manualModeViewString": "", + "allowCalculateOverride": false, + "switchToManualModeLabel": "Can't find address? Switch to manual mode." + }, + { + "id": "e29htko", + "key": "password", + "mask": false, + "type": "password", + "input": true, + "label": "Password", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": true, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "e7b07xd", + "key": "day", + "type": "day", + "input": true, + "label": "Day", + "fields": { + "day": { + "hide": false, + "type": "number", + "required": false, + "placeholder": "" + }, + "year": { + "hide": false, + "type": "number", + "required": false, + "placeholder": "" + }, + "month": { + "hide": false, + "type": "select", + "required": false, + "placeholder": "" + } + }, + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "dayFirst": false, + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": "00/00/0000", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "hideInputLabels": false, + "useLocaleSettings": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "inputsLabelPosition": "top", + "allowCalculateOverride": false + }, + { + "id": "e75lrf", + "key": "selectBoxes1", + "type": "selectboxes", + "input": true, + "label": "Select Boxes", + "hidden": false, + "inline": false, + "prefix": "", + "suffix": "", + "unique": false, + "values": [ + { + "label": "box 1", + "value": "box1", + "shortcut": "" + }, + { + "label": "box 2", + "value": "box2", + "shortcut": "" + }, + { + "label": "box 3", + "value": "box3", + "shortcut": "" + } + ], + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "fieldSet": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "onlyAvailableItems": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputType": "checkbox", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": { + "box1": false, + "box2": false, + "box3": false + }, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "optionsLabelPosition": "right", + "allowCalculateOverride": false + }, + { + "id": "ejis7ri", + "key": "select1", + "data": { + "url": "", + "json": "", + "custom": "", + "values": [ + { + "label": "select 1", + "value": "select1" + }, + { + "label": "select 2", + "value": "select2" + }, + { + "label": "select 3", + "value": "select3" + } + ], + "resource": "" + }, + "type": "select", + "input": true, + "label": "Select", + "limit": 100, + "filter": "", + "hidden": false, + "idPath": "id", + "prefix": "", + "suffix": "", + "unique": false, + "widget": "choicesjs", + "dataSrc": "values", + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "lazyLoad": true, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "template": "{{ item.label }}", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "onlyAvailableItems": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "indexeddb": { + "filter": {} + }, + "minSearch": 0, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": true, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "fuseOptions": { + "include": "score", + "threshold": 0.3 + }, + "ignoreCache": false, + "placeholder": "", + "searchField": "", + "authenticate": false, + "defaultValue": null, + "selectFields": "", + "customOptions": {}, + "dataGridLabel": false, + "labelPosition": "top", + "readOnlyValue": false, + "searchEnabled": true, + "showCharCount": false, + "showWordCount": false, + "uniqueOptions": false, + "valueProperty": "", + "calculateValue": "", + "clearOnRefresh": false, + "useExactSearch": false, + "calculateServer": false, + "searchThreshold": 0.3, + "selectThreshold": 0.3, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "eaumtr8", + "key": "currency", + "mask": false, + "type": "currency", + "input": true, + "label": "Currency", + "hidden": false, + "prefix": "$", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "currency": "CAD", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "max": "", + "min": "", + "step": "any", + "custom": "", + "unique": false, + "integer": "", + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "delimiter": true, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "defaultValue": 100, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "euwruu", + "key": "survey1", + "type": "survey", + "input": true, + "label": "Survey", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "values": [ + { + "label": "yes", + "value": "yes" + }, + { + "label": "no", + "value": "no" + } + ], + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "questions": [ + { + "label": "question 1", + "value": "question1" + }, + { + "label": "question 2", + "value": "question2" + }, + { + "label": "question 3", + "value": "question3" + } + ], + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "ege1gqh", + "key": "signature", + "type": "signature", + "input": true, + "label": "Signature", + "width": "100%", + "footer": "Sign above", + "height": "50px", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "maxWidth": "2.5", + "minWidth": "0.5", + "multiple": false, + "penColor": "black", + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "backgroundColor": "rgb(245,245,235)", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + } + ], + "errorLabel": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": false, + "collapsible": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "eh09bsh", + "key": "advancedFields1", + "tags": [], + "tree": false, + "type": "panel", + "input": false, + "label": "Advanced Fields", + "logic": [], + "theme": "default", + "title": "Advanced Data", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "collapsed": true, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "breadcrumb": "default", + "components": [ + { + "id": "enssvuk", + "key": "hidden1", + "tags": [], + "type": "hidden", + "input": true, + "label": "Hidden", + "logic": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputType": "hidden", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": "this should be hidden", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "ehmnuw8", + "key": "container1", + "tags": [], + "tree": true, + "type": "container", + "input": true, + "label": "Container", + "logic": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "a container will nest contained fields in a new object", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "json": "", + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": true, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "components": [ + { + "id": "euac8cr", + "key": "containedTextField1", + "case": "", + "mask": false, + "tags": [], + "type": "textfield", + "input": true, + "label": "Contained Text Field 1", + "logic": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "json": "", + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": true, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "autocomplete": "", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "ekbclp", + "key": "containedTextField2", + "case": "", + "mask": false, + "tags": [], + "type": "textfield", + "input": true, + "label": "Contained Text Field 2", + "logic": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "json": "", + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": true, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "autocomplete": "", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + } + ], + "errorLabel": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "eyzy4od", + "key": "dataMap", + "tags": [], + "type": "datamap", + "input": true, + "label": "Data Map", + "logic": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "keyLabel": "", + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "json": "", + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "maxLength": 0, + "minLength": 0, + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "addAnother": "Add Another", + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "keyBeforeValue": true, + "valueComponent": { + "id": "e0zi1ic", + "key": "value", + "case": "", + "mask": false, + "tags": [], + "type": "textfield", + "input": true, + "label": "Value", + "logic": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "json": "", + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": true, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": true, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "autocomplete": "", + "defaultValue": "my value", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false, + "disableAddingRemovingRows": false + }, + { + "id": "eirb8xk", + "key": "dataGrid", + "tags": [], + "tree": true, + "type": "datagrid", + "input": true, + "label": "Data Grid", + "logic": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "reorder": false, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "json": "", + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "initEmpty": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "addAnother": "", + "attributes": {}, + "components": [ + { + "id": "ee5xbas0000000000000000000000000000000", + "key": "textFieldInDataGrid1", + "case": "", + "mask": false, + "tags": [], + "type": "textfield", + "input": true, + "label": "Text Field in data grid 1", + "logic": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "json": "", + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": true, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "autocomplete": "", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "eeg46ug000000000000000000000000000000", + "key": "textFieldInDataGrid2", + "case": "", + "mask": false, + "tags": [], + "type": "textfield", + "input": true, + "label": "Text Field in Data Grid 2", + "logic": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "json": "", + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": true, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "autocomplete": "", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + } + ], + "errorLabel": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "layoutFixed": false, + "placeholder": "", + "defaultValue": [ + {} + ], + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "enableRowGroups": false, + "customConditional": "", + "addAnotherPosition": "bottom", + "allowMultipleMasks": false, + "customDefaultValue": "", + "conditionalAddButton": "", + "allowCalculateOverride": false, + "disableAddingRemovingRows": false + }, + { + "id": "e007hv07", + "key": "editGrid", + "tags": [], + "tree": true, + "type": "editgrid", + "input": true, + "label": "Edit Grid", + "logic": [], + "modal": false, + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "saveRow": "", + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "rowClass": "", + "tabindex": "", + "validate": { + "json": "", + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "removeRow": "Cancel", + "rowDrafts": false, + "tableView": false, + "templates": { + "row": "
\n {% util.eachComponent(components, function(component) { %}\n {% if (displayValue(component)) { %}\n
\n {{ isVisibleInRow(component) ? getView(component, row[component.key]) : ''}}\n
\n {% } %}\n {% }) %}\n {% if (!instance.options.readOnly && !instance.disabled) { %}\n
\n
\n \n {% if (!instance.hasRemoveButtons || instance.hasRemoveButtons()) { %}\n \n {% } %}\n
\n
\n {% } %}\n
", + "footer": "", + "header": "
\n {% util.eachComponent(components, function(component) { %}\n {% if (displayValue(component)) { %}\n
{{ t(component.label) }}
\n {% } %}\n {% }) %}\n
" + }, + "addAnother": "", + "attributes": {}, + "components": [ + { + "id": "euaifi", + "key": "textFieldInEditGrid1", + "case": "", + "mask": false, + "tags": [], + "type": "textfield", + "input": true, + "label": "Text Field in Edit Grid 1", + "logic": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "json": "", + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": true, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "autocomplete": "", + "defaultValue": "xyz", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "ewuh44", + "key": "textFieldInEditGrid2", + "case": "", + "mask": false, + "tags": [], + "type": "textfield", + "input": true, + "label": "Text Field in Edit Grid 2", + "logic": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "json": "", + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": true, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "autocomplete": "", + "defaultValue": "abc", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + } + ], + "errorLabel": "", + "inlineEdit": false, + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "defaultOpen": false, + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "openWhenEmpty": false, + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "conditionalAddButton": "", + "allowCalculateOverride": false, + "disableAddingRemovingRows": false + }, + { + "id": "epjf9xl", + "key": "tree", + "tags": [], + "tree": true, + "type": "tree", + "input": true, + "label": "Tree", + "logic": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "json": "", + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "components": [ + { + "id": "ewja7ti", + "key": "textFieldInTree1", + "mask": false, + "type": "textfield", + "input": true, + "label": "Text Field in Tree 1", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": true, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "exy7vls", + "key": "textFieldInTree2", + "mask": false, + "type": "textfield", + "input": true, + "label": "Text Field in Tree 2", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": true, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + } + ], + "errorLabel": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": {}, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + } + ], + "errorLabel": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": false, + "collapsible": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "e4xpg3n", + "key": "bcGov", + "tags": [], + "tree": false, + "type": "panel", + "input": false, + "label": "BC Government ", + "logic": [], + "theme": "default", + "title": "BC Government ", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "collapsed": true, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "breadcrumb": "default", + "components": [ + { + "id": "eubzgq", + "key": "simplefile", + "url": "/files", + "type": "simplefile", + "image": false, + "input": true, + "label": "File Upload", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "webcam": false, + "widget": null, + "dbIndex": false, + "fileKey": "files", + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "storage": "chefs", + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "fileTypes": [ + { + "label": "", + "value": "" + } + ], + "hideLabel": false, + "imageSize": "200", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "uploadOnly": false, + "validateOn": "change", + "webcamSize": 320, + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "formio-component-file", + "description": "", + "fileMaxSize": "1GB", + "fileMinSize": "0KB", + "filePattern": "*", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "privateDownload": false, + "fileNameTemplate": "{{fileName}}", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "ezf5oum", + "key": "orgbook", + "data": { + "url": "https://orgbook.gov.bc.ca/api/v3/search/autocomplete", + "json": "", + "custom": "", + "values": [], + "resource": "" + }, + "type": "orgbook", + "input": true, + "label": "Registered Business Name", + "limit": 100, + "filter": "latest=true&inactive=false&revoked=false", + "hidden": false, + "idPath": "id", + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dataSrc": "url", + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "dataType": "string", + "disabled": false, + "lazyLoad": true, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "template": "{{ item.value }}", + "validate": { + "custom": "", + "select": false, + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "indexeddb": { + "filter": {} + }, + "minSearch": 3, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "fuseOptions": { + "include": "score", + "threshold": 0.3 + }, + "ignoreCache": false, + "placeholder": "Start typing to search BC Registered Businesses database", + "searchField": "q", + "authenticate": false, + "defaultValue": null, + "disableLimit": false, + "selectFields": "", + "selectValues": "results", + "customOptions": { + "duplicateItemsAllowed": false + }, + "dataGridLabel": false, + "labelPosition": "top", + "readOnlyValue": true, + "searchEnabled": true, + "showCharCount": false, + "showWordCount": false, + "uniqueOptions": false, + "valueProperty": "value", + "calculateValue": "", + "clearOnRefresh": false, + "useExactSearch": false, + "calculateServer": false, + "searchThreshold": 3, + "selectThreshold": 0.3, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + } + ], + "errorLabel": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": false, + "collapsible": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "ez5c88", + "key": "submit", + "size": "md", + "type": "button", + "block": false, + "input": true, + "label": "Submit", + "theme": "primary", + "action": "submit", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "leftIcon": "", + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "rightIcon": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": true, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "disableOnInvalid": true, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + } + ] +} diff --git a/frontend/app/tests/fixtures/form/fields/extractedFields.json b/frontend/app/tests/fixtures/form/fields/extractedFields.json new file mode 100644 index 0000000..161cd91 --- /dev/null +++ b/frontend/app/tests/fixtures/form/fields/extractedFields.json @@ -0,0 +1,1884 @@ +[ + "contactName", + "orgbook", + "phoneNumber", + "companyName", + "email", + "mailingAddress", + "plantNameAndAddress1", + "mailingAddress1", + "plantNameAndAddress", + "licenceSOrOtherIdNumbersPleaseUseAddAnotherForEachOne", + "areYouSubmittingANilReport", + "lbs00000", + "value00000", + "Vlbs00000", + "lbs02006", + "value02006", + "lVlbs02006", + "lbs01008", + "value01008", + "Vlbs01008", + "lbs08003", + "value08003", + "Vlbs08003", + "lbs03004", + "value03004", + "Vlbs03004", + "lbs28001", + "value28001", + "Vlbs28001", + "lbs09001", + "value09001", + "lbs798", + "lbs31005", + "value31005", + "Vlbs31005", + "lbs49007", + "value49007", + "Vlbs49007", + "lbs04002", + "value04002", + "Vlbs04002", + "lbs05009", + "value05009", + "Vlbs05009", + "lbs23002", + "value23002", + "Vlbs23002", + "pleaseSpecify", + "lbs38000", + "value38000", + "Vlbs38000", + "lbs06007", + "value06007", + "Vlbs06007", + "lbs07005", + "value07005", + "Vlbs07005", + "lbs17004", + "value17004", + "Vlbs17004", + "specifySpecialtySmokedProducts", + "lbs34009", + "value34009", + "Vlbs34009", + "lbs15008", + "value15008", + "Vlbs15008", + "lbs16006", + "value16006", + "Vlbs16006", + "lbs36004", + "value36004", + "Vlbs36004", + "lbs10009", + "value10009", + "VCase10009", + "lbs20008", + "value20008", + "Vlbs20008", + "lbs30007", + "value30007", + "Vlbs30007", + "lbs00018", + "value00018", + "Vlbs00018", + "lbs02014", + "value02014", + "Vlbs02014", + "lbs01016", + "value01016", + "Vlbs01016", + "lbs08011", + "value08011", + "Vlbs08011", + "lbs03012", + "value03012", + "Vlbs03012", + "lbs28019", + "value28019", + "Vlbs28019", + "lbs09019", + "value09019", + "Vlbs09019", + "lbs31013", + "value31013", + "Vlbs31013", + "lbs49015", + "value49015", + "Vlbs49015", + "lbs04010", + "value04010", + "Vlbs04010", + "lbs05017", + "value05017", + "Vlbs05017", + "lbs23010", + "value23010", + "Vlbs23010", + "pleaseSpecifyTypeOfPortionParkOfSpecialtyProduct", + "lbs38018", + "value38018", + "Vlbs38018", + "lbs06015", + "value06015", + "Vlbs06015", + "lbs07013", + "value07013", + "Vlbs07013", + "lbs17012", + "value17012", + "Vlbs17012", + "pleaseSpecifySpecialtySmokedProducts", + "lbs34017", + "value34017", + "Vlbs34017", + "lbs15016", + "value15016", + "Vlbs15016", + "lbs16014", + "value16014", + "Vlbs16014", + "lbs36012", + "value36012", + "Vlbs36012", + "lbs10017", + "value10017", + "Vlbs10017", + "lbs20016", + "value20016", + "Vlbs20016", + "lbs30015", + "value30015", + "Vlbs30015", + "lbs00026", + "value00026", + "Vlbs00026", + "lbs02022", + "value02022", + "Vlbs02022", + "lbs01024", + "value01024", + "Vlbs01024", + "lbs08029", + "value08029", + "Vlbs08029", + "lbs03020", + "value03020", + "Vlbs03020", + "lbs28027", + "value28027", + "Vlbs28027", + "lbs09027", + "value09027", + "Vlbs09027", + "lbs31021", + "value31021", + "Vlbs31021", + "lbs49023", + "value49023", + "Vlbs49023", + "lbs04028", + "value04028", + "Vlbs04028", + "lbs05025", + "value05025", + "Vlbs05025", + "lbs23028", + "value23028", + "Vlbs23028", + "textSpecifyPortionParkOrSpecialtyProduct", + "lbs38026", + "value38026", + "Vlbs38026", + "lbs06023", + "value06023", + "Vlbs06023", + "lbs07021", + "value07021", + "Vlbs07021", + "lbs17020", + "value17020", + "Vlbs17020", + "pleaseSpecifySpecialtySmokedProduct", + "lbs34025", + "value34025", + "Vlbs34025", + "lbs15024", + "value15024", + "Vlbs15024", + "lbs16022", + "value16022", + "Vlbs16022", + "lbs36020", + "value36020", + "Vlbs36020", + "lbs10025", + "value10025", + "Vlbs10025", + "lbs20024", + "value20024", + "Vlbs20024", + "lbs30023", + "value30023", + "Vlbs30023", + "lbs00034", + "value00034", + "Vlbs00034", + "lbs02030", + "value02030", + "Vlbs02030", + "lbs01032", + "value01032", + "Vlbs01032", + "lbs08037", + "value08037", + "Vlbs08037", + "lbs03038", + "value03038", + "Vlbs03038", + "lbs28035", + "value28035", + "Vlbs28035", + "lbs09035", + "value09035", + "Vlbs09035", + "lbs31039", + "value31039", + "Vlbs31039", + "lbs49031", + "value49031", + "Vlbs49031", + "lbs04036", + "value04036", + "Vlbs04036", + "lbs05033", + "value05033", + "Vlbs05033", + "lbs23036", + "value23036", + "Vlbs23036", + "pleaseListAllThePortionPackProducts", + "lbs38034", + "value38034", + "Vlbs38034", + "lbs06031", + "value06031", + "Vlbs06031", + "lbs07039", + "value07039", + "Vlbs07039", + "lbs17038", + "value17038", + "Vlbs17038", + "pleaseListAllSpecialtySmokedProducts", + "lbs34033", + "value34033", + "Vlbs34033", + "lbs15032", + "value15032", + "Vlbs15032", + "lbs16030", + "value16030", + "Vlbs16030", + "lbs36038", + "value36038", + "Vlbs36038", + "lbs10033", + "value10033", + "Vlbs10033", + "lbs20032", + "value20032", + "Vlbs20032", + "lbs30031", + "value30031", + "Vlbs30031", + "lbs00042", + "value00042", + "vlbs00042", + "lbs02048", + "value02048", + "vlbs02048", + "lbs01040", + "value01040", + "vlbs01040", + "lbs08045", + "value08045", + "vlbs08045", + "lbs03046", + "value03046", + "vlbs03046", + "lbs28043", + "value28043", + "vlbs28043", + "lbs09043", + "value09043", + "vlbs09043", + "lbs31047", + "value31047", + "vlbs31047", + "lbs49049", + "value49049", + "vlbs49049", + "lbs04044", + "value04044", + "vlbs04044", + "lbs05041", + "value05041", + "vlbs05041", + "lbs23044", + "value23044", + "vlbs23044", + "pleaseListAllPortionPackProducts", + "lbs38042", + "value38042", + "vlbs38042", + "lbs06049", + "value06049", + "vlbs06049", + "lbs07047", + "value07047", + "vlbs07047", + "lbs17046", + "value17046", + "vlbs17046", + "pleaseListSpecialtySmokedProducts", + "lbs34041", + "value34041", + "vlbs34041", + "lbs15040", + "value15040", + "vlbs15040", + "lbs16048", + "value16048", + "vlbs16048", + "lbs36046", + "value36046", + "vlbs36046", + "lbs10041", + "value10041", + "vlbs10041", + "lbs20040", + "value20040", + "vlbs20040", + "lbs30049", + "value30049", + "vlbs30049", + "lbs00059", + "value00059", + "vlbs00059", + "lbs02055", + "value02055", + "vlbs02055", + "lbs01057", + "value01057", + "vlbs01057", + "lbs08052", + "value08052", + "vlbs08052", + "lbs03053", + "value03053", + "vlbs3053", + "lbs28050", + "value28050", + "vlbs28050", + "lbs09050", + "value09050", + "vlbs09050", + "lbs31054", + "value31054", + "vlbs31054", + "lbs49056", + "value49056", + "vlbs49056", + "lbs04051", + "value04051", + "vlbs04051", + "lbs05058", + "value05058", + "vlbs05058", + "lbs23051", + "value23051", + "vlbs23051", + "pleaseListAllPortionPackProducts1", + "lbs38059", + "value38059", + "vlbs38059", + "lbs06056", + "value06056", + "vlbs06056", + "lbs07054", + "value07054", + "vlbs07054", + "lbs17053", + "value17053", + "vlbs17053", + "pleaseListAllSpecialtySmokedProducts1", + "lbs34058", + "value34058", + "vlbs34058", + "lbs15057", + "value15057", + "vlbs15057", + "lbs16055", + "value16055", + "vlbs16055", + "lbs36053", + "value36053", + "vlbs36053", + "lbs10058", + "value10058", + "Vlbs10058", + "lbs20057", + "value20057", + "Vlbs20057", + "lbs30056", + "value30056", + "Vlbs30056", + "lbs00067", + "value00067", + "Vlbs00067", + "lbs02063", + "value02063", + "Vlbs02063", + "lbs01065", + "value01065", + "Vlbs01065", + "lbs08060", + "value08060", + "Vlbs08060", + "lbs03061", + "value03061", + "Vlbs03061", + "lbs28068", + "value28068", + "Vlbs28068", + "lbs09068", + "value09068", + "Vlbs09068", + "lbs31062", + "value31062", + "Vlbs31062", + "lbs49064", + "value49064", + "Vlbs49064", + "lbs04069", + "value04069", + "Vlbs04069", + "lbs05066", + "value05066", + "Vlbs05066", + "lbs23069", + "value23069", + "Vlbs23069", + "pleaseListAllPortionPackProducts2", + "lbs38067", + "value38067", + "Vlbs38067", + "lbs06064", + "value06064", + "Vlbs06064", + "lbs07062", + "value07062", + "Vlbs07062", + "lbs17061", + "value17061", + "Vlbs17061", + "pleaseListAllSpecialtySmokedProducts2", + "lbs34066", + "value34066", + "Vlbs34066", + "lbs15065", + "value15065", + "Vlbs15065", + "lbs16063", + "value16063", + "Vlbs16063", + "lbs36061", + "value36061", + "Vlbs36061", + "lbs10066", + "value10066", + "Vlbs10066", + "lbs20065", + "value20065", + "Vlbs20065", + "lbs30064", + "value30064", + "Vlbs30064", + "lbs00075", + "value00075", + "Vlbs00075", + "lbs02071", + "value02071", + "Vlbs02071", + "lbs01073", + "value01073", + "Vlbs01073", + "lbs08078", + "value08078", + "Vlbs08078", + "lbs03079", + "value03079", + "Vlbs03079", + "lbs28076", + "value28076", + "Vlbs28076", + "lbs09076", + "value09076", + "Vlbs09076", + "lbs31070", + "value31070", + "Vlbs31070", + "lbs49072", + "value49072", + "Vlbs49072", + "lbs04077", + "value04077", + "Vlbs04077", + "lbs05074", + "value05074", + "Vlbs05074", + "lbs23077", + "value23077", + "Vlbs23077", + "pleaseListAllPortionPackProducts3", + "lbs38075", + "value38075", + "Vlbs38075", + "lbs06072", + "value06072", + "Vlbs06072", + "lbs07070", + "value07070", + "Vlbs07070", + "lbs17079", + "value17079", + "Vlbs17079", + "pleaseListAllSpecialtySmokedProducts3", + "lbs34074", + "value34074", + "Vlbs34074", + "lbs15073", + "value15073", + "Vlbs15073", + "lbs16071", + "value16071", + "Vlbs16071", + "lbs36079", + "value36079", + "Vlbs36079", + "lbs10074", + "value10074", + "Vlbs10074", + "lbs20073", + "value20073", + "Vlbs20073", + "lbs30072", + "value30072", + "Vlbs30072", + "lbs00083", + "value00083", + "Vlbs00083", + "lbs02089", + "value02089", + "Vlbs02089", + "lbs01081", + "value01081", + "Vlbs01081", + "lbs08086", + "value08086", + "Vlbs08086", + "lbs03087", + "value03087", + "Vlbs03087", + "lbs28084", + "value28084", + "Vlbs28084", + "lbs09084", + "value09084", + "Vlbs09084", + "lbs31088", + "value31088", + "Vlbs31088", + "lbs49080", + "value49080", + "Vlbs49080", + "lbs04085", + "value04085", + "Vlbs04085", + "lbs05082", + "value05082", + "Vlbs05082", + "lbs23085", + "value23085", + "Vlbs23085", + "pleaseListAllPortionPackProducts4", + "lbs38083", + "value38083", + "Vlbs38083", + "lbs06080", + "value06080", + "Vlbs06080", + "lbs07088", + "value07088", + "Vlbs07088", + "lbs17087", + "value17087", + "Vlbs17087", + "pleaseListAllSpecialtySmokedProducts4", + "lbs34082", + "value34082", + "Vlbs34082", + "lbs15081", + "value15081", + "Vlbs15081", + "lbs16089", + "value16089", + "Vlbs16089", + "lbs38087", + "value38087", + "Vlbs38087", + "lbs10082", + "value10082", + "Vlbs10082", + "lbs20081", + "value20081", + "Vlbs20081", + "lbs30080", + "value30080", + "Vlbs30080", + "lbs00091", + "value00091", + "Vlbs00091", + "lbs02097", + "value02097", + "Vlbs02097", + "lbs01099", + "value01099", + "Vlbs01099", + "lbs08094", + "value08094", + "Vlbs08094", + "lbs03095", + "value03095", + "Vlbs03095", + "lbs28092", + "value28092", + "Vlbs28092", + "lbs09092", + "value09092", + "Vlbs09092", + "lbs31096", + "value31096", + "Vlbs31096", + "lbs49098", + "value49098", + "Vlbs49098", + "lbs04093", + "value04093", + "Vlbs04093", + "lbs05090", + "value05090", + "Vlbs05090", + "lbs23093", + "value23093", + "Vlbs23093", + "pleaseListAllPortionPackProducts5", + "lbs38091", + "value38091", + "Vlbs38091", + "lbs06098", + "value06098", + "Vlbs06098", + "lbs07096", + "value07096", + "Vlbs07096", + "lbs17095", + "value17095", + "Vlbs17095", + "pleaseListAllSpecialtySmokedProducts5", + "lbs34090", + "value34090", + "Vlbs34090", + "lbs15099", + "value15099", + "Vlbs15099", + "lbs16097", + "value16097", + "Vlbs16097", + "lbs36095", + "value36095", + "Vlbs36095", + "lbs10090", + "value10090", + "Vlbs10090", + "lbs20099", + "value20099", + "Vlbs20099", + "lbs30098", + "value30098", + "Vlbs30098", + "lbs14027", + "value14027", + "vlbs14027", + "lbs14035", + "value14035", + "vlbs14035", + "lbs13003", + "value13003", + "vlbs13003", + "pleaseToWhomItWasSold", + "lbs13011", + "value13011", + "vlbs13011", + "lbs13029", + "value13029", + "vlbs13029", + "lbs13037", + "value13037", + "vlbs13037", + "lbs13045", + "value13045", + "vlbs13045", + "lbs13052", + "value13052", + "vlbs13052", + "lbs13060", + "value13060", + "vlbs13060", + "lbs14043", + "value14043", + "vlbs14043", + "pleaseListAllOtherProducts7", + "lbs25098", + "value25098", + "vlbs25098", + "lbs25007", + "value25007", + "vlbs25007", + "lbs25015", + "value25015", + "vlbs25015", + "lbs25023", + "value25023", + "vlbs25023", + "lbs25031", + "value25031", + "vlbs25031", + "lbs25049", + "value25049", + "vlbs25049", + "lbs25056", + "value25056", + "vlbs25056", + "lbs25114", + "value25114", + "vlbs25114", + "lbs25064", + "value25064", + "vlbs25064", + "lbs25080", + "value25080", + "vlbs25080", + "lbs25072", + "value25072", + "vlbs25072", + "pleaseListAllOtherHalibutProducts", + "lbs32078", + "value32078", + "vlbs32078", + "lbs32003", + "value32003", + "vlbs32003", + "lbs32011", + "value32011", + "vlbs32011", + "lbs32029", + "value32029", + "vlbs32029", + "lbs32037", + "value32037", + "vlbs32037", + "lbs32045", + "value32045", + "vlbs32045", + "lbs32052", + "value32052", + "vlbs32052", + "lbs32060", + "value32060", + "vlbs32060", + "pleaseListAllOtherDoverSoleProducts", + "lbs33076", + "value33076", + "vlbs33076", + "lbs33001", + "value33001", + "vlbs33001", + "lbs33019", + "value33019", + "vlbs33019", + "lbs33027", + "value33027", + "vlbs33027", + "lbs33035", + "value33035", + "vlbs33035", + "lbs33043", + "value33043", + "vlbs33043", + "lbs33050", + "value33050", + "vlbs33050", + "lbs33068", + "value33068", + "vlbs33068", + "pleaseListAllOtherEnglishSoleProducts", + "lbs29009", + "value29009", + "vlbs29009", + "lbs29017", + "value29017", + "vlbs29017", + "lbs29025", + "value29025", + "vlbs29025", + "lbs29033", + "value29033", + "vlbs29033", + "lbs29041", + "value29041", + "vlbs29041", + "lbs29066", + "value29066", + "vlbs29066", + "pleaseListAllOtherPetraleSoleProducts", + "lbs35071", + "value35071", + "vlbs35071", + "lbs35006", + "value35006", + "vlbs35006", + "lbs35014", + "value35014", + "vlbs35014", + "lbs35022", + "value35022", + "vlbs35022", + "lbs35030", + "value35030", + "vlbs35030", + "lbs35048", + "value35048", + "vlbs35048", + "lbs35055", + "value35055", + "vlbs35055", + "lbs35063", + "value35063", + "vlbs35063", + "pleaseListAllOtherRockSoleProducts", + "lbs86074", + "value86074", + "vlbs86074", + "lbs86009", + "value86009", + "vlbs86009", + "lbs86017", + "value86017", + "vlbs86017", + "lbs86025", + "value86025", + "vlbs86025", + "lbs86033", + "value86033", + "vlbs86033", + "lbs86041", + "value86041", + "vlbs86041", + "lbs86058", + "value86058", + "vlbs86058", + "lbs86066", + "value86066", + "vlbs86066", + "pleaseListAllOtherRexSoleProducts", + "otherSoleSpiecesPleaseSpecifyByChoosingAddAnotherForEachOne", + "lbs37077", + "value37077", + "vlbs37077", + "lbs37002", + "value37002", + "vlbs37002", + "lbs37010", + "value37010", + "vlbs37010", + "lbs37028", + "value37028", + "vlbs37028", + "lbs37036", + "value37036", + "vlbs37036", + "lbs37044", + "value37044", + "vlbs37044", + "lbs37051", + "value37051", + "vlbs37051", + "lbs37069", + "value37069", + "vlbs37069", + "pleaseListAllOtherProducts8", + "lbs41103", + "value41103", + "vlbs41103", + "lbs41004", + "value41004", + "vlbs41004", + "lbs41095", + "value41095", + "vlbs41095", + "lbs41012", + "value41012", + "vlbs41012", + "lbs41020", + "value41020", + "vlbs41020", + "lbs41038", + "value41038", + "vlbs41038", + "lbs41046", + "value41046", + "vlbs41046", + "lbs41053", + "value41053", + "vlbs41053", + "lbs41061", + "value41061", + "vlbs41061", + "lbs41079", + "value41079", + "vlbs41079", + "lbs41087", + "value41087", + "vlbs41087", + "pleaseListAllOtherLingcodProducts", + "lbs42002", + "value42002", + "vlbs42002", + "lbs42093", + "value42093", + "vlbs42093", + "lbs42010", + "value42010", + "vlbs42010", + "lbs42028", + "value42028", + "vlbs42028", + "lbs42036", + "value42036", + "vlbs42036", + "lbs42044", + "value42044", + "vlbs42044", + "lbs42085", + "value42085", + "vlbs42085", + "lbs42051", + "value42051", + "vlbs42051", + "lbs42069", + "value42069", + "vlbs42069", + "lbs42077", + "value42077", + "vlbs42077", + "pleaseListAllOtherGreyCodProducts", + "lbs43109", + "value43109", + "vlbs43109", + "lbs43000", + "value43000", + "vlbs43000", + "lbs43091", + "value43091", + "vlbs43091", + "lbs43018", + "value43018", + "vlbs43018", + "lbs43026", + "value43026", + "vlbs43026", + "lbs43034", + "value43034", + "vlbs43034", + "lbs43042", + "value43042", + "vlbs43042", + "lbs43059", + "value43059", + "vlbs43059", + "lbs43067", + "value43067", + "vlbs43067", + "lbs43117", + "value43117", + "vlbs43117", + "lbs43075", + "value43075", + "vlbs43075", + "lbs43083", + "value43083", + "vlbs43083", + "pleaseListOtherProducts", + "lbs44073", + "value44073", + "Vlbs44073", + "lbs44008", + "value44008", + "Vlbs44008", + "lbs44099", + "value44099", + "Vlbs44099", + "lbs44016", + "value44016", + "Vlbs44016", + "lbs44024", + "value44024", + "Vlbs44024", + "lbs44032", + "value44032", + "Vlbs44032", + "lbs44040", + "value44040", + "Vlbs44040", + "lbs44057", + "value44057", + "Vlbs44057", + "lbs44065", + "value44065", + "Vlbs44065", + "pleaseListAllOtherProducts1", + "lbs40071", + "value40071", + "Vlbs40071", + "lbs40006", + "value40006", + "Vlbs40006", + "lbs40097", + "value40097", + "Vlbs40097", + "lbs40014", + "value40014", + "Vlbs40014", + "lbs40022", + "value40022", + "Vlbs40022", + "lbs40030", + "value40030", + "Vlbs40030", + "lbs40048", + "value40048", + "Vlbs40048", + "lbs40055", + "value40055", + "Vlbs40055", + "lbs40063", + "value40063", + "Vlbs40063", + "pleaseListAllOtherProducts2", + "otherRockfishSpeciesPleaseUseAddAnotherForEachOne", + "lbs47076", + "value47076", + "vlbs47076", + "lbs47001", + "value47001", + "vlbs47001", + "lbs47092", + "value47092", + "vlbs47092", + "lbs47019", + "value47019", + "vlbs47019", + "lbs47027", + "value47027", + "vlbs47027", + "lbs47035", + "value47035", + "vlbs47035", + "lbs47043", + "value47043", + "vlbs47043", + "lbs47050", + "value47050", + "vlbs47050", + "lbs47068", + "value47068", + "vlbs47068", + "pleaseListAllOtherRockfishProducts", + "lbs67074", + "value67074", + "vlbs67074", + "lbs67009", + "value67009", + "vlbs67009", + "lbs67090", + "value67090", + "vlbs67090", + "lbs67017", + "value67017", + "vlbs67017", + "lbs67025", + "value67025", + "vlbs67025", + "lbs67033", + "value67033", + "vlbs67033", + "lbs67041", + "value67041", + "vlbs67041", + "lbs67058", + "value67058", + "vlbs67058", + "pleaseListAllTheOtherDogfishProducts", + "lbs54074", + "value54074", + "vlbs54074", + "lbs54007", + "value54007", + "vlbs54007", + "lbs54015", + "value54015", + "vlbs54015", + "lbs54023", + "value54023", + "vlbs54023", + "lbs54031", + "value54031", + "vlbs54031", + "lbs54049", + "value54049", + "vlbs54049", + "lbs54056", + "value54056", + "vlbs54056", + "lbs54064", + "value54064", + "vlbs54064", + "pleaseListAllOtherFlounderProducts", + "lbs68007", + "value68007", + "Vlbs68008", + "lbs68015", + "value68015", + "Vlbs68016", + "lbs68023", + "value68023", + "Vlbs68024", + "lbs68031", + "value68031", + "Vlbs68032", + "pleaseListAllOtherHagfishProducts", + "lbs63008", + "value63008", + "vlbs63008", + "lbs63016", + "value63016", + "vlbs63016", + "lbs63073", + "value63073", + "vlbs63073", + "lbs63024", + "value63024", + "vlbs63024", + "lbs63032", + "value63032", + "vlbs63032", + "lbs63099", + "value63099", + "vlbs63099", + "lbs63040", + "value63040", + "vlbs63040", + "lbs63065", + "value63065", + "vlbs63065", + "lbs63081", + "value63081", + "vlbs63081", + "lbs63057", + "value63057", + "vlbs63057", + "pleaseListAllOtherHakeProducts", + "lbs64006", + "value64006", + "vlbs64006", + "lbs64097", + "value64097", + "vlbs64097", + "lbs64014", + "value64014", + "vlbs64014", + "lbs64063", + "value64063", + "vlbs64063", + "lbs64022", + "value64022", + "vlbs64022", + "lbs64030", + "value64030", + "vlbs64030", + "lbs64048", + "value64048", + "vlbs64048", + "lbs64055", + "value64055", + "vlbs64055", + "pleaseListAllOtherProducts", + "lbs65003", + "value65003", + "vlbs65003", + "lbs65094", + "value65094", + "vlbs65094", + "lbs65011", + "value65011", + "vlbs65011", + "lbs65029", + "value65029", + "vlbs65029", + "lbs65037", + "value65037", + "vlbs65037", + "lbs65045", + "value65045", + "vlbs65045", + "lbs65052", + "value65052", + "vlbs65052", + "lbs65060", + "value65060", + "vlbs65060", + "lbs65078", + "value65078", + "vlbs65078", + "pleaseListAllOtherPollockProducts", + "lbs55079", + "value55079", + "vlbs55079", + "lbs55004", + "value55004", + "vlbs55004", + "lbs55095", + "value55095", + "vlbs55095", + "lbs55012", + "value55012", + "vlbs55012", + "lbs55053", + "value55053", + "vlbs55053", + "lbs55020", + "value55020", + "vlbs55020", + "lbs55061", + "value55061", + "vlbs55061", + "lbs55038", + "value55038", + "vlbs55038", + "lbs55046", + "value55046", + "vlbs55046", + "pleaseListAllOtherSkateProducts", + "specifyOtherGroundfishSpecies", + "lbs66076", + "value66076", + "Vlbs66076", + "lbs66001", + "value66001", + "Vlbs66001", + "lbs66092", + "value66092", + "Vlbs66092", + "lbs66019", + "value66019", + "Vlbs66019", + "lbs66027", + "value66027", + "Vlbs66027", + "lbs66035", + "value66035", + "Vlbs66035", + "lbs66043", + "value66043", + "Vlbs66043", + "lbs66050", + "value66050", + "Vlbs66050", + "lbs66084", + "value66084", + "Vlbs66084", + "lbs66068", + "value66068", + "Vlbs66068", + "pleaseListAnyOtherProducts", + "lbs96008", + "value96008", + "vlbs96008", + "lbs96016", + "value96016", + "vlbs96016", + "lbs96024", + "value96024", + "vlbs96024", + "lbs96032", + "value96032", + "vlbs96032", + "lbs96040", + "value96040", + "vlbs96040", + "lbs90001", + "value90001", + "Vlbs90001", + "lbs90019", + "value90019", + "Vlbs90019", + "lbs90027", + "value90027", + "Vlbs90027", + "lbs90043", + "value90043", + "Vlbs90043", + "lbs90050", + "value90050", + "Vlbs90050", + "lbs90068", + "value90068", + "Vlbs90068", + "lbs90084", + "value90084", + "Vlbs90084", + "lbs91009", + "value91009", + "Vlbs91009", + "lbs91017", + "value91017", + "Vlbs91017", + "lbs91025", + "value91025", + "Vlbs91025", + "lbs91033", + "value91033", + "Vlbs91033", + "lbs91041", + "value91041", + "Vlbs91041", + "lbs94037", + "value94037", + "Vlbs94037", + "lbs94045", + "value94045", + "Vlbs94045", + "lbs94052", + "value94052", + "Vlbs94052", + "lbs94060", + "value94060", + "Vlbs94060", + "lbs94078", + "value94078", + "Vlbs94078", + "lbs94086", + "value94086", + "Vlbs94086", + "lbs94094", + "value94094", + "Vlbs94094", + "lbs89003", + "value89003", + "Vlbs89003", + "lbs89011", + "value89011", + "Vlbs89011", + "lbs95018", + "value95018", + "Vlbs95018", + "lbs95026", + "value95026", + "Vlbs95026", + "lbs95034", + "value95034", + "Vlbs95034", + "pleaseListAllOtherHerringProducts", + "lbs56002", + "value56002", + "vlbs56002", + "lbs56010", + "value56010", + "vlbs56010", + "lbs56028", + "value56028", + "vlbs56028", + "lbs56036", + "value56036", + "vlbs56036", + "lbs56044", + "value56044", + "vlbs56044", + "pleaseAllOtherEulachonProducts", + "lbs59006", + "value59006", + "vlbs59006", + "lbs59014", + "value59014", + "vlbs59014", + "lbs59022", + "value59022", + "vlbs59022", + "lbs59030", + "value59030", + "vlbs59030", + "lbs59048", + "value59048", + "vlbs59048", + "lbs59097", + "value59097", + "vlbs59097", + "pleaseListAllOtherMackeralProducts", + "lbs51003", + "value51003", + "vlbs51003", + "lbs51011", + "value51011", + "vlbs51011", + "lbs51029", + "value51029", + "vlbs51029", + "lbs51037", + "value51037", + "vlbs51037", + "lbs51094", + "value51094", + "vlbs51094", + "pleaseListAllOtherProducts3", + "lbs62000", + "value62000", + "vlbs62000", + "lbs62018", + "value62018", + "vlbs62018", + "lbs62026", + "value62026", + "vlbs62026", + "lbs62034", + "value62034", + "vlbs62034", + "lbs62042", + "value62042", + "vlbs62042", + "pleaseListAllOtherSmeltProducts", + "lbs57000", + "value57000", + "vlbs57000", + "lbs57018", + "value57018", + "vlbs57018", + "lbs57026", + "value57026", + "vlbs57026", + "lbs57034", + "value57034", + "vlbs57034", + "pleaseListAllOtherSturgeonProducts", + "lbs60004", + "value60004", + "vlbs60004", + "lbs60012", + "value60012", + "vlbs60012", + "lbs60053", + "value60053", + "vlbs60053", + "lbs60020", + "value60020", + "vlbs60020", + "lbs60046", + "value60046", + "vlbs60046", + "lbs60038", + "value60038", + "vlbs60038", + "pleaseListAllOtherTunaProducts", + "pleaseEnterAllOtherFishSpecies", + "lbs48074", + "value48074", + "vlbs48074", + "lbs48009", + "value48009", + "vlbs48009", + "lbs48017", + "value48017", + "vlbs48017", + "lbs48025", + "value48025", + "vlbs48025", + "lbs48033", + "value48033", + "vlbs48033", + "lbs48041", + "value48041", + "vlbs48041", + "leaseListAllOtherProducts", + "lbs73007", + "value73007", + "Vlbs73007", + "lbs73015", + "value73015", + "Vlbs73015", + "lbs73023", + "value73023", + "Vlbs73023", + "lbs73031", + "value73031", + "Vlbs73031", + "lbs73049", + "value73049", + "Vlbs73049", + "lbs73056", + "value73056", + "Vlbs73056", + "pleaseListAllOtherButterClamProducts", + "lbs80804", + "value80804", + "vlbs80804", + "lbs80812", + "value80812", + "vlbs80812", + "lbs80820", + "value80820", + "vlbs80820", + "lbs80838", + "value80838", + "vlbs80838", + "lbs80846", + "value80846", + "vlbs80846", + "lbs80853", + "value80853", + "vlbs80853", + "pleaseListAllOtherGeoduckProducts", + "lbs81000", + "value81000", + "vlbs81000", + "lbs81018", + "value81018", + "vlbs81018", + "lbs81026", + "value81026", + "vlbs81026", + "lbs81034", + "value81034", + "vlbs81034", + "lbs81042", + "value81042", + "vlbs81042", + "pleaseListAllOtherHorseClamProducts", + "lbs74872", + "value74872", + "vlbs74872", + "lbs74807", + "value74807", + "vlbs74807", + "lbs74815", + "value74815", + "vlbs74815", + "lbs74823", + "value74823", + "vlbs74823", + "lbs74849", + "value74849", + "vlbs74849", + "lbs74831", + "value74831", + "vlbs74831", + "pleaseListAllOtherProducts4", + "lbs82800", + "value82800", + "vlbs82800", + "lbs82818", + "value82818", + "vlbs82818", + "lbs82826", + "value82826", + "vlbs82826", + "pleaseListAllOtherMusselProducts", + "lbs79871", + "value79871", + "vlbs79871", + "lbs79806", + "value79806", + "vlbs78806", + "lbs79814", + "value79814", + "vlbs79814", + "lbs79822", + "value79822", + "vlbs79822", + "lbs79830", + "value79830", + "vlbs79830", + "pleaseListAllOtherScallopProdcts", + "lbs83006", + "value83006", + "vlbs83006", + "lbs83097", + "value83097", + "vlbs83097", + "lbs83014", + "value83014", + "vlbs83014", + "pleaseListAllOtherGooseneckBarnacleProducts", + "specifyTheOtherClamSpecies", + "lbs76877", + "value76877", + "Vlbs76877", + "lbs76802", + "value76802", + "Vlbs76802", + "lbs76810", + "value76810", + "Vlbs76810", + "lbs76828", + "value76828", + "Vlbs76828", + "lbs76836", + "value76836", + "Vlbs76836", + "lbs76844", + "value76844", + "Vlbs76844", + "lbs76851", + "value76851", + "Vlbs76851", + "lbs76869", + "value76869", + "Vlbs76869", + "pleaseListAllOtherProducts5", + "lbs70060", + "value70060", + "vlbs70060", + "lbs70003", + "value70003", + "vlbs70003", + "lbs70011", + "value70011", + "vlbs70011", + "lbs70029", + "value70029", + "vlbs70029", + "lbs70078", + "value70078", + "vlbs70078", + "lbs70037", + "value70037", + "vlbs70037", + "lbs70045", + "value70045", + "vlbs70045", + "lbs70052", + "value70052", + "vlbs70052", + "pleaseListAllOtherPrawnProducts", + "lbs71068", + "value71068", + "vlbs71068", + "lbs71001", + "value71001", + "vlbs71001", + "lbs71019", + "value71019", + "vlbs71019", + "lbs71076", + "value71076", + "vlbs71076", + "lbs71027", + "value71027", + "vlbs71027", + "lbs71035", + "value71035", + "vlbs71035", + "lbs71043", + "value71043", + "vlbs71043", + "lbs71050", + "value71050", + "vlbs71050", + "pleaseListAllOtherShrimpProducts", + "lbs78071", + "value78071", + "vlbs78071", + "lbs78006", + "value78006", + "vlbs78006", + "lbs78014", + "value78014", + "vlbs78014", + "lbs78022", + "value78022", + "vlbs78022", + "lbs78030", + "value78030", + "vlbs78030", + "lbs78048", + "value78048", + "vlbs78048", + "lbs78055", + "value78055", + "vlbs78055", + "lbs78063", + "value78063", + "vlbs78063", + "pleaseListAllOverCrabProducts", + "lbs72009", + "value72009", + "vlbs72009", + "lbs72017", + "value72017", + "vlbs72017", + "lbs72025", + "value72025", + "vlbs72025", + "lbs72033", + "value72033", + "vlbs72033", + "pleaseListAllOtherGreenSeaUrchinProducts", + "lbs69807", + "value69807", + "vlbs69807", + "lbs69815", + "value69815", + "vlbs69815", + "lbs69823", + "value69823", + "vlbs69823", + "lbs69849", + "value69849", + "vlbs69849", + "lbs69831", + "value69831", + "vlbs69831", + "pleaseListAllOtherRedSeaUrchinProducts", + "lbs88807", + "value88807", + "vlbs88807", + "lbs88815", + "value88815", + "vlbs88815", + "lbs88823", + "value88823", + "vlbs88823", + "lbs88831", + "value88831", + "vlbs88831", + "pleaseListAllOtherSeaCucumberProducts", + "lbs61077", + "value61077", + "vlbs61077", + "lbs61002", + "value61002", + "vlbs61002", + "lbs61010", + "value61010", + "vlbs61010", + "lbs61028", + "value61028", + "vlbs61028", + "lbs61036", + "value61036", + "vlbs61036", + "pleaseListAllOtherOctopusProducts", + "lbs52001", + "value52001", + "vlbs52001", + "lbs52019", + "value52019", + "vlbs52019", + "lbs52027", + "value52027", + "vlbs52027", + "lbs52050", + "value52050", + "vlbs52050", + "pleaseListAllOtherSquidProducts", + "pleaseSpecifyAllKelpSpecies", + "lbs97808", + "value97808", + "vlbs97808", + "lbs97824", + "value97824", + "vlbs97824", + "lbs97832", + "value97832", + "vlbs97832", + "pleaseListAllOtherKelpProducts", + "lbs98806", + "value98806", + "vlbs98806", + "lbs98814", + "value98814", + "vlbs98814", + "lbs98822", + "value98822", + "vlbs98822", + "pleaseListAllOtherSeaAspasgusProducts", + "specifyAllOtherSpeciesOfSeaweed", + "lbs99804", + "value99804", + "vlbs99804", + "lbs99820", + "value99820", + "vlbs99820", + "lbs99838", + "value99838", + "vlbs99838", + "pleaseListAllOtherProducts6", + "specifySpeciesOfPhytoplankton", + "lbs15313", + "value15313", + "vlbs15313", + "lbs15321", + "value15321", + "vlbs15321", + "lbs15339", + "value15339", + "vlbs15339", + "pleaseListAllOtherPhytoplanktonProducts", + "specifyTheSpeciesOfZooplankton", + "lbs15347", + "value15347", + "vlbs15347", + "lbs15354", + "value15354", + "vlbs15354", + "lbs15362", + "value15362", + "vlbs15362", + "pleaseListAllOtherZooplanktonProducts", + "pleaseEnterAllOtherSpecies", + "lbs84806", + "value84806", + "vlbs84806", + "lbs84814", + "value84814", + "vlbs84814", + "lbs84822", + "value84822", + "vlbs84822", + "lbs84830", + "value84830", + "vlbs84830", + "pleaseListAllOtherProducts9" +] diff --git a/frontend/app/tests/fixtures/form/kitchen_sink_form_schema_multiple_component_test.json b/frontend/app/tests/fixtures/form/kitchen_sink_form_schema_multiple_component_test.json new file mode 100644 index 0000000..5133497 --- /dev/null +++ b/frontend/app/tests/fixtures/form/kitchen_sink_form_schema_multiple_component_test.json @@ -0,0 +1,3644 @@ +{ + "type": "form", + "display": "form", + "components": [ + { + "id": "ejmxllr", + "key": "simplecontent", + "html": "

dsfsdfsdfsdfsdfsdfsdfsdfsdfsd

", + "type": "simplecontent", + "input": false, + "label": "Text/Images", + "addons": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "eegg8ee", + "key": "simplecols2", + "tree": false, + "type": "simplecols2", + "input": false, + "label": "Columns - 2", + "addons": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "columns": [ + { + "pull": 0, + "push": 0, + "size": "md", + "width": 6, + "offset": 0, + "components": [ + { + "id": "esm21q", + "key": "firstName", + "case": "", + "mask": false, + "type": "simpletextfield", + "input": true, + "label": "firstName", + "addons": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "displayMask": "", + "inputFormat": "plain", + "labelMargin": "", + "placeholder": "", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false, + "truncateMultipleSpaces": false + } + ], + "currentWidth": 6 + }, + { + "pull": 0, + "push": 0, + "size": "md", + "width": 6, + "offset": 0, + "components": [ + { + "id": "exxwpem", + "key": "lastName", + "case": "", + "mask": false, + "type": "simpletextfield", + "input": true, + "label": "lastName", + "addons": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "displayMask": "", + "inputFormat": "plain", + "labelMargin": "", + "placeholder": "", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false, + "truncateMultipleSpaces": false + } + ], + "currentWidth": 6 + } + ], + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "lazyLoad": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "autoAdjust": false, + "errorLabel": "", + "labelWidth": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": false, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "labelMargin": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "hideOnChildrenHidden": false, + "allowCalculateOverride": false + }, + { + "id": "e70bat8", + "key": "simplecols3", + "tree": false, + "type": "simplecols3", + "input": false, + "label": "Columns - 3", + "addons": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "columns": [ + { + "pull": 0, + "push": 0, + "size": "md", + "width": 4, + "offset": 0, + "components": [ + { + "id": "eqh0m9h", + "key": "schoolName", + "case": "", + "mask": false, + "type": "simpletextfield", + "input": true, + "label": "School Name", + "addons": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "displayMask": "", + "inputFormat": "plain", + "labelMargin": "", + "placeholder": "", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false, + "truncateMultipleSpaces": false + } + ], + "currentWidth": 4 + }, + { + "pull": 0, + "push": 0, + "size": "md", + "width": 4, + "offset": 0, + "components": [ + { + "id": "ef81ju", + "key": "departmentName", + "case": "", + "mask": false, + "type": "simpletextfield", + "input": true, + "label": "Department Name", + "addons": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "displayMask": "", + "inputFormat": "plain", + "labelMargin": "", + "placeholder": "", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false, + "truncateMultipleSpaces": false + } + ], + "currentWidth": 4 + }, + { + "pull": 0, + "push": 0, + "size": "md", + "width": 4, + "offset": 0, + "components": [ + { + "id": "e6n67u", + "key": "courseName", + "case": "", + "mask": false, + "type": "simpletextfield", + "input": true, + "label": "Course Name", + "addons": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "displayMask": "", + "inputFormat": "plain", + "labelMargin": "", + "placeholder": "", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false, + "truncateMultipleSpaces": false + } + ], + "currentWidth": 4 + } + ], + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "lazyLoad": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "autoAdjust": false, + "errorLabel": "", + "labelWidth": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": false, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "labelMargin": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "hideOnChildrenHidden": false, + "allowCalculateOverride": false + }, + { + "id": "emzwnh", + "key": "simplecols4", + "tree": false, + "type": "simplecols4", + "input": false, + "label": "Columns - 4", + "addons": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "columns": [ + { + "pull": 0, + "push": 0, + "size": "sm", + "width": 3, + "offset": 0, + "components": [ + { + "id": "edf36z7", + "key": "name", + "case": "", + "mask": false, + "type": "simpletextfield", + "input": true, + "label": "name", + "addons": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "displayMask": "", + "inputFormat": "plain", + "labelMargin": "", + "placeholder": "", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false, + "truncateMultipleSpaces": false + } + ], + "currentWidth": 3 + }, + { + "pull": 0, + "push": 0, + "size": "sm", + "width": 3, + "offset": 0, + "components": [ + { + "id": "ebaj3m5", + "key": "testname1", + "case": "", + "mask": false, + "type": "simpletextfield", + "input": true, + "label": "testname1", + "addons": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "displayMask": "", + "inputFormat": "plain", + "labelMargin": "", + "placeholder": "", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false, + "truncateMultipleSpaces": false + } + ], + "currentWidth": 3 + }, + { + "pull": 0, + "push": 0, + "size": "sm", + "width": 3, + "offset": 0, + "components": [ + { + "id": "e5fudfg", + "key": "testname2", + "case": "", + "mask": false, + "type": "simpletextfield", + "input": true, + "label": "testname2", + "addons": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "displayMask": "", + "inputFormat": "plain", + "labelMargin": "", + "placeholder": "", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false, + "truncateMultipleSpaces": false + } + ], + "currentWidth": 3 + }, + { + "pull": 0, + "push": 0, + "size": "sm", + "width": 3, + "offset": 0, + "components": [ + { + "id": "eng4n5v", + "key": "testname3", + "case": "", + "mask": false, + "type": "simpletextfield", + "input": true, + "label": "testname3", + "addons": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "displayMask": "", + "inputFormat": "plain", + "labelMargin": "", + "placeholder": "", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false, + "truncateMultipleSpaces": false + } + ], + "currentWidth": 3 + } + ], + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "lazyLoad": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "autoAdjust": false, + "errorLabel": "", + "labelWidth": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": false, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "labelMargin": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "hideOnChildrenHidden": false, + "allowCalculateOverride": false + }, + { + "id": "em3l3n5", + "key": "tabs", + "tree": false, + "type": "simpletabs", + "input": false, + "label": "Tabs", + "addons": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "lazyLoad": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "components": [ + { + "key": "tab1", + "label": "Tab 1", + "components": [ + { + "id": "exght3", + "key": "simplenumber", + "type": "simplenumber", + "input": true, + "label": "Number", + "addons": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "max": "", + "min": "", + "step": "any", + "custom": "", + "unique": false, + "integer": "", + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "delimiter": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "labelMargin": "", + "placeholder": "", + "decimalLimit": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "requireDecimal": false, + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "e5nmf1", + "key": "simpleemail", + "case": "", + "mask": false, + "type": "simpleemail", + "input": true, + "label": "Email", + "addons": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "kickbox": { + "enabled": false + }, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "email", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": true, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "displayMask": "", + "inputFormat": "plain", + "labelMargin": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false, + "truncateMultipleSpaces": false + } + ] + }, + { + "key": "tab2", + "label": "Tab 2", + "components": [ + { + "id": "e3ifhqd", + "key": "simpledatetime", + "type": "simpledatetime", + "input": true, + "label": "Date / Time", + "addons": [], + "format": "yyyy-MM-dd hh:mm a", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "mode": "single", + "type": "calendar", + "format": "yyyy-MM-dd", + "locale": "en", + "maxDate": null, + "minDate": null, + "time_24hr": false, + "allowInput": true, + "enableTime": false, + "noCalendar": false, + "hourIncrement": 1, + "disableWeekdays": false, + "disableWeekends": false, + "minuteIncrement": 1, + "displayInTimezone": "viewer", + "useLocaleSettings": false + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "timezone": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "allowInput": true, + "attributes": {}, + "datePicker": { + "maxDate": null, + "maxMode": "year", + "minDate": null, + "minMode": "day", + "initDate": "", + "yearRows": 4, + "showWeeks": true, + "startingDay": 0, + "yearColumns": 5, + "disableWeekdays": false, + "disableWeekends": false + }, + "enableDate": true, + "enableTime": false, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "timePicker": { + "hourStep": 1, + "arrowkeys": true, + "minuteStep": 1, + "mousewheel": true, + "showMeridian": true, + "readonlyInput": false + }, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "defaultDate": "", + "description": "", + "labelMargin": "", + "placeholder": "", + "defaultValue": "", + "customOptions": {}, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "datepickerMode": "day", + "calculateServer": false, + "customConditional": "", + "displayInTimezone": "viewer", + "useLocaleSettings": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "eexl9qw", + "key": "simpleday", + "type": "simpleday", + "input": true, + "label": "Day", + "addons": [], + "fields": { + "day": { + "hide": false, + "type": "number", + "required": false, + "placeholder": "" + }, + "year": { + "hide": false, + "type": "number", + "maxYear": "", + "minYear": "", + "required": false, + "placeholder": "" + }, + "month": { + "hide": false, + "type": "select", + "required": false, + "placeholder": "" + } + }, + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "maxDate": "", + "maxYear": "", + "minDate": "", + "minYear": "", + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "dayFirst": false, + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "labelMargin": "", + "placeholder": "", + "defaultValue": "00/00/0000", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "hideInputLabels": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "inputsLabelPosition": "top", + "allowCalculateOverride": false + } + ] + } + ], + "errorLabel": "", + "labelWidth": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "labelMargin": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "verticalLayout": false, + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "e5s7pu", + "key": "simplepanel", + "tree": false, + "type": "simplepanel", + "input": false, + "label": "Panel", + "theme": "default", + "title": "Panel", + "addons": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "lazyLoad": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "collapsed": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "breadcrumb": "default", + "components": [ + { + "id": "ezg957x", + "key": "yes", + "name": "", + "type": "simplecheckbox", + "input": true, + "label": "Yes", + "value": "", + "addons": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputType": "checkbox", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "labelMargin": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": true, + "labelPosition": "right", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "ej4i6xa", + "key": "radioGroup", + "type": "simpleradios", + "input": true, + "label": "Radio Group", + "addons": [], + "hidden": false, + "inline": false, + "prefix": "", + "suffix": "", + "unique": false, + "values": [ + { + "label": "Male", + "value": "male", + "shortcut": "" + }, + { + "label": "Female", + "value": "female", + "shortcut": "" + } + ], + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "fieldSet": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "onlyAvailableItems": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputType": "radio", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "labelMargin": "", + "placeholder": "", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "optionsLabelPosition": "right", + "allowCalculateOverride": false + }, + { + "id": "e6iz3eg", + "key": "checkboxGroup", + "type": "simplecheckboxes", + "input": true, + "label": "Checkbox Group", + "addons": [], + "hidden": false, + "inline": false, + "prefix": "", + "suffix": "", + "unique": false, + "values": [ + { + "label": "10-30", + "value": "1", + "shortcut": "" + }, + { + "label": "20-30", + "value": "2", + "shortcut": "" + } + ], + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "fieldSet": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "maxSelectedCount": "", + "minSelectedCount": "", + "onlyAvailableItems": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputType": "checkbox", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "labelMargin": "", + "placeholder": "", + "defaultValue": {}, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "optionsLabelPosition": "right", + "allowCalculateOverride": false, + "maxSelectedCountMessage": "", + "minSelectedCountMessage": "" + } + ], + "errorLabel": "", + "labelWidth": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": false, + "collapsible": false, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "labelMargin": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "ew432j7", + "key": "testA", + "tags": [], + "tree": false, + "type": "well", + "input": false, + "label": "TestA", + "logic": [], + "addons": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "lazyLoad": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "components": [ + { + "id": "ewyl8ng", + "key": "survey1", + "tags": [], + "type": "survey", + "input": true, + "label": "Survey", + "logic": [], + "addons": [], + "errors": "", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "values": [ + { + "label": "Very", + "value": "very", + "tooltip": "" + }, + { + "label": "Note Very", + "value": "noteVery", + "tooltip": "" + } + ], + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "json": "", + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "questions": [ + { + "label": "Early ", + "value": "early", + "tooltip": "" + }, + { + "label": "Late", + "value": "late", + "tooltip": "" + } + ], + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "labelMargin": "", + "placeholder": "", + "defaultValue": {}, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "einzkhk", + "key": "currency", + "case": "", + "mask": false, + "tags": [], + "type": "currency", + "input": true, + "label": "Currency", + "logic": [], + "addons": [], + "errors": "", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "currency": "USD", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "max": "", + "min": "", + "json": "", + "step": "any", + "custom": "", + "unique": false, + "integer": "", + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "delimiter": true, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "displayMask": "", + "inputFormat": "plain", + "labelMargin": "", + "placeholder": "", + "autocomplete": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false, + "truncateMultipleSpaces": false + } + ], + "errorLabel": "", + "labelWidth": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "labelMargin": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "erlzr5x", + "key": "table", + "rows": [ + [ + { + "components": [ + { + "id": "eineplc00000000000000000000000000000", + "key": "password", + "case": "", + "mask": false, + "tags": [], + "type": "password", + "input": true, + "label": "Password", + "logic": [], + "addons": [], + "errors": "", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "json": "", + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": true, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "displayMask": "", + "inputFormat": "plain", + "labelMargin": "", + "placeholder": "", + "autocomplete": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false, + "truncateMultipleSpaces": false + } + ] + }, + { + "components": [ + { + "id": "eomeup4000000000000000000000000000", + "key": "url", + "mask": false, + "tags": [], + "type": "url", + "input": true, + "label": "Url", + "logic": [], + "addons": [], + "errors": "", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "json": "", + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "url", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": true, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "displayMask": "", + "inputFormat": "plain", + "labelMargin": "", + "placeholder": "", + "autocomplete": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false, + "truncateMultipleSpaces": false + } + ] + }, + { + "components": [ + { + "id": "etgniu0000000000000000000000000", + "key": "textArea", + "case": "", + "mask": false, + "rows": 3, + "tags": [], + "type": "textarea", + "input": true, + "label": "Text Area", + "logic": [], + "addons": [], + "editor": "", + "errors": "", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "wysiwyg": false, + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "json": "", + "custom": "", + "unique": false, + "pattern": "", + "maxWords": "", + "minWords": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "fixedSize": true, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": true, + "attributes": {}, + "autoExpand": false, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "displayMask": "", + "inputFormat": "html", + "labelMargin": "", + "placeholder": "", + "autocomplete": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false, + "truncateMultipleSpaces": false + } + ] + } + ], + [ + { + "components": [ + { + "id": "eppwlc411111111111111111111111", + "key": "number", + "mask": false, + "tags": [], + "type": "number", + "input": true, + "label": "Number", + "logic": [], + "addons": [], + "errors": "", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "max": "", + "min": "", + "json": "", + "step": "any", + "custom": "", + "unique": false, + "integer": "", + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "delimiter": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "displayMask": "", + "inputFormat": "plain", + "labelMargin": "", + "placeholder": "", + "autocomplete": "", + "decimalLimit": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "requireDecimal": false, + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false, + "truncateMultipleSpaces": false + } + ] + }, + { + "components": [ + { + "id": "ei6ioy111111111111111111111", + "key": "number1", + "mask": false, + "tags": [], + "type": "number", + "input": true, + "label": "Number", + "logic": [], + "addons": [], + "errors": "", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "max": "", + "min": "", + "json": "", + "step": "any", + "custom": "", + "unique": false, + "integer": "", + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "delimiter": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "displayMask": "", + "inputFormat": "plain", + "labelMargin": "", + "placeholder": "", + "autocomplete": "", + "decimalLimit": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "requireDecimal": false, + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false, + "truncateMultipleSpaces": false + } + ] + }, + { + "components": [ + { + "id": "ejnfsfd1111111111111111111", + "key": "day", + "tags": [], + "type": "day", + "input": true, + "label": "Day", + "logic": [], + "addons": [], + "errors": "", + "fields": { + "day": { + "hide": false, + "type": "number", + "required": false, + "placeholder": "" + }, + "year": { + "hide": false, + "type": "number", + "maxYear": "", + "minYear": "", + "required": false, + "placeholder": "" + }, + "month": { + "hide": false, + "type": "select", + "required": false, + "placeholder": "" + } + }, + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "maxDate": "", + "maxYear": "", + "minDate": "", + "minYear": "", + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "dayFirst": false, + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "json": "", + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "labelMargin": "", + "placeholder": "", + "defaultValue": "00/00/0000", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "hideInputLabels": false, + "customConditional": "", + "useLocaleSettings": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "inputsLabelPosition": "top", + "allowCalculateOverride": false + } + ] + } + ], + [ + { + "components": [ + { + "id": "er5f6oc22222222222222222", + "key": "selectBoxes1", + "tags": [], + "type": "selectboxes", + "input": true, + "label": "Select Boxes", + "logic": [], + "addons": [], + "errors": "", + "hidden": false, + "inline": false, + "prefix": "", + "suffix": "", + "unique": false, + "values": [ + { + "label": "a", + "value": "a", + "shortcut": "" + }, + { + "label": "b", + "value": "b", + "shortcut": "" + }, + { + "label": "c", + "value": "c", + "shortcut": "" + } + ], + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "fieldSet": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "json": "", + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "maxSelectedCount": "", + "minSelectedCount": "", + "onlyAvailableItems": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputType": "checkbox", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "labelMargin": "", + "placeholder": "", + "defaultValue": {}, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "optionsLabelPosition": "right", + "allowCalculateOverride": false, + "maxSelectedCountMessage": "", + "minSelectedCountMessage": "" + } + ] + }, + { + "components": [ + { + "id": "emxczfl222222222222222", + "key": "select1", + "data": { + "url": "", + "json": "", + "custom": "", + "values": [ + { + "label": "c", + "value": "c" + }, + { + "label": "d", + "value": "d" + } + ], + "resource": "" + }, + "tags": [], + "type": "select", + "input": true, + "label": "Select", + "limit": 100, + "logic": [], + "addons": [], + "errors": "", + "filter": "", + "hidden": false, + "idPath": "id", + "prefix": "", + "suffix": "", + "unique": false, + "widget": "choicesjs", + "dataSrc": "values", + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "dataType": "", + "disabled": false, + "lazyLoad": true, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "template": "{{ item.label }}", + "validate": { + "json": "", + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "onlyAvailableItems": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "indexeddb": { + "filter": {} + }, + "minSearch": 0, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": true, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "fuseOptions": { + "include": "score", + "threshold": 0.3 + }, + "ignoreCache": false, + "labelMargin": "", + "placeholder": "", + "searchField": "", + "authenticate": false, + "defaultValue": "", + "selectFields": "", + "customOptions": {}, + "dataGridLabel": false, + "labelPosition": "top", + "readOnlyValue": false, + "refreshOnBlur": "", + "searchEnabled": true, + "showCharCount": false, + "showWordCount": false, + "uniqueOptions": false, + "valueProperty": "", + "calculateValue": "", + "clearOnRefresh": false, + "searchDebounce": 0.3, + "useExactSearch": false, + "calculateServer": false, + "selectThreshold": 0.3, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + } + ] + }, + { + "components": [ + { + "id": "ezb14t2222222222222", + "key": "radio1", + "tags": [], + "type": "radio", + "input": true, + "label": "Radio", + "logic": [], + "addons": [], + "errors": "", + "hidden": false, + "inline": false, + "prefix": "", + "suffix": "", + "unique": false, + "values": [ + { + "label": "Yes", + "value": "yes", + "shortcut": "" + }, + { + "label": "No", + "value": "no", + "shortcut": "" + } + ], + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "dataType": "", + "disabled": false, + "fieldSet": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "json": "", + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "onlyAvailableItems": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputType": "radio", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "labelMargin": "", + "placeholder": "", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "optionsLabelPosition": "right", + "allowCalculateOverride": false + } + ] + } + ] + ], + "tags": [], + "tree": false, + "type": "table", + "hover": false, + "input": false, + "label": "Table", + "logic": [], + "addons": [], + "header": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "caption": "", + "dbIndex": false, + "numCols": 3, + "numRows": 3, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "striped": false, + "tooltip": "", + "bordered": false, + "disabled": false, + "lazyLoad": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "cloneRows": false, + "condensed": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "labelMargin": "", + "placeholder": "", + "defaultValue": null, + "cellAlignment": "left", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "eaoknvqv", + "key": "content", + "html": "

sdasdasasdasdadfadfdsfs

", + "tags": [], + "type": "content", + "input": false, + "label": "Content", + "logic": [], + "addons": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "labelMargin": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "refreshOnChange": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "encc8xf", + "key": "dataMap", + "tags": [], + "type": "datamap", + "input": true, + "label": "Data Map", + "logic": [], + "addons": [], + "errors": "", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "keyLabel": "", + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "json": "", + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "maxLength": 0, + "minLength": 0, + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "addAnother": "Add Another", + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "labelMargin": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "keyBeforeValue": true, + "valueComponent": { + "key": "value", + "type": "textfield", + "input": true, + "label": "Value", + "hideLabel": true + }, + "calculateServer": false, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false, + "disableAddingRemovingRows": false + }, + { + "id": "emzhau", + "key": "simplefile", + "url": "/files", + "type": "simplefile", + "image": false, + "input": true, + "label": "File Upload", + "addons": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "webcam": false, + "widget": null, + "dbIndex": false, + "fileKey": "files", + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "storage": "chefs", + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "fileTypes": [ + { + "label": "", + "value": "" + } + ], + "hideLabel": false, + "imageSize": "200", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "uploadOnly": false, + "validateOn": "change", + "webcamSize": 320, + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "formio-component-file", + "description": "", + "fileMaxSize": "1GB", + "fileMinSize": "0KB", + "filePattern": "*", + "labelMargin": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "privateDownload": false, + "fileNameTemplate": "{{fileName}}", + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "euhrvc9", + "key": "orgbook", + "data": { + "url": "https://orgbook.gov.bc.ca/api/v3/search/autocomplete", + "json": "", + "custom": "", + "values": [ + { + "label": "", + "value": "" + } + ], + "resource": "" + }, + "tags": [], + "type": "orgbook", + "input": true, + "label": "Registered Business Name", + "limit": 100, + "logic": [], + "addons": [], + "errors": "", + "filter": "latest=true&inactive=false&revoked=false", + "hidden": false, + "idPath": "id", + "prefix": "", + "suffix": "", + "unique": false, + "widget": "", + "dataSrc": "url", + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "dataType": "string", + "disabled": false, + "lazyLoad": true, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "template": "{{ item.value }}", + "validate": { + "json": "", + "custom": "", + "select": false, + "unique": false, + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "onlyAvailableItems": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "indexeddb": { + "filter": {} + }, + "minSearch": 3, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "labelWidth": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "fuseOptions": { + "include": "score", + "threshold": 0.3 + }, + "ignoreCache": false, + "labelMargin": "", + "placeholder": "Start typing to search BC Registered Businesses database", + "searchField": "q", + "authenticate": false, + "defaultValue": "", + "disableLimit": false, + "selectFields": "", + "selectValues": "results", + "customOptions": { + "duplicateItemsAllowed": false + }, + "dataGridLabel": false, + "labelPosition": "top", + "readOnlyValue": true, + "searchEnabled": true, + "showCharCount": false, + "showWordCount": false, + "uniqueOptions": false, + "valueProperty": "value", + "calculateValue": "", + "clearOnRefresh": false, + "searchDebounce": 0.3, + "useExactSearch": false, + "calculateServer": false, + "searchThreshold": 3, + "selectThreshold": 0.3, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "ecjo79d", + "key": "submit", + "size": "md", + "type": "button", + "block": false, + "input": true, + "label": "Submit", + "theme": "primary", + "action": "submit", + "addons": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "leftIcon": "", + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "rightIcon": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": true, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "disableOnInvalid": true, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + } + ] +} \ No newline at end of file diff --git a/frontend/app/tests/fixtures/form/kitchen_sink_schema.json b/frontend/app/tests/fixtures/form/kitchen_sink_schema.json new file mode 100644 index 0000000..5137770 --- /dev/null +++ b/frontend/app/tests/fixtures/form/kitchen_sink_schema.json @@ -0,0 +1,2972 @@ +{ + "type": "form", + "display": "form", + "components": [ + { + "id": "ed8teth", + "key": "panel56666666666666666666666666666666666666666", + "tree": false, + "type": "simplepanel", + "input": false, + "label": "Panel", + "theme": "default", + "title": "Layout & Static Content", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "collapsed": true, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "breadcrumb": "default", + "components": [ + { + "id": "e40aasg", + "key": "tabs1", + "tree": false, + "type": "simpletabs", + "input": false, + "label": "Tabs 1", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "components": [ + { + "key": "2Column", + "label": "2 column", + "components": [ + { + "id": "ez162lc", + "key": "columns2", + "tree": false, + "type": "simplecols2", + "input": false, + "label": "Columns - 2", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "columns": [ + { + "pull": 0, + "push": 0, + "size": "md", + "width": 6, + "offset": 0, + "components": [ + { + "id": "ek5hzl6", + "key": "panelNested", + "tree": false, + "type": "simplepanel", + "input": false, + "label": "Panel", + "theme": "default", + "title": "Panel Nested 1", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "collapsed": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "breadcrumb": "default", + "components": [ + { + "id": "eflswzo", + "key": "textFieldNested1", + "case": "", + "mask": false, + "type": "simpletextfield", + "input": true, + "label": "Text Field Nested 1", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + } + ], + "errorLabel": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": false, + "collapsible": false, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "hideOnChildrenHidden": false, + "allowCalculateOverride": false + } + ] + }, + { + "pull": 0, + "push": 0, + "size": "md", + "width": 6, + "offset": 0, + "components": [ + { + "id": "eebsrxi", + "key": "panelNested2", + "tree": false, + "type": "simplepanel", + "input": false, + "label": "Panel", + "theme": "default", + "title": "Panel Nested 2", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "collapsed": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "breadcrumb": "default", + "components": [ + { + "id": "epo28b6", + "key": "textFieldNested2", + "case": "", + "mask": false, + "type": "simpletextfield", + "input": true, + "label": "Text Field Nested 2", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + } + ], + "errorLabel": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": false, + "collapsible": false, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "hideOnChildrenHidden": false, + "allowCalculateOverride": false + } + ] + } + ], + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "autoAdjust": false, + "errorLabel": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": false, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "hideOnChildrenHidden": false, + "allowCalculateOverride": false + } + ] + }, + { + "key": "3Column", + "label": "3 column", + "components": [ + { + "id": "enqz1hb", + "key": "columns3", + "tree": false, + "type": "simplecols3", + "input": false, + "label": "Columns - 3", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "columns": [ + { + "pull": 0, + "push": 0, + "size": "md", + "width": 4, + "offset": 0, + "components": [ + { + "id": "ev271g", + "key": "heading", + "tag": "h1", + "type": "simpleheading", + "attrs": [], + "input": false, + "label": "Heading", + "logic": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "content": "Static text", + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "headingSize": "h1", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "hideOnChildrenHidden": false, + "allowCalculateOverride": false + }, + { + "id": "e6ekni", + "key": "staticText", + "html": "

Here is some static text.

", + "type": "simplecontent", + "input": false, + "label": "Static Text", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "hideOnChildrenHidden": false, + "allowCalculateOverride": false + } + ] + }, + { + "pull": 0, + "push": 0, + "size": "md", + "width": 4, + "offset": 0, + "components": [ + { + "id": "ekzw7rl", + "key": "fieldSet", + "tree": false, + "type": "simplefieldset", + "input": false, + "label": "Field Set", + "hidden": false, + "legend": "Fieldset Caption 1", + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "components": [ + { + "id": "e7t221q", + "key": "textFieldInFieldset1", + "mask": false, + "type": "simpletextfield", + "input": true, + "label": "Text Field in Fieldset 1", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "e67463a", + "key": "selectListInFieldset1", + "data": { + "url": "", + "json": "", + "custom": "", + "values": [ + { + "label": "1", + "value": "1" + }, + { + "label": "2", + "value": "2" + }, + { + "label": "3", + "value": "3" + } + ], + "resource": "" + }, + "type": "simpleselect", + "input": true, + "label": "Select List in Fieldset 1", + "limit": 100, + "filter": "", + "hidden": false, + "idPath": "id", + "prefix": "", + "suffix": "", + "unique": false, + "widget": "choicesjs", + "dataSrc": "values", + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "dataType": "auto", + "disabled": false, + "lazyLoad": true, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "template": "{{ item.label }}", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "minSearch": 0, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": true, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "fuseOptions": { + "include": "score", + "threshold": 0.3 + }, + "ignoreCache": false, + "placeholder": "", + "searchField": "", + "authenticate": false, + "defaultValue": null, + "selectFields": "", + "customOptions": {}, + "dataGridLabel": false, + "labelPosition": "top", + "readOnlyValue": false, + "searchEnabled": true, + "showCharCount": false, + "showWordCount": false, + "uniqueOptions": false, + "valueProperty": "", + "calculateValue": "", + "clearOnRefresh": false, + "useExactSearch": false, + "calculateServer": false, + "searchThreshold": 0.3, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + } + ], + "errorLabel": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "hideOnChildrenHidden": false, + "allowCalculateOverride": false + } + ] + }, + { + "pull": 0, + "push": 0, + "size": "md", + "width": 4, + "offset": 0, + "components": [ + { + "id": "ercvlob", + "key": "heading1", + "tag": "h1", + "type": "simpleheading", + "attrs": [], + "input": false, + "label": "Heading", + "logic": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "content": "Heading for a Paragraph", + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "headingSize": "h1", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "hideOnChildrenHidden": false, + "allowCalculateOverride": false + }, + { + "id": "ert0gl", + "key": "paragraph", + "tag": "p", + "type": "simpleparagraph", + "attrs": [], + "input": false, + "label": "Paragraph", + "logic": [], + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "content": "Paragraph test with no logic.", + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "hideOnChildrenHidden": false, + "allowCalculateOverride": false + } + ] + } + ], + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "autoAdjust": false, + "errorLabel": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": false, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "hideOnChildrenHidden": false, + "allowCalculateOverride": false + } + ] + }, + { + "key": "4Column", + "label": "4 column", + "components": [ + { + "id": "eajyx53", + "key": "columns4", + "tree": false, + "type": "simplecols4", + "input": false, + "label": "Columns - 4", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "columns": [ + { + "pull": 0, + "push": 0, + "size": "sm", + "width": 3, + "offset": 0, + "components": [ + { + "id": "eejkjy9", + "key": "email2", + "mask": false, + "type": "simpleemail", + "input": true, + "label": "Email 2", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "kickbox": { + "enabled": false + }, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "delimiter": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "email", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": true, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "requireDecimal": false, + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "hideOnChildrenHidden": false, + "allowCalculateOverride": false + } + ] + }, + { + "pull": 0, + "push": 0, + "size": "sm", + "width": 3, + "offset": 0, + "components": [ + { + "id": "eto8jk", + "key": "number2", + "type": "simplenumber", + "input": true, + "label": "Number 2", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "max": "", + "min": "", + "step": "any", + "custom": "", + "unique": false, + "integer": "", + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "delimiter": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "requireDecimal": false, + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "hideOnChildrenHidden": false, + "allowCalculateOverride": false + } + ] + }, + { + "pull": 0, + "push": 0, + "size": "sm", + "width": 3, + "offset": 0, + "components": [ + { + "id": "e4zi6q", + "key": "textField3", + "case": "", + "mask": false, + "type": "simpletextfield", + "input": true, + "label": "Text Field 2", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "hideOnChildrenHidden": false, + "allowCalculateOverride": false + } + ] + }, + { + "pull": 0, + "push": 0, + "size": "sm", + "width": 3, + "offset": 0, + "components": [ + { + "id": "erq1vo", + "key": "phoneNumber2", + "mask": false, + "type": "simplephonenumber", + "input": true, + "label": "Phone Number 2", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "(999) 999-9999", + "inputType": "tel", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": true, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "hideOnChildrenHidden": false, + "allowCalculateOverride": false + } + ] + } + ], + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "autoAdjust": false, + "errorLabel": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": false, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "hideOnChildrenHidden": false, + "allowCalculateOverride": false + } + ] + } + ], + "errorLabel": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + } + ], + "errorLabel": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": false, + "collapsible": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "eukyzom", + "key": "panel1", + "tree": false, + "type": "simplepanel", + "input": false, + "label": "", + "theme": "default", + "title": "Form Fields", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "collapsed": true, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "breadcrumb": "default", + "components": [ + { + "id": "e9kc7ln", + "key": "registeredBusinessName1", + "data": { + "url": "https://orgbook.gov.bc.ca/api/v2/search/autocomplete", + "json": "", + "custom": "", + "values": [], + "resource": "" + }, + "tags": [], + "type": "orgbook", + "input": true, + "label": "Registered Business Name 1", + "limit": 100, + "logic": [], + "filter": "latest=true&inactive=false&revoked=false", + "hidden": false, + "idPath": "id", + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dataSrc": "url", + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "page": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "dataType": "string", + "disabled": false, + "lazyLoad": true, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "template": "{{ item.names[0].text }}", + "validate": { + "json": "", + "custom": "", + "select": false, + "unique": false, + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "indexeddb": { + "filter": {} + }, + "minSearch": 3, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "json": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "fuseOptions": { + "include": "score", + "threshold": 0.3 + }, + "ignoreCache": false, + "placeholder": "Start typing to search BC Registered Businesses database", + "searchField": "q", + "authenticate": false, + "defaultValue": "", + "disableLimit": false, + "selectFields": "", + "selectValues": "results", + "customOptions": { + "duplicateItemsAllowed": false + }, + "dataGridLabel": false, + "labelPosition": "left-left", + "readOnlyValue": true, + "searchEnabled": true, + "showCharCount": false, + "showWordCount": false, + "uniqueOptions": false, + "valueProperty": "names[0].text", + "calculateValue": "", + "clearOnRefresh": false, + "useExactSearch": false, + "calculateServer": false, + "searchThreshold": 3, + "selectThreshold": 0.3, + "customConditional": "", + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "epe4uo", + "key": "textField1", + "case": "", + "mask": false, + "type": "simpletextfield", + "input": true, + "label": "Text Field 1", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "Tooltip for this field appears here.", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "Description text for this field appears here.", + "inputFormat": "plain", + "placeholder": "Example Placeholder", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "left-left", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "eozuc1", + "key": "multiLineText1", + "case": "", + "mask": false, + "rows": 3, + "type": "simpletextarea", + "input": true, + "label": "Multi-line Text 1", + "editor": "", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "wysiwyg": false, + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "maxWords": "", + "minWords": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "fixedSize": true, + "hideLabel": false, + "inputMask": "", + "inputType": "text", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": true, + "attributes": {}, + "autoExpand": false, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "left-left", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "eywliig", + "key": "selectList1", + "data": { + "url": "", + "json": "", + "custom": "", + "values": [ + { + "label": "Choose...", + "value": "choose" + }, + { + "label": "Selection 1", + "value": "selection1" + }, + { + "label": "Selection 2", + "value": "selection2" + }, + { + "label": "Selection 3", + "value": "selection3" + } + ], + "resource": "" + }, + "type": "simpleselect", + "input": true, + "label": "Select List 1", + "limit": 100, + "filter": "", + "hidden": false, + "idPath": "id", + "prefix": "", + "suffix": "", + "unique": false, + "widget": "choicesjs", + "dataSrc": "values", + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "dataType": "auto", + "disabled": false, + "lazyLoad": true, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "template": "{{ item.label }}", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "minSearch": 0, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": true, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "fuseOptions": { + "include": "score", + "threshold": 0.3 + }, + "ignoreCache": false, + "placeholder": "", + "searchField": "", + "authenticate": false, + "defaultValue": "choose", + "selectFields": "", + "customOptions": {}, + "dataGridLabel": false, + "labelPosition": "left-left", + "readOnlyValue": false, + "searchEnabled": true, + "showCharCount": false, + "showWordCount": false, + "uniqueOptions": false, + "valueProperty": "", + "calculateValue": "", + "clearOnRefresh": false, + "useExactSearch": false, + "calculateServer": false, + "searchThreshold": 0.3, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "e1mw1vq", + "key": "selectList2", + "data": { + "url": "", + "json": "", + "custom": "", + "values": [ + { + "label": "Select 1", + "value": "select1" + }, + { + "label": "Select 2", + "value": "select2" + }, + { + "label": "Select 3", + "value": "select3" + } + ], + "resource": "" + }, + "type": "simpleselect", + "input": true, + "label": "Select List 1", + "limit": 100, + "filter": "", + "hidden": false, + "idPath": "id", + "prefix": "", + "suffix": "", + "unique": false, + "widget": "choicesjs", + "dataSrc": "values", + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "dataType": "auto", + "disabled": false, + "lazyLoad": true, + "multiple": true, + "redrawOn": "", + "tabindex": "", + "template": "{{ item.label }}", + "validate": { + "custom": "", + "unique": false, + "multiple": true, + "required": false, + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "minSearch": 0, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": true, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "fuseOptions": { + "include": "score", + "threshold": 0.3 + }, + "ignoreCache": false, + "placeholder": "", + "searchField": "", + "authenticate": false, + "defaultValue": [], + "selectFields": "", + "customOptions": {}, + "dataGridLabel": false, + "labelPosition": "left-left", + "readOnlyValue": false, + "searchEnabled": true, + "showCharCount": false, + "showWordCount": false, + "uniqueOptions": false, + "valueProperty": "", + "calculateValue": "", + "clearOnRefresh": false, + "useExactSearch": false, + "calculateServer": false, + "searchThreshold": 0.3, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "e6ceb5", + "key": "checkbox1", + "name": "", + "type": "simplecheckbox", + "input": true, + "label": "Checkbox 1", + "value": "", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "Tooltip for this field.", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputType": "checkbox", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "Description for this field.", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": true, + "labelPosition": "right", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "eoqkh1", + "key": "checkboxGroup1", + "type": "simplecheckboxes", + "input": true, + "label": "Checkbox Group 1", + "hidden": false, + "inline": false, + "prefix": "", + "suffix": "", + "unique": false, + "values": [ + { + "label": "Check 1", + "value": "check1", + "shortcut": "A" + }, + { + "label": "Check 2", + "value": "check2", + "shortcut": "B" + }, + { + "label": "Check 3", + "value": "check3", + "shortcut": "C" + } + ], + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "fieldSet": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputType": "checkbox", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "left-left", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "optionsLabelPosition": "right", + "allowCalculateOverride": false, + "maxSelectedCountMessage": "", + "minSelectedCountMessage": "" + }, + { + "id": "ev6fyvb", + "key": "radioGroup1", + "type": "simpleradios", + "input": true, + "label": "Radio Group 1", + "hidden": false, + "inline": false, + "prefix": "", + "suffix": "", + "unique": false, + "values": [ + { + "label": "Radio 1", + "value": "radio1", + "shortcut": "" + }, + { + "label": "Radio 2", + "value": "radio2", + "shortcut": "" + }, + { + "label": "Radio 3", + "value": "radio3", + "shortcut": "" + } + ], + "widget": null, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "fieldSet": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputType": "radio", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "left-left", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "optionsLabelPosition": "right", + "allowCalculateOverride": false + }, + { + "id": "ebedo1d", + "key": "number", + "type": "simplenumber", + "input": true, + "label": "Number 1", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "Enter a number.", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "max": "", + "min": "", + "step": "any", + "custom": "", + "unique": false, + "integer": "", + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "delimiter": true, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "Enter a number.", + "placeholder": "", + "decimalLimit": 0, + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "left-left", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "requireDecimal": false, + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "ep7r3ch", + "key": "phoneNumber1", + "mask": false, + "type": "simplephonenumber", + "input": true, + "label": "Phone Number 1", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "(999) 999-9999", + "inputType": "tel", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": true, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "left-left", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "ebejr93", + "key": "email1", + "mask": false, + "type": "simpleemail", + "input": true, + "label": "Email 1", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "kickbox": { + "enabled": false + }, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "delimiter": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "", + "inputType": "email", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": true, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "left-left", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "requireDecimal": false, + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "eb683f", + "key": "dateTime1", + "type": "simpledatetime", + "input": true, + "label": "Date / Time 1", + "format": "yyyy-MM-dd hh:mm a", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "mode": "single", + "type": "calendar", + "format": "yyyy-MM-dd hh:mm a", + "locale": "en", + "maxDate": null, + "minDate": null, + "time_24hr": false, + "allowInput": true, + "enableTime": true, + "noCalendar": false, + "hourIncrement": 1, + "disableWeekdays": false, + "disableWeekends": false, + "minuteIncrement": 1, + "displayInTimezone": "viewer", + "useLocaleSettings": false + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "timezone": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "allowInput": true, + "attributes": {}, + "datePicker": { + "maxDate": null, + "maxMode": "year", + "minDate": null, + "minMode": "day", + "initDate": "", + "yearRows": 4, + "showWeeks": true, + "startingDay": 0, + "yearColumns": 5, + "disableWeekdays": false, + "disableWeekends": false + }, + "enableDate": true, + "enableTime": true, + "errorLabel": "", + "persistent": true, + "properties": {}, + "timePicker": { + "hourStep": 1, + "arrowkeys": true, + "minuteStep": 1, + "mousewheel": true, + "showMeridian": true, + "readonlyInput": false + }, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "defaultDate": "", + "description": "", + "placeholder": "", + "defaultValue": "", + "customOptions": {}, + "dataGridLabel": false, + "labelPosition": "left-left", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "datepickerMode": "day", + "calculateServer": false, + "shortcutButtons": [], + "displayInTimezone": "viewer", + "useLocaleSettings": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "e619db6", + "key": "day1", + "type": "simpleday", + "input": true, + "label": "Day 1", + "fields": { + "day": { + "hide": false, + "type": "number", + "required": false, + "placeholder": "" + }, + "year": { + "hide": false, + "type": "number", + "required": false, + "placeholder": "" + }, + "month": { + "hide": false, + "type": "select", + "required": false, + "placeholder": "" + } + }, + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": null, + "dbIndex": false, + "maxDate": "", + "minDate": "", + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "dayFirst": false, + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": true, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": "00/00/0000", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "hideInputLabels": false, + "useLocaleSettings": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "inputsLabelPosition": "left", + "allowCalculateOverride": false + }, + { + "id": "eupvl3", + "key": "time1", + "mask": false, + "type": "simpletime", + "input": true, + "label": "Time 1", + "format": "HH:mm", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "pattern": "", + "multiple": false, + "required": false, + "maxLength": "", + "minLength": "", + "customMessage": "", + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "inputMask": "99:99", + "inputType": "time", + "modalEdit": false, + "protected": false, + "refreshOn": "", + "tableView": true, + "attributes": {}, + "dataFormat": "HH:mm:ss", + "errorLabel": "", + "persistent": true, + "properties": {}, + "spellcheck": true, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "inputFormat": "plain", + "placeholder": "", + "defaultValue": "", + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + } + ], + "errorLabel": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": false, + "collapsible": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": false, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + }, + { + "id": "ez5c88", + "key": "submit", + "size": "md", + "type": "button", + "block": false, + "input": true, + "label": "Submit", + "theme": "primary", + "action": "submit", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "leftIcon": "", + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "rightIcon": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": true, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "disableOnInvalid": true, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + } + ] +} diff --git a/frontend/app/tests/fixtures/submission/advanced_submission.json b/frontend/app/tests/fixtures/submission/advanced_submission.json new file mode 100644 index 0000000..c481019 --- /dev/null +++ b/frontend/app/tests/fixtures/submission/advanced_submission.json @@ -0,0 +1,105 @@ +{ + "data": { + "day": "01/27/1981", + "tags": "tag1,tag2", + "tree": { + "data": { + "textFieldInTree1": "level1a", + "textFieldInTree2": "level1b" + }, + "children": [ + { + "data": { + "textFieldInTree1": "level2a", + "textFieldInTree2": "level2b" + }, + "children": [] + } + ] + }, + "submit": true, + "address": "my address", + "dataMap": { + "key1": "my val1", + "key2": "my val2" + }, + "hidden1": "this should be hidden", + "orgbook": "ABC PAINTING", + "select1": "select2", + "survey1": { + "question1": "yes", + "question2": "no", + "question3": "yes" + }, + "currency": 500, + "dataGrid": [ + { + "textFieldInDataGrid1": "dgtext1", + "textFieldInDataGrid2": "dgtext11" + }, + { + "textFieldInDataGrid1": "dgtext2", + "textFieldInDataGrid2": "dgtext22" + } + ], + "editGrid": [ + { + "textFieldInEditGrid1": "xyz1", + "textFieldInEditGrid2": "abc1" + }, + { + "textFieldInEditGrid1": "xyz2", + "textFieldInEditGrid2": "abc2" + } + ], + "password": "b2qrqpQebWhmKM7", + "signature": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABrcAAAAyCAYAAAD2poC3AAADcUlEQVR4nO3dL2xTURTA4WfmttRDYHNAttSSbKkhmUDMk7BkcqIJhmSITk7VIBZCahBTlZN1k3VIVPUz1VcfBBl/0g4GDF7O6yc+997NOfqXm1uVMg8AAAAAAADIoGp6AAAAAAAAALgtcQsAAAAAAIA0xC0AAAAAAADSELcAAAAAAABIQ9wCAAAAAAAgDXELAAAAAACANMQtAAAAAAAA0hC3AAAAAAAASEPcAgAAAAAAIA1xCwAAAAAAgDRaFbem06uYTq8anwMAAAAAAIB/ozVx6+DgeVRVFVVVRa+31/g8AAAAAAAA3L1WxK3J5PJr2LrW7e7cydl1PYvJ5DIGg5MYjc4b3xUAAAAAAGCVtSJujccXC3GrqqrY3Hzwx2fW9SwGg5PY3Hzww5n9/nHj+wIAAAAAAKyqVsStUubR7e4sDVzD4dlvnVPXs3j9+lU8fvzozoMZAAAAAAAAf6c1cauUeRwevliIUWtrazGZXN7q/8nkMra3nyyNWtcGg5PG9wQAAAAAAFhVrYpbpcyj19tbCFL379/7ZeAajc6j0+ncGLV6vb0YDs+irmeN7wgAAAAAALCqWhe3SplHv3+8NFCNxxcL39b17Mbvq6qK3d2nMZ1eNb4TAAAAAAAALY1bpczj3bu3sb6+vhCrtrYeRr9/HKPR+dJbXtc2Njbi9PRN43sAAAAAAADwTWvjVilf3tD62ftZN+l0Ord+pwsAAAAAAID/p9Vxq5TfD1zd7k58+vSx8bkBAAAAAABY1Pq4Vco8ptOr2N9/9svbWsPhWdT1rPF5AQAAAAAAWG4l4tb3xuOLODx8Ed3uThwcPI+jo5fx4cN7UQsAAAAAACCBlYtbAAAAAAAA5CVuAQAAAAAAkIa4BQAAAAAAQBriFgAAAAAAAGmIWwAAAAAAAKQhbgEAAAAAAJCGuAUAAAAAAEAa4hYAAAAAAABpiFsAAAAAAACkIW4BAAAAAACQhrgFAAAAAABAGuIWAAAAAAAAaYhbAAAAAAAApCFuAQAAAAAAkIa4BQAAAAAAQBriFgAAAAAAAGmIWwAAAAAAAKQhbgEAAAAAAJCGuAUAAAAAAEAa4hYAAAAAAABpiFsAAAAAAACkIW4BAAAAAACQhrgFAAAAAABAGuIWAAAAAAAAaYhbAAAAAAAApCFuAQAAAAAAkMZnyjsZBuGEkCEAAAAASUVORK5CYII=", + "container1": { + "containedTextField1": "contained1", + "containedTextField2": "contained2" + }, + "simplefile": [ + { + "url": "/app/api/v1/files/b8b3b5ff-a8ca-43b0-b49d-373dba8eb39a", + "data": { + "id": "b8b3b5ff-a8ca-43b0-b49d-373dba8eb39a" + }, + "size": 44, + "storage": "chefs", + "originalName": "test-file-upload.txt" + } + ], + "selectBoxes1": { + "box1": true, + "box2": false, + "box3": true + }, + "textincolumn1": "a1", + "numberintable1": 1, + "numberintable2": 2, + "numberintable3": 3, + "numberintable4": 4, + "textinfieldset": "a2", + "dataGridInPanel": [ + { + "textInDatagridInPanel1": "dgpanel1", + "textInDatagridInPanel2": "dgpanel11" + }, + { + "textInDatagridInPanel1": "dgpanel2", + "textInDatagridInPanel2": "dgpanel22" + } + ] + }, + "state": "submitted", + "metadata": { + "offset": -420, + "onLine": true, + "origin": "http://localhost:8081", + "pathName": "/app/form/submit", + "referrer": "", + "timezone": "America/Vancouver", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0", + "browserName": "Netscape" + } +} diff --git a/frontend/app/tests/fixtures/submission/advanced_submissions_export.json b/frontend/app/tests/fixtures/submission/advanced_submissions_export.json new file mode 100644 index 0000000..3ef00c8 --- /dev/null +++ b/frontend/app/tests/fixtures/submission/advanced_submissions_export.json @@ -0,0 +1,208 @@ +[ + { + "form": { + "confirmationId": "AC571AB6", + "formName": "advanced", + "version": 2, + "createdAt": "2021-09-24T20:06:24.817Z", + "fullName": "Jane Smith", + "username": "janesmith", + "email": "jane.smith@gov.bc.ca", + "status": "SUBMITTED", + "assignee": null, + "assigneeEmail": null + }, + "day": "11/07/0007", + "tags": "uioluo,khkj", + "tree": { + "data": { + "textFieldInTree1": "p][p]", + "textFieldInTree2": "][p][p" + }, + "children": [ + { + "data": { + "textFieldInTree1": "poo[o[", + "textFieldInTree2": "po[po[o" + }, + "children": [] + } + ] + }, + "submit": true, + "address": "my address", + "dataMap": { + "keyipoi": "poiopi", + "keyoipoiop": "poipoip" + }, + "hidden1": "this should be hidden", + "orgbook": "ABC STORAGE", + "select1": "select3", + "survey1": { + "question2": "no" + }, + "currency": 200, + "dataGrid": [ + { + "textFieldInDataGrid1": "op[p", + "textFieldInDataGrid2": "[po[p" + }, + { + "textFieldInDataGrid1": "p][p]", + "textFieldInDataGrid2": "uyuiyiy" + } + ], + "editGrid": [ + { + "textFieldInEditGrid1": "xyz", + "textFieldInEditGrid2": "abc" + }, + { + "textFieldInEditGrid1": "xyzpoipoi", + "textFieldInEditGrid2": "poiopi" + } + ], + "password": "lhjlkjlj", + "signature": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABrcAAAAyCAYAAAD2poC3AAACmElEQVR4nO3dIU4DYRSF0RH1/wpIFahmNkBYAGISJKIewXJQWBQSWYesQ1ZVj0FXPwQJAQxVnbnhiOOv//LyusPhvQAAAAAAACBBN/UAAAAAAAAAOJa4BQAAAAAAQAxxCwAAAAAAgBjiFgAAAAAAADHELQAAAAAAAGKIWwAAAAAAAMQQtwAAAAAAAIghbgEAAAAAABBD3AIAAAAAACCGuAUAAAAAAEAMcQsAAAAAAIAY4hYAAAAAAAAxxC0AAAAAAABiiFsAAAAAAADEELcAAAAAAACIERO3ttvXur+/q2G4rt3ubfI9AAAAAAAAnF5E3NpsXqq1Vl3XVdd11VqbfBMAAAAAAACnN5u4tdm8VN+vark8q2G4rvX6tm5uhlouz76i1nfb7evkmwEAAAAAADitWcSt3e7tx2XWX/p+NflmAAAAAAAATm8Wcev5+enosNVac7UFAAAAAADwT80ibo3j/uiLLWELAAAAAADg/5pF3DocPn9uXV1dVt+vfgStxWJRFxfn9fj4UOO4n3wnAAAAAAAA05lN3PptHPdfpt4CAAAAAADAPMw2bgEAAAAAAMBv4hYAAAAAAAAxxC0AAAAAAABiiFsAAAAAAADEELcAAAAAAACIIW4BAAAAAAAQQ9wCAAAAAAAghrgFAAAAAABADHELAAAAAACAGOIWAAAAAAAAMcQtAAAAAAAAYohbAAAAAAAAxBC3AAAAAAAAiCFuAQAAAAAAEEPcAgAAAAAAIIa4BQAAAAAAQAxxCwAAAAAAgBjiFgAAAAAAADHELQAAAAAAAGKIWwAAAAAAAMQQtwAAAAAAAIghbgEAAAAAABBD3AIAAAAAACCGuAUAAAAAAEAMcQsAAAAAAIAY4hYAAAAAAAAxPgB/u+8bHoNO5QAAAABJRU5ErkJggg==", + "container1": { + "containedTextField1": "ghkjh", + "containedTextField2": "kjhk" + }, + "simplefile": [ + { + "url": "/app/api/v1/files/b8b3b5ff-a8ca-43b0-b49d-373dba8eb39a", + "data": { + "id": "b8b3b5ff-a8ca-43b0-b49d-373dba8eb39a" + }, + "size": 44, + "storage": "chefs", + "originalName": "test-file-upload.txt" + } + ], + "selectBoxes1": { + "box1": false, + "box2": true, + "box3": false + }, + "textincolumn1": "jklkjlk", + "numberintable1": 1, + "numberintable2": 2, + "numberintable3": 3, + "numberintable4": 4, + "textinfieldset": "uoiuoi", + "dataGridInPanel": [ + { + "textInDatagridInPanel1": "iuyi", + "textInDatagridInPanel2": "iuyiy" + }, + { + "textInDatagridInPanel1": "rytry", + "textInDatagridInPanel2": "tyryry" + } + ] + }, + { + "form": { + "confirmationId": "536B0C30", + "formName": "advanced", + "version": 2, + "createdAt": "2021-09-24T19:55:58.869Z", + "fullName": "Jane Smith", + "username": "janesmith", + "email": "jane.smith@gov.bc.ca", + "status": "SUBMITTED", + "assignee": null, + "assigneeEmail": null + }, + "day": "01/27/1981", + "tags": "tag1,tag2", + "tree": { + "data": { + "textFieldInTree1": "level1a", + "textFieldInTree2": "level1b" + }, + "children": [ + { + "data": { + "textFieldInTree1": "level2a", + "textFieldInTree2": "level2b" + }, + "children": [] + } + ] + }, + "submit": true, + "address": "my address", + "dataMap": { + "key1": "my val1", + "key2": "my val2" + }, + "hidden1": "this should be hidden", + "orgbook": "ABC PAINTING", + "select1": "select2", + "survey1": { + "question1": "yes", + "question2": "no", + "question3": "yes" + }, + "currency": 500, + "dataGrid": [ + { + "textFieldInDataGrid1": "dgtext1", + "textFieldInDataGrid2": "dgtext11" + }, + { + "textFieldInDataGrid1": "dgtext2", + "textFieldInDataGrid2": "dgtext22" + } + ], + "editGrid": [ + { + "textFieldInEditGrid1": "xyz1", + "textFieldInEditGrid2": "abc1" + }, + { + "textFieldInEditGrid1": "xyz2", + "textFieldInEditGrid2": "abc2" + } + ], + "password": "b2qrqpQebWhmKM7", + "signature": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABrcAAAAyCAYAAAD2poC3AAACmElEQVR4nO3dIU4DYRSF0RH1/wpIFahmNkBYAGISJKIewXJQWBQSWYesQ1ZVj0FXPwQJAQxVnbnhiOOv//LyusPhvQAAAAAAACBBN/UAAAAAAAAAOJa4BQAAAAAAQAxxCwAAAAAAgBjiFgAAAAAAADHELQAAAAAAAGKIWwAAAAAAAMQQtwAAAAAAAIghbgEAAAAAABBD3AIAAAAAACCGuAUAAAAAAEAMcQsAAAAAAIAY4hYAAAAAAAAxxC0AAAAAAABiiFsAAAAAAADEELcAAAAAAACIERO3ttvXur+/q2G4rt3ubfI9AAAAAAAAnF5E3NpsXqq1Vl3XVdd11VqbfBMAAAAAAACnN5u4tdm8VN+vark8q2G4rvX6tm5uhlouz76i1nfb7evkmwEAAAAAADitWcSt3e7tx2XWX/p+NflmAAAAAAAATm8Wcev5+enosNVac7UFAAAAAADwT80ibo3j/uiLLWELAAAAAADg/5pF3DocPn9uXV1dVt+vfgStxWJRFxfn9fj4UOO4n3wnAAAAAAAA05lN3PptHPdfpt4CAAAAAADAPMw2bgEAAAAAAMBv4hYAAAAAAAAxxC0AAAAAAABiiFsAAAAAAADEELcAAAAAAACIIW4BAAAAAAAQQ9wCAAAAAAAghrgFAAAAAABADHELAAAAAACAGOIWAAAAAAAAMcQtAAAAAAAAYohbAAAAAAAAxBC3AAAAAAAAiCFuAQAAAAAAEEPcAgAAAAAAIIa4BQAAAAAAQAxxCwAAAAAAgBjiFgAAAAAAADHELQAAAAAAAGKIWwAAAAAAAMQQtwAAAAAAAIghbgEAAAAAABBD3AIAAAAAACCGuAUAAAAAAEAMcQsAAAAAAIAY4hYAAAAAAAAxPgB/u+8bHoNO5QAAAABJRU5ErkJggg==", + "container1": { + "containedTextField1": "contained1", + "containedTextField2": "contained2" + }, + "simplefile": [ + { + "url": "/app/api/v1/files/b8b3b5ff-a8ca-43b0-b49d-373dba8eb39a", + "data": { + "id": "b8b3b5ff-a8ca-43b0-b49d-373dba8eb39a" + }, + "size": 44, + "storage": "chefs", + "originalName": "test-file-upload.txt" + } + ], + "selectBoxes1": { + "box1": true, + "box2": false, + "box3": true + }, + "textincolumn1": "a1", + "numberintable1": 1, + "numberintable2": 2, + "numberintable3": 3, + "numberintable4": 4, + "textinfieldset": "a2", + "dataGridInPanel": [ + { + "textInDatagridInPanel1": "dgpanel1", + "textInDatagridInPanel2": "dgpanel11" + }, + { + "textInDatagridInPanel1": "dgpanel2", + "textInDatagridInPanel2": "dgpanel22" + } + ] + } +] diff --git a/frontend/app/tests/fixtures/submission/kitchen_sink_submission.json b/frontend/app/tests/fixtures/submission/kitchen_sink_submission.json new file mode 100644 index 0000000..b390350 --- /dev/null +++ b/frontend/app/tests/fixtures/submission/kitchen_sink_submission.json @@ -0,0 +1,117 @@ +{ + "data": { + "day1": "01/01/2021", + "time1": "01:01:00", + "email1": "email@abc.com", + "email2": "email@abc.com", + "number": 456, + "submit": true, + "number2": 123, + "checkbox1": false, + "dateTime1": "2021-01-01T13:01:00-08:00", + "textField1": "abcdefg", + "textField3": "abcdef", + "radioGroup1": "radio1", + "selectList1": "selection1", + "selectList2": [ + "select1" + ], + "phoneNumber1": "(456) 000-0000", + "phoneNumber2": "(123) 000-0000", + "checkboxGroup1": { + "check1": true, + "check2": false, + "check3": false + }, + "multiLineText1": "multi text abc", + "textFieldNested1": "abc", + "textFieldNested2": "abcd", + "textFieldInFieldset1": "abcde", + "selectListInFieldset1": 1, + "registeredBusinessName1": "ABC WOODWORKS" + }, + "state": "submitted", + "metadata": { + "offset": -420, + "onLine": true, + "origin": "http://localhost:8081", + "pathName": "/app/form/submit", + "referrer": "", + "timezone": "America/Vancouver", + "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0", + "browserName": "Netscape" + }, + "component": { + "id": "ez5c88", + "key": "submit", + "size": "md", + "type": "button", + "block": false, + "input": true, + "label": "Submit", + "theme": "primary", + "action": "submit", + "hidden": false, + "prefix": "", + "suffix": "", + "unique": false, + "widget": { + "type": "input" + }, + "dbIndex": false, + "overlay": { + "top": "", + "left": "", + "style": "", + "width": "", + "height": "" + }, + "tooltip": "", + "disabled": false, + "leftIcon": "", + "multiple": false, + "redrawOn": "", + "tabindex": "", + "validate": { + "custom": "", + "unique": false, + "multiple": false, + "required": false, + "customPrivate": false, + "strictDateValidation": false + }, + "autofocus": false, + "encrypted": false, + "hideLabel": false, + "modalEdit": false, + "protected": false, + "refreshOn": "", + "rightIcon": "", + "tableView": false, + "attributes": {}, + "errorLabel": "", + "persistent": false, + "properties": {}, + "validateOn": "change", + "clearOnHide": true, + "conditional": { + "eq": "", + "show": null, + "when": null + }, + "customClass": "", + "description": "", + "placeholder": "", + "defaultValue": null, + "dataGridLabel": true, + "labelPosition": "top", + "showCharCount": false, + "showWordCount": false, + "calculateValue": "", + "calculateServer": false, + "disableOnInvalid": true, + "allowMultipleMasks": false, + "customDefaultValue": "", + "allowCalculateOverride": false + } +} diff --git a/frontend/app/tests/fixtures/submission/kitchen_sink_submission_data_export_datagrid.json b/frontend/app/tests/fixtures/submission/kitchen_sink_submission_data_export_datagrid.json new file mode 100644 index 0000000..d5969c3 --- /dev/null +++ b/frontend/app/tests/fixtures/submission/kitchen_sink_submission_data_export_datagrid.json @@ -0,0 +1,53 @@ +[ + { + "form": { + "confirmationId": "B75F4403", + "formName": "fisheriesTest", + "version": 1, + "createdAt": "2023-02-15T18:57:59.919Z", + "fullName": "Ayobamii Idowu", + "username": "AIDOWU", + "email": "ayobamii.idowu@gov.bc.ca" + }, + "email": "ayobami@gmail.com", + "oneRowPerLake": [ + { + "dataGrid": [ + { + "fishType": "rainbow", + "numberKept": 1, + "numberCaught": 1 + }, + { + "fishType": "cutthroat", + "numberKept": 1, + "numberCaught": 1 + } + ], + "lakeName": "Chad", + "closestTown": "Chadian", + "numberOfDays": 1 + }, + { + "dataGrid": [ + { + "fishType": "dollyVardon", + "numberKept": 1, + "numberCaught": 1 + }, + { + "fishType": "smallmouthBass", + "numberKept": 1, + "numberCaught": 1 + } + ], + "lakeName": "Tal", + "closestTown": "Talian", + "numberOfDays": 1 + } + ], + "fishermansName": "Ayobami Idowu", + "didYouFishAnyBcLakesThisYear": "yes", + "forWhichBcLakeRegionAreYouCompletingTheseQuestions": 1 + } +] \ No newline at end of file diff --git a/frontend/app/tests/fixtures/submission/kitchen_sink_submission_data_export_datagrid_fields_selection.json b/frontend/app/tests/fixtures/submission/kitchen_sink_submission_data_export_datagrid_fields_selection.json new file mode 100644 index 0000000..04c506a --- /dev/null +++ b/frontend/app/tests/fixtures/submission/kitchen_sink_submission_data_export_datagrid_fields_selection.json @@ -0,0 +1,22 @@ +[ + "form.confirmationId", + "form.formName", + "form.version", + "form.createdAt", + "form.fullName", + "form.username", + "form.email", + "fishermansName", + "email", + "forWhichBcLakeRegionAreYouCompletingTheseQuestions", + "didYouFishAnyBcLakesThisYear", + "oneRowPerLake.0.lakeName", + "oneRowPerLake.0.closestTown", + "oneRowPerLake.0.numberOfDays", + "oneRowPerLake.0.dataGrid.0.fishType", + "oneRowPerLake.0.dataGrid.1.fishType", + "oneRowPerLake.0.dataGrid.0.numberCaught", + "oneRowPerLake.0.dataGrid.1.numberCaught", + "oneRowPerLake.0.dataGrid.0.numberKept", + "oneRowPerLake.0.dataGrid.1.numberKept" +] \ No newline at end of file diff --git a/frontend/app/tests/fixtures/submission/kitchen_sink_submission_data_multiple_component_test.json b/frontend/app/tests/fixtures/submission/kitchen_sink_submission_data_multiple_component_test.json new file mode 100644 index 0000000..5c7f749 --- /dev/null +++ b/frontend/app/tests/fixtures/submission/kitchen_sink_submission_data_multiple_component_test.json @@ -0,0 +1,56 @@ +[ + { + "form": { + "confirmationId": "046A6534", + "formName": "formschematest", + "version": 1, + "createdAt": "2023-02-16T05:52:04.798Z", + "fullName": "Ayobamii Idowu", + "username": "AIDOWU", + "email": "ayobamii.idowu@gov.bc.ca" + }, + "day": "01/01/1900", + "url": "https://google.com", + "yes": true, + "name": "Geirge", + "number": 34, + "radio1": "yes", + "dataMap": { + "yellow": "red" + }, + "number1": 50, + "orgbook": "FFG HOLDINGS", + "select1": "c", + "survey1": { + "late": "very", + "early": "noteVery" + }, + "currency": 443443434, + "lastName": "Idowu", + "password": "sdfsdf", + "textArea": "dfsdfsd,sdfsdfsdf,sdfsdfsd,sdfsdf", + "firstName": "Ayobami", + "simpleday": "01/01/1900", + "testname1": "Horse", + "testname2": "Burna", + "testname3": "Huth", + "courseName": "Sociology", + "radioGroup": "male", + "schoolName": "University of Manitoba", + "simplefile": [ + ], + "simpleemail": "timi@gmail.com", + "selectBoxes1": { + "a": true, + "b": true, + "c": false + }, + "simplenumber": 344, + "checkboxGroup": { + "1": true, + "2": true + }, + "departmentName": "Sociology", + "simpledatetime": "2023-02-15T00:00:00-07:00" + } +] \ No newline at end of file diff --git a/frontend/app/tests/fixtures/submission/kitchen_sink_submission_extract_field_csv_export.json b/frontend/app/tests/fixtures/submission/kitchen_sink_submission_extract_field_csv_export.json new file mode 100644 index 0000000..53280ab --- /dev/null +++ b/frontend/app/tests/fixtures/submission/kitchen_sink_submission_extract_field_csv_export.json @@ -0,0 +1,537 @@ +[ + { + "confirmationId": "93E2EFFB", + "formName": "Fisheries", + "version": 1, + "createdAt": "2023-04-02T18:06:30.840Z", + "fullName": "Ayobamii Idowu", + "username": "AIDOWU", + "email": "ayobamii.idowu@gov.bc.ca", + "submission": { + "email": "Aurth@gmail.com", + "submit": true, + "oneRowPerLake": [ + { + "dataGrid": [ + { + "fishType": "rainbow", + "numberKept": 1, + "numberCaught": 1 + }, + { + "fishType": "cutthroat", + "numberKept": 2, + "numberCaught": 2 + } + ], + "lakeName": "Ran", + "closestTown": "Ranian", + "numberOfDays": 1 + }, + { + "dataGrid": [ + { + "fishType": "rainbow", + "numberKept": 1, + "numberCaught": 1 + }, + { + "fishType": "smallmouthBass", + "numberKept": 1, + "numberCaught": 1 + } + ], + "lakeName": "Cat", + "closestTown": "Catian", + "numberOfDays": 1 + } + ], + "fishermansName": "Geroge Aurth", + "didYouFishAnyBcLakesThisYear": "yes", + "forWhichBcLakeRegionAreYouCompletingTheseQuestions": 1 + } + }, + { + "confirmationId": "E6DCBB3A", + "formName": "Fisheries", + "version": 1, + "createdAt": "2023-04-02T18:06:30.619Z", + "fullName": "Ayobamii Idowu", + "username": "AIDOWU", + "email": "ayobamii.idowu@gov.bc.ca", + "submission": { + "email": "Aurth@gmail.com", + "submit": true, + "oneRowPerLake": [ + { + "dataGrid": [ + { + "fishType": "rainbow", + "numberKept": 1, + "numberCaught": 1 + }, + { + "fishType": "cutthroat", + "numberKept": 2, + "numberCaught": 2 + } + ], + "lakeName": "Ran", + "closestTown": "Ranian", + "numberOfDays": 1 + }, + { + "dataGrid": [ + { + "fishType": "rainbow", + "numberKept": 1, + "numberCaught": 1 + }, + { + "fishType": "smallmouthBass", + "numberKept": 1, + "numberCaught": 1 + } + ], + "lakeName": "Cat", + "closestTown": "Catian", + "numberOfDays": 1 + } + ], + "fishermansName": "Geroge Aurth", + "didYouFishAnyBcLakesThisYear": "yes", + "forWhichBcLakeRegionAreYouCompletingTheseQuestions": 1 + } + }, + { + "confirmationId": "E4D9700A", + "formName": "Fisheries", + "version": 1, + "createdAt": "2023-04-02T18:06:30.097Z", + "fullName": "Ayobamii Idowu", + "username": "AIDOWU", + "email": "ayobamii.idowu@gov.bc.ca", + "submission": { + "email": "Aurth@gmail.com", + "submit": true, + "oneRowPerLake": [ + { + "dataGrid": [ + { + "fishType": "rainbow", + "numberKept": 1, + "numberCaught": 1 + }, + { + "fishType": "cutthroat", + "numberKept": 2, + "numberCaught": 2 + } + ], + "lakeName": "Ran", + "closestTown": "Ranian", + "numberOfDays": 1 + }, + { + "dataGrid": [ + { + "fishType": "rainbow", + "numberKept": 1, + "numberCaught": 1 + }, + { + "fishType": "smallmouthBass", + "numberKept": 1, + "numberCaught": 1 + } + ], + "lakeName": "Cat", + "closestTown": "Catian", + "numberOfDays": 1 + } + ], + "fishermansName": "Geroge Aurth", + "didYouFishAnyBcLakesThisYear": "yes", + "forWhichBcLakeRegionAreYouCompletingTheseQuestions": 1 + } + }, + { + "confirmationId": "5C9455DF", + "formName": "Fisheries", + "version": 1, + "createdAt": "2023-04-02T18:06:28.382Z", + "fullName": "Ayobamii Idowu", + "username": "AIDOWU", + "email": "ayobamii.idowu@gov.bc.ca", + "submission": { + "email": "Aurth@gmail.com", + "submit": true, + "oneRowPerLake": [ + { + "dataGrid": [ + { + "fishType": "rainbow", + "numberKept": 1, + "numberCaught": 1 + }, + { + "fishType": "cutthroat", + "numberKept": 2, + "numberCaught": 2 + } + ], + "lakeName": "Ran", + "closestTown": "Ranian", + "numberOfDays": 1 + }, + { + "dataGrid": [ + { + "fishType": "rainbow", + "numberKept": 1, + "numberCaught": 1 + }, + { + "fishType": "smallmouthBass", + "numberKept": 1, + "numberCaught": 1 + } + ], + "lakeName": "Cat", + "closestTown": "Catian", + "numberOfDays": 1 + } + ], + "fishermansName": "Geroge Aurth", + "didYouFishAnyBcLakesThisYear": "yes", + "forWhichBcLakeRegionAreYouCompletingTheseQuestions": 1 + } + }, + { + "confirmationId": "C51594C1", + "formName": "Fisheries", + "version": 1, + "createdAt": "2023-04-02T18:06:26.559Z", + "fullName": "Ayobamii Idowu", + "username": "AIDOWU", + "email": "ayobamii.idowu@gov.bc.ca", + "submission": { + "email": "Aurth@gmail.com", + "submit": true, + "oneRowPerLake": [ + { + "dataGrid": [ + { + "fishType": "rainbow", + "numberKept": 1, + "numberCaught": 1 + }, + { + "fishType": "cutthroat", + "numberKept": 2, + "numberCaught": 2 + } + ], + "lakeName": "Ran", + "closestTown": "Ranian", + "numberOfDays": 1 + }, + { + "dataGrid": [ + { + "fishType": "rainbow", + "numberKept": 1, + "numberCaught": 1 + }, + { + "fishType": "smallmouthBass", + "numberKept": 1, + "numberCaught": 1 + } + ], + "lakeName": "Cat", + "closestTown": "Catian", + "numberOfDays": 1 + } + ], + "fishermansName": "Geroge Aurth", + "didYouFishAnyBcLakesThisYear": "yes", + "forWhichBcLakeRegionAreYouCompletingTheseQuestions": 1 + } + }, + { + "confirmationId": "40EDE76F", + "formName": "Fisheries", + "version": 1, + "createdAt": "2023-06-02T18:09:26.559Z", + "updatedAt": "2023-06-02T18:10:26.559Z", + "draft": true, + "deleted": false, + "fullName": "Prabhjot Tugger", + "username": "ptugger", + "email": "prabhjot.tugger@gov.bc.ca", + "submission": { + "email": "prabhjot.tugger@gov.bc.ca", + "submit": true, + "oneRowPerLake": [ + { + "dataGrid": [ + { + "fishType": "rainbow", + "numberKept": 1, + "numberCaught": 1 + }, + { + "fishType": "cutthroat", + "numberKept": 2, + "numberCaught": 2 + } + ], + "lakeName": "Ran", + "closestTown": "Ranian", + "numberOfDays": 1 + }, + { + "dataGrid": [ + { + "fishType": "rainbow", + "numberKept": 1, + "numberCaught": 1 + }, + { + "fishType": "smallmouthBass", + "numberKept": 1, + "numberCaught": 1 + } + ], + "lakeName": "Cat", + "closestTown": "Catian", + "numberOfDays": 1 + } + ], + "fishermansName": "Geroge Aurth", + "didYouFishAnyBcLakesThisYear": "yes", + "forWhichBcLakeRegionAreYouCompletingTheseQuestions": 1 + } + }, + { + "confirmationId": "3E105CA1", + "formName": "Fisheries", + "version": 1, + "createdAt": "2023-06-02T18:06:26.559Z", + "updatedAt": "2023-06-02T18:06:26.559Z", + "draft": false, + "deleted": false, + "fullName": "Prabhjot Tugger", + "username": "AIDOWU", + "email": "prabhjot.tugger@gov.bc.ca", + "submission": { + "email": "prabhjot.tugger@gov.bc.ca", + "submit": true, + "oneRowPerLake": [ + { + "dataGrid": [ + { + "fishType": "rainbow", + "numberKept": 1, + "numberCaught": 1 + }, + { + "fishType": "cutthroat", + "numberKept": 2, + "numberCaught": 2 + } + ], + "lakeName": "Ran", + "closestTown": "Ranian", + "numberOfDays": 1 + }, + { + "dataGrid": [ + { + "fishType": "rainbow", + "numberKept": 1, + "numberCaught": 1 + }, + { + "fishType": "smallmouthBass", + "numberKept": 1, + "numberCaught": 1 + } + ], + "lakeName": "Cat", + "closestTown": "Catian", + "numberOfDays": 1 + } + ], + "fishermansName": "Geroge Aurth", + "didYouFishAnyBcLakesThisYear": "yes", + "forWhichBcLakeRegionAreYouCompletingTheseQuestions": 1 + } + }, + { + "confirmationId": "CD097322", + "formName": "Fisheries", + "version": 1, + "createdAt": "2023-06-03T18:06:26.559Z", + "updatedAt": "2023-06-04T18:06:26.559Z", + "draft": true, + "deleted": true, + "fullName": "Prabhjot Tugger", + "username": "AIDOWU", + "email": "prabhjot.tugger@gov.bc.ca", + "submission": { + "email": "prabhjot.tugger@gov.bc.ca", + "submit": true, + "oneRowPerLake": [ + { + "dataGrid": [ + { + "fishType": "rainbow", + "numberKept": 1, + "numberCaught": 1 + }, + { + "fishType": "cutthroat", + "numberKept": 2, + "numberCaught": 2 + } + ], + "lakeName": "Ran", + "closestTown": "Ranian", + "numberOfDays": 1 + }, + { + "dataGrid": [ + { + "fishType": "rainbow", + "numberKept": 1, + "numberCaught": 1 + }, + { + "fishType": "smallmouthBass", + "numberKept": 1, + "numberCaught": 1 + } + ], + "lakeName": "Cat", + "closestTown": "Catian", + "numberOfDays": 1 + } + ], + "fishermansName": "Geroge Aurth", + "didYouFishAnyBcLakesThisYear": "yes", + "forWhichBcLakeRegionAreYouCompletingTheseQuestions": 1 + } + }, + { + "confirmationId": "CD935788", + "formName": "Fisheries", + "version": 1, + "createdAt": "2023-06-02T18:06:26.559Z", + "updatedAt": "2023-06-02T18:06:26.559Z", + "draft": false, + "deleted": true, + "fullName": "Prabhjot Tugger", + "username": "AIDOWU", + "email": "prabhjot.tugger@gov.bc.ca", + "submission": { + "email": "prabhjot.tugger@gov.bc.ca", + "submit": true, + "oneRowPerLake": [ + { + "dataGrid": [ + { + "fishType": "rainbow", + "numberKept": 1, + "numberCaught": 1 + }, + { + "fishType": "cutthroat", + "numberKept": 2, + "numberCaught": 2 + } + ], + "lakeName": "Ran", + "closestTown": "Ranian", + "numberOfDays": 1 + }, + { + "dataGrid": [ + { + "fishType": "rainbow", + "numberKept": 1, + "numberCaught": 1 + }, + { + "fishType": "smallmouthBass", + "numberKept": 1, + "numberCaught": 1 + } + ], + "lakeName": "Cat", + "closestTown": "Catian", + "numberOfDays": 1 + } + ], + "fishermansName": "Geroge Aurth", + "didYouFishAnyBcLakesThisYear": "yes", + "forWhichBcLakeRegionAreYouCompletingTheseQuestions": 1 + } + }, + { + "confirmationId": "CD085969", + "formName": "Fisheries", + "version": 1, + "createdAt": "2023-06-02T18:06:26.559Z", + "updatedAt": "2023-06-02T18:06:26.559Z", + "draft": false, + "deleted": false, + "fullName": "Prabhjot Tugger", + "username": "AIDOWU", + "email": "prabhjot.tugger@gov.bc.ca", + "submission": { + "email": "prabhjot.tugger@gov.bc.ca", + "submit": true, + "oneRowPerLake": [ + { + "dataGrid": [ + { + "fishType": "rainbow", + "numberKept": 1, + "numberCaught": 1 + }, + { + "fishType": "cutthroat", + "numberKept": 2, + "numberCaught": 2 + } + ], + "lakeName": "Ran", + "closestTown": "Ranian", + "numberOfDays": 1 + }, + { + "dataGrid": [ + { + "fishType": "rainbow", + "numberKept": 1, + "numberCaught": 1 + }, + { + "fishType": "smallmouthBass", + "numberKept": 1, + "numberCaught": 1 + } + ], + "lakeName": "Cat", + "closestTown": "Catian", + "numberOfDays": 1 + } + ], + "fishermansName": "Geroge Aurth", + "didYouFishAnyBcLakesThisYear": "yes", + "forWhichBcLakeRegionAreYouCompletingTheseQuestions": 1 + } + } +] \ No newline at end of file diff --git a/frontend/app/tests/fixtures/submission/kitchen_sink_submission_pagination.json b/frontend/app/tests/fixtures/submission/kitchen_sink_submission_pagination.json new file mode 100644 index 0000000..27b7a06 --- /dev/null +++ b/frontend/app/tests/fixtures/submission/kitchen_sink_submission_pagination.json @@ -0,0 +1,212 @@ +[ + { + "confirmationId":"50EA8540", + "createdAt":"2023-08-19T19:12:17.307Z", + "formId":"6512b945-1ec9-4be2-873c-4807a25140ee", + "formSubmissionStatusCode":"SUBMITTED", + "submissionId":"50ea8540-ab3b-4399-8a73-50e311652a2c", + "deleted":false, + "createdBy":"AIDOWU@idir", + "formVersionId":"2881bc5e-7c4c-49cb-9c42-5f1ab33eec13", + "date":null, + "submitter":null, + "status":null, + "lateEntry":false + }, + { + "confirmationId":"B1513631", + "createdAt":"2023-08-19T19:11:52.616Z", + "formId":"6512b945-1ec9-4be2-873c-4807a25140ee", + "formSubmissionStatusCode":"SUBMITTED", + "submissionId":"b1513631-956f-4616-8105-27605b4a57b6", + "deleted":false, + "createdBy":"AIDOWU@idir", + "formVersionId":"2881bc5e-7c4c-49cb-9c42-5f1ab33eec13", + "date":null, + "submitter":null, + "status":null, + "lateEntry":false + }, + { + "confirmationId":"931555F6", + "createdAt":"2023-08-19T19:11:28.638Z", + "formId":"6512b945-1ec9-4be2-873c-4807a25140ee", + "formSubmissionStatusCode":"SUBMITTED", + "submissionId":"931555f6-0125-44cb-a1a5-e80405691d57", + "deleted":false, + "createdBy":"AIDOWU@idir", + "formVersionId":"2881bc5e-7c4c-49cb-9c42-5f1ab33eec13", + "date":null, + "submitter":null, + "status":null, + "lateEntry":false + }, + { + "confirmationId":"41495016", + "createdAt":"2023-08-19T19:11:03.524Z", + "formId":"6512b945-1ec9-4be2-873c-4807a25140ee", + "formSubmissionStatusCode":"SUBMITTED", + "submissionId":"41495016-8c34-43b6-b417-5ce197a60c05", + "deleted":false, + "createdBy":"AIDOWU@idir", + "formVersionId":"2881bc5e-7c4c-49cb-9c42-5f1ab33eec13", + "date":null, + "submitter":null, + "status":null, + "lateEntry":false + }, + { + "confirmationId":"7800BC4D", + "createdAt":"2023-08-19T19:10:35.635Z", + "formId":"6512b945-1ec9-4be2-873c-4807a25140ee", + "formSubmissionStatusCode":"SUBMITTED", + "submissionId":"7800bc4d-7a6d-4b26-afca-91d9c887cccc", + "deleted":false, + "createdBy":"AIDOWU@idir", + "formVersionId":"2881bc5e-7c4c-49cb-9c42-5f1ab33eec13", + "date":null, + "submitter":null, + "status":null, + "lateEntry":false + }, + { + "confirmationId":"1BFC8A79", + "createdAt":"2023-08-19T19:10:12.971Z", + "formId":"6512b945-1ec9-4be2-873c-4807a25140ee", + "formSubmissionStatusCode":"SUBMITTED", + "submissionId":"1bfc8a79-4bd7-4aa6-be31-af95c9b07ea4", + "deleted":false, + "createdBy":"AIDOWU@idir", + "formVersionId":"2881bc5e-7c4c-49cb-9c42-5f1ab33eec13", + "date":null, + "submitter":null, + "status":null, + "lateEntry":false + }, + { + "confirmationId":"CAC6F359", + "createdAt":"2023-08-19T19:09:45.488Z", + "formId":"6512b945-1ec9-4be2-873c-4807a25140ee", + "formSubmissionStatusCode":"SUBMITTED", + "submissionId":"cac6f359-32df-4e40-8742-c7e6995b9055", + "deleted":false, + "createdBy":"AIDOWU@idir", + "formVersionId":"2881bc5e-7c4c-49cb-9c42-5f1ab33eec13", + "date":null, + "submitter":null, + "status":null, + "lateEntry":false + }, + { + "confirmationId":"494A08B0", + "createdAt":"2023-08-19T19:09:18.808Z", + "formId":"6512b945-1ec9-4be2-873c-4807a25140ee", + "formSubmissionStatusCode":"SUBMITTED", + "submissionId":"494a08b0-762e-4736-92a5-3e2b61f1b3c8", + "deleted":false, + "createdBy":"AIDOWU@idir", + "formVersionId":"2881bc5e-7c4c-49cb-9c42-5f1ab33eec13", + "date":null, + "submitter":null, + "status":null, + "lateEntry":false + }, + { + "confirmationId":"64AF3402", + "createdAt":"2023-08-19T19:08:53.086Z", + "formId":"6512b945-1ec9-4be2-873c-4807a25140ee", + "formSubmissionStatusCode":"SUBMITTED", + "submissionId":"64af3402-1cb5-483c-af1f-eb72d4e52452", + "deleted":false, + "createdBy":"AIDOWU@idir", + "formVersionId":"2881bc5e-7c4c-49cb-9c42-5f1ab33eec13", + "date":null, + "submitter":null, + "status":null, + "lateEntry":false + }, + { + "confirmationId":"035C655E", + "createdAt":"2023-08-19T19:08:25.494Z", + "formId":"6512b945-1ec9-4be2-873c-4807a25140ee", + "formSubmissionStatusCode":"SUBMITTED", + "submissionId":"035c655e-4fcc-4fa7-9735-175e73e12806", + "deleted":false, + "createdBy":"AIDOWU@idir", + "formVersionId":"2881bc5e-7c4c-49cb-9c42-5f1ab33eec13", + "date":null, + "submitter":null, + "status":null, + "lateEntry":false + }, + { + "confirmationId":"9ACB68DC", + "createdAt":"2023-08-19T19:07:47.961Z", + "formId":"6512b945-1ec9-4be2-873c-4807a25140ee", + "formSubmissionStatusCode":"SUBMITTED", + "submissionId":"9acb68dc-7281-4b68-bda7-31698a08ecc9", + "deleted":false, + "createdBy":"AIDOWU@idir", + "formVersionId":"2881bc5e-7c4c-49cb-9c42-5f1ab33eec13", + "date":null, + "submitter":null, + "status":null, + "lateEntry":false + }, + { + "confirmationId":"B1B292A4", + "createdAt":"2023-08-19T19:03:23.559Z", + "formId":"6512b945-1ec9-4be2-873c-4807a25140ee", + "formSubmissionStatusCode":"SUBMITTED", + "submissionId":"b1b292a4-d49a-404b-a1e7-d767bd17d427", + "deleted":false, + "createdBy":"AIDOWU@idir", + "formVersionId":"2881bc5e-7c4c-49cb-9c42-5f1ab33eec13", + "date":null, + "submitter":null, + "status":null, + "lateEntry":false + }, + { + "confirmationId":"BAD18078", + "createdAt":"2023-08-19T19:02:40.244Z", + "formId":"6512b945-1ec9-4be2-873c-4807a25140ee", + "formSubmissionStatusCode":"SUBMITTED", + "submissionId":"bad18078-1fbe-427c-9d3f-3003ac83005d", + "deleted":false, + "createdBy":"AIDOWU@idir", + "formVersionId":"2881bc5e-7c4c-49cb-9c42-5f1ab33eec13", + "date":null, + "submitter":null, + "status":null, + "lateEntry":false + }, + { + "confirmationId":"29501EC4", + "createdAt":"2023-08-19T19:02:13.465Z", + "formId":"6512b945-1ec9-4be2-873c-4807a25140ee", + "formSubmissionStatusCode":"SUBMITTED", + "submissionId":"29501ec4-12d8-4223-9fcf-44ec2f275f8c", + "deleted":false, + "createdBy":"AIDOWU@idir", + "formVersionId":"2881bc5e-7c4c-49cb-9c42-5f1ab33eec13", + "date":null, + "submitter":null, + "status":null, + "lateEntry":false + }, + { + "confirmationId":"ED97EE64", + "createdAt":"2023-08-19T19:00:51.244Z", + "formId":"6512b945-1ec9-4be2-873c-4807a25140ee", + "formSubmissionStatusCode":"SUBMITTED", + "submissionId":"ed97ee64-9ca5-4316-a9d6-32777761231e", + "deleted":false, + "createdBy":"AIDOWU@idir", + "formVersionId":"2881bc5e-7c4c-49cb-9c42-5f1ab33eec13", + "date":null, + "submitter":null, + "status":null, + "lateEntry":false + } + ] \ No newline at end of file diff --git a/frontend/app/tests/fixtures/submission/kitchen_sink_submissions_export.json b/frontend/app/tests/fixtures/submission/kitchen_sink_submissions_export.json new file mode 100644 index 0000000..a872c89 --- /dev/null +++ b/frontend/app/tests/fixtures/submission/kitchen_sink_submissions_export.json @@ -0,0 +1,84 @@ +[ + { + "form": { + "confirmationId": "75B7FC7F", + "formName": "kitchen sink", + "version": 1, + "createdAt": "2021-09-22T21:08:38.837Z", + "fullName": "John Smith", + "username": "jsmith", + "email": "john.smith@gov.bc.ca", + "status": "SUBMITTED", + "assignee": null, + "assigneeEmail": null + }, + "day1": "01/01/2021", + "time1": "01:01:00", + "email1": "email@abc.com", + "email2": "email@abc.com", + "number": 456, + "submit": true, + "number2": 123, + "checkbox1": false, + "dateTime1": "2021-01-01T13:01:00-08:00", + "textField1": "abcdefg", + "textField3": "abcdef", + "radioGroup1": "radio1", + "selectList1": "selection1", + "selectList2": [ + "select1" + ], + "phoneNumber1": "(456) 000-0000", + "phoneNumber2": "(123) 000-0000", + "checkboxGroup1": { + "check1": true, + "check2": false, + "check3": false + }, + "multiLineText1": "multi text abc", + "textFieldNested1": "abc", + "textFieldNested2": "abcd", + "textFieldInFieldset1": "abcde", + "selectListInFieldset1": 1, + "registeredBusinessName1": "ABC WOODWORKS" + }, + { + "form": { + "confirmationId": "058633F9", + "formName": "kitchen sink", + "version": 1, + "createdAt": "2021-06-16T19:09:12.823Z", + "fullName": "Jane Smith", + "username": "jasmith", + "email": "jane.smith@gov.bc.ca", + "status": "SUBMITTED", + "assignee": null, + "assigneeEmail": null + }, + "day1": "00/00/0000", + "time1": "", + "email1": "", + "email2": "", + "submit": true, + "checkbox1": false, + "dateTime1": "", + "textField1": "", + "textField3": "", + "radioGroup1": "", + "selectList1": "choose", + "selectList2": [], + "phoneNumber1": "", + "phoneNumber2": "", + "checkboxGroup1": { + "check1": false, + "check2": false, + "check3": false + }, + "multiLineText1": "", + "textFieldNested1": "text field nested 1", + "textFieldNested2": "text field nested 2", + "textFieldInFieldset1": "", + "selectListInFieldset1": "", + "registeredBusinessName1": "" + } +] diff --git a/frontend/app/tests/unit/components/errorToProblem.spec.js b/frontend/app/tests/unit/components/errorToProblem.spec.js new file mode 100644 index 0000000..7efcdaa --- /dev/null +++ b/frontend/app/tests/unit/components/errorToProblem.spec.js @@ -0,0 +1,22 @@ +const errorToProblem = require('../../../src/components/errorToProblem'); + +const SERVICE = 'TESTSERVICE'; + +describe('errorToProblem', () => { + it('should throw a 422', () => { + const e = { + response: { + data: { detail: 'detail' }, + status: 422, + }, + }; + expect(() => errorToProblem(SERVICE, e)).toThrow('422'); + }); + + it('should throw a 502', () => { + const e = { + message: 'msg', + }; + expect(() => errorToProblem(SERVICE, e)).toThrow('502'); + }); +}); diff --git a/frontend/app/tests/unit/components/log.spec.js b/frontend/app/tests/unit/components/log.spec.js new file mode 100644 index 0000000..e0ded5a --- /dev/null +++ b/frontend/app/tests/unit/components/log.spec.js @@ -0,0 +1,36 @@ +const config = require('config'); + +const getLogger = require('../../../src/components/log'); +const httpLogger = require('../../../src/components/log').httpLogger; + +describe('getLogger', () => { + const assertLogger = (log) => { + expect(log).toBeTruthy(); + expect(typeof log).toBe('object'); + expect(typeof log.pipe).toBe('function'); + expect(log.exitOnError).toBeFalsy(); + expect(log.format).toBeTruthy(); + expect(log.level).toBe(config.get('server.logLevel')); + expect(log.transports).toHaveLength(1); + }; + + it('should return a winston logger', () => { + const result = getLogger(); + assertLogger(result); + }); + + it('should return a child winston logger with metadata overrides', () => { + const result = getLogger('test'); + assertLogger(result); + }); +}); + +describe('httpLogger', () => { + it('should return a winston middleware function', () => { + const result = httpLogger; + + expect(result).toBeTruthy(); + expect(typeof result).toBe('function'); + expect(result.length).toBe(3); + }); +}); diff --git a/frontend/app/tests/unit/forms/admin/controller.spec.js b/frontend/app/tests/unit/forms/admin/controller.spec.js new file mode 100644 index 0000000..d31bbd9 --- /dev/null +++ b/frontend/app/tests/unit/forms/admin/controller.spec.js @@ -0,0 +1,55 @@ +const controller = require('../../../../src/forms/admin/controller'); +const service = require('../../../../src/forms/admin/service'); + +const req = { + params: {}, + body: {}, + currentUser: {}, + headers: {}, +}; + +describe('form controller', () => { + it('should create proactive help for content form.io component', async () => { + const formComponentsProactiveHelp = { + componentname: 'Content', + externallink: 'https://helplink.com', + image: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAB3g', + version: 1, + groupname: 'Basic Layout', + description: 'gughuhiuhuih', + publishstatus: false, + }; + + service.createFormComponentsProactiveHelp = jest.fn().mockReturnValue(formComponentsProactiveHelp); + + await controller.createFormComponentsProactiveHelp(req, {}, jest.fn()); + expect(service.createFormComponentsProactiveHelp).toHaveBeenCalledTimes(1); + }); + + it('should update proactive help component publish status', async () => { + req.params['publishStatus'] = true; + req.params['componentId'] = '5b97417a-252c-46c2-b132-85adac5ab3bc'; + + const formComponentsProactiveHelp = { + componentName: 'Content', + externalLink: 'https://helplink.com', + image: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAB3g', + version: 1, + groupName: 'Basic Layout', + description: 'gughuhiuhuih', + status: false, + }; + + service.updateFormComponentsProactiveHelp = jest.fn().mockReturnValue(formComponentsProactiveHelp); + + await controller.updateFormComponentsProactiveHelp(req, {}, jest.fn()); + expect(service.updateFormComponentsProactiveHelp).toHaveBeenCalledTimes(1); + }); + + it('should get list of all proactive help components', async () => { + service.listFormComponentsProactiveHelp = jest.fn().mockReturnValue({}); + + await controller.listFormComponentsProactiveHelp(req, {}, jest.fn()); + expect(service.listFormComponentsProactiveHelp).toHaveBeenCalledTimes(1); + }); +}); diff --git a/frontend/app/tests/unit/forms/admin/service.spec.js b/frontend/app/tests/unit/forms/admin/service.spec.js new file mode 100644 index 0000000..8c2c452 --- /dev/null +++ b/frontend/app/tests/unit/forms/admin/service.spec.js @@ -0,0 +1,119 @@ +const service = require('../../../../src/forms/admin/service'); + +describe('Admin service', () => { + it('createFormComponentsProactiveHelp()', async () => { + const formComponentsHelpInfo = { + componentName: 'Content', + externalLink: 'https://helplink.com', + image: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAB3g', + version: 1, + groupName: 'Basic Layout', + description: 'gughuhiuhuih', + status: false, + }; + + // mock readVersion function + service.createFormComponentsProactiveHelp = jest.fn().mockReturnValue(formComponentsHelpInfo); + // get fields + const result = await service.createFormComponentsProactiveHelp(); + // test cases + expect(result).toEqual(formComponentsHelpInfo); + }); + + it('updateFormComponentsProactiveHelp()', async () => { + const formComponentsHelpInfo = { + componentName: 'Content', + externalLink: 'https://helplink.com', + image: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAB3g', + version: 1, + groupName: 'Basic Layout', + description: 'gughuhiuhuih', + status: true, + }; + + // mock readVersion function + service.updateFormComponentsProactiveHelp = jest.fn().mockReturnValue(formComponentsHelpInfo); + // get fields + const result = await service.updateFormComponentsProactiveHelp(); + // test cases + expect(result).toEqual(formComponentsHelpInfo); + }); + + it('listFormComponentsProactiveHelp()', async () => { + const formComponentsHelpInfo = [ + { + componentname: 'Content', + externallink: 'https://helplink.com', + image: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAB3g', + version: 1, + groupname: 'Basic Layout', + description: 'gughuhiuhuih', + publishstatus: false, + }, + { + componentname: 'Text Field', + externallink: 'https://helplink.com', + image: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAB3g', + version: 1, + groupname: 'Basic Layout', + description: 'gughuhiuhuih', + publishstatus: false, + }, + ]; + + formComponentsHelpInfo.reduce(function (r, a) { + r[a.groupName] = r[a.groupName] || []; + r[a.groupName].push(a); + return r; + }, Object.create(null)); + + // mock readVersion function + service.listFormComponentsProactiveHelp = jest.fn().mockReturnValue(formComponentsHelpInfo); + // get fields + const fields = await service.listFormComponentsProactiveHelp(); + // test cases + expect(Object.keys(fields).length).toEqual(2); + }); + + it('readFormComponentsProactiveHelp()', async () => { + const returnValue = { + componentname: 'Text Field', + externallink: 'https://helplink.com', + image: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAB3g', + version: 1, + groupname: 'Basic Layout', + description: 'gughuhiuhuih', + publishstatus: false, + id: 1, + }; + + const formComponentsHelpInfo = [ + { + componentname: 'Content', + externallink: 'https://helplink.com', + image: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAB3g', + version: 1, + groupname: 'Basic Layout', + description: 'gughuhiuhuih', + publishstatus: false, + }, + { + componentname: 'Text Field', + externallink: 'https://helplink.com', + image: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAB3g', + version: 1, + groupname: 'Basic Layout', + description: 'gughuhiuhuih', + publishstatus: false, + id: 1, + }, + ]; + + // mock readVersion function + service.readFormComponentsProactiveHelp = jest.fn().mockReturnValue(returnValue); + // get fields + const fields = await service.readFormComponentsProactiveHelp(); + // test cases + expect(fields).toEqual(formComponentsHelpInfo[1]); + }); +}); diff --git a/frontend/app/tests/unit/forms/auth/authService.spec.js b/frontend/app/tests/unit/forms/auth/authService.spec.js new file mode 100644 index 0000000..aa070bb --- /dev/null +++ b/frontend/app/tests/unit/forms/auth/authService.spec.js @@ -0,0 +1,73 @@ +const service = require('../../../../src/forms/auth/service'); + +afterEach(() => { + jest.clearAllMocks(); +}); + +describe('parseToken', () => { + it('returns a default object when an exception happens', () => { + const result = service.parseToken(undefined); + expect(result).toEqual({ + idpUserId: undefined, + username: 'public', + firstName: undefined, + lastName: undefined, + fullName: 'public', + email: undefined, + idp: 'public', + public: true, + }); + }); +}); + +describe('formAccessToForm', () => { + it('transforms the object', () => { + const form = { + formId: 1, + formName: 2, + formDescription: 3, + labels: 4, + idps: 5, + active: 6, + formVersionId: 7, + version: 8, + published: 9, + versionUpdatedAt: 10, + roles: 11, + permissions: 12, + }; + const result = service.formAccessToForm(form); + expect(result).toEqual(form); + }); +}); + +describe('login', () => { + const resultSample = { + user: 'me', + forms: [{ formID: 1 }, { formId: 2 }], + deletedForms: [{ formID: 1 }, { formId: 2 }], + }; + + it('returns a currentUser object', async () => { + service.parseToken = jest.fn().mockReturnValue('userInf'); + service.getUserId = jest.fn().mockReturnValue({ user: 'me' }); + service.getUserForms = jest.fn().mockReturnValue([{ formID: 1 }, { formId: 2 }]); + const params = { p: 1 }; + const token = 'token'; + const result = await service.login(token, params); + expect(service.parseToken).toHaveBeenCalledTimes(1); + expect(service.parseToken).toHaveBeenCalledWith(token); + expect(service.getUserId).toHaveBeenCalledTimes(1); + expect(service.getUserId).toHaveBeenCalledWith('userInf'); + expect(service.getUserForms).toHaveBeenCalledTimes(2); + expect(service.getUserForms).toHaveBeenCalledWith({ user: 'me' }, { p: 1, active: false }); + expect(result).toBeTruthy(); + expect(result).toEqual(resultSample); + }); + + it('works with no params supplied', async () => { + const token = 'token'; + const result = await service.login(token); + expect(result).toEqual(resultSample); + }); +}); diff --git a/frontend/app/tests/unit/forms/auth/middleware/apiAccess.spec.js b/frontend/app/tests/unit/forms/auth/middleware/apiAccess.spec.js new file mode 100644 index 0000000..6a3600d --- /dev/null +++ b/frontend/app/tests/unit/forms/auth/middleware/apiAccess.spec.js @@ -0,0 +1,212 @@ +const apiAccess = require('../../../../../src/forms/auth/middleware/apiAccess'); + +const formService = require('../../../../../src/forms/form/service'); +const submissionService = require('../../../../../src/forms/submission/service'); + +describe('apiAccess', () => { + const formId = 'c6455376-382c-439d-a811-0381a012d696'; + const formSubmissionId = '3ba5659c-1a3f-4e76-a0d4-ef00f5102387'; + const secret = 'dd7d1699-61ec-4037-aa33-727f8aa79c0a'; + const token = Buffer.from(`${formId}:${secret}`).toString('base64'); + const authHeader = `Basic ${token}`; + + const baseRes = { status: () => ({ json: () => {} }) }; + + const next = jest.fn(); + const mockReadApiKey = jest.spyOn(formService, 'readApiKey'); + + beforeEach(() => { + next.mockReset(); + mockReadApiKey.mockReset(); + }); + + afterAll(() => { + mockReadApiKey.mockRestore(); + }); + + it('should only call next if there are no headers', async () => { + const req = {}; + const res = { ...baseRes }; + await apiAccess(req, res, next); + + expect(req.apiUser).toBeFalsy(); + expect(next).toHaveBeenCalledTimes(1); + expect(mockReadApiKey).toHaveBeenCalledTimes(0); + }); + + it('should only call next if there are no auth headers', async () => { + const req = { headers: {} }; + const res = { ...baseRes }; + await apiAccess(req, res, next); + + expect(req.apiUser).toBeFalsy(); + expect(next).toHaveBeenCalledTimes(1); + expect(mockReadApiKey).toHaveBeenCalledTimes(0); + }); + + it('should only call next with bearer authorization', async () => { + const req = { headers: { authorization: 'Bearer JWT' } }; + const res = { ...baseRes }; + await apiAccess(req, res, next); + + expect(req.apiUser).toBeFalsy(); + expect(next).toHaveBeenCalledTimes(1); + expect(mockReadApiKey).toHaveBeenCalledTimes(0); + }); + + it('should not call readApiKey with no formId or formSubmissionId param', async () => { + const req = { headers: { authorization: authHeader } }; + const res = { ...baseRes }; + await apiAccess(req, res, next); + + expect(req.apiUser).toBeFalsy(); + expect(next).toHaveBeenCalledTimes(0); + expect(mockReadApiKey).toHaveBeenCalledTimes(0); + }); + + it('should not call readApiKey with invalid formId param', async () => { + const req = { + headers: { authorization: authHeader }, + params: { formId: 'invalidForm' }, + }; + const res = { ...baseRes }; + await apiAccess(req, res, next); + + expect(req.apiUser).toBeFalsy(); + expect(next).toHaveBeenCalledTimes(0); + expect(mockReadApiKey).toHaveBeenCalledTimes(0); + }); + + it('should not call readApiKey with invalid formSubmissionId param', async () => { + const req = { + headers: { authorization: authHeader }, + params: { formSubmissionId: 'invalidForm' }, + }; + const res = { ...baseRes }; + await apiAccess(req, res, next); + + expect(req.apiUser).toBeFalsy(); + expect(next).toHaveBeenCalledTimes(0); + expect(mockReadApiKey).toHaveBeenCalledTimes(0); + }); + + it('should flag apiUser as false with no API key result', async () => { + mockReadApiKey.mockResolvedValue(); + const req = { + headers: { authorization: authHeader }, + params: { formId: formId }, + }; + const res = { ...baseRes }; + await apiAccess(req, res, next); + + expect(req.apiUser).toBeFalsy(); + expect(next).toHaveBeenCalledTimes(0); + expect(mockReadApiKey).toHaveBeenCalledTimes(1); + }); + + it('should flag apiUser as false with no API key secret', async () => { + mockReadApiKey.mockResolvedValue({}); + const req = { + headers: { authorization: authHeader }, + params: { formId: formId }, + }; + const res = { ...baseRes }; + await apiAccess(req, res, next); + + expect(req.apiUser).toBeFalsy(); + expect(next).toHaveBeenCalledTimes(0); + expect(mockReadApiKey).toHaveBeenCalledTimes(1); + }); + + it('should flag apiUser as false with invalid formId credentials', async () => { + mockReadApiKey.mockResolvedValue({ secret: 'invalidSecret' }); + const req = { + headers: { authorization: authHeader }, + params: { formId: formId }, + }; + const res = { ...baseRes }; + await apiAccess(req, res, next); + + expect(req.apiUser).toBeFalsy(); + expect(next).toHaveBeenCalledTimes(0); + expect(mockReadApiKey).toHaveBeenCalledTimes(1); + }); + + it('should flag apiUser as false with invalid formSubmissionId credentials', async () => { + mockReadApiKey.mockResolvedValue({ secret: 'invalidSecret' }); + submissionService.read = jest.fn().mockReturnValue({ form: { id: formId } }); + + const req = { + headers: { authorization: authHeader }, + params: { formSubmissionId: formSubmissionId }, + }; + const res = { ...baseRes }; + await apiAccess(req, res, next); + + expect(req.apiUser).toBeFalsy(); + expect(next).toHaveBeenCalledTimes(0); + expect(mockReadApiKey).toHaveBeenCalledTimes(1); + }); + + it('should flag apiUser as false with no submission result', async () => { + mockReadApiKey.mockResolvedValue({ secret: 'invalidSecret' }); + submissionService.read = jest.fn().mockReturnValue(); + + const req = { + headers: { authorization: authHeader }, + params: { formSubmissionId: formSubmissionId }, + }; + const res = { ...baseRes }; + await apiAccess(req, res, next); + + expect(req.apiUser).toBeFalsy(); + expect(next).toHaveBeenCalledTimes(0); + expect(mockReadApiKey).toHaveBeenCalledTimes(0); + }); + + it('should flag apiUser as false with submission result without form', async () => { + mockReadApiKey.mockResolvedValue({ secret: 'invalidSecret' }); + submissionService.read = jest.fn().mockReturnValue({}); + + const req = { + headers: { authorization: authHeader }, + params: { formSubmissionId: formSubmissionId }, + }; + const res = { ...baseRes }; + await apiAccess(req, res, next); + + expect(req.apiUser).toBeFalsy(); + expect(next).toHaveBeenCalledTimes(0); + expect(mockReadApiKey).toHaveBeenCalledTimes(0); + }); + + it('should flag apiUser as false with submission result without form id', async () => { + mockReadApiKey.mockResolvedValue({ secret: 'invalidSecret' }); + submissionService.read = jest.fn().mockReturnValue({ form: {} }); + + const req = { + headers: { authorization: authHeader }, + params: { formSubmissionId: formSubmissionId }, + }; + const res = { ...baseRes }; + await apiAccess(req, res, next); + + expect(req.apiUser).toBeFalsy(); + expect(next).toHaveBeenCalledTimes(0); + expect(mockReadApiKey).toHaveBeenCalledTimes(0); + }); + + it('should flag apiUser as true with valid credentials', async () => { + mockReadApiKey.mockResolvedValue({ secret: secret }); + const req = { + headers: { authorization: authHeader }, + params: { formId: formId }, + }; + const res = { ...baseRes }; + await apiAccess(req, res, next); + + expect(req.apiUser).toBeTruthy(); + expect(next).toHaveBeenCalledTimes(1); + expect(mockReadApiKey).toHaveBeenCalledTimes(1); + }); +}); diff --git a/frontend/app/tests/unit/forms/auth/middleware/userAccess.spec.js b/frontend/app/tests/unit/forms/auth/middleware/userAccess.spec.js new file mode 100644 index 0000000..f85d688 --- /dev/null +++ b/frontend/app/tests/unit/forms/auth/middleware/userAccess.spec.js @@ -0,0 +1,1882 @@ +const { currentUser, hasFormPermissions, hasSubmissionPermissions, hasFormRoles, hasRolePermissions } = require('../../../../../src/forms/auth/middleware/userAccess'); + +const keycloak = require('../../../../../src/components/keycloak'); +const Problem = require('api-problem'); +const service = require('../../../../../src/forms/auth/service'); +const rbacService = require('../../../../../src/forms/rbac/service'); + +const kauth = { + grant: { + access_token: 'fsdfhsd08f0283hr', + }, +}; + +const userId = 'c6455376-382c-439d-a811-0381a012d695'; +const userId2 = 'c6455376-382c-439d-a811-0381a012d696'; +const formId = 'c6455376-382c-439d-a811-0381a012d697'; + +const Roles = { + OWNER: 'owner', + TEAM_MANAGER: 'team_manager', + FORM_DESIGNER: 'form_designer', + SUBMISSION_REVIEWER: 'submission_reviewer', + FORM_SUBMITTER: 'form_submitter', +}; + +// Mock the token validation in the KC lib +keycloak.grantManager.validateAccessToken = jest.fn().mockReturnValue('yeah ok'); + +// Mock the service login +const mockUser = { user: 'me' }; +service.login = jest.fn().mockReturnValue(mockUser); + +const testRes = { + writeHead: jest.fn(), + end: jest.fn(), +}; + +afterEach(() => { + jest.clearAllMocks(); +}); + +describe('currentUser', () => { + it('gets the current user with valid request', async () => { + const testReq = { + params: { + formId: 2, + }, + headers: { + authorization: 'Bearer hjvds0uds', + }, + kauth: kauth, + }; + + const nxt = jest.fn(); + + await currentUser(testReq, testRes, nxt); + expect(keycloak.grantManager.validateAccessToken).toHaveBeenCalledTimes(1); + expect(keycloak.grantManager.validateAccessToken).toHaveBeenCalledWith('hjvds0uds'); + expect(service.login).toHaveBeenCalledTimes(1); + expect(service.login).toHaveBeenCalledWith(kauth.grant.access_token, { formId: 2 }); + expect(testReq.currentUser).toEqual(mockUser); + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(); + }); + + it('prioritizes the url param if both url and query are provided', async () => { + const testReq = { + params: { + formId: 2, + }, + query: { + formId: 99, + }, + headers: { + authorization: 'Bearer hjvds0uds', + }, + kauth: kauth, + }; + + await currentUser(testReq, testRes, jest.fn()); + expect(service.login).toHaveBeenCalledWith(kauth.grant.access_token, { formId: 2 }); + }); + + it('uses the query param if both if that is whats provided', async () => { + const testReq = { + query: { + formId: 99, + }, + headers: { + authorization: 'Bearer hjvds0uds', + }, + kauth: kauth, + }; + + await currentUser(testReq, testRes, jest.fn()); + expect(service.login).toHaveBeenCalledWith(kauth.grant.access_token, { formId: 99 }); + }); + + it('403s if the token is invalid', async () => { + const testReq = { + headers: { + authorization: 'Bearer hjvds0uds', + }, + }; + + const nxt = jest.fn(); + keycloak.grantManager.validateAccessToken = jest.fn().mockReturnValue(undefined); + + await currentUser(testReq, testRes, nxt); + expect(keycloak.grantManager.validateAccessToken).toHaveBeenCalledTimes(1); + expect(keycloak.grantManager.validateAccessToken).toHaveBeenCalledWith('hjvds0uds'); + expect(service.login).toHaveBeenCalledTimes(0); + expect(testReq.currentUser).toEqual(undefined); + expect(nxt).toHaveBeenCalledTimes(0); + // expect(nxt).toHaveBeenCalledWith(new Problem(403, { detail: 'Authorization token is invalid.' })); + }); +}); + +describe('getToken', () => { + it('returns a null token if no kauth in the request', async () => { + const testReq = { + params: { + formId: 2, + }, + }; + + await currentUser(testReq, testRes, jest.fn()); + expect(service.login).toHaveBeenCalledTimes(1); + expect(service.login).toHaveBeenCalledWith(null, { formId: 2 }); + }); +}); + +describe('hasFormPermissions', () => { + it('returns a middleware function', async () => { + const mw = hasFormPermissions(['abc']); + expect(mw).toBeInstanceOf(Function); + }); + + it('401s if the request has no current user', async () => { + const mw = hasFormPermissions(['abc']); + const nxt = jest.fn(); + const req = { a: '1' }; + + mw(req, testRes, nxt); + expect(nxt).toHaveBeenCalledTimes(0); + // expect(nxt).toHaveBeenCalledWith(new Problem(401, { detail: 'Current user not found on request.' })); + }); + + it('401s if the request has no formId', async () => { + const mw = hasFormPermissions(['abc']); + const nxt = jest.fn(); + const req = { + currentUser: { + forms: 1, + }, + params: { + submissionId: 123, + }, + query: { + otherQueryThing: 'abc', + }, + }; + + mw(req, testRes, nxt); + expect(nxt).toHaveBeenCalledTimes(0); + // expect(nxt).toHaveBeenCalledWith(new Problem(401, { detail: 'Form Id not found on request.' })); + }); + + it('401s if the user does not have access to the form', async () => { + const mw = hasFormPermissions(['abc']); + const nxt = jest.fn(); + const req = { + currentUser: { + forms: [ + { + formId: '456', + }, + { + formId: '789', + }, + ], + }, + params: { + formId: '123', + }, + }; + + mw(req, testRes, nxt); + expect(nxt).toHaveBeenCalledTimes(0); + // expect(nxt).toHaveBeenCalledWith(new Problem(401, { detail: 'Current user has no access to form.' })); + }); + + it('401s if the user does not have access to the form nor is it in their deleted', async () => { + const mw = hasFormPermissions(['abc']); + const nxt = jest.fn(); + const req = { + currentUser: { + forms: [ + { + formId: '456', + }, + { + formId: '789', + }, + ], + deletedForms: [ + { + formId: '888', + }, + { + formId: '999', + }, + ], + }, + params: { + formId: '123', + }, + }; + + mw(req, testRes, nxt); + expect(nxt).toHaveBeenCalledTimes(0); + // expect(nxt).toHaveBeenCalledWith(new Problem(401, { detail: 'Current user has no access to form.' })); + }); + + it('does not 401 if the user has deleted form access', async () => { + const mw = hasFormPermissions(['abc']); + const nxt = jest.fn(); + const req = { + currentUser: { + forms: [ + { + formId: '456', + }, + { + formId: '789', + }, + ], + deletedForms: [ + { + formId: '888', + }, + { + formId: '123', + permissions: ['abc'], + }, + ], + }, + params: { + formId: '123', + }, + }; + + mw(req, testRes, nxt); + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(); + }); + + it('401s if the expected permissions are not included', async () => { + const mw = hasFormPermissions(['FORM_READ', 'SUBMISSION_DELETE', 'DESIGN_CREATE']); + const nxt = jest.fn(); + const req = { + currentUser: { + forms: [ + { + formId: '456', + }, + { + formId: '123', + permissions: ['FORM_READ', 'SUBMISSION_READ', 'DESIGN_CREATE'], + }, + ], + }, + params: { + formId: '123', + }, + }; + + mw(req, testRes, nxt); + expect(nxt).toHaveBeenCalledTimes(0); + // expect(nxt).toHaveBeenCalledWith(new Problem(401, { detail: 'Current user does not have required permission(s) on form.' })); + }); + + it('401s if the expected permissions are not included (string, not array check)', async () => { + const mw = hasFormPermissions('FORM_READ'); + const nxt = jest.fn(); + const req = { + currentUser: { + forms: [ + { + formId: '456', + }, + { + formId: '123', + permissions: ['FORM_DELETE'], + }, + ], + }, + params: { + formId: '123', + }, + }; + + mw(req, testRes, nxt); + expect(nxt).toHaveBeenCalledTimes(0); + // expect(nxt).toHaveBeenCalledWith(new Problem(401, { detail: 'Current user does not have required permission(s) on form.' })); + }); + + it('moves on if the expected permissions are included', async () => { + const mw = hasFormPermissions(['FORM_READ', 'SUBMISSION_DELETE', 'DESIGN_CREATE']); + const nxt = jest.fn(); + const req = { + currentUser: { + forms: [ + { + formId: '456', + }, + { + formId: '123', + permissions: ['FORM_READ', 'SUBMISSION_DELETE', 'DESIGN_CREATE'], + }, + ], + }, + params: { + formId: '123', + }, + }; + + mw(req, testRes, nxt); + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(); + }); + + it('moves on if a valid API key user has already been set', async () => { + const mw = hasFormPermissions(['abc']); + const nxt = jest.fn(); + const req = { + apiUser: 1, + }; + + mw(req, testRes, nxt); + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(); + }); +}); + +describe('hasSubmissionPermissions', () => { + it('returns a middleware function', () => { + const mw = hasSubmissionPermissions(['abc']); + expect(mw).toBeInstanceOf(Function); + }); + + it('moves on if a valid API key user has already been set', async () => { + const mw = hasSubmissionPermissions(['abc']); + const nxt = jest.fn(); + const req = { + apiUser: 1, + }; + + mw(req, testRes, nxt); + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(); + }); + + it('401s if the request has no formId', async () => { + const mw = hasSubmissionPermissions(['abc']); + const nxt = jest.fn(); + const req = { + params: { + formId: 123, + }, + query: { + otherQueryThing: 'abc', + }, + }; + + await mw(req, testRes, nxt); + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(new Problem(401, { detail: 'Submission Id not found on request.' })); + }); + + it('401s if the submission was deleted', async () => { + service.getSubmissionForm = jest.fn().mockReturnValue({ submission: { deleted: true } }); + + const mw = hasSubmissionPermissions(['abc']); + const nxt = jest.fn(); + const req = { + params: { + formSubmissionId: 123, + }, + }; + + await mw(req, testRes, nxt); + expect(service.getSubmissionForm).toHaveBeenCalledTimes(1); + expect(service.getSubmissionForm).toHaveBeenCalledWith(123); + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(new Problem(401, { detail: 'You do not have access to this submission.' })); + }); + + it('moves on if the form is public and you are only requesting read permission', async () => { + service.getSubmissionForm = jest.fn().mockReturnValue({ + submission: { deleted: false }, + form: { identityProviders: [{ code: 'random' }, { code: 'public' }] }, + }); + + const mw = hasSubmissionPermissions('submission_read'); + const nxt = jest.fn(); + const req = { + params: { + formSubmissionId: 123, + }, + }; + + await mw(req, testRes, nxt); + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(); + }); + + it('moves on if the form is public and you are only requesting read permission (only 1 idp)', async () => { + service.getSubmissionForm = jest.fn().mockReturnValue({ + submission: { deleted: false }, + form: { identityProviders: [{ code: 'public' }] }, + }); + + const mw = hasSubmissionPermissions(['submission_read']); + const nxt = jest.fn(); + const req = { + params: { + formSubmissionId: 123, + }, + }; + + await mw(req, testRes, nxt); + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(); + }); + + it('does not allow public access if more than read permission is needed', async () => { + service.getSubmissionForm = jest.fn().mockReturnValue({ + submission: { deleted: false }, + form: { identityProviders: [{ code: 'public' }] }, + }); + service.checkSubmissionPermission = jest.fn().mockReturnValue(undefined); + + const mw = hasSubmissionPermissions(['submission_read', 'submission_delete']); + const nxt = jest.fn(); + const req = { + params: { + formSubmissionId: 123, + }, + }; + + await mw(req, testRes, nxt); + // just run to the end and fall into the base case + expect(service.checkSubmissionPermission).toHaveBeenCalledTimes(1); + expect(service.checkSubmissionPermission).toHaveBeenCalledWith(undefined, 123, ['submission_read', 'submission_delete']); + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(new Problem(401, { detail: 'You do not have access to this submission.' })); + }); + + it('does not allow public access if the form does not have the public idp', async () => { + service.getSubmissionForm = jest.fn().mockReturnValue({ + submission: { deleted: false }, + form: { identityProviders: [{ code: 'idir' }, { code: 'bceid' }] }, + }); + service.checkSubmissionPermission = jest.fn().mockReturnValue(undefined); + + const mw = hasSubmissionPermissions('submission_read'); + const nxt = jest.fn(); + const req = { + params: { + formSubmissionId: 123, + }, + }; + + await mw(req, testRes, nxt); + // just run to the end and fall into the base case + expect(service.checkSubmissionPermission).toHaveBeenCalledTimes(1); + expect(service.checkSubmissionPermission).toHaveBeenCalledWith(undefined, 123, ['submission_read']); + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(new Problem(401, { detail: 'You do not have access to this submission.' })); + }); + + it('moves on if the permission check query succeeds', async () => { + service.getSubmissionForm = jest.fn().mockReturnValue({ + submission: { deleted: false }, + form: { identityProviders: [{ code: 'idir' }, { code: 'bceid' }] }, + }); + service.checkSubmissionPermission = jest.fn().mockReturnValue(true); + + const mw = hasSubmissionPermissions('submission_read'); + const nxt = jest.fn(); + const req = { + params: { + formSubmissionId: 123, + }, + }; + + await mw(req, testRes, nxt); + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(); + }); + + it('falls through to the query if the current user has no forms', async () => { + service.getSubmissionForm = jest.fn().mockReturnValue({ + submission: { deleted: false }, + form: { identityProviders: [{ code: 'idir' }, { code: 'bceid' }] }, + }); + service.checkSubmissionPermission = jest.fn().mockReturnValue(undefined); + + const mw = hasSubmissionPermissions('submission_read'); + const nxt = jest.fn(); + const cu = { + forms: [], + }; + const req = { + currentUser: cu, + params: { + formSubmissionId: 123, + }, + }; + + await mw(req, testRes, nxt); + // just run to the end and fall into the base case + expect(service.checkSubmissionPermission).toHaveBeenCalledTimes(1); + expect(service.checkSubmissionPermission).toHaveBeenCalledWith(cu, 123, ['submission_read']); + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(new Problem(401, { detail: 'You do not have access to this submission.' })); + }); + + it('falls through to the query if the current user does not have any FORM access on the current form', async () => { + service.getSubmissionForm = jest.fn().mockReturnValue({ + submission: { deleted: false }, + form: { id: '999', identityProviders: [{ code: 'idir' }, { code: 'bceid' }] }, + }); + service.checkSubmissionPermission = jest.fn().mockReturnValue(undefined); + + const mw = hasSubmissionPermissions('submission_read'); + const nxt = jest.fn(); + const cu = { + forms: [ + { + formId: '456', + }, + { + formId: '789', + }, + ], + }; + const req = { + currentUser: cu, + params: { + formSubmissionId: 123, + }, + }; + + await mw(req, testRes, nxt); + // just run to the end and fall into the base case + expect(service.checkSubmissionPermission).toHaveBeenCalledTimes(1); + expect(service.checkSubmissionPermission).toHaveBeenCalledWith(cu, 123, ['submission_read']); + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(new Problem(401, { detail: 'You do not have access to this submission.' })); + }); + + it('falls through to the query if the current user does not have the expected permission for FORM access on the current form', async () => { + service.getSubmissionForm = jest.fn().mockReturnValue({ + submission: { deleted: false }, + form: { + id: '999', + identityProviders: [{ code: 'idir' }, { code: 'bceid' }], + }, + }); + service.checkSubmissionPermission = jest.fn().mockReturnValue(undefined); + + const mw = hasSubmissionPermissions(['submission_delete', 'submission_create']); + const nxt = jest.fn(); + const cu = { + forms: [ + { + formId: '456', + }, + { + formId: '999', + permissions: ['submission_read', 'submission_update'], + }, + ], + }; + const req = { + currentUser: cu, + params: { + formSubmissionId: 123, + }, + }; + + await mw(req, testRes, nxt); + // just run to the end and fall into the base case + expect(service.checkSubmissionPermission).toHaveBeenCalledTimes(1); + expect(service.checkSubmissionPermission).toHaveBeenCalledWith(cu, 123, ['submission_delete', 'submission_create']); + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(new Problem(401, { detail: 'You do not have access to this submission.' })); + }); + + it('falls through to the query if the current user does not have the expected permission for FORM access on the current form (single check)', async () => { + service.getSubmissionForm = jest.fn().mockReturnValue({ + submission: { deleted: false }, + form: { + id: '999', + identityProviders: [{ code: 'idir' }, { code: 'bceid' }], + }, + }); + service.checkSubmissionPermission = jest.fn().mockReturnValue(undefined); + + const mw = hasSubmissionPermissions('submission_delete'); + const nxt = jest.fn(); + const cu = { + forms: [ + { + formId: '456', + }, + { + formId: '999', + permissions: ['submission_read'], + }, + ], + }; + const req = { + currentUser: cu, + params: { + formSubmissionId: 123, + }, + }; + + await mw(req, testRes, nxt); + // just run to the end and fall into the base case + expect(service.checkSubmissionPermission).toHaveBeenCalledTimes(1); + expect(service.checkSubmissionPermission).toHaveBeenCalledWith(cu, 123, ['submission_delete']); + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(new Problem(401, { detail: 'You do not have access to this submission.' })); + }); + + it('moves on if the user has the appropriate requested permissions', async () => { + service.getSubmissionForm = jest.fn().mockReturnValue({ + submission: { deleted: false }, + form: { + id: '999', + identityProviders: [{ code: 'idir' }, { code: 'bceid' }], + }, + }); + service.checkSubmissionPermission = jest.fn().mockReturnValue(undefined); + + const mw = hasSubmissionPermissions(['submission_read', 'submission_update']); + const nxt = jest.fn(); + const cu = { + forms: [ + { + formId: '456', + }, + { + formId: '999', + permissions: ['submission_read', 'submission_update'], + }, + ], + }; + const req = { + currentUser: cu, + params: { + formSubmissionId: 123, + }, + }; + + await mw(req, testRes, nxt); + // just run to the end and fall into the base case + expect(service.checkSubmissionPermission).toHaveBeenCalledTimes(0); + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(); + }); + + it('moves on if the user has the appropriate requested permissions (single included in array)', async () => { + service.getSubmissionForm = jest.fn().mockReturnValue({ + submission: { deleted: false }, + form: { + id: '999', + identityProviders: [{ code: 'idir' }, { code: 'bceid' }], + }, + }); + service.checkSubmissionPermission = jest.fn().mockReturnValue(undefined); + + const mw = hasSubmissionPermissions('submission_read'); + const nxt = jest.fn(); + const cu = { + forms: [ + { + formId: '456', + }, + { + formId: '999', + permissions: ['submission_read', 'submission_update', 'submission_delete'], + }, + ], + }; + const req = { + currentUser: cu, + params: { + formSubmissionId: 123, + }, + }; + + await mw(req, testRes, nxt); + // just run to the end and fall into the base case + expect(service.checkSubmissionPermission).toHaveBeenCalledTimes(0); + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(); + }); +}); + +describe('hasFormRoles', () => { + it('falls through if the current user does not have any forms', async () => { + const hfr = hasFormRoles([Roles.OWNER, Roles.TEAM_MANAGER]); + const nxt = jest.fn(); + const cu = { + forms: [], + }; + const req = { + currentUser: cu, + params: {}, + query: { + formId: formId, + }, + }; + + await hfr(req, testRes, nxt); + + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(new Problem(401, { detail: 'You do not have any forms.' })); + }); + + it('falls through if the current user does not have at least one of the required form roles', async () => { + const hfr = hasFormRoles([Roles.OWNER, Roles.TEAM_MANAGER]); + const nxt = jest.fn(); + const cu = { + forms: [ + { + id: formId, + roles: [], + }, + ], + }; + const req = { + currentUser: cu, + params: {}, + query: { + formId: formId, + }, + }; + + await hfr(req, testRes, nxt); + + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(new Problem(401, { detail: 'You do not have permission to update this role.' })); + }); + + it('falls through if the current user does not have all of the required form roles', async () => { + const hfr = hasFormRoles([Roles.OWNER, Roles.TEAM_MANAGER], true); + const nxt = jest.fn(); + const cu = { + forms: [ + { + id: formId, + roles: [Roles.TEAM_MANAGER], + }, + ], + }; + const req = { + currentUser: cu, + params: {}, + query: { + formId: formId, + }, + }; + + await hfr(req, testRes, nxt); + + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(new Problem(401, { detail: 'You do not have permission to update this role.' })); + }); + + it('moves on if the user has at least one of the required form roles', async () => { + const hfr = hasFormRoles([Roles.OWNER, Roles.TEAM_MANAGER]); + const nxt = jest.fn(); + const cu = { + forms: [ + { + formId: formId, + roles: [Roles.TEAM_MANAGER], + }, + ], + }; + const req = { + currentUser: cu, + params: {}, + query: { + formId: formId, + }, + }; + + await hfr(req, testRes, nxt); + + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(); + }); + + it('moves on if the user has all of the required form roles', async () => { + const hfr = hasFormRoles([Roles.OWNER, Roles.TEAM_MANAGER], true); + const nxt = jest.fn(); + const cu = { + forms: [ + { + formId: formId, + roles: [Roles.OWNER, Roles.TEAM_MANAGER], + }, + ], + }; + const req = { + currentUser: cu, + params: {}, + query: { + formId: formId, + }, + }; + + await hfr(req, testRes, nxt); + + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(); + }); +}); + +describe('hasRolePermissions', () => { + describe('when removing users from a team', () => { + describe('as an owner', () => { + it('should succeed with valid data', async () => { + rbacService.readUserRole = jest.fn().mockReturnValue([ + { + userId: userId2, + formId: formId, + role: Roles.OWNER, + }, + ]); + const hrp = hasRolePermissions(true); + const nxt = jest.fn(); + + const cu = { + id: userId, + forms: [ + { + formId: formId, + roles: [Roles.OWNER, Roles.TEAM_MANAGER], + }, + ], + }; + const req = { + currentUser: cu, + params: {}, + query: { + formId: formId, + }, + body: [userId2], + }; + + await hrp(req, testRes, nxt); + + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(); + }); + }); + + describe('as a team manager', () => { + it('should succeed with valid data', async () => { + rbacService.readUserRole = jest.fn().mockReturnValue([ + { + userId: userId2, + formId: formId, + role: Roles.FORM_SUBMITTER, + }, + ]); + + const hrp = hasRolePermissions(true); + + const nxt = jest.fn(); + + const cu = { + id: userId, + forms: [ + { + formId: formId, + roles: [Roles.TEAM_MANAGER], + }, + ], + }; + const req = { + currentUser: cu, + params: {}, + query: { + formId: formId, + }, + body: [userId2], + }; + + await hrp(req, testRes, nxt); + + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(); + }); + + it("falls through if you're trying to remove your own team manager role", async () => { + rbacService.readUserRole = jest.fn().mockReturnValue([ + { + userId: userId2, + formId: formId, + role: Roles.TEAM_MANAGER, + }, + ]); + + const hrp = hasRolePermissions(true); + + const nxt = jest.fn(); + + const cu = { + id: userId, + forms: [ + { + formId: formId, + roles: [Roles.TEAM_MANAGER], + }, + ], + }; + const req = { + currentUser: cu, + params: {}, + query: { + formId: formId, + }, + body: [userId2], + }; + + await hrp(req, testRes, nxt); + + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(); + }); + + it("falls through if you're trying to remove an owner role", async () => { + rbacService.readUserRole = jest.fn().mockReturnValue([ + { + userId: userId2, + formId: formId, + role: Roles.OWNER, + }, + ]); + + const hrp = hasRolePermissions(true); + + const nxt = jest.fn(); + + const cu = { + id: userId, + forms: [ + { + formId: formId, + roles: [Roles.TEAM_MANAGER], + }, + ], + }; + const req = { + currentUser: cu, + params: {}, + query: { + formId: formId, + }, + body: [userId2], + }; + + await hrp(req, testRes, nxt); + + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(new Problem(401, { detail: "You can't update an owner's roles." })); + }); + + it("falls through if you're trying to remove a form designer role", async () => { + rbacService.readUserRole = jest.fn().mockReturnValue([ + { + userId: userId2, + formId: formId, + role: Roles.FORM_DESIGNER, + }, + ]); + + const hrp = hasRolePermissions(true); + + const nxt = jest.fn(); + + const cu = { + id: userId, + forms: [ + { + formId: formId, + roles: [Roles.TEAM_MANAGER], + }, + ], + }; + const req = { + currentUser: cu, + params: {}, + query: { + formId: formId, + }, + body: [userId2], + }; + + await hrp(req, testRes, nxt); + + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(new Problem(401, { detail: "You can't remove a form designer role." })); + }); + }); + }); + + describe('when updating user roles on a team', () => { + describe('as an owner', () => { + it('should succeed when removing any roles', async () => { + rbacService.readUserRole = jest.fn().mockReturnValue([ + { + id: '1', + role: Roles.OWNER, + formId: formId, + userId: userId2, + createdBy: '', + createdAt: '', + updatedBy: '', + updatedAt: '', + }, + { + id: '2', + role: Roles.TEAM_MANAGER, + formId: formId, + userId: userId2, + createdBy: '', + createdAt: '', + updatedBy: '', + updatedAt: '', + }, + { + id: '3', + role: Roles.SUBMISSION_REVIEWER, + formId: formId, + userId: userId2, + createdBy: '', + createdAt: '', + updatedBy: '', + updatedAt: '', + }, + { + id: '4', + role: Roles.FORM_DESIGNER, + formId: formId, + userId: userId2, + createdBy: '', + createdAt: '', + updatedBy: '', + updatedAt: '', + }, + { + id: '5', + role: Roles.FORM_SUBMITTER, + formId: formId, + userId: userId2, + createdBy: '', + createdAt: '', + updatedBy: '', + updatedAt: '', + }, + ]); + + const hrp = hasRolePermissions(false); + + const nxt = jest.fn(); + + const cu = { + id: userId, + forms: [ + { + formId: formId, + roles: [Roles.OWNER], + }, + ], + }; + const req = { + currentUser: cu, + params: { + userId: userId2, + formId: formId, + }, + query: { + formId: formId, + }, + body: [], + }; + + await hrp(req, testRes, nxt); + + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(); + }); + }); + + describe('as a team manager', () => { + describe('the user being updated is your own', () => { + it("falls through if you're trying to remove your own team manager role", async () => { + rbacService.readUserRole = jest.fn().mockReturnValue([ + { + id: '1', + role: Roles.TEAM_MANAGER, + formId: formId, + userId: userId, + createdBy: '', + createdAt: '', + updatedBy: '', + updatedAt: '', + }, + { + id: '2', + role: Roles.FORM_DESIGNER, + formId: formId, + userId: userId, + createdBy: '', + createdAt: '', + updatedBy: '', + updatedAt: '', + }, + ]); + + const hrp = hasRolePermissions(false); + + const nxt = jest.fn(); + + const cu = { + id: userId, + forms: [ + { + formId: formId, + roles: [Roles.TEAM_MANAGER, Roles.FORM_DESIGNER], + }, + ], + }; + const req = { + currentUser: cu, + params: { + userId: cu.id, + }, + query: { + formId: formId, + }, + body: [ + { + userId: cu.id, + formId: formId, + role: Roles.FORM_DESIGNER, + }, + ], + }; + + await hrp(req, testRes, nxt); + + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(new Problem(401, { detail: "You can't remove your own team manager role." })); + }); + }); + + describe('the user being updated is not your own', () => { + describe('is an owner', () => { + it('falls through if trying to make any role changes', async () => { + rbacService.readUserRole = jest.fn().mockReturnValue([ + { + id: '1', + role: Roles.OWNER, + formId: formId, + userId: userId2, + createdBy: '', + createdAt: '', + updatedBy: '', + updatedAt: '', + }, + { + id: '2', + role: Roles.FORM_DESIGNER, + formId: formId, + userId: userId2, + createdBy: '', + createdAt: '', + updatedBy: '', + updatedAt: '', + }, + { + id: '3', + role: Roles.SUBMISSION_REVIEWER, + formId: formId, + userId: userId2, + createdBy: '', + createdAt: '', + updatedBy: '', + updatedAt: '', + }, + ]); + + const hrp = hasRolePermissions(false); + + const nxt = jest.fn(); + + const cu = { + id: userId, + forms: [ + { + formId: formId, + roles: [Roles.TEAM_MANAGER], + }, + ], + }; + const req = { + currentUser: cu, + params: { + userId: userId2, + }, + query: { + formId: formId, + }, + body: [ + { + userId: userId2, + formId: formId, + role: Roles.SUBMISSION_REVIEWER, + }, + { + userId: userId2, + formId: formId, + role: Roles.FORM_SUBMITTER, + }, + ], + }; + + await hrp(req, testRes, nxt); + + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(new Problem(401, { detail: "You can't update an owner's roles." })); + }); + }); + + describe('is not an owner', () => { + it('falls through if trying to add an owner role', async () => { + rbacService.readUserRole = jest.fn().mockReturnValue([ + { + id: '1', + role: Roles.FORM_SUBMITTER, + formId: formId, + userId: userId2, + createdBy: '', + createdAt: '', + updatedBy: '', + updatedAt: '', + }, + { + id: '3', + role: Roles.SUBMISSION_REVIEWER, + formId: formId, + userId: userId2, + createdBy: '', + createdAt: '', + updatedBy: '', + updatedAt: '', + }, + ]); + + const hrp = hasRolePermissions(false); + + const nxt = jest.fn(); + + const cu = { + id: userId, + forms: [ + { + formId: formId, + roles: [Roles.TEAM_MANAGER], + }, + ], + }; + const req = { + currentUser: cu, + params: { + userId: userId2, + }, + query: { + formId: formId, + }, + body: [ + { + userId: userId2, + formId: formId, + role: Roles.OWNER, + }, + { + userId: userId2, + formId: formId, + role: Roles.FORM_SUBMITTER, + }, + ], + }; + + await hrp(req, testRes, nxt); + + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(new Problem(401, { detail: "You can't add an owner role." })); + }); + + it('falls through if trying to remove an owner role', async () => { + rbacService.readUserRole = jest.fn().mockReturnValue([ + { + id: '1', + role: Roles.OWNER, + formId: formId, + userId: userId2, + createdBy: '', + createdAt: '', + updatedBy: '', + updatedAt: '', + }, + { + id: '2', + role: Roles.FORM_DESIGNER, + formId: formId, + userId: userId2, + createdBy: '', + createdAt: '', + updatedBy: '', + updatedAt: '', + }, + { + id: '3', + role: Roles.SUBMISSION_REVIEWER, + formId: formId, + userId: userId2, + createdBy: '', + createdAt: '', + updatedBy: '', + updatedAt: '', + }, + ]); + + const hrp = hasRolePermissions(false); + + const nxt = jest.fn(); + + const cu = { + id: userId, + forms: [ + { + formId: formId, + roles: [Roles.TEAM_MANAGER], + }, + ], + }; + const req = { + currentUser: cu, + params: { + userId: userId2, + }, + query: { + formId: formId, + }, + body: [ + { + userId: userId2, + formId: formId, + role: Roles.SUBMISSION_REVIEWER, + }, + { + userId: userId2, + formId: formId, + role: Roles.FORM_SUBMITTER, + }, + ], + }; + + await hrp(req, testRes, nxt); + + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(new Problem(401, { detail: "You can't update an owner's roles." })); + }); + + it('falls through if trying to add a designer role', async () => { + rbacService.readUserRole = jest.fn().mockReturnValue([ + { + id: '1', + role: Roles.FORM_SUBMITTER, + formId: formId, + userId: userId2, + createdBy: '', + createdAt: '', + updatedBy: '', + updatedAt: '', + }, + { + id: '3', + role: Roles.SUBMISSION_REVIEWER, + formId: formId, + userId: userId2, + createdBy: '', + createdAt: '', + updatedBy: '', + updatedAt: '', + }, + ]); + + const hrp = hasRolePermissions(false); + + const nxt = jest.fn(); + + const cu = { + id: userId, + forms: [ + { + formId: formId, + roles: [Roles.TEAM_MANAGER], + }, + ], + }; + const req = { + currentUser: cu, + params: { + userId: userId2, + }, + query: { + formId: formId, + }, + body: [ + { + userId: userId2, + formId: formId, + role: Roles.FORM_DESIGNER, + }, + { + userId: userId2, + formId: formId, + role: Roles.FORM_SUBMITTER, + }, + ], + }; + + await hrp(req, testRes, nxt); + + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(new Problem(401, { detail: "You can't add a form designer role." })); + }); + + it('falls through if trying to remove a designer role', async () => { + rbacService.readUserRole = jest.fn().mockReturnValue([ + { + id: '1', + role: Roles.FORM_SUBMITTER, + formId: formId, + userId: userId2, + createdBy: '', + createdAt: '', + updatedBy: '', + updatedAt: '', + }, + { + id: '2', + role: Roles.FORM_DESIGNER, + formId: formId, + userId: userId2, + createdBy: '', + createdAt: '', + updatedBy: '', + updatedAt: '', + }, + { + id: '3', + role: Roles.SUBMISSION_REVIEWER, + formId: formId, + userId: userId2, + createdBy: '', + createdAt: '', + updatedBy: '', + updatedAt: '', + }, + ]); + + const hrp = hasRolePermissions(false); + + const nxt = jest.fn(); + + const cu = { + id: userId, + forms: [ + { + formId: formId, + roles: [Roles.TEAM_MANAGER], + }, + ], + }; + const req = { + currentUser: cu, + params: { + userId: userId2, + }, + query: { + formId: formId, + }, + body: [ + { + userId: userId2, + formId: formId, + role: Roles.SUBMISSION_REVIEWER, + }, + { + userId: userId2, + formId: formId, + role: Roles.FORM_SUBMITTER, + }, + ], + }; + + await hrp(req, testRes, nxt); + + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(new Problem(401, { detail: "You can't remove a form designer role." })); + }); + + it('should succeed when adding a manager/reviewer/submitter roles', async () => { + rbacService.readUserRole = jest.fn().mockReturnValue([]); + + const hrp = hasRolePermissions(false); + + const nxt = jest.fn(); + + const cu = { + id: userId, + forms: [ + { + formId: formId, + roles: [Roles.TEAM_MANAGER], + }, + ], + }; + const req = { + currentUser: cu, + params: { + userId: userId2, + }, + query: { + formId: formId, + }, + body: [ + { + userId: userId2, + formId: formId, + role: Roles.TEAM_MANAGER, + }, + { + userId: userId2, + formId: formId, + role: Roles.SUBMISSION_REVIEWER, + }, + { + userId: userId2, + formId: formId, + role: Roles.FORM_SUBMITTER, + }, + ], + }; + + await hrp(req, testRes, nxt); + + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(); + }); + + it('should succeed when removing a manager roles', async () => { + rbacService.readUserRole = jest.fn().mockReturnValue([ + { + id: '1', + role: Roles.FORM_SUBMITTER, + formId: formId, + userId: userId2, + createdBy: '', + createdAt: '', + updatedBy: '', + updatedAt: '', + }, + { + id: '2', + role: Roles.TEAM_MANAGER, + formId: formId, + userId: userId2, + createdBy: '', + createdAt: '', + updatedBy: '', + updatedAt: '', + }, + { + id: '3', + role: Roles.SUBMISSION_REVIEWER, + formId: formId, + userId: userId2, + createdBy: '', + createdAt: '', + updatedBy: '', + updatedAt: '', + }, + ]); + + const hrp = hasRolePermissions(false); + + const nxt = jest.fn(); + + const cu = { + id: userId, + forms: [ + { + formId: formId, + roles: [Roles.TEAM_MANAGER], + }, + ], + }; + const req = { + currentUser: cu, + params: { + userId: userId2, + formId: formId, + }, + query: { + formId: formId, + }, + body: [ + { + userId: userId2, + formId: formId, + role: Roles.SUBMISSION_REVIEWER, + }, + { + userId: userId2, + formId: formId, + role: Roles.FORM_SUBMITTER, + }, + ], + }; + + await hrp(req, testRes, nxt); + + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(); + }); + + it('should succeed when removing a reviewer roles', async () => { + rbacService.readUserRole = jest.fn().mockReturnValue([ + { + id: '1', + role: Roles.FORM_SUBMITTER, + formId: formId, + userId: userId2, + createdBy: '', + createdAt: '', + updatedBy: '', + updatedAt: '', + }, + { + id: '2', + role: Roles.TEAM_MANAGER, + formId: formId, + userId: userId2, + createdBy: '', + createdAt: '', + updatedBy: '', + updatedAt: '', + }, + { + id: '3', + role: Roles.SUBMISSION_REVIEWER, + formId: formId, + userId: userId2, + createdBy: '', + createdAt: '', + updatedBy: '', + updatedAt: '', + }, + ]); + + const hrp = hasRolePermissions(false); + + const nxt = jest.fn(); + + const cu = { + id: userId, + forms: [ + { + formId: formId, + roles: [Roles.TEAM_MANAGER], + }, + ], + }; + const req = { + currentUser: cu, + params: { + userId: userId2, + formId: formId, + }, + query: { + formId: formId, + }, + body: [ + { + userId: userId2, + formId: formId, + role: Roles.TEAM_MANAGER, + }, + { + userId: userId2, + formId: formId, + role: Roles.FORM_SUBMITTER, + }, + ], + }; + + await hrp(req, testRes, nxt); + + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(); + }); + + it('should succeed when removing a submitter roles', async () => { + rbacService.readUserRole = jest.fn().mockReturnValue([ + { + id: '1', + role: Roles.FORM_SUBMITTER, + formId: formId, + userId: userId2, + createdBy: '', + createdAt: '', + updatedBy: '', + updatedAt: '', + }, + { + id: '2', + role: Roles.TEAM_MANAGER, + formId: formId, + userId: userId2, + createdBy: '', + createdAt: '', + updatedBy: '', + updatedAt: '', + }, + { + id: '3', + role: Roles.SUBMISSION_REVIEWER, + formId: formId, + userId: userId2, + createdBy: '', + createdAt: '', + updatedBy: '', + updatedAt: '', + }, + ]); + + const hrp = hasRolePermissions(false); + + const nxt = jest.fn(); + + const cu = { + id: userId, + forms: [ + { + formId: formId, + roles: [Roles.TEAM_MANAGER], + }, + ], + }; + const req = { + currentUser: cu, + params: { + userId: userId2, + formId: formId, + }, + query: { + formId: formId, + }, + body: [ + { + userId: userId2, + formId: formId, + role: Roles.TEAM_MANAGER, + }, + { + userId: userId2, + formId: formId, + role: Roles.SUBMISSION_REVIEWER, + }, + ], + }; + + await hrp(req, testRes, nxt); + + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(); + }); + + it('should succeed when removing a manager/reviewer/submitter roles', async () => { + rbacService.readUserRole = jest.fn().mockReturnValue([ + { + id: '1', + role: Roles.FORM_SUBMITTER, + formId: formId, + userId: userId2, + createdBy: '', + createdAt: '', + updatedBy: '', + updatedAt: '', + }, + { + id: '2', + role: Roles.TEAM_MANAGER, + formId: formId, + userId: userId2, + createdBy: '', + createdAt: '', + updatedBy: '', + updatedAt: '', + }, + { + id: '3', + role: Roles.SUBMISSION_REVIEWER, + formId: formId, + userId: userId2, + createdBy: '', + createdAt: '', + updatedBy: '', + updatedAt: '', + }, + ]); + + const hrp = hasRolePermissions(false); + + const nxt = jest.fn(); + + const cu = { + id: userId, + forms: [ + { + formId: formId, + roles: [Roles.TEAM_MANAGER], + }, + ], + }; + const req = { + currentUser: cu, + params: { + userId: userId2, + formId: formId, + }, + query: { + formId: formId, + }, + body: [], + }; + + await hrp(req, testRes, nxt); + + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(); + }); + }); + }); + }); + }); +}); diff --git a/frontend/app/tests/unit/forms/bcgeoaddress/controller.spec.js b/frontend/app/tests/unit/forms/bcgeoaddress/controller.spec.js new file mode 100644 index 0000000..3ec7add --- /dev/null +++ b/frontend/app/tests/unit/forms/bcgeoaddress/controller.spec.js @@ -0,0 +1,42 @@ +const controller = require('../../../../src/forms/bcgeoaddress/controller'); +const service = require('../../../../src/forms/bcgeoaddress/service'); + +const req = { + query: { brief: true, autocomplete: true, matchAccuracy: 100, addressString: 25, url: 'test Url' }, +}; + +describe('search BCGEO Address', () => { + it('should call searchBCGeoAddress method ', async () => { + let res = jest.fn(); + let next = jest.fn(); + service.searchBCGeoAddress = jest.fn().mockReturnValue({ + features: [ + { + geometry: { coordinates: [-118.4683663, 49.0257091] }, + properties: { fullAddress: '25th St, Grand Forks, BC' }, + }, + ], + }); + await controller.searchBCGeoAddress(req, res, next); + expect(service.searchBCGeoAddress).toHaveBeenCalledTimes(1); + }); +}); +describe('search BCGEO Address', () => { + it('should call advancedSearchBCGeoAddress method ', async () => { + let res = jest.fn(); + let next = jest.fn(); + service.searchBCGeoAddress = jest.fn().mockReturnValue({ + type: 'FeatureCollection', + queryAddress: 25, + features: [ + { + type: 'Feature', + geometry: { type: 'Point', crs: { type: 'EPSG', properties: { code: 4326 } }, coordinates: [-118.4683663, 49.0257091] }, + properties: { fullAddress: '25th St, Grand Forks, BC', score: 61, matchPrecision: 'STREET', siteStatus: '' }, + }, + ], + }); + await controller.searchBCGeoAddress(req, res, next); + expect(service.searchBCGeoAddress).toHaveBeenCalledTimes(1); + }); +}); diff --git a/frontend/app/tests/unit/forms/bcgeoaddress/service.spec.js b/frontend/app/tests/unit/forms/bcgeoaddress/service.spec.js new file mode 100644 index 0000000..32e368b --- /dev/null +++ b/frontend/app/tests/unit/forms/bcgeoaddress/service.spec.js @@ -0,0 +1,48 @@ +const service = require('../../../../src/forms/bcgeoaddress/service'); +const geoAddressService = require('../../../../src/components/geoAddressService'); + +describe('searchBCGeoAddress', () => { + it('should test searchBCGeoAddress', async () => { + let response = { + features: [ + { + type: 'Feature', + geometry: { coordinates: [-118.4683663, 49.0257091] }, + properties: { fullAddress: '25th St, Grand Forks, BC' }, + }, + ], + }; + + geoAddressService.addressQuerySearch = jest.fn().mockReturnValue(response); + + const query = { brief: true, autocomplete: true, matchAccuracy: 100, addressString: 25, url: 'test Url' }; + + await service.searchBCGeoAddress(query).then(() => { + expect(geoAddressService.addressQuerySearch).toHaveBeenCalledTimes(1); + }); + }); + + it('should test advanceSearchBCGeoAddress', async () => { + let response = { + type: 'FeatureCollection', + queryAddress: 25, + features: [ + { + type: 'Feature', + geometry: { type: 'Point', crs: { type: 'EPSG', properties: { code: 4326 } }, coordinates: [-118.4683663, 49.0257091] }, + properties: { fullAddress: '25th St, Grand Forks, BC', score: 61, matchPrecision: 'STREET', siteStatus: '' }, + }, + ], + }; + + geoAddressService.addressQuerySearch = jest.fn().mockReturnValue(response); + + const query = { brief: true, autocomplete: true, matchAccuracy: 100, addressString: 25, url: 'test Url' }; + + const result = await service.advanceSearchBCGeoAddress(query); + + expect(geoAddressService.addressQuerySearch).toHaveBeenCalledTimes(1); + + expect(result).toEqual(response); + }); +}); diff --git a/frontend/app/tests/unit/forms/common/models/utils.spec.js b/frontend/app/tests/unit/forms/common/models/utils.spec.js new file mode 100644 index 0000000..b5f693a --- /dev/null +++ b/frontend/app/tests/unit/forms/common/models/utils.spec.js @@ -0,0 +1,52 @@ +const { toArray, inArrayClause, inArrayFilter } = require('../../../../../src/forms/common/models/utils'); + +describe('Test Model Utils toArray function', () => { + it('should return blank array if nothing specified', () => { + expect(toArray()).toEqual([]); + expect(toArray(undefined)).toEqual([]); + expect(toArray(null)).toEqual([]); + expect(toArray(false)).toEqual([]); + }); + + it('should return an array if one is specified', () => { + const arr = ['1', '2', '3']; + expect(toArray(arr)).toEqual(arr); + }); + + it('should return an array with trimmed blank values', () => { + const arr = ['1', '', '3', ' ', '4']; + expect(toArray(arr)).toEqual(['1', '3', '4']); + }); + + it('should convert to an array', () => { + expect(toArray('hello')).toEqual(['hello']); + }); +}); + +describe('Test Model Utils inArrayClause function', () => { + it('should return the desired clause for a single values', () => { + const col = 'user'; + const vals = ['1']; + expect(inArrayClause(col, vals)).toEqual('\'1\' = ANY("user")'); + }); + + it('should return the desired clause for multiple values joined with OR', () => { + const col = 'user'; + const vals = ['1', '2', '3']; + expect(inArrayClause(col, vals)).toEqual('\'1\' = ANY("user") or \'2\' = ANY("user") or \'3\' = ANY("user")'); + }); + + it('should return a blank string for a blank array', () => { + const col = 'user'; + const vals = []; + expect(inArrayClause(col, vals)).toEqual(''); + }); +}); + +describe('Test Model Utils inArrayFilter function', () => { + it('should return the desired clause for multiple values joined with OR', () => { + const col = 'user'; + const vals = ['1', '2', '3']; + expect(inArrayFilter(col, vals)).toEqual('(array_length("user", 1) > 0 and (\'1\' = ANY("user") or \'2\' = ANY("user") or \'3\' = ANY("user")))'); + }); +}); diff --git a/frontend/app/tests/unit/forms/common/utils.spec.js b/frontend/app/tests/unit/forms/common/utils.spec.js new file mode 100644 index 0000000..d30c967 --- /dev/null +++ b/frontend/app/tests/unit/forms/common/utils.spec.js @@ -0,0 +1,205 @@ +const { queryUtils, typeUtils, validateScheduleObject } = require('../../../../src/forms/common/utils'); + +describe('Test Query Utils functions', () => { + it('defaultActiveOnly should return params object', () => { + const params = queryUtils.defaultActiveOnly(null); + expect(params).toBeDefined(); + expect(params).toEqual({ active: true }); + }); + + it('defaultActiveOnly should return active = true', () => { + let params = queryUtils.defaultActiveOnly(null); + expect(params).toBeDefined(); + expect(params).toEqual({ active: true }); + + params = queryUtils.defaultActiveOnly({}); + expect(params).toBeDefined(); + expect(params).toEqual({ active: true }); + + params = queryUtils.defaultActiveOnly({ other: 'value' }); + expect(params).toBeDefined(); + expect(params).toEqual({ active: true, other: 'value' }); + + params = queryUtils.defaultActiveOnly({ active: 'not a false value', other: 'value' }); + expect(params).toBeDefined(); + expect(params).toEqual({ active: true, other: 'value' }); + + params = queryUtils.defaultActiveOnly({ active: true, other: 'value' }); + expect(params).toBeDefined(); + expect(params).toEqual({ active: true, other: 'value' }); + }); + + it('defaultActiveOnly should return active = false', () => { + let params = queryUtils.defaultActiveOnly({ active: false }); + expect(params).toBeDefined(); + expect(params).toEqual({ active: false }); + + params = queryUtils.defaultActiveOnly({ active: 'false' }); + expect(params).toBeDefined(); + expect(params).toEqual({ active: false }); + + params = queryUtils.defaultActiveOnly({ active: 0 }); + expect(params).toBeDefined(); + expect(params).toEqual({ active: false }); + }); +}); + +describe('Test Type Utils functions', () => { + it('isInt should return true for int and int like strings', () => { + let result = typeUtils.isInt(1); + expect(result).toBeDefined(); + expect(result).toBeTruthy(); + + result = typeUtils.isInt('1'); + expect(result).toBeDefined(); + expect(result).toBeTruthy(); + + result = typeUtils.isInt(-1); + expect(result).toBeDefined(); + expect(result).toBeTruthy(); + }); + + it('isInt should return false for not ints', () => { + let result = typeUtils.isInt(1.1); + expect(result).toBeDefined(); + expect(result).toBeFalsy(); + + result = typeUtils.isInt({ key: 1 }); + expect(result).toBeDefined(); + expect(result).toBeFalsy(); + + result = typeUtils.isInt('Not Int'); + expect(result).toBeDefined(); + expect(result).toBeFalsy(); + + result = typeUtils.isInt(() => { + return 1; + }); + expect(result).toBeDefined(); + expect(result).toBeFalsy(); + }); + + it('isString should return true for strings', () => { + let result = typeUtils.isString('a string'); + expect(result).toBeDefined(); + expect(result).toBeTruthy(); + + result = typeUtils.isString(`another string ${result}`); + expect(result).toBeDefined(); + expect(result).toBeTruthy(); + + result = typeUtils.isString(new String('value of string')); + expect(result).toBeDefined(); + expect(result).toBeTruthy(); + + result = typeUtils.isString(new Object('value of object')); + expect(result).toBeDefined(); + expect(result).toBeTruthy(); + + result = typeUtils.isString('1'); + expect(result).toBeDefined(); + expect(result).toBeTruthy(); + }); + + it('isString should return false for not strings', () => { + let result = typeUtils.isString(1.1); + expect(result).toBeDefined(); + expect(result).toBeFalsy(); + + result = typeUtils.isString({ key: 'string' }); + expect(result).toBeDefined(); + expect(result).toBeFalsy(); + + result = typeUtils.isString(() => { + return 'string'; + }); + expect(result).toBeDefined(); + expect(result).toBeFalsy(); + + result = typeUtils.isString(new Boolean(true)); + expect(result).toBeDefined(); + expect(result).toBeFalsy(); + }); + + it('isBoolean should return true for booleans', () => { + let result = typeUtils.isBoolean(new Boolean(true)); + expect(result).toBeDefined(); + expect(result).toBeTruthy(); + + result = typeUtils.isBoolean(new Boolean(false)); + expect(result).toBeDefined(); + expect(result).toBeTruthy(); + + result = typeUtils.isBoolean(true); + expect(result).toBeDefined(); + expect(result).toBeTruthy(); + + result = typeUtils.isBoolean(false); + expect(result).toBeDefined(); + expect(result).toBeTruthy(); + }); + + it('isBoolean should return false for not boolean', () => { + let result = typeUtils.isBoolean(1.1); + expect(result).toBeDefined(); + expect(result).toBeFalsy(); + + result = typeUtils.isBoolean({ key: 'string' }); + expect(result).toBeDefined(); + expect(result).toBeFalsy(); + + result = typeUtils.isBoolean(() => { + return 'string'; + }); + expect(result).toBeDefined(); + expect(result).toBeFalsy(); + + result = typeUtils.isBoolean('true'); + expect(result).toBeDefined(); + expect(result).toBeFalsy(); + + result = typeUtils.isBoolean(1); + expect(result).toBeDefined(); + expect(result).toBeFalsy(); + + result = typeUtils.isBoolean(0); + expect(result).toBeDefined(); + expect(result).toBeFalsy(); + }); +}); + +describe('Test Schedule object validation Utils functions', () => { + it('validateScheduleObject should return status = error for empty object passed as parameter.', () => { + let result = validateScheduleObject({}); + expect(result).toBeDefined(); + expect(result).toHaveProperty('status', 'success'); + }); + + it('validateScheduleObject should return status = success for schedule type manual and with its required data.', () => { + let testPayload = { enabled: true, scheduleType: 'manual', openSubmissionDateTime: '2023-03-31' }; + let result = validateScheduleObject(testPayload); + expect(result).toBeDefined(); + expect(result).toHaveProperty('status', 'success'); + }); + + it('validateScheduleObject should return status = success for schedule type closingDate and with its required data.', () => { + let testPayload = { enabled: true, scheduleType: 'closingDate', openSubmissionDateTime: '2023-03-31', closeSubmissionDateTime: '2023-09-31' }; + let result = validateScheduleObject(testPayload); + expect(result).toBeDefined(); + expect(result).toHaveProperty('status', 'success'); + }); + + it('validateScheduleObject should return status = success for schedule type period and with its required data.', () => { + let testPayload = { + enabled: true, + scheduleType: 'period', + openSubmissionDateTime: '2023-03-31', + keepOpenForInterval: 'days', + keepOpenForTerm: '4', + repeatSubmission: { everyTerm: '15', repeatUntil: '2024-04-01', everyIntervalType: 'days' }, + }; + let result = validateScheduleObject(testPayload); + expect(result).toBeDefined(); + expect(result).toHaveProperty('status', 'success'); + }); +}); diff --git a/frontend/app/tests/unit/forms/email/emailService.spec.js b/frontend/app/tests/unit/forms/email/emailService.spec.js new file mode 100644 index 0000000..89b87fa --- /dev/null +++ b/frontend/app/tests/unit/forms/email/emailService.spec.js @@ -0,0 +1,587 @@ +const chesService = require('../../../../src/components/chesService'); +const emailService = require('../../../../src/forms/email/emailService'); +const formService = require('../../../../src/forms/form/service'); +const fs = require('fs'); +const mockedReadFileSync = jest.spyOn(fs, 'readFileSync'); + +const referer = 'https://submit.digital.gov.bc.ca'; + +describe('_appUrl', () => { + it('should format the url', () => { + expect(emailService._appUrl('https://chefs-dev.apps.silver.devops.gov.bc.ca/pr-139/form/success?s=13978f3b-056b-4022-9a30-60d3b63ec459')).toEqual( + 'https://chefs-dev.apps.silver.devops.gov.bc.ca/pr-139' + ); + expect(emailService._appUrl('https://chefs.nrs.gov.bc.ca/app/form/success?s=13978f3b-056b-4022-9a30-60d3b63ec459')).toEqual('https://chefs.nrs.gov.bc.ca/app'); + }); + + it('should rethrow exceptions', () => { + expect(() => emailService._appUrl('notaurl')).toThrow('Invalid URL'); + }); +}); + +describe('_mergeEmailTemplate', () => { + it('should merge two html files', () => { + mockedReadFileSync.mockReturnValueOnce('').mockReturnValueOnce('

New Body

'); + + const result = emailService._mergeEmailTemplate('test-file.html'); + + expect(result).toMatch('

New Body

'); + mockedReadFileSync.mockRestore(); + }); +}); + +describe('_sendEmailTemplate', () => { + const submission = { + confirmationId: 'abc', + id: '123', + }; + const configData = { + assignmentNotificationEmail: 'a@b.com', + body: { + to: 'c@d.com', + }, + form: { + showSubmissionConfirmation: 'confirmation', + submissionReceivedEmails: ['x@y.com', 'a@b.com'], + }, + }; + + beforeEach(() => { + mockedReadFileSync.mockReturnValueOnce('').mockReturnValueOnce('

New Body

'); + }); + + afterEach(() => { + mockedReadFileSync.mockRestore(); + }); + + it('should call chesService to send an email with type sendStatusAssigned', () => { + chesService.merge = jest.fn().mockReturnValue('sent'); + emailService._mergeEmailTemplate = jest.fn().mockReturnValue('merged'); + + const result = emailService._sendEmailTemplate('sendStatusAssigned', configData, submission, referer); + + expect(result).toBeTruthy(); + expect(chesService.merge).toHaveBeenCalledTimes(1); + }); + + it('should call chesService to send an email with type sendSubmissionConfirmation', () => { + chesService.merge = jest.fn().mockReturnValue('sent'); + emailService._mergeEmailTemplate = jest.fn().mockReturnValue('merged'); + + const result = emailService._sendEmailTemplate('sendSubmissionConfirmation', configData, submission, referer); + + expect(result).toBeTruthy(); + expect(chesService.merge).toHaveBeenCalledTimes(1); + }); + + it('should call chesService to send an email with type sendSubmissionReceived', () => { + chesService.merge = jest.fn().mockReturnValue('sent'); + emailService._mergeEmailTemplate = jest.fn().mockReturnValue('merged'); + + const result = emailService._sendEmailTemplate('sendSubmissionReceived', configData, submission, referer); + + expect(result).toBeTruthy(); + expect(chesService.merge).toHaveBeenCalledTimes(1); + }); +}); + +describe('public methods', () => { + const currentStatus = { + submissionId: '456', + formSubmissionId: '123', + }; + const form = { + id: 'xxx-yyy', + showSubmissionConfirmation: true, + name: '123', + submissionReceivedEmails: ['a@b.com', 'z@y.com'], + identityProviders: [ + { + idp: 'public', + }, + ], + }; + const form_idir = { + ...form, + identityProviders: [ + { + idp: 'idir', + }, + ], + }; + const submission = { + confirmationId: 'abc', + id: '123', + submission: { + data: { + problem: 'Testing', + }, + }, + }; + const assignmentNotificationEmail = 'x@y.com'; + const body = { to: 'a@b.com' }; + const body_high = { priority: 'high', to: 'a@b.com' }; + const body_low = { priority: 'low', to: 'a@b.com' }; + const body_normal = { priority: 'normal', to: 'a@b.com' }; + const emailContent = 'Email Content'; + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('statusAssigned should call send a status email', async () => { + formService.readForm = jest.fn().mockReturnValue(form); + formService.readSubmission = jest.fn().mockReturnValue(submission); + emailService._sendEmailTemplate = jest.fn().mockReturnValue('ret'); + const result = await emailService.statusAssigned('123', currentStatus, assignmentNotificationEmail, emailContent, referer); + const configData = { + bodyTemplate: 'send-status-assigned-email-body.html', + title: `${form.name} Submission Assignment`, + subject: 'Form Submission Assignment', + messageLinkText: `You have been assigned to a ${form.name} submission. Please login to review it.`, + priority: 'normal', + form, + }; + + const contexts = [ + { + context: { + allFormSubmissionUrl: 'https://user/submissions?f=xxx-yyy', + confirmationNumber: 'abc', + form: form, + messageLinkText: 'You have been assigned to a 123 submission. Please login to review it.', + messageLinkUrl: 'https://form/view?s=123', + emailContent: 'Email Content', + title: '123 Submission Assignment', + }, + to: ['x@y.com'], + }, + ]; + + expect(result).toEqual('ret'); + expect(emailService._sendEmailTemplate).toHaveBeenCalledTimes(1); + expect(emailService._sendEmailTemplate).toHaveBeenCalledWith(configData, contexts); + }); + + it('statusRevising should send a status email', async () => { + formService.readForm = jest.fn().mockReturnValue(form); + formService.readSubmission = jest.fn().mockReturnValue(submission); + emailService._sendEmailTemplate = jest.fn().mockReturnValue('ret'); + const result = await emailService.statusRevising('123', currentStatus, assignmentNotificationEmail, emailContent, referer); + const configData = { + bodyTemplate: 'send-status-revising-email-body.html', + title: `${form.name} Submission Revision Requested`, + subject: 'Form Submission Revision Request', + messageLinkText: `You have been asked to revise a ${form.name} submission. Please login to review it.`, + priority: 'normal', + form, + }; + + const contexts = [ + { + context: { + allFormSubmissionUrl: 'https://user/submissions?f=xxx-yyy', + confirmationNumber: 'abc', + form: form, + messageLinkText: `You have been asked to revise a ${form.name} submission. Please login to review it.`, + messageLinkUrl: `https://user/view?s=${form.name}`, + emailContent: 'Email Content', + title: `${form.name} Submission Revision Requested`, + }, + to: ['x@y.com'], + }, + ]; + + expect(result).toEqual('ret'); + expect(emailService._sendEmailTemplate).toHaveBeenCalledTimes(1); + expect(emailService._sendEmailTemplate).toHaveBeenCalledWith(configData, contexts); + }); + + it('statusCompleted should send a status email', async () => { + formService.readForm = jest.fn().mockReturnValue(form); + formService.readSubmission = jest.fn().mockReturnValue(submission); + emailService._sendEmailTemplate = jest.fn().mockReturnValue('ret'); + const result = await emailService.statusCompleted('123', currentStatus, assignmentNotificationEmail, emailContent, referer); + const configData = { + bodyTemplate: 'submission-completed.html', + title: `${form.name} Has Been Completed`, + subject: 'Form Has Been Completed', + messageLinkText: `Your submission from ${form.name} has been Completed.`, + priority: 'normal', + form, + }; + + const contexts = [ + { + context: { + allFormSubmissionUrl: 'https://user/submissions?f=xxx-yyy', + confirmationNumber: 'abc', + form: form, + messageLinkText: `Your submission from ${form.name} has been Completed.`, + messageLinkUrl: `https://user/view?s=${form.name}`, + emailContent: 'Email Content', + title: `${form.name} Has Been Completed`, + }, + to: ['x@y.com'], + }, + ]; + + expect(result).toEqual('ret'); + expect(emailService._sendEmailTemplate).toHaveBeenCalledTimes(1); + expect(emailService._sendEmailTemplate).toHaveBeenCalledWith(configData, contexts); + }); + + it('submissionConfirmation should send login email for idir', async () => { + formService.readEmailTemplate = jest.fn().mockReturnValue({ + body: 'Thank you for your {{form.name}} submission. You can view your submission details by visiting the following links:', + subject: '{{form.name}} Accepted', + title: '{{form.name}} Accepted', + }); + formService.readForm = jest.fn().mockReturnValue(form_idir); + formService.readSubmission = jest.fn().mockReturnValue(submission); + emailService._sendEmailTemplate = jest.fn().mockReturnValue('ret'); + + const result = await emailService.submissionConfirmation(form_idir.id, submission.id, body_low, referer); + + const configData = { + bodyTemplate: 'submission-received-confirmation-login.html', + subject: `${form_idir.name} Accepted`, + priority: 'low', + messageLinkText: `Thank you for your ${form_idir.name} submission. You can view your submission details by visiting the following links:`, + title: `${form_idir.name} Accepted`, + form: { ...form_idir }, + }; + + const contexts = [ + { + context: { + allFormSubmissionUrl: 'https://user/submissions?f=xxx-yyy', + confirmationNumber: 'abc', + form: form_idir, + messageLinkText: `Thank you for your ${form_idir.name} submission. You can view your submission details by visiting the following links:`, + messageLinkUrl: `https://form/success?s=${form_idir.name}`, + revisionNotificationEmailContent: undefined, + title: `${form_idir.name} Accepted`, + }, + to: ['a@b.com'], + }, + ]; + + expect(result).toEqual('ret'); + expect(formService.readForm).toHaveBeenCalledTimes(1); + expect(formService.readForm).toHaveBeenCalledWith(form_idir.id); + expect(formService.readSubmission).toHaveBeenCalledTimes(1); + expect(formService.readSubmission).toHaveBeenCalledWith(submission.id); + expect(emailService._sendEmailTemplate).toHaveBeenCalledTimes(1); + expect(emailService._sendEmailTemplate).toHaveBeenCalledWith(configData, contexts); + }); + + it('submissionConfirmation should send a low priority email', async () => { + formService.readEmailTemplate = jest.fn().mockReturnValue({ + body: 'Thank you for your {{form.name}} submission. You can view your submission details by visiting the following links:', + subject: '{{form.name}} Accepted', + title: '{{form.name}} Accepted', + }); + formService.readForm = jest.fn().mockReturnValue(form); + formService.readSubmission = jest.fn().mockReturnValue(submission); + emailService._sendEmailTemplate = jest.fn().mockReturnValue('ret'); + + const result = await emailService.submissionConfirmation(form.id, submission.id, body_low, referer); + + const configData = { + bodyTemplate: 'submission-received-confirmation-public.html', + subject: `${form.name} Accepted`, + priority: 'low', + messageLinkText: `Thank you for your ${form.name} submission. You can view your submission details by visiting the following links:`, + title: `${form.name} Accepted`, + form, + }; + + const contexts = [ + { + context: { + allFormSubmissionUrl: 'https://user/submissions?f=xxx-yyy', + confirmationNumber: 'abc', + form: form, + messageLinkText: `Thank you for your ${form.name} submission. You can view your submission details by visiting the following links:`, + messageLinkUrl: `https://form/success?s=${form.name}`, + revisionNotificationEmailContent: undefined, + title: `${form.name} Accepted`, + }, + to: ['a@b.com'], + }, + ]; + + expect(result).toEqual('ret'); + expect(formService.readForm).toHaveBeenCalledTimes(1); + expect(formService.readForm).toHaveBeenCalledWith(form.id); + expect(formService.readSubmission).toHaveBeenCalledTimes(1); + expect(formService.readSubmission).toHaveBeenCalledWith(submission.id); + expect(emailService._sendEmailTemplate).toHaveBeenCalledTimes(1); + expect(emailService._sendEmailTemplate).toHaveBeenCalledWith(configData, contexts); + }); + + it('submissionConfirmation should send a normal priority email', async () => { + formService.readEmailTemplate = jest.fn().mockReturnValue({ + body: 'Thank you for your {{form.name}} submission. You can view your submission details by visiting the following links:', + subject: '{{form.name}} Accepted', + title: '{{form.name}} Accepted', + }); + formService.readForm = jest.fn().mockReturnValue(form); + formService.readSubmission = jest.fn().mockReturnValue(submission); + emailService._sendEmailTemplate = jest.fn().mockReturnValue('ret'); + + const result = await emailService.submissionConfirmation(form.id, submission.id, body_normal, referer); + + const configData = { + bodyTemplate: 'submission-received-confirmation-public.html', + subject: `${form.name} Accepted`, + priority: 'normal', + messageLinkText: `Thank you for your ${form.name} submission. You can view your submission details by visiting the following links:`, + title: `${form.name} Accepted`, + form, + }; + + const contexts = [ + { + context: { + allFormSubmissionUrl: 'https://user/submissions?f=xxx-yyy', + confirmationNumber: 'abc', + form: form, + messageLinkText: `Thank you for your ${form.name} submission. You can view your submission details by visiting the following links:`, + messageLinkUrl: `https://form/success?s=${form.name}`, + revisionNotificationEmailContent: undefined, + title: `${form.name} Accepted`, + }, + to: ['a@b.com'], + }, + ]; + + expect(result).toEqual('ret'); + expect(formService.readForm).toHaveBeenCalledTimes(1); + expect(formService.readForm).toHaveBeenCalledWith(form.id); + expect(formService.readSubmission).toHaveBeenCalledTimes(1); + expect(formService.readSubmission).toHaveBeenCalledWith(submission.id); + expect(emailService._sendEmailTemplate).toHaveBeenCalledTimes(1); + expect(emailService._sendEmailTemplate).toHaveBeenCalledWith(configData, contexts); + }); + + it('submissionConfirmation should send a high priority email', async () => { + formService.readEmailTemplate = jest.fn().mockReturnValue({ + body: 'Thank you for your {{form.name}} submission. You can view your submission details by visiting the following links:', + subject: '{{form.name}} Accepted', + title: '{{form.name}} Accepted', + }); + formService.readForm = jest.fn().mockReturnValue(form); + formService.readSubmission = jest.fn().mockReturnValue(submission); + emailService._sendEmailTemplate = jest.fn().mockReturnValue('ret'); + + const result = await emailService.submissionConfirmation(form.id, submission.id, body_high, referer); + + const configData = { + bodyTemplate: 'submission-received-confirmation-public.html', + subject: `${form.name} Accepted`, + priority: 'high', + messageLinkText: `Thank you for your ${form.name} submission. You can view your submission details by visiting the following links:`, + title: `${form.name} Accepted`, + form, + }; + + const contexts = [ + { + context: { + allFormSubmissionUrl: 'https://user/submissions?f=xxx-yyy', + confirmationNumber: 'abc', + form: form, + messageLinkText: `Thank you for your ${form.name} submission. You can view your submission details by visiting the following links:`, + messageLinkUrl: `https://form/success?s=${form.name}`, + revisionNotificationEmailContent: undefined, + title: `${form.name} Accepted`, + }, + to: ['a@b.com'], + }, + ]; + + expect(result).toEqual('ret'); + expect(formService.readForm).toHaveBeenCalledTimes(1); + expect(formService.readForm).toHaveBeenCalledWith(form.id); + expect(formService.readSubmission).toHaveBeenCalledTimes(1); + expect(formService.readSubmission).toHaveBeenCalledWith(submission.id); + expect(emailService._sendEmailTemplate).toHaveBeenCalledTimes(1); + expect(emailService._sendEmailTemplate).toHaveBeenCalledWith(configData, contexts); + }); + + it('submissionConfirmation should send an email without submission fields', async () => { + formService.readEmailTemplate = jest.fn().mockReturnValue({ + body: 'Thank you for your {{form.name}} submission regarding {{problem}}. You can view your submission details by visiting the following links:', + subject: '{{form.name}} Accepted', + title: '{{form.name}} Accepted', + }); + formService.readForm = jest.fn().mockReturnValue(form); + formService.readSubmission = jest.fn().mockReturnValue(submission); + emailService._sendEmailTemplate = jest.fn().mockReturnValue('ret'); + + const result = await emailService.submissionConfirmation(form.id, submission.id, body_normal, referer); + + const configData = { + bodyTemplate: 'submission-received-confirmation-public.html', + subject: `${form.name} Accepted`, + priority: 'normal', + messageLinkText: `Thank you for your ${form.name} submission regarding . You can view your submission details by visiting the following links:`, + title: `${form.name} Accepted`, + form, + }; + + const contexts = [ + { + context: { + allFormSubmissionUrl: 'https://user/submissions?f=xxx-yyy', + confirmationNumber: 'abc', + form: form, + messageLinkText: `Thank you for your ${form.name} submission regarding . You can view your submission details by visiting the following links:`, + messageLinkUrl: `https://form/success?s=${form.name}`, + revisionNotificationEmailContent: undefined, + title: `${form.name} Accepted`, + }, + to: ['a@b.com'], + }, + ]; + + expect(result).toEqual('ret'); + expect(formService.readForm).toHaveBeenCalledTimes(1); + expect(formService.readForm).toHaveBeenCalledWith(form.id); + expect(formService.readSubmission).toHaveBeenCalledTimes(1); + expect(formService.readSubmission).toHaveBeenCalledWith(submission.id); + expect(emailService._sendEmailTemplate).toHaveBeenCalledTimes(1); + expect(emailService._sendEmailTemplate).toHaveBeenCalledWith(configData, contexts); + }); + + it('submissionConfirmation should produce errors on failure', async () => { + formService.readEmailTemplate = jest.fn().mockRejectedValue(new Error('SQL Error')); + formService.readForm = jest.fn().mockReturnValue(form); + formService.readSubmission = jest.fn().mockReturnValue(submission); + emailService._sendEmailTemplate = jest.fn().mockReturnValue('ret'); + + await expect(emailService.submissionConfirmation(form.id, submission.id, body_normal, referer)).rejects.toThrow(); + }); + + it('submissionReceived should call send a submission email', async () => { + formService.readForm = jest.fn().mockReturnValue(form); + formService.readSubmission = jest.fn().mockReturnValue(submission); + emailService._sendEmailTemplate = jest.fn().mockReturnValue('ret'); + + const result = await emailService.submissionReceived(form.id, submission.id, body, referer); + + const configData = { + bodyTemplate: 'submission-confirmation.html', + title: `${form.name} Submission`, + subject: `${form.name} Submission`, + messageLinkText: `There is a new ${form.name} submission. Please login to review it.`, + priority: 'normal', + body, + form, + }; + + const contexts = [ + { + context: { + allFormSubmissionUrl: 'https://user/submissions?f=xxx-yyy', + confirmationNumber: 'abc', + form: form, + messageLinkText: `There is a new ${form.name} submission. Please login to review it.`, + messageLinkUrl: `https://form/view?s=${form.name}`, + revisionNotificationEmailContent: undefined, + title: `${form.name} Submission`, + }, + to: ['a@b.com', 'z@y.com'], + }, + ]; + + expect(result).toEqual('ret'); + expect(formService.readForm).toHaveBeenCalledTimes(1); + expect(formService.readForm).toHaveBeenCalledWith(form.id); + expect(formService.readSubmission).toHaveBeenCalledTimes(1); + expect(formService.readSubmission).toHaveBeenCalledWith(submission.id); + expect(emailService._sendEmailTemplate).toHaveBeenCalledTimes(1); + expect(form.submissionReceivedEmails).toBeInstanceOf(Array); + expect(emailService._sendEmailTemplate).toHaveBeenCalledWith(configData, contexts); + }); + + it('submissionUnassigned should send a uninvited email', async () => { + formService.readForm = jest.fn().mockReturnValue(form); + formService.readSubmission = jest.fn().mockReturnValue(submission); + emailService._sendEmailTemplate = jest.fn().mockReturnValue('ret'); + + const result = await emailService.submissionUnassigned(form.id, currentStatus, assignmentNotificationEmail, referer); + + const configData = { + bodyTemplate: 'submission-unassigned.html', + title: `Uninvited From ${form.name} Draft`, + subject: 'Uninvited From Submission Draft', + messageLinkText: `You have been uninvited from ${form.name} submission draft.`, + priority: 'normal', + form, + }; + + const contexts = [ + { + context: { + allFormSubmissionUrl: 'https://user/submissions?f=xxx-yyy', + confirmationNumber: 'abc', + form: form, + messageLinkText: `You have been uninvited from ${form.name} submission draft.`, + messageLinkUrl: `https://user/view?s=${form.name}`, + revisionNotificationEmailContent: undefined, + title: `Uninvited From ${form.name} Draft`, + }, + to: ['x@y.com'], + }, + ]; + + expect(result).toEqual('ret'); + expect(formService.readForm).toHaveBeenCalledTimes(1); + expect(formService.readForm).toHaveBeenCalledWith(form.id); + expect(emailService._sendEmailTemplate).toHaveBeenCalledTimes(1); + expect(emailService._sendEmailTemplate).toHaveBeenCalledWith(configData, contexts); + }); + + it('submissionAssigned should send a uninvited email', async () => { + formService.readForm = jest.fn().mockReturnValue(form); + formService.readSubmission = jest.fn().mockReturnValue(submission); + emailService._sendEmailTemplate = jest.fn().mockReturnValue('ret'); + + const result = await emailService.submissionAssigned(form.id, currentStatus, assignmentNotificationEmail, referer); + + const configData = { + bodyTemplate: 'submission-assigned.html', + title: `Invited to ${form.name} Draft`, + subject: 'Invited to Submission Draft', + messageLinkText: `You have been invited to a ${form.name} submission draft. You can review your submission draft details by visiting the following links:`, + priority: 'normal', + form, + }; + + const contexts = [ + { + context: { + allFormSubmissionUrl: 'https://user/submissions?f=xxx-yyy', + confirmationNumber: 'abc', + form: form, + messageLinkText: `You have been invited to a ${form.name} submission draft. You can review your submission draft details by visiting the following links:`, + messageLinkUrl: `https://user/view?s=${form.name}`, + revisionNotificationEmailContent: undefined, + title: `Invited to ${form.name} Draft`, + }, + to: ['x@y.com'], + }, + ]; + + expect(result).toEqual('ret'); + expect(formService.readForm).toHaveBeenCalledTimes(1); + expect(formService.readForm).toHaveBeenCalledWith(form.id); + expect(formService.readSubmission).toHaveBeenCalledTimes(1); + expect(formService.readSubmission).toHaveBeenCalledWith(currentStatus.formSubmissionId); + expect(emailService._sendEmailTemplate).toHaveBeenCalledTimes(1); + expect(emailService._sendEmailTemplate).toHaveBeenCalledWith(configData, contexts); + }); +}); diff --git a/frontend/app/tests/unit/forms/email/reminderService.spec.js b/frontend/app/tests/unit/forms/email/reminderService.spec.js new file mode 100644 index 0000000..a433562 --- /dev/null +++ b/frontend/app/tests/unit/forms/email/reminderService.spec.js @@ -0,0 +1,113 @@ +/* eslint-disable quotes */ + +const reminderService = require('../../../../src/forms/email/reminderService'); +const moment = require('moment'); + +const schedule = { + enabled: true, + scheduleType: 'period', + closingMessage: null, + keepOpenForTerm: '10', + repeatSubmission: { + enabled: true, + everyTerm: '1', + repeatUntil: '2023-08-10', + everyIntervalType: 'months', + }, + keepOpenForInterval: 'days', + allowLateSubmissions: { + enabled: null, + forNext: { + term: null, + intervalType: null, + }, + }, + closingMessageEnabled: null, + openSubmissionDateTime: '2022-07-10', + closeSubmissionDateTime: null, +}; + +describe('getDifference', () => { + it('should return the difference between 2 arrays of object', () => { + let obj1 = [ + { + userId: 1, + }, + { + userId: 2, + }, + { + userId: 3, + }, + { + userId: 4, + }, + ]; + let obj2 = [ + { + userId: 4, + }, + { + userId: 2, + }, + ]; + reminderService.getDifference(obj1, obj2).then((objs) => { + expect(objs.length).toEqual(2); + expect(objs[0].userId).toEqual(1); + }); + // eslint-disable-next-line no-console + }); +}); + +describe('getCurrentPeriod', () => { + it('should return the current period', () => { + let toDay = moment('2022-09-12'); + let periodes = reminderService._listDates(schedule); + let periode = reminderService.getCurrentPeriod(periodes, toDay, schedule.allowLateSubmissions.enabled); + expect(periode.state).toEqual(1); + expect(periode.index).toEqual(2); + }); + + it('should return null', () => { + let toDay = moment('2022-11-12'); + let periode = reminderService.getCurrentPeriod([], toDay, schedule.allowLateSubmissions.enabled); + expect(periode).toBe(null); + periode = reminderService.getCurrentPeriod([], toDay, schedule.allowLateSubmissions.enabled); + expect(periode).toBe(null); + // eslint-disable-next-line no-console + }); + + it('should return any period but the current date is after the periodes', () => { + let toDay = moment('2023-11-12'); + let periodes = reminderService._listDates(schedule); + let periode = reminderService.getCurrentPeriod(periodes, toDay, schedule.allowLateSubmissions.enabled); + expect(periode.state).toEqual(0); + expect(periode.index).toEqual(-1); + }); + + it('should return any period but the current date is before the periodes', () => { + let toDay = moment('2021-11-12'); + let periodes = reminderService._listDates(schedule); + let periode = reminderService.getCurrentPeriod(periodes, toDay, schedule.allowLateSubmissions.enabled); + expect(periode.state).toEqual(-1); + expect(periode.index).toEqual(-1); + }); +}); + +describe('checkIfInMiddleOfThePeriod', () => { + it('should return the false', () => { + const now = moment('2023-02-03'); + const days_diff = 5; + const start_date = moment('2023-02-01'); + const result = reminderService.checkIfInMiddleOfThePeriod(now, start_date, days_diff); + expect(result).toEqual(false); + }); + + it('should return the true', () => { + const now = moment('2023-02-06'); + const days_diff = 10; + const start_date = moment('2023-02-01'); + const result = reminderService.checkIfInMiddleOfThePeriod(now, start_date, days_diff); + expect(result).toEqual(true); + }); +}); diff --git a/frontend/app/tests/unit/forms/file/middleware/filePermissions.spec.js b/frontend/app/tests/unit/forms/file/middleware/filePermissions.spec.js new file mode 100644 index 0000000..8013bdf --- /dev/null +++ b/frontend/app/tests/unit/forms/file/middleware/filePermissions.spec.js @@ -0,0 +1,257 @@ +const Problem = require('api-problem'); + +const { currentFileRecord, hasFileCreate, hasFilePermissions } = require('../../../../../src/forms/file/middleware/filePermissions'); +const service = require('../../../../../src/forms/file/service'); +const userAccess = require('../../../../../src/forms/auth/middleware/userAccess'); + +const testRes = { + writeHead: jest.fn(), + end: jest.fn(), +}; +const zeroUuid = '00000000-0000-0000-0000-000000000000'; +const oneUuid = '11111111-1111-1111-1111-111111111111'; + +describe('currentFileRecord', () => { + const readFileSpy = jest.spyOn(service, 'read'); + + beforeEach(() => { + readFileSpy.mockReset(); + }); + + it('403s if there is no current user on the request scope', async () => { + const testReq = { + params: { + id: zeroUuid, + }, + }; + + const nxt = jest.fn(); + + await currentFileRecord(testReq, testRes, nxt); + expect(testReq.currentFileRecord).toEqual(undefined); + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(new Problem(403, { detail: 'File access to this ID is unauthorized.' })); + expect(readFileSpy).toHaveBeenCalledTimes(0); + }); + + it('403s if there is no file ID on the request scope', async () => { + const testReq = { + params: {}, + currentUser: { + idpUserId: zeroUuid, + username: 'jsmith@idir', + }, + }; + + const nxt = jest.fn(); + + await currentFileRecord(testReq, testRes, nxt); + expect(testReq.currentFileRecord).toEqual(undefined); + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(new Problem(403, { detail: 'File access to this ID is unauthorized.' })); + expect(readFileSpy).toHaveBeenCalledTimes(0); + }); + + it('403s if there is no file record to be found', async () => { + const testReq = { + params: { id: zeroUuid }, + currentUser: { + idpUserId: oneUuid, + username: 'jsmith@idir', + }, + }; + + const nxt = jest.fn(); + readFileSpy.mockImplementation(() => { + return undefined; + }); + + await currentFileRecord(testReq, testRes, nxt); + expect(testReq.currentFileRecord).toEqual(undefined); + expect(readFileSpy).toHaveBeenCalledTimes(1); + expect(readFileSpy).toHaveBeenCalledWith(zeroUuid); + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(new Problem(403, { detail: 'File access to this ID is unauthorized.' })); + }); + + it('403s if an exception occurs from the file lookup', async () => { + const testReq = { + params: { id: zeroUuid }, + currentUser: { + idpUserId: oneUuid, + username: 'jsmith@idir', + }, + }; + + const nxt = jest.fn(); + readFileSpy.mockImplementation(() => { + throw new Error(); + }); + + await currentFileRecord(testReq, testRes, nxt); + expect(testReq.currentFileRecord).toEqual(undefined); + expect(readFileSpy).toHaveBeenCalledTimes(1); + expect(readFileSpy).toHaveBeenCalledWith(zeroUuid); + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(new Problem(403, { detail: 'File access to this ID is unauthorized.' })); + }); + + it('403s if an exception occurs from the file lookup', async () => { + const testReq = { + params: { id: zeroUuid }, + currentUser: { + idpUserId: oneUuid, + username: 'jsmith@idir', + }, + }; + const testRecord = { + name: 'test', + }; + + const nxt = jest.fn(); + readFileSpy.mockImplementation(() => { + return testRecord; + }); + + await currentFileRecord(testReq, testRes, nxt); + expect(readFileSpy).toHaveBeenCalledTimes(1); + expect(readFileSpy).toHaveBeenCalledWith(zeroUuid); + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(); + expect(testReq.currentFileRecord).toEqual(testRecord); + }); +}); + +describe('hasFileCreate', () => { + it('403s if there is no current user on the request scope', async () => { + const testReq = { + headers: { + authorization: 'Bearer hjvds0uds', + }, + }; + + const nxt = jest.fn(); + + await hasFileCreate(testReq, testRes, nxt); + expect(testReq.currentFileRecord).toEqual(undefined); + expect(testReq.currentUser).toEqual(undefined); + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(new Problem(403, { detail: 'Invalid authorization credentials.' })); + }); + + it('403s if the current user is not an actual user (IE, public)', async () => { + const testReq = { + currentUser: { + idpUserId: undefined, + username: 'public', + }, + }; + + const nxt = jest.fn(); + + await hasFileCreate(testReq, testRes, nxt); + expect(testReq.currentFileRecord).toEqual(undefined); + expect(testReq.currentUser).toEqual(testReq.currentUser); + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(new Problem(403, { detail: 'Invalid authorization credentials.' })); + }); + + it('passes if a authed user is on the request', async () => { + const testReq = { + currentUser: { + idpUserId: zeroUuid, + username: 'jsmith@idir', + }, + }; + + const nxt = jest.fn(); + + await hasFileCreate(testReq, testRes, nxt); + expect(testReq.currentFileRecord).toEqual(undefined); + expect(testReq.currentUser).toEqual(testReq.currentUser); + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(); + }); +}); + +describe('hasFilePermissions', () => { + const perm = 'submission_read'; + + const subPermSpy = jest.spyOn(userAccess, 'hasSubmissionPermissions'); + beforeEach(() => { + subPermSpy.mockReset(); + }); + + it('returns a middleware function', async () => { + const mw = hasFilePermissions(perm); + expect(mw).toBeInstanceOf(Function); + }); + + it('403s if the request has no current user', async () => { + const mw = hasFilePermissions(perm); + const nxt = jest.fn(); + const req = { a: '1' }; + + mw(req, testRes, nxt); + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(new Problem(403, { detail: 'Unauthorized to read file' })); + }); + + it('403s if the request is a unauthed user', async () => { + const mw = hasFilePermissions(perm); + const nxt = jest.fn(); + const req = { + currentUser: { + idpUserId: undefined, + username: 'public', + }, + }; + + mw(req, testRes, nxt); + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(new Problem(403, { detail: 'Unauthorized to read file' })); + }); + + it('passes through if the user is authed and the file record has no submission', async () => { + const mw = hasFilePermissions(perm); + const nxt = jest.fn(); + const req = { + currentUser: { + idpUserId: zeroUuid, + username: 'jsmith@idir', + }, + currentFileRecord: { + name: 'unsubmitted file', + }, + }; + + mw(req, testRes, nxt); + expect(nxt).toHaveBeenCalledTimes(1); + expect(nxt).toHaveBeenCalledWith(); + }); + + it('returns the result of the submission checking middleware', async () => { + // Submission checking middleware is fully tested out in useraccess.spec.js + // treat as black box for this testing + subPermSpy.mockReturnValue(jest.fn()); + + const mw = hasFilePermissions(perm); + const nxt = jest.fn(); + const req = { + query: {}, + currentUser: { + idpUserId: zeroUuid, + username: 'jsmith@idir', + }, + currentFileRecord: { + formSubmissionId: oneUuid, + name: 'unsubmitted file', + }, + }; + + mw(req, testRes, nxt); + expect(subPermSpy).toHaveBeenCalledTimes(1); + expect(subPermSpy).toHaveBeenCalledWith(perm); + expect(nxt).toHaveBeenCalledTimes(0); + }); +}); diff --git a/frontend/app/tests/unit/forms/form/controller.spec.js b/frontend/app/tests/unit/forms/form/controller.spec.js new file mode 100644 index 0000000..55ae94f --- /dev/null +++ b/frontend/app/tests/unit/forms/form/controller.spec.js @@ -0,0 +1,46 @@ +const controller = require('../../../../src/forms/form/controller'); +const exportService = require('../../../../src/forms/form/exportService'); + +const req = { + params: { formId: 'bd4dcf26-65bd-429b-967f-125500bfd8a4' }, + query: { + type: 'submissions', + draft: false, + deleted: false, + version: 1, + }, + body: {}, + currentUser: {}, + headers: {}, +}; + +describe('form controller', () => { + it('should get all form and submissions fields for CSV export', async () => { + const formFields = [ + 'form.confirmationId', + 'form.formName', + 'form.version', + 'form.createdAt', + 'form.fullName', + 'form.username', + 'form.email', + 'fishermansName', + 'email', + 'forWhichBcLakeRegionAreYouCompletingTheseQuestions', + 'didYouFishAnyBcLakesThisYear', + 'oneRowPerLake', + 'oneRowPerLake.lakeName', + 'oneRowPerLake.closestTown', + 'oneRowPerLake.numberOfDays', + 'oneRowPerLake.dataGrid', + 'oneRowPerLake.dataGrid.fishType', + 'oneRowPerLake.dataGrid.numberCaught', + 'oneRowPerLake.dataGrid.numberKept', + ]; + + exportService.fieldsForCSVExport = jest.fn().mockReturnValue(formFields); + + await controller.readFieldsForCSVExport(req, {}, jest.fn()); + expect(exportService.fieldsForCSVExport).toHaveBeenCalledTimes(1); + }); +}); diff --git a/frontend/app/tests/unit/forms/form/exportService.spec.js b/frontend/app/tests/unit/forms/form/exportService.spec.js new file mode 100644 index 0000000..9baccec --- /dev/null +++ b/frontend/app/tests/unit/forms/form/exportService.spec.js @@ -0,0 +1,623 @@ +const exportService = require('../../../../src/forms/form/exportService'); +const MockModel = require('../../../../src/forms/common/models/views/submissionData'); +const _ = require('lodash'); +jest.mock('../../../../src/forms/common/models/views/submissionData', () => ({ + query: jest.fn().mockReturnThis(), + select: jest.fn().mockReturnThis(), + column: jest.fn().mockReturnThis(), + where: jest.fn().mockReturnThis(), + modify: jest.fn().mockReturnThis(), + then: jest.fn().mockReturnThis(), +})); + +describe('_readSchemaFields', () => { + it('should get form fields in the order they appear in the kitchen sink form', async () => { + // form schema from db + const formSchema = require('../../../fixtures/form/kitchen_sink_schema.json'); + + // expected field names in correct order returned from Kitchen Sink form schema + const expectedFieldNames = [ + 'textFieldNested1', + 'textFieldNested2', + 'heading', + 'textFieldInFieldset1', + 'selectListInFieldset1', + 'heading1', + 'paragraph', + 'email2', + 'number2', + 'textField3', + 'phoneNumber2', + 'registeredBusinessName1', + 'textField1', + 'multiLineText1', + 'selectList1', + 'selectList2', + 'checkbox1', + 'checkboxGroup1.check1', + 'checkboxGroup1.check2', + 'checkboxGroup1.check3', + 'radioGroup1', + 'number', + 'phoneNumber1', + 'email1', + 'dateTime1', + 'day1', + 'time1', + ]; + + const result = await exportService._readSchemaFields(formSchema); + expect(result).toHaveLength(27); + expect(result).toEqual(expectedFieldNames); + }); + + it('should get form fields in the order they appear in an advanced form', async () => { + // form schema from db + const formSchema = require('../../../fixtures/form/advanced_schema.json'); + + // expected input field names in correct order + const expectedFieldNames = [ + 'textincolumn1', + 'textinfieldset', + 'numberintable1', + 'numberintable2', + 'numberintable3', + 'numberintable4', + 'dataGridInPanel', + 'dataGridInPanel.textInDatagridInPanel1', + 'dataGridInPanel.textInDatagridInPanel2', + 'tags', + 'address', + 'address.address1', + 'address.address2', + 'address.city', + 'address.state', + 'address.country', + 'address.zip', + 'password', + 'day', + 'selectBoxes1.box1', + 'selectBoxes1.box2', + 'selectBoxes1.box3', + 'select1', + 'currency', + 'survey1.question1', + 'survey1.question2', + 'survey1.question3', + 'signature', + 'hidden1', + 'container1', + 'container1.containedTextField1', + 'container1.containedTextField2', + 'dataMap', + 'dataGrid', + 'dataGrid.textFieldInDataGrid1', + 'dataGrid.textFieldInDataGrid2', + 'editGrid', + 'editGrid.textFieldInEditGrid1', + 'editGrid.textFieldInEditGrid2', + 'tree', + 'tree.textFieldInTree1', + 'tree.textFieldInTree2', + 'simplefile', + 'orgbook', + ]; + + const result = await exportService._readSchemaFields(formSchema); + expect(result).toHaveLength(44); + expect(result).toEqual(expectedFieldNames); + }); + + it('should get form fields in the order they appear in the kitchen sink form for datagrid', async () => { + // form schema from db + const formSchema = require('../../../fixtures/form/Kitchen_sink_form_schema_datagrid.json'); + + // expected field names in correct order returned from Kitchen Sink form schema + const expectedFieldNames = [ + 'fishermansName', + 'email', + 'forWhichBcLakeRegionAreYouCompletingTheseQuestions', + 'didYouFishAnyBcLakesThisYear', + 'oneRowPerLake', + 'oneRowPerLake.lakeName', + 'oneRowPerLake.closestTown', + 'oneRowPerLake.numberOfDays', + 'oneRowPerLake.dataGrid', + 'oneRowPerLake.dataGrid.fishType', + 'oneRowPerLake.dataGrid.numberCaught', + 'oneRowPerLake.dataGrid.numberKept', + ]; + + const result = await exportService._readSchemaFields(formSchema); + expect(result).toHaveLength(12); + expect(result).toEqual(expectedFieldNames); + }); + + it('should get form fields in the order they appear in the kitchen sink form for multiple components', async () => { + // form schema from db + const formSchema = require('../../../fixtures/form/kitchen_sink_form_schema_multiple_component_test.json'); + + // expected field names in correct order returned from Kitchen Sink form schema + const expectedFieldNames = [ + 'firstName', + 'lastName', + 'schoolName', + 'departmentName', + 'courseName', + 'name', + 'testname1', + 'testname2', + 'testname3', + 'simplenumber', + 'simpleemail', + 'simpledatetime', + 'simpleday', + 'yes', + 'radioGroup', + 'checkboxGroup.1', + 'checkboxGroup.2', + 'survey1.early', + 'survey1.late', + 'currency', + 'password', + 'url', + 'textArea', + 'number', + 'number1', + 'day', + 'selectBoxes1.a', + 'selectBoxes1.b', + 'selectBoxes1.c', + 'select1', + 'radio1', + 'dataMap', + 'simplefile', + 'orgbook', + ]; + + const result = await exportService._readSchemaFields(formSchema); + expect(result).toHaveLength(34); + expect(result).toEqual(expectedFieldNames); + }); +}); + +describe('_buildCsvHeaders', () => { + it('should build correct csv headers', async () => { + // + + // form schema from db + const formSchema = require('../../../fixtures/form/kitchen_sink_schema.json'); + + // form object from db + const form = { id: 123 }; + + // mock latestFormSchema + exportService._readLatestFormSchema = jest.fn(() => { + return formSchema; + }); + + // submissions export (matchces the format that is downloaded in UI) + const submissionsExport = require('../../../fixtures/submission/kitchen_sink_submissions_export.json'); + + // build csv headers + // gets a a list of form meta fieldfs followed by submission fields + const result = await exportService._buildCsvHeaders(form, submissionsExport, null); + + expect(result).toHaveLength(44); + expect(result).toEqual(expect.arrayContaining(['form.confirmationId', 'textFieldNested1', 'textFieldNested2'])); + expect(exportService._readLatestFormSchema).toHaveBeenCalledTimes(1); + // expect(exportService._readLatestFormSchema).toHaveBeenCalledWith(123); + + // restore mocked function to it's original implementation + exportService._readLatestFormSchema.mockRestore(); + }); +}); + +describe('_buildCsvHeaders', () => { + it('should build correct csv headers for single row export option', async () => { + // + + // form schema from db + const formSchema = require('../../../fixtures/form/Kitchen_sink_form_schema_datagrid.json'); + + // form object from db + const form = { id: 123 }; + + // mock latestFormSchema + exportService._readLatestFormSchema = jest.fn(() => { + return formSchema; + }); + + // submissions export (matchces the format that is downloaded in UI) + const submissionsExport = require('../../../fixtures/submission/kitchen_sink_submission_data_export_datagrid.json'); + + // build csv headers + // gets a a list of form meta fieldfs followed by submission fields + const result = await exportService._buildCsvHeaders(form, submissionsExport, 1, null, true); + + expect(result).toHaveLength(29); + expect(result).toEqual( + expect.arrayContaining(['form.confirmationId', 'oneRowPerLake.0.closestTown', 'oneRowPerLake.0.dataGrid.0.fishType', 'oneRowPerLake.0.dataGrid.1.fishType']) + ); + expect(exportService._readLatestFormSchema).toHaveBeenCalledTimes(1); + expect(exportService._readLatestFormSchema).toHaveBeenCalledWith(123, 1); + + // restore mocked function to it's original implementation + exportService._readLatestFormSchema.mockRestore(); + }); +}); + +describe('_buildCsvHeaders', () => { + it('should build correct csv headers for single row export option when selected fields provided', async () => { + // form schema from db + const formSchema = require('../../../fixtures/form/Kitchen_sink_form_schema_datagrid.json'); + + // form object from db + const form = { id: 123 }; + + // mock latestFormSchema + exportService._readLatestFormSchema = jest.fn(() => { + return formSchema; + }); + + // submissions export (matchces the format that is downloaded in UI) + const submissionsExport = require('../../../fixtures/submission/kitchen_sink_submission_data_export_datagrid.json'); + + // build csv headers + // get fields which we gonna filtered column needed from + const fields = require('../../../fixtures/submission/kitchen_sink_submission_data_export_datagrid_fields_selection.json'); + // get result columns if we need to filter out the columns + const result = await exportService._buildCsvHeaders(form, submissionsExport, 1, fields, true); + + expect(result).toHaveLength(20); + expect(result).toEqual( + expect.arrayContaining([ + 'form.confirmationId', + 'oneRowPerLake.0.closestTown', + 'oneRowPerLake.0.dataGrid.0.fishType', + 'oneRowPerLake.0.dataGrid.1.fishType', + 'oneRowPerLake.0.dataGrid.0.numberKept', + ]) + ); + expect(result).toEqual( + expect.not.arrayContaining([ + 'oneRowPerLake.1.dataGrid.0.numberKept', + 'oneRowPerLake.1.lakeName', + 'oneRowPerLake.1.dataGrid.0.numberCaught', + 'oneRowPerLake.1.numberOfDays', + 'lateEntry', + ]) + ); + expect(exportService._readLatestFormSchema).toHaveBeenCalledTimes(1); + expect(exportService._readLatestFormSchema).toHaveBeenCalledWith(123, 1); + + // restore mocked function to it's original implementation + exportService._readLatestFormSchema.mockRestore(); + }); +}); + +describe('_buildCsvHeaders', () => { + it('should build correct csv headers with correct order (as it goes in form design) for single row export option', async () => { + // form schema from db + const formSchema = require('../../../fixtures/form/Kitchen_sink_form_schema_datagrid.json'); + + // form object from db + const form = { id: 123 }; + + // mock latestFormSchema + exportService._readLatestFormSchema = jest.fn(() => { + return formSchema; + }); + + // submissions export (matchces the format that is downloaded in UI) + const submissionsExport = require('../../../fixtures/submission/kitchen_sink_submission_data_export_datagrid.json'); + + // build csv headers + // get result columns if we need to filter out the columns + const result = await exportService._buildCsvHeaders(form, submissionsExport, 1, null, true); + + expect(result).toHaveLength(29); + + // making sure that order of the result columns are same as it goes in a form designer + expect(result[0]).toEqual('form.confirmationId'); + expect(result[7]).toEqual('fishermansName'); + expect(result[10]).toEqual('didYouFishAnyBcLakesThisYear'); + expect(result[11]).toEqual('oneRowPerLake.0.dataGrid.0.fishType'); + expect(result[13]).toEqual('oneRowPerLake.0.dataGrid.0.numberCaught'); + expect(result[18]).toEqual('oneRowPerLake.0.closestTown'); + expect(result[28]).toEqual('oneRowPerLake.1.numberOfDays'); + expect(exportService._readLatestFormSchema).toHaveBeenCalledTimes(1); + expect(exportService._readLatestFormSchema).toHaveBeenCalledWith(123, 1); + + // restore mocked function to it's original implementation + exportService._readLatestFormSchema.mockRestore(); + }); +}); + +describe('_buildCsvHeaders', () => { + it('should build correct csv headers multiple components', async () => { + // + + // form schema from db + const formSchema = require('../../../fixtures/form/kitchen_sink_form_schema_multiple_component_test.json'); + + // form object from db + const form = { id: 123 }; + + // mock latestFormSchema + exportService._readLatestFormSchema = jest.fn(() => { + return formSchema; + }); + + // submissions export (matchces the format that is downloaded in UI) + const submissionsExport = require('../../../fixtures/submission/kitchen_sink_submission_data_multiple_component_test.json'); + + // build csv headers + // gets a a list of form meta fieldfs followed by submission fields + const result = await exportService._buildCsvHeaders(form, submissionsExport, 1, null, true); + + expect(result).toHaveLength(41); + expect(result).toEqual(expect.arrayContaining(['number1', 'selectBoxes1.a', 'number'])); + expect(exportService._readLatestFormSchema).toHaveBeenCalledTimes(1); + expect(exportService._readLatestFormSchema).toHaveBeenCalledWith(123, 1); + + // restore mocked function to it's original implementation + exportService._readLatestFormSchema.mockRestore(); + }); +}); + +describe('', () => { + it('should return right number of fields with columns for csv export', async () => { + // form schema from db + const submission = require('../../../fixtures/submission/kitchen_sink_submission_extract_field_csv_export.json'); + + const form = { + id: 'bd4dcf26-65bd-429b-967f-125500bfd8a4', + name: 'Fisheries', + description: '', + active: true, + labels: [], + createdBy: 'AIDOWU@idir', + createdAt: '2023-03-29T14:09:28.457Z', + updatedBy: 'AIDOWU@idir', + updatedAt: '2023-04-10T16:19:43.491Z', + showSubmissionConfirmation: true, + submissionReceivedEmails: [], + enableStatusUpdates: false, + enableSubmitterDraft: true, + schedule: {}, + reminder_enabled: false, + enableCopyExistingSubmission: false, + }; + + const params = { + type: 'submissions', + draft: false, + deleted: false, + version: 1, + }; + + const formFields = [ + 'form.confirmationId', + 'form.formName', + 'form.version', + 'form.createdAt', + 'form.fullName', + 'form.username', + 'form.email', + 'fishermansName', + 'email', + 'forWhichBcLakeRegionAreYouCompletingTheseQuestions', + 'didYouFishAnyBcLakesThisYear', + 'oneRowPerLake', + 'oneRowPerLake.lakeName', + 'oneRowPerLake.closestTown', + 'oneRowPerLake.numberOfDays', + 'oneRowPerLake.dataGrid', + 'oneRowPerLake.dataGrid.fishType', + 'oneRowPerLake.dataGrid.numberCaught', + 'oneRowPerLake.dataGrid.numberKept', + ]; + + // mock readVersion function + exportService._getForm = jest.fn().mockReturnValue(form); + + exportService._getData = jest.fn().mockReturnValue(submission); + + exportService._buildCsvHeaders = jest.fn().mockReturnValue(formFields); + + // get fields + const fields = await exportService.fieldsForCSVExport('bd4dcf26-65bd-429b-967f-125500bfd8a4', params); + + expect(exportService._getForm).toHaveBeenCalledWith('bd4dcf26-65bd-429b-967f-125500bfd8a4'); + expect(exportService._getData).toHaveBeenCalledWith(params.type, params.version, form, params); + expect(exportService._getForm).toHaveBeenCalledTimes(1); + expect(exportService._getData).toHaveBeenCalledTimes(1); + expect(exportService._buildCsvHeaders).toHaveBeenCalledTimes(1); + // test cases + expect(fields.length).toEqual(19); + }); +}); + +describe('_submissionsColumns', () => { + const form = { + id: 'bd4dcf26-65bd-429b-967f-125500bfd8a4', + name: 'Fisheries', + description: '', + active: true, + labels: [], + createdBy: 'AIDOWU@idir', + createdAt: '2023-03-29T14:09:28.457Z', + updatedBy: 'AIDOWU@idir', + updatedAt: '2023-04-10T16:19:43.491Z', + showSubmissionConfirmation: true, + submissionReceivedEmails: [], + enableStatusUpdates: false, + enableSubmitterDraft: true, + schedule: {}, + reminder_enabled: false, + enableCopyExistingSubmission: false, + }; + + it('should return right columns, when no prefered columns passed as params.', async () => { + const params = { + type: 'submissions', + format: 'json', + drafts: true, + deleted: false, + version: 1, + }; + + const submissions = exportService._submissionsColumns(form, params); + expect(submissions.length).toEqual(9); + expect(submissions).toEqual(expect.arrayContaining(['submissionId', 'confirmationId', 'formName', 'version', 'createdAt', 'fullName', 'username', 'email', 'submission'])); + }); + + it('should return right number of columns, when 1 prefered column (deleted) passed as params.', async () => { + const params = { + type: 'submissions', + format: 'json', + drafts: true, + deleted: false, + version: 1, + columns: ['deleted'], + }; + + const submissions = exportService._submissionsColumns(form, params); + expect(submissions.length).toEqual(10); + }); + + it('should return right number of columns, when 1 prefered column (draft) passed as params.', async () => { + const params = { + type: 'submissions', + format: 'json', + drafts: true, + deleted: false, + version: 1, + columns: ['draft'], + }; + + const submissions = exportService._submissionsColumns(form, params); + expect(submissions.length).toEqual(10); + }); + + it('should return right number of columns, when 2 prefered column (draft & deleted) passed as params.', async () => { + const params = { + type: 'submissions', + format: 'json', + drafts: true, + deleted: false, + version: 1, + columns: ['draft', 'deleted'], + }; + + const submissions = exportService._submissionsColumns(form, params); + + expect(submissions.length).toEqual(11); + }); + + it('should return right number of columns, when a garbage or NON-allowed column (testCol1 & testCol2) passed as params.', async () => { + const params = { + type: 'submissions', + format: 'json', + drafts: true, + deleted: false, + version: 1, + columns: ['testCol1', 'testCol2'], + }; + + const submissions = exportService._submissionsColumns(form, params); + expect(submissions.length).toEqual(9); + }); +}); + +describe('_getSubmissions', () => { + // form schema from db + const form = { + id: 'bd4dcf26-65bd-429b-967f-125500bfd8a4', + name: 'Fisheries', + description: '', + active: true, + labels: [], + createdBy: 'AIDOWU@idir', + createdAt: '2023-03-29T14:09:28.457Z', + updatedBy: 'AIDOWU@idir', + updatedAt: '2023-04-10T16:19:43.491Z', + showSubmissionConfirmation: true, + submissionReceivedEmails: [], + enableStatusUpdates: false, + enableSubmitterDraft: true, + schedule: {}, + reminder_enabled: false, + enableCopyExistingSubmission: false, + }; + + it('Should pass this test with empty preference passed to _getSubmissions', async () => { + const params = { + type: 'submissions', + draft: false, + deleted: false, + version: 1, + preference: { + updatedMinDate: '', + updatedMaxDate: '', + }, + }; + + MockModel.query.mockImplementation(() => MockModel); + exportService._submissionsColumns = jest.fn().mockReturnThis(); + + let preference; + if (params.preference && _.isString(params.preference)) { + preference = JSON.parse(params.preference); + } else { + preference = params.preference; + } + exportService._getSubmissions(form, params, params.version); + expect(MockModel.query).toHaveBeenCalledTimes(1); + expect(MockModel.modify).toHaveBeenCalledTimes(7); + expect(MockModel.modify).toHaveBeenCalledWith('filterUpdatedAt', preference && preference.updatedMinDate, preference && preference.updatedMaxDate); + }); + + it('Should pass this test without preference passed to _getSubmissions and without calling updatedAt modifier', async () => { + const params = { + type: 'submissions', + draft: false, + deleted: false, + version: 1, + }; + + MockModel.query.mockImplementation(() => MockModel); + exportService._submissionsColumns = jest.fn().mockReturnThis(); + exportService._getSubmissions(form, params, params.version); + expect(MockModel.query).toHaveBeenCalledTimes(1); + expect(MockModel.modify).toHaveBeenCalledTimes(7); + }); + + it('Should pass this test with preference passed to _getSubmissions', async () => { + const params = { + type: 'submissions', + draft: false, + deleted: false, + version: 1, + preference: { + updatedMinDate: '2020-12-10T08:00:00Z', + updatedMaxDate: '2020-12-17T08:00:00Z', + }, + }; + + MockModel.query.mockImplementation(() => MockModel); + exportService._submissionsColumns = jest.fn().mockReturnThis(); + + let preference; + if (params.preference && _.isString(params.preference)) { + preference = JSON.parse(params.preference); + } else { + preference = params.preference; + } + exportService._getSubmissions(form, params, params.version); + expect(MockModel.query).toHaveBeenCalledTimes(1); + expect(MockModel.modify).toHaveBeenCalledTimes(7); + expect(MockModel.modify).toHaveBeenCalledWith('filterUpdatedAt', preference && preference.updatedMinDate, preference && preference.updatedMaxDate); + }); +}); diff --git a/frontend/app/tests/unit/forms/form/service.spec.js b/frontend/app/tests/unit/forms/form/service.spec.js new file mode 100644 index 0000000..d7eee48 --- /dev/null +++ b/frontend/app/tests/unit/forms/form/service.spec.js @@ -0,0 +1,637 @@ +const { MockModel, MockTransaction } = require('../../../common/dbHelper'); + +const { v4: uuidv4 } = require('uuid'); + +const { EmailTypes } = require('../../../../src/forms/common/constants'); +const service = require('../../../../src/forms/form/service'); + +jest.mock('../../../../src/forms/common/models/tables/formEmailTemplate', () => MockModel); +jest.mock('../../../../src/forms/common/models/views/submissionMetadata', () => MockModel); + +const emailTemplateSubmissionConfirmation = { + body: 'default submission confirmation body', + formId: uuidv4(), + subject: 'default submission confirmation subject', + title: 'default submission confirmation title', + type: EmailTypes.SUBMISSION_CONFIRMATION, +}; +const emailTemplate = { + body: 'body', + formId: uuidv4(), + subject: 'subject', + title: 'title', + type: EmailTypes.SUBMISSION_CONFIRMATION, +}; + +beforeEach(() => { + MockModel.mockReset(); + MockTransaction.mockReset(); +}); + +afterEach(() => { + jest.restoreAllMocks(); +}); + +describe('_findFileIds', () => { + it('should handle a blank everything', () => { + const schema = { + components: [], + }; + const data = { + submission: { + data: {}, + }, + }; + const fileIds = service._findFileIds(schema, data); + expect(fileIds).toEqual([]); + }); + + it('should return an empty array if no file controls', () => { + const schema = { + components: [ + { + type: 'simpletextfield', + key: 'aTextBox', + }, + ], + }; + const data = { + submission: { + data: { + aTextBox: '', + }, + }, + }; + const fileIds = service._findFileIds(schema, data); + expect(fileIds).toEqual([]); + }); + + it('should return an empty array if there is a file control with no file in it', () => { + const schema = { + components: [ + { + type: 'simpletextfield', + key: 'aTextBox', + }, + { + type: 'simplefile', + key: 'theFirstFile', + }, + ], + }; + const data = { + submission: { + data: { + aTextBox: '', + theFirstFile: [], + }, + }, + }; + const fileIds = service._findFileIds(schema, data); + expect(fileIds).toEqual([]); + }); + + it('should return an empty array if there are multiple file controls with no files in them', () => { + const schema = { + components: [ + { + type: 'simpletextfield', + key: 'aTextBox', + }, + { + type: 'simplefile', + key: 'theFirstFile', + }, + { + type: 'simpletextfield', + key: 'bTextBox', + }, + { + type: 'simplefile', + key: 'theSecondFile', + }, + ], + }; + const data = { + submission: { + data: { + aTextBox: '', + theFirstFile: [], + theSecondFile: [], + }, + }, + }; + const fileIds = service._findFileIds(schema, data); + expect(fileIds).toEqual([]); + }); + + it('should return a fileId for a populated file control', () => { + const schema = { + components: [ + { + type: 'simplefile', + key: 'theFirstFile', + }, + { + type: 'simpletextfield', + key: 'aTextBox', + }, + ], + }; + const data = { + submission: { + data: { + aTextBox: '', + theFirstFile: [ + { + storage: 'chefs', + url: '/app/api/v1/files/009c1edc-59f5-462f-bdd1-460aa71b9e22', + size: 253400, + data: { + id: '009c1edc-59f5-462f-bdd1-460aa71b9e22', + }, + originalName: 'v18.json', + }, + ], + }, + }, + }; + const fileIds = service._findFileIds(schema, data); + expect(fileIds).toEqual(['009c1edc-59f5-462f-bdd1-460aa71b9e22']); + }); + + it('should return a list of fileIds for multiple populated file controls', () => { + const schema = { + components: [ + { + type: 'simplefile', + key: 'theFirstFile', + }, + { + type: 'simpletextfield', + key: 'aTextBox', + }, + { + type: 'simplefile', + key: 'theSecondFile', + }, + { + type: 'simpletextfield', + key: 'bTextBox', + }, + ], + }; + const data = { + submission: { + data: { + aTextBox: '', + theFirstFile: [ + { + storage: 'chefs', + url: '/app/api/v1/files/009c1edc-59f5-462f-bdd1-460aa71b9e22', + size: 253400, + data: { + id: '009c1edc-59f5-462f-bdd1-460aa71b9e22', + }, + originalName: 'v18.json', + }, + ], + bTextBox: 'yes', + theSecondFile: [ + { + storage: 'chefs', + url: '/app/api/v1/files/009c1edc-59f5-462f-bdd1-460aa71b9e22', + size: 253400, + data: { + id: '70daceba-14cf-42c9-8532-9e5717809266', + }, + originalName: 'something.docx', + }, + ], + }, + }, + }; + const fileIds = service._findFileIds(schema, data); + expect(fileIds).toEqual(['009c1edc-59f5-462f-bdd1-460aa71b9e22', '70daceba-14cf-42c9-8532-9e5717809266']); + }); + + it('should return a blank array for a hidden file control', () => { + const schema = { + components: [ + { + type: 'simplefile', + key: 'theFirstFile', + }, + { + type: 'simpletextfield', + key: 'aTextBox', + }, + ], + }; + const data = { + submission: { + data: { + aTextBox: '', + }, + }, + }; + const fileIds = service._findFileIds(schema, data); + expect(fileIds).toEqual([]); + }); + + it('should return a single item array for 1 shown, and 1 hidden file control', () => { + const schema = { + components: [ + { + type: 'simplefile', + key: 'theFirstFile', + }, + { + type: 'simpletextfield', + key: 'aTextBox', + }, + { + type: 'simplefile', + key: 'theSecondFile', + }, + ], + }; + const data = { + submission: { + data: { + aTextBox: '', + theSecondFile: [ + { + storage: 'chefs', + url: '/app/api/v1/files/009c1edc-59f5-462f-bdd1-460aa71b9e22', + size: 253400, + data: { + id: '70daceba-14cf-42c9-8532-9e5717809266', + }, + originalName: 'something.docx', + }, + ], + }, + }, + }; + const fileIds = service._findFileIds(schema, data); + expect(fileIds).toEqual(['70daceba-14cf-42c9-8532-9e5717809266']); + }); +}); + +describe('readVersionFields', () => { + it('should not return hidden fields', async () => { + const schema = { + type: 'form', + components: [ + { + input: true, + hidden: true, + key: 'firstName', + type: 'textfield', + }, + ], + }; + + // mock readVersion function + service.readVersion = jest.fn().mockReturnValue({ schema }); + // get fields + const fields = await service.readVersionFields(); + // test cases + expect(fields.length).toEqual(0); + }); + + it('should return right number of fields without columns', async () => { + const schema = { + type: 'form', + components: [ + { + type: 'textfield', + input: true, + key: 'firstName', + }, + ], + }; + + // mock readVersion function + service.readVersion = jest.fn().mockReturnValue({ schema }); + // get fields + const fields = await service.readVersionFields(); + // test cases + expect(fields.length).toEqual(1); + }); + + it('should return right number of fields with columns', async () => { + const schema = { + type: 'form', + components: [ + { + type: 'textfield', + input: true, + key: 'firstName', + }, + { + type: 'columns', + input: false, + key: 'myColumns', + columns: [ + { + size: 'lg', + components: [], + }, + { + size: 'lg', + components: [ + { + type: 'textfield', + input: true, + key: 'lastName', + }, + ], + }, + { + size: 'lg', + components: [], + }, + ], + }, + ], + }; + + // mock readVersion function + service.readVersion = jest.fn().mockReturnValue({ schema }); + // get fields + const fields = await service.readVersionFields(); + // test cases + expect(fields.length).toEqual(2); + }); + + it('should return right number of fields in a table', async () => { + const schema = { + type: 'form', + components: [ + { + key: 'table', + rows: [ + [ + { + components: [ + { + input: true, + key: 'key', + }, + ], + }, + ], + ], + }, + ], + }; + + // mock readVersion function + service.readVersion = jest.fn().mockReturnValue({ schema }); + // get fields + const fields = await service.readVersionFields(); + // test cases + expect(fields.length).toEqual(1); + }); +}); + +describe('processPaginationData', () => { + const SubmissionData = require('../../../fixtures/submission/kitchen_sink_submission_pagination.json'); + + // Put the MockModel.query back to what it was, so that the tests that follow + // can run. + afterAll(() => { + MockModel.query = jest.fn().mockReturnThis(); + }); + + it('fetch first-page data with 10 items per page', async () => { + MockModel.query.mockImplementation((data) => { + return { + page: function (page, itemsPerPage) { + let start = page * itemsPerPage; + let end = page * itemsPerPage + itemsPerPage; + return { results: data.slice(start, end), total: data.length }; + }, + modify: () => jest.fn().mockReturnThis(), + }; + }); + let result = await service.processPaginationData(MockModel.query(SubmissionData), 0, 10, 0, null, false); + expect(result.results).toHaveLength(10); + expect(result.total).toEqual(SubmissionData.length); + }); + it('fetch first-page data with 5 items per page', async () => { + MockModel.query.mockImplementation((data) => { + return { + page: function (page, itemsPerPage) { + let start = page * itemsPerPage; + let end = page * itemsPerPage + itemsPerPage; + return { results: data.slice(start, end), total: data.length }; + }, + modify: () => jest.fn().mockReturnThis(), + }; + }); + let result = await service.processPaginationData(MockModel.query(SubmissionData), 0, 5, 0, null, false); + expect(result.results).toHaveLength(5); + expect(result.total).toEqual(SubmissionData.length); + }); + it('fetch second-page data with 5 items per page', async () => { + MockModel.query.mockImplementation((data) => { + return { + page: function (page, itemsPerPage) { + let start = page * itemsPerPage; + let end = page * itemsPerPage + itemsPerPage; + return { results: data.slice(start, end), total: data.length }; + }, + modify: () => jest.fn().mockReturnThis(), + }; + }); + let result = await service.processPaginationData(MockModel.query(SubmissionData), 1, 5, 0, null, false); + expect(result.results).toHaveLength(5); + expect(result.total).toEqual(SubmissionData.length); + }); + it('search submission data with pagination base on datetime', async () => { + MockModel.query.mockImplementation((data) => data); + let result = await service.processPaginationData(MockModel.query(SubmissionData), 0, 5, 0, '2023-08-19T19:11', true); + expect(result.results).toHaveLength(3); + expect(result.total).toEqual(3); + }); + it('search submission data with pagination base on any value (first page)', async () => { + MockModel.query.mockImplementation((data) => data); + let result = await service.processPaginationData(MockModel.query(SubmissionData), 0, 5, 0, 'a', true); + expect(result.results).toHaveLength(5); + }); + it('search submission data with pagination base on any value (second page)', async () => { + MockModel.query.mockImplementation((data) => data); + let result = await service.processPaginationData(MockModel.query(SubmissionData), 1, 5, 0, 'a', true); + expect(result.results).toHaveLength(5); + }); + it('search submission data with pagination base on any value (test for case)', async () => { + MockModel.query.mockImplementation((data) => data); + let result = await service.processPaginationData(MockModel.query(SubmissionData), 0, 10, 0, 'A', true); + expect(result.results).toHaveLength(10); + }); +}); + +describe('popFormLevelInfo', () => { + it('should remove all the form level properties', () => { + const givenArrayOfSubmission = [ + { + form: { + confirmationId: '3A31A078', + formName: 'FormTest', + version: 4, + createdAt: '2023-08-31T16:50:33.571Z', + fullName: 'John DOe', + username: 'JOHNDOE', + email: 'john.doe@example.ca', + status: 'SUBMITTED', + assignee: null, + assigneeEmail: null, + }, + lateEntry: false, + simplenumber: 4444, + }, + ]; + const expectedArrayOfSubmission = [ + { + form: {}, + simplenumber: 4444, + }, + ]; + + const response = service.popFormLevelInfo(givenArrayOfSubmission); + expect(response).toEqual(expectedArrayOfSubmission); + }); +}); + +describe('_getDefaultEmailTemplate', () => { + it('should return a template', async () => { + const formId = uuidv4(); + const template = service._getDefaultEmailTemplate(formId, EmailTypes.SUBMISSION_CONFIRMATION); + + expect(template.formId).toEqual(formId); + expect(template.type).toEqual(EmailTypes.SUBMISSION_CONFIRMATION); + expect(template).toHaveProperty('body'); + expect(template).toHaveProperty('subject'); + expect(template).toHaveProperty('title'); + }); +}); + +describe('readEmailTemplate', () => { + it('should return template by searching form ID and type', async () => { + service._getDefaultEmailTemplate = jest.fn().mockReturnValue(emailTemplateSubmissionConfirmation); + MockModel.mockResolvedValue(emailTemplate); + + const template = await service.readEmailTemplate(emailTemplate.formId, emailTemplate.type); + + expect(MockModel.query).toHaveBeenCalledTimes(1); + expect(MockModel.modify).toHaveBeenCalledTimes(2); + expect(MockModel.modify).toHaveBeenCalledWith('filterFormId', emailTemplate.formId); + expect(MockModel.modify).toHaveBeenCalledWith('filterType', emailTemplate.type); + expect(template).toEqual(emailTemplate); + }); + + it('should return default template when form ID and type not found', async () => { + service._getDefaultEmailTemplate = jest.fn().mockReturnValue(emailTemplateSubmissionConfirmation); + MockModel.mockResolvedValue(); + + const template = await service.readEmailTemplate(emailTemplate.formId, emailTemplate.type); + + expect(MockModel.query).toHaveBeenCalledTimes(1); + expect(MockModel.modify).toHaveBeenCalledTimes(2); + expect(MockModel.modify).toHaveBeenCalledWith('filterFormId', emailTemplate.formId); + expect(MockModel.modify).toHaveBeenCalledWith('filterType', emailTemplate.type); + expect(template).toEqual(emailTemplateSubmissionConfirmation); + }); +}); + +describe('readEmailTemplates', () => { + it('should return template by searching form ID', async () => { + service._getDefaultEmailTemplate = jest.fn().mockReturnValue(emailTemplateSubmissionConfirmation); + MockModel.mockResolvedValue([emailTemplate]); + + const template = await service.readEmailTemplates(emailTemplate.formId); + + expect(MockModel.query).toHaveBeenCalledTimes(1); + expect(MockModel.modify).toHaveBeenCalledTimes(1); + expect(MockModel.modify).toHaveBeenCalledWith('filterFormId', emailTemplate.formId); + expect(template).toEqual([emailTemplate]); + }); + + it('should return default template when form ID not found', async () => { + service._getDefaultEmailTemplate = jest.fn().mockReturnValue(emailTemplateSubmissionConfirmation); + MockModel.mockResolvedValue([]); + + const template = await service.readEmailTemplates(emailTemplate.formId); + + expect(MockModel.query).toHaveBeenCalledTimes(1); + expect(MockModel.modify).toHaveBeenCalledTimes(1); + expect(MockModel.modify).toHaveBeenCalledWith('filterFormId', emailTemplate.formId); + expect(template).toEqual([emailTemplateSubmissionConfirmation]); + }); +}); + +describe('createOrUpdateEmailTemplates', () => { + const user = { usernameIdp: 'username' }; + + it('should create template when it does not exist', async () => { + service.readEmailTemplate = jest.fn().mockReturnValue(emailTemplate); + service.readEmailTemplates = jest.fn().mockReturnValue([emailTemplate]); + + await service.createOrUpdateEmailTemplate(emailTemplate.formId, emailTemplate, user); + + expect(MockModel.insert).toHaveBeenCalledTimes(1); + expect(MockModel.insert).toHaveBeenCalledWith({ + createdBy: user.usernameIdp, + id: expect.any(String), + ...emailTemplate, + }); + expect(MockTransaction.commit).toHaveBeenCalledTimes(1); + }); + + it('should update template when it already exists', async () => { + const id = uuidv4(); + service.readEmailTemplate = jest.fn().mockReturnValue({ id: id, ...emailTemplate }); + service.readEmailTemplates = jest.fn().mockReturnValue([{ id: id, ...emailTemplate }]); + + await service.createOrUpdateEmailTemplate(emailTemplate.formId, emailTemplate, user); + + expect(MockModel.update).toHaveBeenCalledTimes(1); + expect(MockModel.update).toHaveBeenCalledWith({ + updatedBy: user.usernameIdp, + ...emailTemplate, + }); + expect(MockTransaction.commit).toHaveBeenCalledTimes(1); + }); + + it('should not rollback when an error occurs outside transaction', async () => { + service.readEmailTemplate = jest.fn().mockRejectedValue(new Error('SQL Error')); + + await expect(service.createOrUpdateEmailTemplate(emailTemplate.formId, emailTemplate, user)).rejects.toThrow(); + + expect(MockTransaction.rollback).toHaveBeenCalledTimes(0); + }); + + it('should rollback when an insert error occurs inside transaction', async () => { + service.readEmailTemplate = jest.fn().mockReturnValue(emailTemplate); + service.readEmailTemplates = jest.fn().mockReturnValue([emailTemplate]); + MockModel.insert = jest.fn().mockRejectedValue(new Error('SQL Error')); + + await expect(service.createOrUpdateEmailTemplate(emailTemplate.formId, emailTemplate, user)).rejects.toThrow(); + + expect(MockTransaction.rollback).toHaveBeenCalledTimes(1); + }); + + it('should rollback when an update error occurs inside transaction', async () => { + const id = uuidv4(); + service.readEmailTemplate = jest.fn().mockReturnValue({ id: id, ...emailTemplate }); + service.readEmailTemplates = jest.fn().mockReturnValue([{ id: id, ...emailTemplate }]); + MockModel.update = jest.fn().mockRejectedValue(new Error('SQL Error')); + + await expect(service.createOrUpdateEmailTemplate(emailTemplate.formId, emailTemplate, user)).rejects.toThrow(); + + expect(MockTransaction.rollback).toHaveBeenCalledTimes(1); + }); +}); diff --git a/frontend/app/tests/unit/forms/rbac/controller.spec.js b/frontend/app/tests/unit/forms/rbac/controller.spec.js new file mode 100644 index 0000000..0a2e482 --- /dev/null +++ b/frontend/app/tests/unit/forms/rbac/controller.spec.js @@ -0,0 +1,38 @@ +const controller = require('../../../../src/forms/rbac/controller'); +const service = require('../../../../src/forms/rbac/service'); +const emailService = require('../../../../src/forms/email/emailService'); +const formService = require('../../../../../app/src/forms/submission/service'); + +describe('getSubmissionUsers', () => { + const req = { + query: { formSubmissionId: '1', userId: '2' }, + body: { permissions: [] }, + currentUser: {}, + headers: { referer: 'a' }, + }; + it('should call the service with the query params', async () => { + service.getSubmissionUsers = jest.fn().mockReturnValue({ form: { id: '123' } }); + await controller.getSubmissionUsers(req, {}, jest.fn()); + + expect(service.getSubmissionUsers).toHaveBeenCalledTimes(1); + expect(service.getSubmissionUsers).toHaveBeenCalledWith(req.query); + }); +}); + +describe('setSubmissionUserPermissions', () => { + const req = { + query: { formSubmissionId: '1', userId: '2', selectedUserEmail: 'a@a.com' }, + body: { permissions: [1, 2, 3] }, + currentUser: { me: 'I' }, + headers: { referer: 'a' }, + }; + it('should call the service with the appropriate request stuff', async () => { + formService.read = jest.fn().mockReturnValue({ form: { id: '123' } }); + service.modifySubmissionUser = jest.fn().mockReturnValue({ form: { id: '123' } }); + emailService.submissionAssigned = jest.fn().mockReturnValue({}); + await controller.setSubmissionUserPermissions(req, {}, jest.fn()); + + expect(service.modifySubmissionUser).toHaveBeenCalledTimes(1); + expect(service.modifySubmissionUser).toHaveBeenCalledWith(req.query.formSubmissionId, req.query.userId, req.body, req.currentUser); + }); +}); diff --git a/frontend/app/tests/unit/forms/submission/controller.spec.js b/frontend/app/tests/unit/forms/submission/controller.spec.js new file mode 100644 index 0000000..f20f9ee --- /dev/null +++ b/frontend/app/tests/unit/forms/submission/controller.spec.js @@ -0,0 +1,173 @@ +const { Statuses } = require('../../../../src/forms/common/constants'); +const controller = require('../../../../src/forms/submission/controller'); +const emailService = require('../../../../src/forms/email/emailService'); +const service = require('../../../../src/forms/submission/service'); +const cdogsService = require('../../../../src/components/cdogsService'); + +const req = { + params: { formSubmissionId: '1' }, + body: { code: Statuses.ASSIGNED }, + currentUser: {}, + headers: { referer: 'a' }, +}; + +describe('addStatus', () => { + it('should not call email service if no email specified', async () => { + service.read = jest.fn().mockReturnValue({ form: { id: '123' } }); + service.changeStatusState = jest.fn().mockReturnValue([1, 2, 3]); + emailService.statusAssigned = jest.fn().mockReturnValue(true); + await controller.addStatus(req, {}, jest.fn()); + + expect(service.changeStatusState).toHaveBeenCalledTimes(1); + expect(emailService.statusAssigned).toHaveBeenCalledTimes(0); + }); + + it('should call email service if an email specified', async () => { + req.body.assignmentNotificationEmail = 'a@a.com'; + req.body.revisionNotificationEmailContent = 'Email Content'; + service.read = jest.fn().mockReturnValue({ form: { id: '123' } }); + service.changeStatusState = jest.fn().mockReturnValue([1, 2, 3]); + emailService.statusAssigned = jest.fn().mockReturnValue(true); + await controller.addStatus(req, {}, jest.fn()); + + expect(service.changeStatusState).toHaveBeenCalledTimes(1); + expect(emailService.statusAssigned).toHaveBeenCalledTimes(1); + expect(emailService.statusAssigned).toHaveBeenCalledWith('123', 1, 'a@a.com', 'Email Content', 'a'); + }); + + it('should call statusRevising if email specified', async () => { + req.body.submissionUserEmail = 'a@a.com'; + req.body.revisionNotificationEmailContent = 'Email content'; + req.body.code = Statuses.REVISING; + service.read = jest.fn().mockReturnValue({ form: { id: '123' } }); + service.changeStatusState = jest.fn().mockReturnValue([1, 2, 3]); + emailService.statusRevising = jest.fn().mockReturnValue(true); + await controller.addStatus(req, {}, jest.fn()); + + expect(service.changeStatusState).toHaveBeenCalledTimes(1); + expect(emailService.statusRevising).toHaveBeenCalledTimes(1); + expect(emailService.statusRevising).toHaveBeenCalledWith('123', 1, 'a@a.com', 'Email content', 'a'); + }); + + it('should call statusCompleted if email specified', async () => { + req.body.submissionUserEmail = 'a@a.com'; + req.body.revisionNotificationEmailContent = 'Email Content'; + req.body.confirmCompleted = true; + req.body.code = Statuses.COMPLETED; + service.read = jest.fn().mockReturnValue({ form: { id: '123' } }); + service.changeStatusState = jest.fn().mockReturnValue([1, 2, 3]); + emailService.statusCompleted = jest.fn().mockReturnValue(true); + await controller.addStatus(req, {}, jest.fn()); + + expect(service.changeStatusState).toHaveBeenCalledTimes(1); + expect(emailService.statusCompleted).toHaveBeenCalledTimes(1); + expect(emailService.statusCompleted).toHaveBeenCalledWith('123', 1, 'a@a.com', 'Email Content', 'a'); + }); +}); + +describe('templateUploadAndRender', () => { + const content = 'SGVsbG8ge2Quc2ltcGxldGV4dGZpZWxkfSEK'; + const contentFileType = 'txt'; + const outputFileName = 'template_hello_world'; + const outputFileType = 'pdf'; + + const templateBody = { + body: { + options: { + reportName: outputFileName, + convertTo: outputFileType, + overwrite: true, + }, + template: { + content: content, + encodingType: 'base64', + fileType: contentFileType, + }, + }, + }; + + const templateReq = { ...req, ...templateBody }; + + const mockCdogsResponse = { + data: {}, + headers: {}, + status: 200, + }; + + const mockTemplateReadResponse = { + form: { + id: '123', + }, + submission: { + submission: { + submission: { + data: { + simpletextfield: 'fistName lastName', + submit: true, + }, + }, + }, + }, + }; + + mockCdogsResponse.headers['content-disposition'] = 'attachment; filename=template_hello_world.pdf'; + + it('should call cdogs service if a body specified', async () => { + service.read = jest.fn().mockReturnValue(mockTemplateReadResponse); + cdogsService.templateUploadAndRender = jest.fn().mockReturnValue(mockCdogsResponse); + await controller.templateUploadAndRender(templateReq, {}, jest.fn()); + + expect(cdogsService.templateUploadAndRender).toHaveBeenCalledTimes(1); + expect(cdogsService.templateUploadAndRender).toHaveBeenCalledWith(templateReq.body); + }); +}); + +describe('deleteMutipleSubmissions', () => { + const returnValue = { + submission: [ + { id: 'ac4ef441-43b1-414a-a0d4-1e2f67c2a745', formVersionId: '8d8e24ce-326f-4536-9100-a0844c27d5a0', confirmationId: 'AC4EF441', draft: false, deleted: true }, + { id: '0715b1ac-4069-4778-a868-b4f71fdea18d', formVersionId: '8d8e24ce-326f-4536-9100-a0844c27d5a0', confirmationId: '0715B1AC', draft: false, deleted: true }, + ], + version: [{ id: '8d8e24ce-326f-4536-9100-a0844c27d5a0', formId: 'a9ac13d3-340d-4b73-8920-8c8776b4eeca', version: 1, schema: {}, createdBy: 'testa@idir' }], + form: [{ id: 'a9ac13d3-340d-4b73-8920-8c8776b4eeca', name: 'FisheriesAA', description: '', active: true, labels: null }], + }; + + const req = { + params: {}, + body: { submissionIds: ['ac4ef441-43b1-414a-a0d4-1e2f67c2a745', '0715b1ac-4069-4778-a868-b4f71fdea18d'] }, + currentUser: {}, + headers: {}, + }; + it('should call deleteMutipleSubmissions service in controller', async () => { + service.deleteMutipleSubmissions = jest.fn().mockReturnValue(returnValue); + await controller.deleteMutipleSubmissions(req, {}, jest.fn()); + + expect(service.deleteMutipleSubmissions).toHaveBeenCalledTimes(1); + expect(service.deleteMutipleSubmissions).toHaveBeenCalledWith(req.body.submissionIds, req.currentUser); + }); +}); + +describe('restoreMutipleSubmissions', () => { + const returnValue = { + submission: [ + { id: 'ac4ef441-43b1-414a-a0d4-1e2f67c2a745', formVersionId: '8d8e24ce-326f-4536-9100-a0844c27d5a0', confirmationId: 'AC4EF441', draft: false, deleted: false }, + { id: '0715b1ac-4069-4778-a868-b4f71fdea18d', formVersionId: '8d8e24ce-326f-4536-9100-a0844c27d5a0', confirmationId: '0715B1AC', draft: false, deleted: false }, + ], + version: [{ id: '8d8e24ce-326f-4536-9100-a0844c27d5a0', formId: 'a9ac13d3-340d-4b73-8920-8c8776b4eeca', version: 1, schema: {}, createdBy: 'testa@idir' }], + form: [{ id: 'a9ac13d3-340d-4b73-8920-8c8776b4eeca', name: 'FisheriesAA', description: '', active: true, labels: null }], + }; + + const req = { + params: {}, + body: { submissionIds: ['ac4ef441-43b1-414a-a0d4-1e2f67c2a745', '0715b1ac-4069-4778-a868-b4f71fdea18d'] }, + currentUser: {}, + headers: {}, + }; + it('should call restoreMutipleSubmissions service in controller', async () => { + service.restoreMutipleSubmissions = jest.fn().mockReturnValue(returnValue); + await controller.restoreMutipleSubmissions(req, {}, jest.fn()); + + expect(service.restoreMutipleSubmissions).toHaveBeenCalledTimes(1); + expect(service.restoreMutipleSubmissions).toHaveBeenCalledWith(req.body.submissionIds, req.currentUser); + }); +}); diff --git a/frontend/app/tests/unit/forms/submission/service.spec.js b/frontend/app/tests/unit/forms/submission/service.spec.js new file mode 100644 index 0000000..3b1e020 --- /dev/null +++ b/frontend/app/tests/unit/forms/submission/service.spec.js @@ -0,0 +1,115 @@ +const { MockModel, MockTransaction } = require('../../../common/dbHelper'); +const { v4: uuidv4 } = require('uuid'); + +jest.mock('../../../../src/forms/common/models/tables/formSubmissionStatus', () => MockModel); +jest.mock('../../../../src/forms/common/models/tables/formSubmission', () => MockModel); + +const service = require('../../../../src/forms/submission/service'); + +beforeEach(() => { + MockModel.mockReset(); + MockTransaction.mockReset(); +}); + +afterEach(() => { + jest.restoreAllMocks(); +}); + +describe('read', () => { + it('should call the internal _fetchSubmissionData method', async () => { + service._fetchSubmissionData = jest.fn().mockReturnValue({ a: 'b' }); + const res = await service.read('abc'); + + expect(res).toEqual({ a: 'b' }); + expect(service._fetchSubmissionData).toHaveBeenCalledTimes(1); + expect(service._fetchSubmissionData).toHaveBeenCalledWith('abc'); + }); +}); + +describe('addNote', () => { + it('should call the internal _createNote method', async () => { + service._createNote = jest.fn().mockReturnValue({ a: 'b' }); + const res = await service.addNote('abc', { data: true }, { user: 'me' }); + + expect(res).toEqual({ a: 'b' }); + expect(service._createNote).toHaveBeenCalledTimes(1); + expect(service._createNote).toHaveBeenCalledWith('abc', { data: true }, { user: 'me' }); + }); +}); + +describe('createStatus', () => { + it('should perform appropriate db queries', async () => { + const trx = {}; + service.getStatus = jest.fn().mockReturnValue({ a: 'b' }); + const res = await service.createStatus('abc', { data: true }, { user: 'me' }, trx); + + expect(res).toEqual({ a: 'b' }); + expect(MockModel.startTransaction).toHaveBeenCalledTimes(0); + expect(MockModel.query).toHaveBeenCalledTimes(1); + expect(MockModel.query).toHaveBeenCalledWith(expect.anything()); + expect(MockModel.insert).toHaveBeenCalledTimes(1); + expect(MockModel.insert).toHaveBeenCalledWith(expect.anything()); + }); +}); + +describe('deleteMutipleSubmissions', () => { + it('should delete the selected submissions', async () => { + let submissionId1 = uuidv4(); + let submissionId2 = uuidv4(); + const submissionIds = [submissionId1, submissionId2]; + + const returnValue = { + submission: [ + { id: submissionId1, formVersionId: '8d8e24ce-326f-4536-9100-a0844c27d5a0', confirmationId: 'AC4EF441', draft: false, deleted: true }, + { id: submissionId2, formVersionId: '8d8e24ce-326f-4536-9100-a0844c27d5a0', confirmationId: '0715B1AC', draft: false, deleted: true }, + ], + version: [{ id: '8d8e24ce-326f-4536-9100-a0844c27d5a0', formId: 'a9ac13d3-340d-4b73-8920-8c8776b4eeca', version: 1, schema: {}, createdBy: 'testa@idir' }], + form: [{ id: 'a9ac13d3-340d-4b73-8920-8c8776b4eeca', name: 'FisheriesAA', description: '', active: true, labels: null }], + }; + + const currentUser = { usernameIdp: 'TEST@idir' }; + service.readSubmissionData = jest.fn().mockReturnValue(returnValue); + const spy = jest.spyOn(service, 'readSubmissionData'); + const res = await service.deleteMutipleSubmissions(submissionIds, currentUser); + expect(MockModel.startTransaction).toHaveBeenCalledTimes(1); + expect(MockModel.query).toHaveBeenCalledTimes(1); + expect(MockModel.query).toHaveBeenCalledWith(expect.anything()); + expect(MockModel.patch).toHaveBeenCalledTimes(1); + expect(MockModel.patch).toHaveBeenCalledWith({ deleted: true, updatedBy: currentUser.usernameIdp }); + expect(MockModel.whereIn).toHaveBeenCalledTimes(1); + expect(MockModel.whereIn).toHaveBeenCalledWith('id', submissionIds); + expect(spy).toHaveBeenCalledWith(submissionIds); + expect(res).toEqual(returnValue); + }); +}); + +describe('restoreMutipleSubmissions', () => { + it('should delete the selected submissions', async () => { + let submissionId1 = uuidv4(); + let submissionId2 = uuidv4(); + const submissionIds = [submissionId1, submissionId2]; + + const returnValue = { + submission: [ + { id: submissionId1, formVersionId: '8d8e24ce-326f-4536-9100-a0844c27d5a0', confirmationId: 'AC4EF441', draft: false, deleted: false }, + { id: submissionId2, formVersionId: '8d8e24ce-326f-4536-9100-a0844c27d5a0', confirmationId: '0715B1AC', draft: false, deleted: false }, + ], + version: [{ id: '8d8e24ce-326f-4536-9100-a0844c27d5a0', formId: 'a9ac13d3-340d-4b73-8920-8c8776b4eeca', version: 1, schema: {}, createdBy: 'testa@idir' }], + form: [{ id: 'a9ac13d3-340d-4b73-8920-8c8776b4eeca', name: 'FisheriesAA', description: '', active: true, labels: null }], + }; + + const currentUser = { usernameIdp: 'TEST@idir' }; + service.readSubmissionData = jest.fn().mockReturnValue(returnValue); + const spy = jest.spyOn(service, 'readSubmissionData'); + const res = await service.restoreMutipleSubmissions(submissionIds, currentUser); + expect(MockModel.startTransaction).toHaveBeenCalledTimes(1); + expect(MockModel.query).toHaveBeenCalledTimes(1); + expect(MockModel.query).toHaveBeenCalledWith(expect.anything()); + expect(MockModel.patch).toHaveBeenCalledTimes(1); + expect(MockModel.patch).toHaveBeenCalledWith({ deleted: false, updatedBy: currentUser.usernameIdp }); + expect(MockModel.whereIn).toHaveBeenCalledTimes(1); + expect(MockModel.whereIn).toHaveBeenCalledWith('id', submissionIds); + expect(spy).toHaveBeenCalledWith(submissionIds); + expect(res).toEqual(returnValue); + }); +}); diff --git a/frontend/app/tests/unit/forms/user/service.spec.js b/frontend/app/tests/unit/forms/user/service.spec.js new file mode 100644 index 0000000..828d055 --- /dev/null +++ b/frontend/app/tests/unit/forms/user/service.spec.js @@ -0,0 +1,236 @@ +const { MockModel, MockTransaction } = require('../../../common/dbHelper'); + +jest.mock('../../../../src/forms/common/models/tables/user', () => MockModel); +jest.mock('../../../../src/forms/common/models/tables/userFormPreferences', () => MockModel); + +const service = require('../../../../src/forms/user/service'); + +const formId = '4d33f4cb-0b72-4c3d-9e41-f2651805fee1'; +const userId = 'cc8c64b7-a457-456e-ade0-09ff7ee75a2b'; +const preferences = { columns: [] }; + +beforeEach(() => { + MockModel.mockReset(); + MockTransaction.mockReset(); +}); + +describe('list', () => { + it('should query user table by id', async () => { + const params = { + email: 'email', + firstName: 'firstName', + fullName: 'fullName', + idpUserId: 'idpUserId', + lastName: 'lastName', + search: 'search', + username: 'username', + idpCode: 'idp', + }; + + await service.list(params); + + expect(MockModel.query).toHaveBeenCalledTimes(1); + expect(MockModel.query).toHaveBeenCalledWith(); + expect(MockModel.modify).toHaveBeenCalledTimes(9); + expect(MockModel.modify).toHaveBeenCalledWith('filterIdpUserId', params.idpUserId); + expect(MockModel.modify).toHaveBeenCalledWith('filterIdpCode', params.idpCode); + expect(MockModel.modify).toHaveBeenCalledWith('filterUsername', params.username, false); + expect(MockModel.modify).toHaveBeenCalledWith('filterFullName', params.fullName); + expect(MockModel.modify).toHaveBeenCalledWith('filterFirstName', params.firstName); + expect(MockModel.modify).toHaveBeenCalledWith('filterLastName', params.lastName); + expect(MockModel.modify).toHaveBeenCalledWith('filterEmail', params.email, false); + expect(MockModel.modify).toHaveBeenCalledWith('filterSearch', params.search); + expect(MockModel.modify).toHaveBeenCalledWith('orderLastFirstAscending'); + }); +}); + +describe('read', () => { + it('should query user table by id', async () => { + await service.read(userId); + + expect(MockModel.query).toHaveBeenCalledTimes(1); + expect(MockModel.query).toHaveBeenCalledWith(); + expect(MockModel.findById).toHaveBeenCalledTimes(1); + expect(MockModel.findById).toHaveBeenCalledWith(userId); + expect(MockModel.throwIfNotFound).toHaveBeenCalledTimes(1); + expect(MockModel.throwIfNotFound).toHaveBeenCalledWith(); + }); +}); + +describe('deleteUserPreferences', () => { + it('should delete user form preference table by user id', async () => { + await service.deleteUserPreferences({ id: userId }); + + expect(MockModel.query).toHaveBeenCalledTimes(1); + expect(MockModel.query).toHaveBeenCalledWith(); + expect(MockModel.delete).toHaveBeenCalledTimes(1); + expect(MockModel.delete).toHaveBeenCalledWith(); + expect(MockModel.where).toHaveBeenCalledTimes(1); + expect(MockModel.where).toHaveBeenCalledWith('userId', userId); + expect(MockModel.throwIfNotFound).toHaveBeenCalledTimes(1); + expect(MockModel.throwIfNotFound).toHaveBeenCalledWith(); + }); +}); + +describe('readUserPreferences', () => { + it('should query user form preference table by user id', async () => { + await service.readUserPreferences({ id: userId }); + + expect(MockModel.query).toHaveBeenCalledTimes(1); + expect(MockModel.query).toHaveBeenCalledWith(); + expect(MockModel.where).toHaveBeenCalledTimes(1); + expect(MockModel.where).toHaveBeenCalledWith('userId', userId); + }); +}); + +describe('deleteUserFormPreferences', () => { + it('should delete user form preference table by user id', async () => { + await service.deleteUserFormPreferences({ id: userId }, formId); + + expect(MockModel.query).toHaveBeenCalledTimes(1); + expect(MockModel.query).toHaveBeenCalledWith(); + expect(MockModel.deleteById).toHaveBeenCalledTimes(1); + expect(MockModel.deleteById).toHaveBeenCalledWith([userId, formId]); + expect(MockModel.throwIfNotFound).toHaveBeenCalledTimes(1); + expect(MockModel.throwIfNotFound).toHaveBeenCalledWith(); + }); +}); + +describe('readUserFormPreferences', () => { + it('should query user form preference table by user id', async () => { + await service.readUserFormPreferences({ id: userId }, formId); + + expect(MockModel.query).toHaveBeenCalledTimes(1); + expect(MockModel.query).toHaveBeenCalledWith(); + expect(MockModel.findById).toHaveBeenCalledTimes(1); + expect(MockModel.findById).toHaveBeenCalledWith([userId, formId]); + expect(MockModel.first).toHaveBeenCalledTimes(1); + expect(MockModel.first).toHaveBeenCalledWith(); + }); +}); + +describe('updateUserPreferences', () => { + const body = { + forms: [ + { + formId: formId, + preferences: preferences, + }, + ], + }; + const readUserPreferencesSpy = jest.spyOn(service, 'readUserPreferences'); + const readUserFormPreferencesSpy = jest.spyOn(service, 'readUserFormPreferences'); + + beforeEach(() => { + readUserPreferencesSpy.mockReset(); + readUserFormPreferencesSpy.mockReset(); + }); + + it('should throw when invalid options are provided', () => { + MockModel.mockResolvedValue(undefined); + const fn = (currentUser, body) => service.updateUserPreferences(currentUser, body); + + expect(fn({ id: userId }, undefined)).rejects.toThrow(); + expect(fn({ id: userId }, {})).rejects.toThrow(); + expect(fn({ id: userId }, { forms: {} })).rejects.toThrow(); + expect(MockModel.startTransaction).toHaveBeenCalledTimes(0); + expect(MockModel.query).toHaveBeenCalledTimes(0); + }); + + it('should insert preferences', async () => { + MockModel.mockResolvedValue(undefined); + readUserPreferencesSpy.mockResolvedValue(undefined); + readUserFormPreferencesSpy.mockResolvedValue(undefined); + + await service.updateUserPreferences({ id: userId }, body); + + expect(MockModel.startTransaction).toHaveBeenCalledTimes(1); + expect(MockModel.query).toHaveBeenCalledTimes(1); + expect(MockModel.query).toHaveBeenCalledWith(expect.anything()); + expect(MockModel.insert).toHaveBeenCalledTimes(1); + expect(MockModel.insert).toHaveBeenCalledWith({ + userId: userId, + formId: formId, + preferences: preferences, + createdBy: undefined, + }); + expect(MockTransaction.commit).toHaveBeenCalledTimes(1); + }); + + it('should update preferences', async () => { + MockModel.mockResolvedValue({}); + readUserPreferencesSpy.mockResolvedValue({}); + readUserFormPreferencesSpy.mockResolvedValue({}); + + await service.updateUserPreferences({ id: userId }, body); + + expect(MockModel.startTransaction).toHaveBeenCalledTimes(1); + expect(MockModel.query).toHaveBeenCalledTimes(1); + expect(MockModel.query).toHaveBeenCalledWith(expect.anything()); + expect(MockModel.patchAndFetchById).toHaveBeenCalledTimes(1); + expect(MockModel.patchAndFetchById).toHaveBeenCalledWith([userId, formId], { + preferences: preferences, + updatedBy: undefined, + }); + expect(MockTransaction.commit).toHaveBeenCalledTimes(1); + }); +}); + +describe('updateUserFormPreferences', () => { + const readUserFormPreferencesSpy = jest.spyOn(service, 'readUserFormPreferences'); + + beforeEach(() => { + readUserFormPreferencesSpy.mockReset(); + }); + + it('should insert preferences', async () => { + MockModel.mockReset(); + MockTransaction.mockReset(); + + MockModel.mockResolvedValue(undefined); + readUserFormPreferencesSpy.mockResolvedValue(undefined); + await service.updateUserFormPreferences({ id: userId }, formId, preferences); + + expect(MockModel.startTransaction).toHaveBeenCalledTimes(1); + expect(MockModel.query).toHaveBeenCalledTimes(1); + expect(MockModel.query).toHaveBeenCalledWith(expect.anything()); + expect(MockModel.insertAndFetch).toHaveBeenCalledTimes(1); + expect(MockModel.insertAndFetch).toHaveBeenCalledWith({ + userId: userId, + formId: formId, + preferences: preferences, + createdBy: undefined, + }); + expect(MockTransaction.commit).toHaveBeenCalledTimes(1); + }); + + it('should update preferences', async () => { + MockModel.mockResolvedValue({}); + readUserFormPreferencesSpy.mockResolvedValue({}); + + await service.updateUserFormPreferences({ id: userId }, formId, preferences); + + expect(MockModel.startTransaction).toHaveBeenCalledTimes(1); + expect(MockModel.query).toHaveBeenCalledTimes(1); + expect(MockModel.query).toHaveBeenCalledWith(expect.anything()); + expect(MockModel.patchAndFetchById).toHaveBeenCalledTimes(1); + expect(MockModel.patchAndFetchById).toHaveBeenCalledWith([userId, formId], { + preferences: preferences, + updatedBy: undefined, + }); + expect(MockTransaction.commit).toHaveBeenCalledTimes(1); + }); + + it('should handle errors gracefully', async () => { + MockModel.mockResolvedValue(undefined); + readUserFormPreferencesSpy.mockImplementation(() => { + throw new Error(); + }); + + const fn = () => service.updateUserFormPreferences({ id: userId }, formId, preferences); + + await expect(fn()).rejects.toThrow(); + expect(MockModel.startTransaction).toHaveBeenCalledTimes(0); + expect(MockModel.query).toHaveBeenCalledTimes(0); + }); +}); diff --git a/frontend/app/tests/unit/routes/v1.spec.js b/frontend/app/tests/unit/routes/v1.spec.js new file mode 100644 index 0000000..20c5f99 --- /dev/null +++ b/frontend/app/tests/unit/routes/v1.spec.js @@ -0,0 +1,80 @@ +const request = require('supertest'); + +const { expressHelper } = require('../../common/helper'); +const router = require('../../../src/routes/v1'); + +// Simple Express Server +const basePath = '/api/v1'; +const app = expressHelper(basePath, router); + +describe(`${basePath}`, () => { + const path = `${basePath}`; + + describe('GET', () => { + it('should return all available endpoints', async () => { + const response = await request(app).get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + expect(Array.isArray(response.body.endpoints)).toBeTruthy(); + expect(response.body.endpoints).toHaveLength(11); + expect(response.body.endpoints).toContain('/docs'); + expect(response.body.endpoints).toContain('/files'); + expect(response.body.endpoints).toContain('/forms'); + expect(response.body.endpoints).toContain('/permissions'); + expect(response.body.endpoints).toContain('/public'); + expect(response.body.endpoints).toContain('/rbac'); + expect(response.body.endpoints).toContain('/roles'); + expect(response.body.endpoints).toContain('/submissions'); + expect(response.body.endpoints).toContain('/users'); + expect(response.body.endpoints).toContain('/utils'); + }); + }); +}); + +describe(`${basePath}/api-spec.json`, () => { + const path = `${basePath}/api-spec.json`; + + describe('GET', () => { + it('should return the OpenAPI spec in json', async () => { + const response = await request(app).get(path); + + expect(response.statusCode).toBe(200); + expect(response.headers['content-type']).toBeTruthy(); + expect(response.headers['content-type']).toMatch('application/json; charset=utf-8'); + expect(response.body).toBeTruthy(); + expect(response.body.openapi).toMatch('3.0.3'); + expect(response.body.info.title).toMatch('Common Hosted Form Service (CHEFS)'); + }); + }); +}); + +describe(`${basePath}/api-spec.yaml`, () => { + const path = `${basePath}/api-spec.yaml`; + + describe('GET', () => { + it('should return the OpenAPI spec in yaml', async () => { + const response = await request(app).get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + expect(response.headers['content-type']).toBeTruthy(); + expect(response.headers['content-type']).toMatch('application/yaml; charset=utf-8'); + expect(response.text).toContain('openapi: 3.0.3'); + expect(response.text).toContain('title: Common Hosted Form Service (CHEFS)'); + }); + }); +}); + +describe(`${basePath}/docs`, () => { + const path = `${basePath}/docs`; + + describe('GET', () => { + it('should return a redoc html page', async () => { + const response = await request(app).get(path); + + expect(response.statusCode).toBe(200); + expect(response.text).toContain('Common Hosted Form Service - Documentation '); + }); + }); +}); diff --git a/frontend/app/tests/unit/routes/v1/admin.spec.js b/frontend/app/tests/unit/routes/v1/admin.spec.js new file mode 100644 index 0000000..7bcfd20 --- /dev/null +++ b/frontend/app/tests/unit/routes/v1/admin.spec.js @@ -0,0 +1,633 @@ +const request = require('supertest'); +const Problem = require('api-problem'); + +const { expressHelper } = require('../../../common/helper'); + +// +// mock middleware +// +const keycloak = require('../../../../src/components/keycloak'); + +// +// test assumes that caller has appropriate token, we are not testing middleware here... +// +keycloak.protect = jest.fn(() => { + return jest.fn((_req, _res, next) => { + next(); + }); +}); + +const userAccess = require('../../../../src/forms/auth/middleware/userAccess'); +userAccess.currentUser = jest.fn((_req, _res, next) => { + next(); +}); + +// +// we will mock the underlying data service calls... +// +const service = require('../../../../src/forms/admin/service'); + +const formService = require('../../../../src/forms/form/service'); +const rbacService = require('../../../../src/forms/rbac/service'); +const userService = require('../../../../src/forms/user/service'); + +// +// mocks are in place, create the router +// +const router = require('../../../../src/forms/admin/routes'); + +// Simple Express Server +const basePath = '/admin'; +const app = expressHelper(basePath, router); +const appRequest = request(app); + +afterEach(() => { + jest.clearAllMocks(); +}); + +describe(`${basePath}/formcomponents/proactivehelp/imageUrl/:componentId`, () => { + const path = `${basePath}/formcomponents/proactivehelp/imageUrl/:componentId`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.getFCProactiveHelpImageUrl = jest.fn().mockReturnValue({}); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.getFCProactiveHelpImageUrl = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.getFCProactiveHelpImageUrl = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/formcomponents/proactivehelp/list`, () => { + const path = `${basePath}/formcomponents/proactivehelp/list`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.listFormComponentsProactiveHelp = jest.fn().mockReturnValue({}); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.listFormComponentsProactiveHelp = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.listFormComponentsProactiveHelp = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/formcomponents/proactivehelp/object`, () => { + const path = `${basePath}/formcomponents/proactivehelp/object`; + + describe('POST', () => { + it('should return 200', async () => { + const formComponentsHelpInfo = { + componentname: 'Content', + description: 'gughuhiuhuih', + externallink: 'https://helplink.com', + groupname: 'Basic Layout', + image: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAB3g', + status: false, + version: 1, + }; + + // mock a success return value... + service.createFormComponentsProactiveHelp = jest.fn().mockReturnValue(formComponentsHelpInfo); + + const response = await appRequest.post(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.createFormComponentsProactiveHelp = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.post(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.createFormComponentsProactiveHelp = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.post(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/formcomponents/proactivehelp/:publishStatus/:componentId`, () => { + const path = `${basePath}/formcomponents/proactivehelp/:publishStatus/:componentId`; + + describe('PUT', () => { + it('should return 200', async () => { + const formComponentsHelpInfo = { + componentname: 'Content', + externallink: 'https://helplink.com', + image: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAB3g', + version: 1, + groupname: 'Basic Layout', + description: 'gughuhiuhuih', + status: false, + }; + + // mock a success return value... + service.updateFormComponentsProactiveHelp = jest.fn().mockReturnValue(formComponentsHelpInfo); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.updateFormComponentsProactiveHelp = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.updateFormComponentsProactiveHelp = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/forms`, () => { + const path = `${basePath}/forms`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.listForms = jest.fn().mockReturnValue([]); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.listForms = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.listForms = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/forms/:formId`, () => { + const path = `${basePath}/forms/:formId`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.readForm = jest.fn().mockReturnValue([]); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.readForm = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.readForm = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/forms/:formId/addUser`, () => { + const path = `${basePath}/forms/:formId/addUser`; + + describe('PUT', () => { + it('should return 200', async () => { + // mock a success return value... + rbacService.setFormUsers = jest.fn().mockReturnValue([]); + + const response = await appRequest.put(path).query({ userId: '123' }).send({ userId: '123' }); + + expect(rbacService.setFormUsers).toHaveBeenCalledWith(':formId', '123', { userId: '123' }, undefined); + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should 422 if no userId is supplied', async () => { + // mock an authentication/permission issue... + rbacService.setFormUsers = jest.fn().mockReturnValue([]); + + const response = await appRequest.put(path).query({ val: 'Test1' }).send({ otherBody: '123' }); + + expect(response.statusCode).toBe(422); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + rbacService.setFormUsers = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.put(path).query({ userId: '123' }).send({ userId: '123' }); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + rbacService.setFormUsers = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.put(path).query({ userId: '123' }).send({ userId: '123' }); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/forms/:formId/apiKey`, () => { + const path = `${basePath}/forms/:formId/apiKey`; + + describe('DELETE', () => { + it('should return 204', async () => { + // mock a success return value... + formService.deleteApiKey = jest.fn().mockReturnValue({}); + + const response = await appRequest.delete(path); + + expect(response.statusCode).toBe(204); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + formService.deleteApiKey = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.delete(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + formService.deleteApiKey = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.delete(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + formService.readApiKey = jest.fn().mockReturnValue({}); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + formService.readApiKey = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + formService.readApiKey = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/forms/:formId/formUsers`, () => { + const path = `${basePath}/forms/:formId/formUsers`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.getFormUserRoles = jest.fn().mockReturnValue([]); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.getFormUserRoles = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.getFormUserRoles = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/forms/:formId/restore`, () => { + const path = `${basePath}/forms/:formId/restore`; + + describe('PUT', () => { + it('should return 200', async () => { + // mock a success return value... + service.restoreForm = jest.fn().mockReturnValue([]); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.restoreForm = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.restoreForm = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/forms/:formId/versions/:formVersionId`, () => { + const path = `${basePath}/forms/:formId/versions/:formVersionId`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.readVersion = jest.fn().mockReturnValue([]); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.readVersion = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.readVersion = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/users`, () => { + const path = `${basePath}/users`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.getUsers = jest.fn().mockReturnValue([]); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.getUsers = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.getUsers = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/users/:userId`, () => { + const path = `${basePath}/users/:userId`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + userService.readSafe = jest.fn().mockReturnValue([]); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + userService.readSafe = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + userService.readSafe = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); diff --git a/frontend/app/tests/unit/routes/v1/form.spec.js b/frontend/app/tests/unit/routes/v1/form.spec.js new file mode 100644 index 0000000..f8a5a94 --- /dev/null +++ b/frontend/app/tests/unit/routes/v1/form.spec.js @@ -0,0 +1,1487 @@ +const request = require('supertest'); +const Problem = require('api-problem'); + +const { expressHelper } = require('../../../common/helper'); + +// +// mock middleware +// +const keycloak = require('../../../../src/components/keycloak'); + +// +// test assumes that caller has appropriate token, we are not testing middleware here... +// +keycloak.protect = jest.fn(() => { + return jest.fn((_req, _res, next) => { + next(); + }); +}); + +const userAccess = require('../../../../src/forms/auth/middleware/userAccess'); +userAccess.currentUser = jest.fn((_req, _res, next) => { + next(); +}); +userAccess.hasFormPermissions = jest.fn(() => { + return jest.fn((_req, _res, next) => { + next(); + }); +}); + +// +// we will mock the underlying data service calls... +// +const service = require('../../../../src/forms/form/service'); + +const emailService = require('../../../../src/forms/email/emailService'); +const exportService = require('../../../../src/forms/form/exportService'); +const fileService = require('../../../../src/forms/file/service'); + +// +// mocks are in place, create the router +// +const router = require('../../../../src/forms/form/routes'); + +// Simple Express Server +const basePath = '/form'; +const app = expressHelper(basePath, router); +const appRequest = request(app); + +// +// We don't want static code analysis complaining about hard-coded tokens, even +// if they're fake. Mock a token with a non-existing ("undefined") environment +// variable. +// +const bearerAuth = `Bearer: ${process.env.DOES_NOT_EXIST}`; + +afterEach(() => { + jest.clearAllMocks(); +}); + +describe(`${basePath}`, () => { + const path = `${basePath}`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.listForms = jest.fn().mockReturnValue([]); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.listForms = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.listForms = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); + + describe('POST', () => { + it('should return 201', async () => { + // mock a success return value... + service.createForm = jest.fn().mockReturnValue({}); + + const response = await appRequest.post(path); + + expect(response.statusCode).toBe(201); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.createForm = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.post(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.createForm = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.post(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/formcomponents/proactivehelp/imageUrl/:componentId`, () => { + const path = `${basePath}/formcomponents/proactivehelp/imageUrl/:componentId`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.getFCProactiveHelpImageUrl = jest.fn().mockReturnValue([{}]); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.getFCProactiveHelpImageUrl = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.getFCProactiveHelpImageUrl = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/formcomponents/proactivehelp/list`, () => { + const path = `${basePath}/formcomponents/proactivehelp/list`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.listFormComponentsProactiveHelp = jest.fn().mockReturnValue([{}]); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.listFormComponentsProactiveHelp = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.listFormComponentsProactiveHelp = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/:formId`, () => { + const path = `${basePath}/:formId`; + + describe('DELETE', () => { + it('should return 204', async () => { + // mock a success return value... + service.deleteForm = jest.fn().mockReturnValue([]); + + const response = await appRequest.delete(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(204); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.deleteForm = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.delete(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.deleteForm = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.delete(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.readForm = jest.fn().mockReturnValue([]); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.readForm = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.readForm = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); + + describe('PUT', () => { + it('should return 200', async () => { + // mock a success return value... + service.updateForm = jest.fn().mockReturnValue([]); + + const response = await appRequest.put(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.updateForm = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.put(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.updateForm = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.put(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/:formId/apiKey`, () => { + const path = `${basePath}/:formId/apiKey`; + + describe('DELETE', () => { + it('should return 204', async () => { + // mock a success return value... + service.deleteApiKey = jest.fn().mockReturnValue([]); + + const response = await appRequest.delete(path); + + expect(response.statusCode).toBe(204); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.deleteApiKey = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.delete(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.deleteApiKey = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.delete(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.readApiKey = jest.fn().mockReturnValue([]); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.readApiKey = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.readApiKey = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); + + describe('PUT', () => { + it('should return 200', async () => { + // mock a success return value... + service.createOrReplaceApiKey = jest.fn().mockReturnValue([]); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.createOrReplaceApiKey = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.createOrReplaceApiKey = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/:formId/csvexport/fields`, () => { + const path = `${basePath}/:formId/csvexport/fields`; + + describe('GET', () => { + it('should return 200', async () => { + const formFields = [ + 'form.confirmationId', + 'form.formName', + 'form.version', + 'form.createdAt', + 'form.fullName', + 'form.username', + 'form.email', + 'fishermansName', + 'email', + 'forWhichBcLakeRegionAreYouCompletingTheseQuestions', + 'didYouFishAnyBcLakesThisYear', + 'oneRowPerLake', + 'oneRowPerLake.lakeName', + 'oneRowPerLake.closestTown', + 'oneRowPerLake.numberOfDays', + 'oneRowPerLake.dataGrid', + 'oneRowPerLake.dataGrid.fishType', + 'oneRowPerLake.dataGrid.numberCaught', + 'oneRowPerLake.dataGrid.numberKept', + ]; + + // mock a success return value... + exportService.fieldsForCSVExport = jest.fn().mockReturnValue(formFields); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + exportService.fieldsForCSVExport = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + exportService.fieldsForCSVExport = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/:formId/drafts`, () => { + const path = `${basePath}/:formId/drafts`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.listDrafts = jest.fn().mockReturnValue([]); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.listDrafts = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.listDrafts = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); + + describe('POST', () => { + it('should return 201', async () => { + // mock a success return value... + service.createDraft = jest.fn().mockReturnValue({}); + + const response = await appRequest.post(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(201); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.createDraft = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.post(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.createDraft = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.post(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/:formId/drafts/:formVersionDraftId`, () => { + const path = `${basePath}/:formId/drafts/:formVersionDraftId`; + + describe('DELETE', () => { + it('should return 204', async () => { + // mock a success return value... + service.deleteDraft = jest.fn().mockReturnValue([]); + + const response = await appRequest.delete(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(204); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.deleteDraft = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.delete(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.deleteDraft = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.delete(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.readDraft = jest.fn().mockReturnValue([]); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.readDraft = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.readDraft = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); + + describe('PUT', () => { + it('should return 200', async () => { + // mock a success return value... + service.updateDraft = jest.fn().mockReturnValue([]); + + const response = await appRequest.put(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.updateDraft = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.put(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.updateDraft = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.put(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/:formId/drafts/:formVersionDraftId/publish`, () => { + const path = `${basePath}/:formId/drafts/:formVersionDraftId/publish`; + + describe('POST', () => { + it('should return 200', async () => { + // mock a success return value... + service.publishDraft = jest.fn().mockReturnValue({}); + + const response = await appRequest.post(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.publishDraft = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.post(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.publishDraft = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.post(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/:formId/emailTemplate`, () => { + const path = `${basePath}/:formId/emailTemplate`; + + describe('PUT', () => { + it('should return 200', async () => { + // mock a success return value... + service.createOrUpdateEmailTemplate = jest.fn().mockReturnValue([{}]); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.createOrUpdateEmailTemplate = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.createOrUpdateEmailTemplate = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/:formId/emailTemplates`, () => { + const path = `${basePath}/:formId/emailTemplates`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.readEmailTemplates = jest.fn().mockReturnValue([{}]); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.readEmailTemplates = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.readEmailTemplates = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/:formId/export`, () => { + const path = `${basePath}/:formId/export`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + exportService.export = jest.fn().mockReturnValue({ + data: {}, + headers: { + 'content-disposition': 'attachment; filename="not-real.csv"', + 'content-type': 'text/csv', + }, + }); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + exportService.export = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + exportService.export = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/:formId/export/fields`, () => { + const path = `${basePath}/:formId/export/fields`; + + describe('POST', () => { + it('should return 200', async () => { + // mock a success return value... + exportService.export = jest.fn().mockReturnValue({ + data: {}, + headers: { + 'content-disposition': 'attachment; filename="not-real.csv"', + 'content-type': 'text/csv', + }, + }); + + const response = await appRequest.post(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + exportService.export = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.post(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + exportService.export = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.post(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/:formId/options`, () => { + const path = `${basePath}/:formId/options`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.readFormOptions = jest.fn().mockReturnValue([]); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.readFormOptions = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.readFormOptions = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/:formId/statusCodes`, () => { + const path = `${basePath}/:formId/statusCodes`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.getStatusCodes = jest.fn().mockReturnValue([]); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.getStatusCodes = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.getStatusCodes = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/:formId/submissions`, () => { + const path = `${basePath}/:formId/submissions`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.listFormSubmissions = jest.fn().mockReturnValue([]); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.listFormSubmissions = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.listFormSubmissions = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/:formId/subscriptions`, () => { + const path = `${basePath}/:formId/subscriptions`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.readFormSubscriptionDetails = jest.fn().mockReturnValue([{}]); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.readFormSubscriptionDetails = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.readFormSubscriptionDetails = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); + + describe('PUT', () => { + it('should return 200', async () => { + // mock a success return value... + service.createOrUpdateSubscriptionDetails = jest.fn().mockReturnValue([{}]); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.createOrUpdateSubscriptionDetails = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.createOrUpdateSubscriptionDetails = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/:formId/version`, () => { + const path = `${basePath}/:formId/version`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.readPublishedForm = jest.fn().mockReturnValue([]); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.readPublishedForm = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.readPublishedForm = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/:formId/versions/:formVersionId`, () => { + const path = `${basePath}/:formId/versions/:formVersionId`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.readVersion = jest.fn().mockReturnValue([]); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.readVersion = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.readVersion = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/:formId/versions/:formVersionId/fields`, () => { + const path = `${basePath}/:formId/versions/:formVersionId/fields`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.readVersionFields = jest.fn().mockReturnValue([]); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.readVersionFields = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.readVersionFields = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/:formId/versions/:formVersionId/multiSubmission`, () => { + const path = `${basePath}/:formId/versions/:formVersionId/multiSubmission`; + + describe('POST', () => { + it('should return 201', async () => { + // mock a success return value... + service.createMultiSubmission = jest.fn().mockReturnValue([]); + + const response = await appRequest.post(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(201); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.createMultiSubmission = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.post(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.createMultiSubmission = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.post(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/:formId/versions/:formVersionId/publish`, () => { + const path = `${basePath}/:formId/versions/:formVersionId/publish`; + + describe('POST', () => { + it('should return 200', async () => { + // mock a success return value... + service.publishVersion = jest.fn().mockReturnValue({}); + + const response = await appRequest.post(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.publishVersion = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.post(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.publishVersion = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.post(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/:formId/versions/:formVersionId/submissions`, () => { + const path = `${basePath}/:formId/versions/:formVersionId/submissions`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.listSubmissions = jest.fn().mockReturnValue([]); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.listSubmissions = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.listSubmissions = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); + + describe('POST', () => { + const createSubmissionResult = { id: 'id' }; + + it('should return 201', async () => { + // mock a success return value... + service.createSubmission = jest.fn().mockReturnValue(createSubmissionResult); + emailService.submissionReceived = jest.fn(() => Promise.resolve({})); + fileService.moveSubmissionFiles = jest.fn(() => Promise.resolve({})); + + const response = await appRequest.post(path).set('Authorization', bearerAuth); + + expect(emailService.submissionReceived).toHaveBeenCalledTimes(1); + expect(fileService.moveSubmissionFiles).toHaveBeenCalledTimes(1); + expect(response.statusCode).toBe(201); + expect(response.body).toBeTruthy(); + }); + + it('should not call email service if it is a draft', async () => { + // mock a success return value... + service.createSubmission = jest.fn().mockReturnValue(createSubmissionResult); + emailService.submissionReceived = jest.fn(() => Promise.resolve({})); + fileService.moveSubmissionFiles = jest.fn(() => Promise.resolve({})); + + const response = await appRequest.post(path).send({ draft: true }).set('Authorization', bearerAuth); + + expect(emailService.submissionReceived).toHaveBeenCalledTimes(0); + expect(fileService.moveSubmissionFiles).toHaveBeenCalledTimes(1); + expect(response.statusCode).toBe(201); + expect(response.body).toBeTruthy(); + }); + + it('should call email service if draft is provided and false', async () => { + // mock a success return value... + service.createSubmission = jest.fn().mockReturnValue(createSubmissionResult); + emailService.submissionReceived = jest.fn(() => Promise.resolve({})); + fileService.moveSubmissionFiles = jest.fn(() => Promise.resolve({})); + + const response = await appRequest.post(path).send({ draft: false }).set('Authorization', bearerAuth); + + expect(emailService.submissionReceived).toHaveBeenCalledTimes(1); + expect(fileService.moveSubmissionFiles).toHaveBeenCalledTimes(1); + expect(response.statusCode).toBe(201); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.createSubmission = jest.fn(() => { + throw new Problem(401); + }); + emailService.submissionReceived = jest.fn().mockReturnValue(true); + fileService.moveSubmissionFiles = jest.fn(() => Promise.resolve({})); + + const response = await appRequest.post(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.createSubmission = jest.fn(() => { + throw new Error(); + }); + emailService.submissionReceived = jest.fn().mockReturnValue(true); + fileService.moveSubmissionFiles = jest.fn(() => Promise.resolve({})); + + const response = await appRequest.post(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + + it('should handle error from email service gracefully', async () => { + service.createSubmission = jest.fn().mockReturnValue(createSubmissionResult); + emailService.submissionReceived = jest.fn(() => Promise.reject({})); + fileService.moveSubmissionFiles = jest.fn(() => Promise.resolve({})); + + const response = await appRequest.post(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(201); + expect(response.body).toBeTruthy(); + }); + + it('should handle error from file service gracefully', async () => { + service.createSubmission = jest.fn().mockReturnValue(createSubmissionResult); + emailService.submissionReceived = jest.fn(() => Promise.resolve({})); + fileService.moveSubmissionFiles = jest.fn(() => Promise.reject({})); + + const response = await appRequest.post(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(201); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/:formId/versions/:formVersionId/submissions/discover`, () => { + const path = `${basePath}/:formId/versions/:formVersionId/submissions/discover`; + + describe('GET', () => { + it('should return 200 with comma separated fields', async () => { + // mock a success return value... + service.listSubmissionFields = jest.fn().mockReturnValue([]); + service.readVersionFields = jest.fn().mockReturnValue([]); + + const response = await appRequest.get(path).set('Authorization', bearerAuth).query({ fields: 'foo,bar' }); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should return 200 with discrete fields', async () => { + // mock a success return value... + service.listSubmissionFields = jest.fn().mockReturnValue([]); + service.readVersionFields = jest.fn().mockReturnValue([]); + + const response = await appRequest + .get(path) + .set('Authorization', bearerAuth) + .query({ fields: ['foo', 'bar'] }); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.listSubmissionFields = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.listSubmissionFields = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); diff --git a/frontend/app/tests/unit/routes/v1/permission.spec.js b/frontend/app/tests/unit/routes/v1/permission.spec.js new file mode 100644 index 0000000..b950557 --- /dev/null +++ b/frontend/app/tests/unit/routes/v1/permission.spec.js @@ -0,0 +1,194 @@ +const request = require('supertest'); +const Problem = require('api-problem'); + +const { expressHelper } = require('../../../common/helper'); + +// +// mock middleware +// +const keycloak = require('../../../../src/components/keycloak'); + +// +// test assumes that caller has appropriate token, we are not testing middleware here... +// +keycloak.protect = jest.fn(() => { + return jest.fn((_req, _res, next) => { + next(); + }); +}); + +const userAccess = require('../../../../src/forms/auth/middleware/userAccess'); +userAccess.currentUser = jest.fn((_req, _res, next) => { + next(); +}); + +// +// we will mock the underlying data service calls... +// +const service = require('../../../../src/forms/permission/service'); + +// +// mocks are in place, create the router +// +const router = require('../../../../src/forms/permission/routes'); + +// Simple Express Server +const basePath = '/permissions'; +const app = expressHelper(basePath, router); +const appRequest = request(app); + +afterEach(() => { + jest.clearAllMocks(); +}); + +describe(`${basePath}`, () => { + const path = `${basePath}`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.list = jest.fn().mockReturnValue([]); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.list = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.list = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); + + describe('POST', () => { + it('should return 201', async () => { + // mock a success return value... + service.create = jest.fn().mockReturnValue({}); + + const response = await appRequest.post(path); + + expect(response.statusCode).toBe(201); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.create = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.post(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.create = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.post(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/:code`, () => { + const path = `${basePath}/:code`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.read = jest.fn().mockReturnValue([]); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.read = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.read = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); + + describe('PUT', () => { + it('should return 200', async () => { + // mock a success return value... + service.update = jest.fn().mockReturnValue([]); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.update = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.update = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); diff --git a/frontend/app/tests/unit/routes/v1/rbac.spec.js b/frontend/app/tests/unit/routes/v1/rbac.spec.js new file mode 100644 index 0000000..3cea1e4 --- /dev/null +++ b/frontend/app/tests/unit/routes/v1/rbac.spec.js @@ -0,0 +1,452 @@ +const request = require('supertest'); +const Problem = require('api-problem'); + +const { expressHelper } = require('../../../common/helper'); + +// +// mock middleware +// +const keycloak = require('../../../../src/components/keycloak'); + +// +// test assumes that caller has appropriate token, we are not testing middleware here... +// +keycloak.protect = jest.fn(() => { + return jest.fn((_req, _res, next) => { + next(); + }); +}); + +const userAccess = require('../../../../src/forms/auth/middleware/userAccess'); +userAccess.currentUser = jest.fn((_req, _res, next) => { + next(); +}); +userAccess.hasFormPermissions = jest.fn(() => { + return jest.fn((_req, _res, next) => { + next(); + }); +}); +userAccess.hasFormRoles = jest.fn(() => { + return jest.fn((_req, _res, next) => { + next(); + }); +}); +userAccess.hasRolePermissions = jest.fn(() => { + return jest.fn((_req, _res, next) => { + next(); + }); +}); +userAccess.hasSubmissionPermissions = jest.fn(() => { + return jest.fn((_req, _res, next) => { + next(); + }); +}); + +// +// we will mock the underlying data service calls... +// +const service = require('../../../../src/forms/rbac/service'); + +const emailService = require('../../../../src/forms/email/emailService'); +const submissionService = require('../../../../src/forms/submission/service'); + +// +// mocks are in place, create the router +// +const router = require('../../../../src/forms/rbac/routes'); + +// Simple Express Server +const basePath = '/rbac'; +const app = expressHelper(basePath, router); +const appRequest = request(app); + +afterEach(() => { + jest.clearAllMocks(); +}); + +describe(`${basePath}/current`, () => { + const path = `${basePath}/current`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.getCurrentUser = jest.fn().mockReturnValue({}); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.getCurrentUser = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.getCurrentUser = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/current/submissions`, () => { + const path = `${basePath}/current/submissions`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.getCurrentUserSubmissions = jest.fn().mockReturnValue({}); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.getCurrentUserSubmissions = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.getCurrentUserSubmissions = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/idps`, () => { + const path = `${basePath}/idps`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.getIdentityProviders = jest.fn().mockReturnValue([]); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.getIdentityProviders = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.getIdentityProviders = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/forms`, () => { + const path = `${basePath}/forms`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.getFormUsers = jest.fn().mockReturnValue([]); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.getFormUsers = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.getFormUsers = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); + + describe('PUT', () => { + it('should return 200', async () => { + // mock a success return value... + service.setFormUsers = jest.fn().mockReturnValue([]); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.setFormUsers = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.setFormUsers = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/submissions`, () => { + const path = `${basePath}/submissions`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.getSubmissionUsers = jest.fn().mockReturnValue([]); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.getSubmissionUsers = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.getSubmissionUsers = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); + + describe('PUT', () => { + it('should return 200', async () => { + // mock a success return value... + service.modifySubmissionUser = jest.fn().mockReturnValue([]); + emailService.submissionAssigned = jest.fn().mockReturnValue([]); + emailService.submissionUnassigned = jest.fn().mockReturnValue([]); + submissionService.read = jest.fn().mockReturnValue([]); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.modifySubmissionUser = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.modifySubmissionUser = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/users`, () => { + const path = `${basePath}/users`; + + describe('DELETE', () => { + it('should return 200', async () => { + // mock a success return value... + service.removeMultiUsers = jest.fn().mockReturnValue({}); + + const response = await appRequest.delete(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.removeMultiUsers = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.delete(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.removeMultiUsers = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.delete(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.getUserForms = jest.fn().mockReturnValue([]); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.getUserForms = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.getUserForms = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); + + describe('PUT', () => { + it('should return 200', async () => { + // mock a success return value... + service.setUserForms = jest.fn().mockReturnValue([]); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.setUserForms = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.setUserForms = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); diff --git a/frontend/app/tests/unit/routes/v1/role.spec.js b/frontend/app/tests/unit/routes/v1/role.spec.js new file mode 100644 index 0000000..7a388ef --- /dev/null +++ b/frontend/app/tests/unit/routes/v1/role.spec.js @@ -0,0 +1,194 @@ +const request = require('supertest'); +const Problem = require('api-problem'); + +const { expressHelper } = require('../../../common/helper'); + +// +// mock middleware +// +const keycloak = require('../../../../src/components/keycloak'); + +// +// test assumes that caller has appropriate token, we are not testing middleware here... +// +keycloak.protect = jest.fn(() => { + return jest.fn((_req, _res, next) => { + next(); + }); +}); + +const userAccess = require('../../../../src/forms/auth/middleware/userAccess'); +userAccess.currentUser = jest.fn((_req, _res, next) => { + next(); +}); + +// +// we will mock the underlying data service calls... +// +const service = require('../../../../src/forms/role/service'); + +// +// mocks are in place, create the router +// +const router = require('../../../../src/forms/role/routes'); + +// Simple Express Server +const basePath = '/roles'; +const app = expressHelper(basePath, router); +const appRequest = request(app); + +afterEach(() => { + jest.clearAllMocks(); +}); + +describe(`${basePath}`, () => { + const path = `${basePath}`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.list = jest.fn().mockReturnValue([]); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.list = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.list = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); + + describe('POST', () => { + it('should return 201', async () => { + // mock a success return value... + service.create = jest.fn().mockReturnValue({}); + + const response = await appRequest.post(path); + + expect(response.statusCode).toBe(201); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.create = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.post(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.create = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.post(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/role`, () => { + const path = `${basePath}/role`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.read = jest.fn().mockReturnValue([]); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.read = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.read = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); + + describe('PUT', () => { + it('should return 200', async () => { + // mock a success return value... + service.update = jest.fn().mockReturnValue([]); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.update = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.update = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); diff --git a/frontend/app/tests/unit/routes/v1/submission.spec.js b/frontend/app/tests/unit/routes/v1/submission.spec.js new file mode 100644 index 0000000..c943e6b --- /dev/null +++ b/frontend/app/tests/unit/routes/v1/submission.spec.js @@ -0,0 +1,629 @@ +const request = require('supertest'); +const Problem = require('api-problem'); + +const { expressHelper } = require('../../../common/helper'); + +// +// mock middleware +// +const userAccess = require('../../../../src/forms/auth/middleware/userAccess'); +userAccess.currentUser = jest.fn((_req, _res, next) => { + next(); +}); +userAccess.filterMultipleSubmissions = jest.fn(() => { + return jest.fn((_req, _res, next) => { + next(); + }); +}); +userAccess.hasSubmissionPermissions = jest.fn(() => { + return jest.fn((_req, _res, next) => { + next(); + }); +}); + +// +// we will mock the underlying data service calls... +// +const service = require('../../../../src/forms/submission/service'); + +const cdogsService = require('../../../../src/components/cdogsService'); +const emailService = require('../../../../src/forms/email/emailService'); + +// +// mocks are in place, create the router +// +const router = require('../../../../src/forms/submission/routes'); + +// Simple Express Server +const basePath = '/submissions'; +const app = expressHelper(basePath, router); +const appRequest = request(app); + +// +// We don't want static code analysis complaining about hard-coded tokens, even +// if they're fake. Mock a token with a non-existing ("undefined") environment +// variable. +// +const bearerAuth = `Bearer: ${process.env.DOES_NOT_EXIST}`; + +afterEach(() => { + jest.clearAllMocks(); +}); + +describe(`${basePath}/:formSubmissionId`, () => { + const path = `${basePath}/:formSubmissionId`; + + describe('DELETE', () => { + it('should return 200', async () => { + // mock a success return value... + service.delete = jest.fn().mockReturnValue({}); + + const response = await appRequest.delete(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.delete = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.delete(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.delete = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.delete(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.read = jest.fn().mockReturnValue({}); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.read = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.read = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); + + describe('PUT', () => { + it('should return 200', async () => { + // mock a success return value... + service.update = jest.fn().mockReturnValue({}); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.update = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error. + service.update = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/:formSubmissionId/edits`, () => { + const path = `${basePath}/:formSubmissionId/edits`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.listEdits = jest.fn().mockReturnValue({}); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.listEdits = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.listEdits = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/:formSubmissionId/email`, () => { + const path = `${basePath}/:formSubmissionId/email`; + + describe('POST', () => { + const submissionResult = { form: { id: '' }, submission: { id: '' }, version: { id: '' } }; + + it('should return 200', async () => { + // mock a success return value... + service.read = jest.fn().mockReturnValue(submissionResult); + emailService.submissionConfirmation = jest.fn().mockReturnValue(true); + + const response = await appRequest.post(path, { to: 'account@fake.com' }); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.read = jest.fn(() => { + throw new Problem(401); + }); + emailService.submissionConfirmation = jest.fn().mockReturnValue(true); + + const response = await appRequest.post(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error. + service.read = jest.fn(() => { + throw new Error(); + }); + emailService.submissionConfirmation = jest.fn().mockReturnValue(true); + + const response = await appRequest.post(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500 from email service', async () => { + // mock an unexpected error from email. + service.read = jest.fn().mockReturnValue(submissionResult); + emailService.submissionConfirmation = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.post(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/:formSubmissionId/:formId/submissions`, () => { + const path = `${basePath}/:formSubmissionId/:formId/submissions`; + + describe('DELETE', () => { + it('should return 200', async () => { + // mock a success return value... + service.deleteMutipleSubmissions = jest.fn().mockReturnValue({}); + + const response = await appRequest.delete(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.deleteMutipleSubmissions = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.delete(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.deleteMutipleSubmissions = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.delete(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/:formSubmissionId/:formId/submissions/restore`, () => { + const path = `${basePath}/:formSubmissionId/:formId/submissions/restore`; + + describe('PUT', () => { + it('should return 200', async () => { + // mock a success return value... + service.restoreMutipleSubmissions = jest.fn().mockReturnValue({}); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.restoreMutipleSubmissions = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.restoreMutipleSubmissions = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/:formSubmissionId/notes`, () => { + const path = `${basePath}/:formSubmissionId/notes`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.getNotes = jest.fn().mockReturnValue({}); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.getNotes = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.getNotes = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); + + describe('POST', () => { + it('should return 200', async () => { + const noteRes = { note: 'responseNote' }; + // mock a success return value... + service.addNote = jest.fn().mockReturnValue(noteRes); + + const response = await appRequest.post(path, { note: 'requestNote' }); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.addNote = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.post(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error. + service.addNote = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.post(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/:formSubmissionId/options`, () => { + const path = `${basePath}/:formSubmissionId/options`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.readOptions = jest.fn().mockReturnValue({}); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.readOptions = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.readOptions = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/:formSubmissionId/restore`, () => { + const path = `${basePath}/:formSubmissionId/restore`; + + describe('PUT', () => { + it('should return 200', async () => { + // mock a success return value... + service.restore = jest.fn().mockReturnValue({}); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.restore = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.restore = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/:formSubmissionId/status`, () => { + const path = `${basePath}/:formSubmissionId/status`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.getStatus = jest.fn().mockReturnValue({}); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.getStatus = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.getStatus = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path).set('Authorization', bearerAuth); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); + + describe('POST', () => { + it('should return 200', async () => { + const statRes = { code: 'SUBMITTED', user: {} }; + // mock a success return value... + service.changeStatusState = jest.fn().mockReturnValue(statRes); + emailService.statusAssigned = jest.fn().mockReturnValue(true); + + const response = await appRequest.post(path, { code: 'SUBMITTED', user: {} }); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + expect(emailService.statusAssigned).toHaveBeenCalledTimes(0); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.changeStatusState = jest.fn(() => { + throw new Problem(401); + }); + emailService.statusAssigned = jest.fn().mockReturnValue(true); + + const response = await appRequest.post(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error. + service.changeStatusState = jest.fn(() => { + throw new Error(); + }); + emailService.statusAssigned = jest.fn().mockReturnValue(true); + + const response = await appRequest.post(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/:formSubmissionId/template/render`, () => { + const path = `${basePath}/:formSubmissionId/template/render`; + + describe('POST', () => { + it('should return 200', async () => { + // mock a success return value... + const readResponse = { + submission: { + submission: {}, + }, + }; + const renderResponse = { + headers: {}, + status: 200, + }; + service.read = jest.fn().mockReturnValue(readResponse); + cdogsService.templateUploadAndRender = jest.fn().mockReturnValue(renderResponse); + + const response = await appRequest.post(path, {}); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.read = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.post(path, {}); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error. + service.read = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.post(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); diff --git a/frontend/app/tests/unit/routes/v1/user.spec.js b/frontend/app/tests/unit/routes/v1/user.spec.js new file mode 100644 index 0000000..9b882fc --- /dev/null +++ b/frontend/app/tests/unit/routes/v1/user.spec.js @@ -0,0 +1,346 @@ +const request = require('supertest'); +const Problem = require('api-problem'); + +const { expressHelper } = require('../../../common/helper'); + +// +// mock middleware +// +const keycloak = require('../../../../src/components/keycloak'); + +// +// test assumes that caller has appropriate token, we are not testing middleware here... +// +keycloak.protect = jest.fn(() => { + return jest.fn((_req, _res, next) => { + next(); + }); +}); + +const userAccess = require('../../../../src/forms/auth/middleware/userAccess'); +userAccess.currentUser = jest.fn((_req, _res, next) => { + next(); +}); + +// +// we will mock the underlying data service calls... +// +const service = require('../../../../src/forms/user/service'); + +// +// mocks are in place, create the router +// +const router = require('../../../../src/forms/user/routes'); + +// Simple Express Server +const basePath = '/users'; +const app = expressHelper(basePath, router); +const appRequest = request(app); + +afterEach(() => { + jest.clearAllMocks(); +}); + +describe(`${basePath}`, () => { + const path = `${basePath}`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.list = jest.fn().mockReturnValue([]); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.list = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.list = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/:userId`, () => { + const path = `${basePath}/:userId`; + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.readSafe = jest.fn().mockReturnValue([]); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.readSafe = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.readSafe = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/preferences`, () => { + const path = `${basePath}/preferences`; + + describe('DELETE', () => { + it('should return 204', async () => { + // mock a success return value... + service.deleteUserPreferences = jest.fn().mockReturnValue([]); + + const response = await appRequest.delete(path); + + expect(response.statusCode).toBe(204); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.deleteUserPreferences = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.delete(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.deleteUserPreferences = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.delete(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.readUserPreferences = jest.fn().mockReturnValue([]); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.readUserPreferences = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.readUserPreferences = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); + + describe('PUT', () => { + it('should return 200', async () => { + // mock a success return value... + service.updateUserPreferences = jest.fn().mockReturnValue([]); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.updateUserPreferences = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.updateUserPreferences = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); + +describe(`${basePath}/preferences/forms/:formId`, () => { + const path = `${basePath}/preferences/forms/:formId`; + + describe('DELETE', () => { + it('should return 204', async () => { + // mock a success return value... + service.deleteUserFormPreferences = jest.fn().mockReturnValue([]); + + const response = await appRequest.delete(path); + + expect(response.statusCode).toBe(204); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.deleteUserFormPreferences = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.delete(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.deleteUserFormPreferences = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.delete(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); + + describe('GET', () => { + it('should return 200', async () => { + // mock a success return value... + service.readUserFormPreferences = jest.fn().mockReturnValue([]); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.readUserFormPreferences = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.readUserFormPreferences = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.get(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); + + describe('PUT', () => { + it('should return 200', async () => { + // mock a success return value... + service.updateUserFormPreferences = jest.fn().mockReturnValue([]); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(200); + expect(response.body).toBeTruthy(); + }); + + it('should handle 401', async () => { + // mock an authentication/permission issue... + service.updateUserFormPreferences = jest.fn(() => { + throw new Problem(401); + }); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(401); + expect(response.body).toBeTruthy(); + }); + + it('should handle 500', async () => { + // mock an unexpected error... + service.updateUserFormPreferences = jest.fn(() => { + throw new Error(); + }); + + const response = await appRequest.put(path); + + expect(response.statusCode).toBe(500); + expect(response.body).toBeTruthy(); + }); + }); +}); diff --git a/frontend/components/.codeclimate.yml b/frontend/components/.codeclimate.yml new file mode 100644 index 0000000..57c4271 --- /dev/null +++ b/frontend/components/.codeclimate.yml @@ -0,0 +1,63 @@ +version: "2" +exclude_patterns: + - config/ + - "**/db/" + - dist/ + - features/ + - "**/node_modules/" + - script/ + - "**/spec/" + - "**/test/" + - "**/tests/" + - Tests/ + - "**/vendor/" + - "**/*_test.go" + - "**/*.d.ts" +plugins: + csslint: + enabled: true + editorconfig: + enabled: true + checks: + END_OF_LINE: + enabled: false + INDENTATION_SPACES: + enabled: false + INDENTATION_SPACES_AMOUNT: + enabled: false + TRAILINGSPACES: + enabled: false + eslint: + enabled: true + channel: "eslint-7" + config: + config: app/.eslintrc.js + fixme: + enabled: true + git-legal: + enabled: true + markdownlint: + enabled: true + checks: + MD002: + enabled: false + MD013: + enabled: false + MD029: + enabled: false + MD046: + enabled: false + nodesecurity: + enabled: true + sass-lint: + enabled: true +checks: + method-complexity: + config: + threshold: 6 + method-lines: + config: + threshold: 40 + file-lines: + config: + threshold: 500 diff --git a/frontend/components/.gitignore b/frontend/components/.gitignore new file mode 100644 index 0000000..701b500 --- /dev/null +++ b/frontend/components/.gitignore @@ -0,0 +1,17 @@ +# Editor directories and files +.DS_Store +lib +dist +node_modules + +# Editor directories and files +.idea +.vscode +*.iml +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? +*.mp4 + diff --git a/frontend/components/.prettierrc b/frontend/components/.prettierrc new file mode 100644 index 0000000..937375d --- /dev/null +++ b/frontend/components/.prettierrc @@ -0,0 +1,4 @@ +{ + "semi": true, + "singleQuote": true +} diff --git a/frontend/components/README.md b/frontend/components/README.md new file mode 100644 index 0000000..bcfa058 --- /dev/null +++ b/frontend/components/README.md @@ -0,0 +1,56 @@ +# Form.io contrib components library + +This module contains contributed components for use with Form.io. It also serves as a good example on how you can create your very own custom components library that can be used with Form.io platform. + +## Installation + +To install this library, do the following. + +```sh +npm install --save @formio/contrib +``` + +## Usage + +```javascript +import { Formio } from 'formiojs'; +import FormioContrib from '@formio/contrib'; +Formio.use(FormioContrib); +``` + +You can also include this library within the DOM of your application like the following. + +```html +<link rel="stylesheet" href="https://unpkg.com/formiojs@latest/dist/formio.full.min.css"> +<script src="https://unpkg.com/formiojs@latest/dist/formio.full.min.js"></script> +<script src="https://unpkg.com/@formio/contrib@latest/dist/formio-contrib.min.js"></script> +<link rel="stylesheet" href="https://unpkg.com/@formio/contrib@latest/dist/formio-contrib.css"> +<script type="text/javascript"> + Formio.use(FormioContrib); +</script> +``` + +Or you can use the **formio-contrib.use.min.js** file which automatically adds the ```Formio.use``` method. + +```html +<link rel="stylesheet" href="https://unpkg.com/formiojs@latest/dist/formio.full.min.css"> +<script src="https://unpkg.com/formiojs@latest/dist/formio.full.min.js"></script> +<script src="https://unpkg.com/@formio/contrib@latest/dist/formio-contrib.use.min.js"></script> +<link rel="stylesheet" href="https://unpkg.com/@formio/contrib@latest/dist/formio-contrib.css"> +``` + +### Using within the Form.io Developer Portal + +It is also possible to inject custom components within the Form.io Developer Portal. This allows you to use the Developer Portal to create forms that include your custom components. Note: This currently only works with the Next portal @ <https://next.form.io> + +To make this work, navigate to your project settings, and then click on **Custom JS and CSS**. Within the **Custom JavaScript** box, you will then place the hosted URL to the **dist/formio-contrib.use.min.js** file within this library, like so. + +![Custom CSS and Javascript](https://api.monosnap.com/file/download?id=dQmYlhPWLa7mDDDJMN1VpkJwXy7iHG) + +You can also use the unpkg url to this repo to test this out. [https://unpkg.com/@formio/contrib@latest/dist/formio-contrib.use.min.js](https://unpkg.com/@formio/contrib@latest/dist/formio-contrib.use.min.js) + +### Using within the Form Manager application + +You can also use this method to introduce custom components into the Form Manager application. To get this to work, you just need to Enable Public configurations within your project settings, and then provide the **js** setting to contain the URL of the **dist/formio-contrib.use.min.js** file within this repository like so. + +![Public Configurations](https://api.monosnap.com/file/download?id=lvK2kW9eOuAEVDMNW96hP5qLOCaQEY) diff --git a/frontend/components/gulpfile.js b/frontend/components/gulpfile.js new file mode 100644 index 0000000..38021ab --- /dev/null +++ b/frontend/components/gulpfile.js @@ -0,0 +1,24 @@ +'use strict'; +const gulp = require('gulp'); +const insert = require('gulp-insert'); +const rename = require('gulp-rename'); +const template = require('gulp-template'); + +// Compile all *.ejs files to pre-compiled templates and append *.js to the filename. +gulp.task('templates', () => + gulp.src('./src/**/*.ejs') + .pipe(template.precompile({ + evaluate: /\{%([\s\S]+?)%\}/g, + interpolate: /\{\{([\s\S]+?)\}\}/g, + escape: /\{\{\{([\s\S]+?)\}\}\}/g, + variable: 'ctx' + })) + .pipe(insert.prepend('Object.defineProperty(exports, "__esModule", {\n' + + ' value: true\n' + + '});\n' + + 'exports.default=')) + .pipe(rename({ + extname: '.ejs.js' + })) + .pipe(gulp.dest('lib')) +); diff --git a/frontend/components/package-lock.json b/frontend/components/package-lock.json new file mode 100644 index 0000000..2d69357 --- /dev/null +++ b/frontend/components/package-lock.json @@ -0,0 +1,9035 @@ +{ + "name": "@bcgov/formio", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@bcgov/formio", + "version": "1.0.0", + "license": "Apache-2.0", + "dependencies": { + "autocompleter": "^7.0.1", + "formiojs": "^4.14.6", + "lodash": "^4.17.21", + "native-promise-only": "^0.8.1", + "path-browserify": "^1.0.1", + "webpack": "^5.75.0" + }, + "devDependencies": { + "@types/chai": "^4.3.1", + "@types/ejs": "^3.1.1", + "@types/mocha": "^9.1.1", + "@types/node": "^16.11.8", + "@types/sinon": "^10.0.12", + "chai": "^4.3.6", + "glob-parent": "^6.0.2", + "gulp": "^4.0.2", + "gulp-insert": "^0.5.0", + "gulp-rename": "^2.0.0", + "gulp-template": "^5.0.0", + "mocha": "^9.1.3", + "nyc": "^15.0.1", + "pre-commit": "^1.2.2", + "sass": "^1.62.0", + "sinon": "^12.0.1", + "ts-node": "^10.8.2", + "ts-sinon": "^2.0.2", + "tslint": "^6.1.3", + "typescript": "^4.7.4", + "vite": "^4.3.5", + "webpack-cli": "^4.10.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/@babel/core": { + "version": "7.11.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.11.6.tgz", + "integrity": "sha512-Wpcv03AGnmkgm6uS6k8iwhIwTrcP0m17TL1n1sy7qD0qelDu4XNeW0dN0mHfa+Gei211yDaLoEe/VlbXQzM4Bg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.11.6", + "@babel/helper-module-transforms": "^7.11.0", + "@babel/helpers": "^7.10.4", + "@babel/parser": "^7.11.5", + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.11.5", + "@babel/types": "^7.11.5", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.19", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core/node_modules/debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/@babel/core/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@babel/generator": { + "version": "7.11.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.11.6.tgz", + "integrity": "sha512-DWtQ1PV3r+cLbySoHrwn9RWEgKMBLLma4OBQloPRyDYvc5msJM9kvTLo1YnlJd1P/ZuKbdli3ijr5q3FvAF3uA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.11.5", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", + "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "dev": true, + "dependencies": { + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/helper-get-function-arity": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", + "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "dev": true, + "dependencies": { + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz", + "integrity": "sha512-JbFlKHFntRV5qKw3YC0CvQnDZ4XMwgzzBbld7Ly4Mj4cbFy3KywcR8NtNctRToMWJOVvLINJv525Gd6wwVEx/Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.11.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz", + "integrity": "sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz", + "integrity": "sha512-02EVu8COMuTRO1TAzdMtpBPbe6aQ1w/8fePD2YgQmxZU4gpNWaL9gK3Jp7dxlkUlUCJOTaSeA+Hrm1BRQwqIhg==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.10.4", + "@babel/helper-replace-supers": "^7.10.4", + "@babel/helper-simple-access": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/template": "^7.10.4", + "@babel/types": "^7.11.0", + "lodash": "^4.17.19" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz", + "integrity": "sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz", + "integrity": "sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A==", + "dev": true, + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.10.4", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz", + "integrity": "sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz", + "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.11.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "node_modules/@babel/helpers": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.10.4.tgz", + "integrity": "sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA==", + "dev": true, + "dependencies": { + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.11.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.5.tgz", + "integrity": "sha512-X9rD8qqm695vgmeaQ4fvz/o3+Wk4ZzQvSHkDBgpYKxpD4qTAUm88ZKtHkVqIOsYFFbIQ6wQYhC6q7pjqVK0E0Q==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.18.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.0.tgz", + "integrity": "sha512-YMQvx/6nKEaucl0MY56mwIG483xk8SDNdlUwb2Ts6FUpr7fm85DxEmsY18LXBNhcTz6tO6JwZV8w1W06v8UKeg==", + "dependencies": { + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", + "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/traverse": { + "version": "7.11.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.11.5.tgz", + "integrity": "sha512-EjiPXt+r7LiCZXEfRpSJd+jUMnBd4/9OUv7Nx3+0u9+eimMwJmG0Q98lw4/289JCoxSE8OolDMNZaaF/JZ69WQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.11.5", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/parser": "^7.11.5", + "@babel/types": "^7.11.5", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.19" + } + }, + "node_modules/@babel/traverse/node_modules/debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/@babel/traverse/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@babel/types": { + "version": "7.11.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.5.tgz", + "integrity": "sha512-bvM7Qz6eKnJVFIn+1LPtjlBFPVN5jNDc1XmN15vWe7Q3DPBufWWsLiIvUu7xW87uTG6QoggpIDnUgLQvPheU+Q==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.2.tgz", + "integrity": "sha512-HyYEUDeIj5rRQU2Hk5HTB2uHsbRQpF70nvMhVzi+VJR0X+xNEhjPui4/kBf3VeH/wqD28PT4sVOm8qqLjBrSZg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.17.18", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.18.tgz", + "integrity": "sha512-qU25Ma1I3NqTSHJUOKi9sAH1/Mzuvlke0ioMJRthLXKm7JiSKVwFghlGbDLOO2sARECGhja4xYfRAZNPAkooYg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@formio/bootstrap3": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/@formio/bootstrap3/-/bootstrap3-2.12.2.tgz", + "integrity": "sha512-Y1WD/U22HHKRl1MzUt65bXeFHYO9Wlt+wefRqXFrOhIgbmkfTjCx6e0n2b8t/IYz9FUMg+/GTKdqaBrTZgjrTA==", + "dependencies": { + "resize-observer-polyfill": "^1.5.1" + } + }, + "node_modules/@formio/choices.js": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@formio/choices.js/-/choices.js-9.0.1.tgz", + "integrity": "sha512-+JQRWH0yhaeemVJGE1L4oPe9KPFhipzDlms3Pd31gePXpy8q7Mf3Is54/f0fc88+mWeMjK4GyIhcKIKmuGx5Xw==", + "dependencies": { + "deepmerge": "^4.2.0", + "fuse.js": "^3.4.5", + "redux": "^4.0.4" + } + }, + "node_modules/@formio/semantic": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@formio/semantic/-/semantic-2.6.0.tgz", + "integrity": "sha512-RwMEVXkyz+B6RivflrrKIqvvnGR/eZDLQs74u67StcrzO6n3/5D2J8XqTQRSUzQzr5QV6Wq0eZ51z/+mGm6THw==" + }, + "node_modules/@formio/vanilla-text-mask": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@formio/vanilla-text-mask/-/vanilla-text-mask-5.1.1.tgz", + "integrity": "sha512-7MhrbMypySPi7RLchg0ys7HnS3Wqddbq/btAijKB1nA94TE7AOOLhpZJWcNm3kOlX0Y3nHfoavj/HP7vsvF34Q==" + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", + "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.5", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.5.tgz", + "integrity": "sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/samsam": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.3.1.tgz", + "integrity": "sha512-1Hc0b1TtyfBu8ixF/tpfSHTVWKwCBLY4QJbkgnE7HcwyvT2xArDxb4K7dMgqRm3szI+LJbzmW/s4xxEhv6hwDg==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.6.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "node_modules/@sinonjs/text-encoding": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz", + "integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==", + "dev": true + }, + "node_modules/@sphinxxxx/color-conversion": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@sphinxxxx/color-conversion/-/color-conversion-2.2.2.tgz", + "integrity": "sha512-XExJS3cLqgrmNBIP3bBw6+1oQ1ksGjFh0+oClDKFYpCCqx/hlqwWO5KO/S63fzUo67SxI9dMrF0y5T/Ey7h8Zw==" + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.8.tgz", + "integrity": "sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.9.tgz", + "integrity": "sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.1.tgz", + "integrity": "sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", + "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", + "dev": true + }, + "node_modules/@types/chai": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.1.tgz", + "integrity": "sha512-/zPMqDkzSZ8t3VtxOa4KPq7uzzW978M9Tvh+j7GHKuo6k6GTLxPJ4J5gE5cjfJ26pnXst0N5Hax8Sr0T2Mi9zQ==", + "dev": true + }, + "node_modules/@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "dev": true + }, + "node_modules/@types/ejs": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/ejs/-/ejs-3.1.1.tgz", + "integrity": "sha512-RQul5wEfY7BjWm0sYY86cmUN/pcXWGyVxWX93DFFJvcrxax5zKlieLwA3T77xJGwNcZW0YW6CYG70p1m8xPFmA==", + "dev": true + }, + "node_modules/@types/eslint": { + "version": "8.4.10", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.10.tgz", + "integrity": "sha512-Sl/HOqN8NKPmhWo2VBEPm0nvHnu2LL3v9vKo8MEq0EtbJ4eVzGPl41VNPvn5E1i5poMk4/XD8UriLHpJvEP/Nw==", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", + "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==" + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==" + }, + "node_modules/@types/mocha": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz", + "integrity": "sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==", + "dev": true + }, + "node_modules/@types/node": { + "version": "16.11.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.8.tgz", + "integrity": "sha512-hmT5gfpRkkHr7DZZHMf3jBe/zNcVGN+jXSL2f8nAsYfBPxQFToKwQlS/zES4Sjp488Bi73i+p6bvrNRRGU0x9Q==" + }, + "node_modules/@types/sinon": { + "version": "10.0.12", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.12.tgz", + "integrity": "sha512-uWf4QJ4oky/GckJ1MYQxU52cgVDcXwBhDkpvLbi4EKoLPqLE4MOH6T/ttM33l3hi0oZ882G6oIzWv/oupRYSxQ==", + "dev": true, + "dependencies": { + "@types/sinonjs__fake-timers": "*" + } + }, + "node_modules/@types/sinon-chai": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/@types/sinon-chai/-/sinon-chai-3.2.5.tgz", + "integrity": "sha512-bKQqIpew7mmIGNRlxW6Zli/QVyc3zikpGzCa797B/tRnD9OtHvZ/ts8sYXV+Ilj9u3QRaUEM8xrjgd1gwm1BpQ==", + "dev": true, + "dependencies": { + "@types/chai": "*", + "@types/sinon": "*" + } + }, + "node_modules/@types/sinonjs__fake-timers": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.2.tgz", + "integrity": "sha512-dIPoZ3g5gcx9zZEszaxLSVTvMReD3xxyyDnQUjA6IYDG9Ba2AV0otMPs+77sG9ojB4Qr2N2Vk5RnKeuA0X/0bg==", + "dev": true + }, + "node_modules/@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", + "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", + "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", + "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", + "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-opt": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6", + "@webassemblyjs/wast-printer": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", + "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", + "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", + "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", + "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + }, + "node_modules/acorn": { + "version": "8.8.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/ansi-colors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "dev": true, + "dependencies": { + "ansi-wrap": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-cyan": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-cyan/-/ansi-cyan-0.1.1.tgz", + "integrity": "sha1-U4rlKK+JgvKK4w2G8vF0VtJgmHM=", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-gray": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", + "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-red": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz", + "integrity": "sha1-jGOPnRCAgAo1PJwoyKgcpHBdlGw=", + "dev": true, + "dependencies": { + "ansi-wrap": "0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ansi-wrap": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", + "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "dependencies": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "node_modules/anymatch/node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/append-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", + "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=", + "dev": true, + "dependencies": { + "buffer-equal": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/append-transform": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", + "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", + "dev": true, + "dependencies": { + "default-require-extensions": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-filter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz", + "integrity": "sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4=", + "dev": true, + "dependencies": { + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz", + "integrity": "sha1-Onc0X/wc814qkYJWAfnljy4kysQ=", + "dev": true, + "dependencies": { + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-filter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-1.0.0.tgz", + "integrity": "sha1-uveeYubvTCpMC4MSMtr/7CUfnYM=" + }, + "node_modules/array-initial": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz", + "integrity": "sha1-L6dLJnOTccOUe9enrcc74zSz15U=", + "dev": true, + "dependencies": { + "array-slice": "^1.0.0", + "is-number": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-initial/node_modules/is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-last": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz", + "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==", + "dev": true, + "dependencies": { + "is-number": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-last/node_modules/is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-slice": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-sort": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz", + "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==", + "dev": true, + "dependencies": { + "default-compare": "^1.0.0", + "get-value": "^2.0.6", + "kind-of": "^5.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-sort/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/async-done": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz", + "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.2", + "process-nextick-args": "^2.0.0", + "stream-exhaust": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "dev": true + }, + "node_modules/async-settle": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", + "integrity": "sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs=", + "dev": true, + "dependencies": { + "async-done": "^1.2.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/atoa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atoa/-/atoa-1.0.0.tgz", + "integrity": "sha1-DMDpGkgOc4+SPrwQNnZHF3mzSkk=" + }, + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true, + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/autocompleter": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/autocompleter/-/autocompleter-7.0.1.tgz", + "integrity": "sha512-PD+/PaKE6cQ2hW35dEK0exZcGUknIEbw2ef1LTLclj6jfYLeXqyTojL/tQeVacLxEg7FOiMlyqXdB/j4XSVxlA==" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz", + "integrity": "sha512-XWX3OX8Onv97LMk/ftVyBibpGwY5a8SmuxZPzeOxqmuEqUCOM9ZE+uIaD1VNJ5QnvU2UQusvmKbuM1FR8QWGfQ==", + "dependencies": { + "array-filter": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/bach": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", + "integrity": "sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA=", + "dev": true, + "dependencies": { + "arr-filter": "^1.1.1", + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "array-each": "^1.0.0", + "array-initial": "^1.0.0", + "array-last": "^1.1.1", + "async-done": "^1.2.2", + "async-settle": "^1.0.0", + "now-and-later": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "node_modules/base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "dependencies": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "optional": true, + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/braces/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/browser-cookies": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browser-cookies/-/browser-cookies-1.2.0.tgz", + "integrity": "sha1-/KP/ubamOq3E2MCZnGtX0Pp9KbU=" + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/browserslist": { + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.9" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz", + "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "node_modules/builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "dependencies": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/caching-transform": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", + "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", + "dev": true, + "dependencies": { + "hasha": "^5.0.0", + "make-dir": "^3.0.0", + "package-hash": "^4.0.0", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "node_modules/camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001434", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001434.tgz", + "integrity": "sha512-aOBHrLmTQw//WFa2rcF1If9fa3ypkC1wzqqiKHgfdrXTWcU8C4gKVZT77eQAPWN1APys3+uQ0Df07rKauXGEYA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, + "node_modules/chai": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.6.tgz", + "integrity": "sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.2", + "deep-eql": "^3.0.1", + "get-func-name": "^2.0.0", + "loupe": "^2.3.1", + "pathval": "^1.1.1", + "type-detect": "^4.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/check-error": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", + "integrity": "sha1-V00xLt2Iu13YkS6Sht1sCu1KrII=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "dev": true, + "dependencies": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + }, + "optionalDependencies": { + "fsevents": "^1.2.7" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "dependencies": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", + "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/clone-stats": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", + "dev": true + }, + "node_modules/cloneable-readable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz", + "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "process-nextick-args": "^2.0.0", + "readable-stream": "^2.3.5" + } + }, + "node_modules/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/collection-map": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz", + "integrity": "sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw=", + "dev": true, + "dependencies": { + "arr-map": "^2.0.2", + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "dependencies": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "node_modules/compare-versions": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", + "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==" + }, + "node_modules/component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/contra": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/contra/-/contra-1.9.4.tgz", + "integrity": "sha1-9TveQtfltZhcrk2ZqNYQUm3o8o0=", + "dependencies": { + "atoa": "1.0.0", + "ticky": "1.0.1" + } + }, + "node_modules/convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/copy-props": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.5.tgz", + "integrity": "sha512-XBlx8HSqrT0ObQwmSzM7WE5k8FxTV75h1DX1Z3n6NhQ/UYYAvInWYmG06vFt7hQZArE2fuO62aihiWIVQwh1sw==", + "dev": true, + "dependencies": { + "each-props": "^1.3.2", + "is-plain-object": "^5.0.0" + } + }, + "node_modules/copy-props/node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/core-js": { + "version": "3.22.5", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.22.5.tgz", + "integrity": "sha512-VP/xYuvJ0MJWRAobcmQ8F2H6Bsn+s7zqAAjFaHGBMc5AQm7zaelhD1LGduFn2EehEcQcU+br6t+fwbpQ5d1ZWA==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crossvent": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/crossvent/-/crossvent-1.5.5.tgz", + "integrity": "sha1-rSCHjkkh6b5z2daXb4suzQ9xoLE=", + "dependencies": { + "custom-event": "^1.0.0" + } + }, + "node_modules/custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=" + }, + "node_modules/custom-event-polyfill": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/custom-event-polyfill/-/custom-event-polyfill-1.0.7.tgz", + "integrity": "sha512-TDDkd5DkaZxZFM8p+1I3yAlvM3rSr1wbrOliG4yJiwinMZN8z/iGL7BTlDkrJcYTmgUSb4ywVCc3ZaUtOtC76w==" + }, + "node_modules/d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "dependencies": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/deep-eql": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz", + "integrity": "sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/deep-equal": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.0.5.tgz", + "integrity": "sha512-nPiRgmbAtm1a3JsnLCf6/SLfXcjyN5v8L1TXzdCmHrXJ4hx+gW/w1YCcn7z8gJtSiDArZCgYtbao3QqLm/N1Sw==", + "dependencies": { + "call-bind": "^1.0.0", + "es-get-iterator": "^1.1.1", + "get-intrinsic": "^1.0.1", + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.2", + "is-regex": "^1.1.1", + "isarray": "^2.0.5", + "object-is": "^1.1.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "regexp.prototype.flags": "^1.3.0", + "side-channel": "^1.0.3", + "which-boxed-primitive": "^1.0.1", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/deep-equal/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "node_modules/deep-equal/node_modules/object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/deepmerge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz", + "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==", + "dev": true, + "dependencies": { + "kind-of": "^5.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-compare/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/default-require-extensions": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz", + "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==", + "dev": true, + "dependencies": { + "strip-bom": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/default-require-extensions/node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/default-resolution": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", + "integrity": "sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dependencies": { + "object-keys": "^1.0.12" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-property/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-property/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-property/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dialog-polyfill": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/dialog-polyfill/-/dialog-polyfill-0.5.6.tgz", + "integrity": "sha512-ZbVDJI9uvxPAKze6z146rmfUZjBqNEwcnFTVamQzXH+svluiV7swmVIGr7miwADgfgt1G2JQIytypM9fbyhX4w==" + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dompurify": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.3.8.tgz", + "integrity": "sha512-eVhaWoVibIzqdGYjwsBWodIQIaXFSB+cKDf4cfxLMsK0xiud6SE+/WCVx/Xw/UwQsa4cS3T2eITcdtmTg2UKcw==" + }, + "node_modules/downloadjs": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/downloadjs/-/downloadjs-1.4.7.tgz", + "integrity": "sha1-9p+W+UDg0FU9rCkROYZaPNAQHjw=" + }, + "node_modules/dragula": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/dragula/-/dragula-3.7.3.tgz", + "integrity": "sha512-/rRg4zRhcpf81TyDhaHLtXt6sEywdfpv1cRUMeFFy7DuypH2U0WUL0GTdyAQvXegviT4PJK4KuMmOaIDpICseQ==", + "dependencies": { + "contra": "1.9.4", + "crossvent": "1.5.5" + } + }, + "node_modules/duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/each-props": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz", + "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.1", + "object.defaults": "^1.1.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.14.0.tgz", + "integrity": "sha512-+DCows0XNwLDcUhbFJPdlQEVnT2zXlCv7hPxemTz86/O+B/hCQ+mb7ydkPKiflpVraqLPCAfu7lDy+hBXueojw==", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/envinfo": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", + "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", + "dev": true, + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.18.0-next.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.0.tgz", + "integrity": "sha512-elZXTZXKn51hUBdJjSZGYRujuzilgXo8vSPQzjGYXLvSlGiCo8VO8ZGV3kjo9a0WNJJ57hENagwbtlRuHuzkcQ==", + "dev": true, + "dependencies": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-negative-zero": "^2.0.0", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-get-iterator": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", + "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.0", + "has-symbols": "^1.0.1", + "is-arguments": "^1.1.0", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.5", + "isarray": "^2.0.5" + } + }, + "node_modules/es-get-iterator/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "node_modules/es-module-lexer": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.2.1.tgz", + "integrity": "sha512-9978wrXM50Y4rTMmW5kXIC09ZdXQZqkE4mxhwkd8VbzsGkXGPgV4zWuqQJgCEzYngdo2dYDa0l8xhX4fkSwJSg==" + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es5-ext": { + "version": "0.10.62", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz", + "integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "node_modules/es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/esbuild": { + "version": "0.17.18", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.18.tgz", + "integrity": "sha512-z1lix43jBs6UKjcZVKOw2xx69ffE2aG0PygLL5qJ9OS/gy0Ewd1gW/PUQIOIQGXBHWNywSc0floSKoMFF8aK2w==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/android-arm": "0.17.18", + "@esbuild/android-arm64": "0.17.18", + "@esbuild/android-x64": "0.17.18", + "@esbuild/darwin-arm64": "0.17.18", + "@esbuild/darwin-x64": "0.17.18", + "@esbuild/freebsd-arm64": "0.17.18", + "@esbuild/freebsd-x64": "0.17.18", + "@esbuild/linux-arm": "0.17.18", + "@esbuild/linux-arm64": "0.17.18", + "@esbuild/linux-ia32": "0.17.18", + "@esbuild/linux-loong64": "0.17.18", + "@esbuild/linux-mips64el": "0.17.18", + "@esbuild/linux-ppc64": "0.17.18", + "@esbuild/linux-riscv64": "0.17.18", + "@esbuild/linux-s390x": "0.17.18", + "@esbuild/linux-x64": "0.17.18", + "@esbuild/netbsd-x64": "0.17.18", + "@esbuild/openbsd-x64": "0.17.18", + "@esbuild/sunos-x64": "0.17.18", + "@esbuild/win32-arm64": "0.17.18", + "@esbuild/win32-ia32": "0.17.18", + "@esbuild/win32-x64": "0.17.18" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "dependencies": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ext": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", + "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", + "dev": true, + "dependencies": { + "type": "^2.0.0" + } + }, + "node_modules/ext/node_modules/type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.1.0.tgz", + "integrity": "sha512-G9absDWvhAWCV2gmF1zKud3OyC61nZDwWvBL2DApaVFogI07CprggiQAOOjvp2NRjYWFzPyu7vwtDrQFq8jeSA==", + "dev": true + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extend-shallow/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "dependencies": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fancy-log": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", + "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", + "dev": true, + "dependencies": { + "ansi-gray": "^0.1.1", + "color-support": "^1.1.3", + "parse-node-version": "^1.0.0", + "time-stamp": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==" + }, + "node_modules/fast-json-patch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-json-patch/-/fast-json-patch-3.1.1.tgz", + "integrity": "sha512-vf6IHUX2SBcA+5/+4883dsIjpBTqmfBjmYiWK1savxQmFk4JfBMLa7ynTYOs1Rolp/T1betJxHiGD3g1Mn8lUQ==" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/fast-levenshtein": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz", + "integrity": "sha1-5qdUzI8V5YmHqpy9J69m/W9OWvk=", + "dev": true + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", + "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", + "dev": true + }, + "node_modules/fetch-ponyfill": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/fetch-ponyfill/-/fetch-ponyfill-7.1.0.tgz", + "integrity": "sha512-FhbbL55dj/qdVO3YNK7ZEkshvj3eQ7EuIGV2I6ic/2YiocvyWv+7jg2s4AyS0wdRU75s3tA8ZxI/xPigb0v5Aw==", + "dependencies": { + "node-fetch": "~2.6.1" + } + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "optional": true + }, + "node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fill-range/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/find-cache-dir": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", + "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "dependencies": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/findup-sync": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "dev": true, + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/fined": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", + "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^2.0.3", + "object.defaults": "^1.1.0", + "object.pick": "^1.2.0", + "parse-filepath": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/flagged-respawn": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", + "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "dev": true, + "dependencies": { + "for-in": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" + }, + "node_modules/foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/formiojs": { + "version": "4.14.7", + "resolved": "https://registry.npmjs.org/formiojs/-/formiojs-4.14.7.tgz", + "integrity": "sha512-o2rBRO+ZC5TUCTkDBZDMSN0Jl6NXKbi/udmOYrb9uyRV79TZFnXUh+CnIF0a8stDOBRCHFa84+mvzoIPcqtmBg==", + "dependencies": { + "@formio/bootstrap3": "^2.12.2", + "@formio/choices.js": "^9.0.1", + "@formio/semantic": "^2.6.0", + "@formio/vanilla-text-mask": "^5.1.1", + "autocompleter": "^6.1.2", + "browser-cookies": "^1.2.0", + "compare-versions": "^3.6.0", + "core-js": "^3.19.3", + "custom-event-polyfill": "^1.0.7", + "dialog-polyfill": "^0.5.6", + "dompurify": "^2.3.4", + "downloadjs": "^1.4.7", + "dragula": "^3.7.3", + "eventemitter3": "^4.0.7", + "fast-deep-equal": "^3.1.3", + "fast-json-patch": "^3.1.0", + "fetch-ponyfill": "^7.1.0", + "i18next": "^21.6.0", + "idb": "^6.1.5", + "ismobilejs": "^1.1.1", + "json-logic-js": "^2.0.0", + "jstimezonedetect": "^1.0.7", + "jwt-decode": "^3.1.2", + "lodash": "^4.17.21", + "moment": "^2.29.2", + "moment-timezone": "^0.5.34", + "native-promise-only": "^0.8.1", + "quill": "^2.0.0-dev.3", + "resize-observer-polyfill": "^1.5.1", + "signature_pad": "^2.3.2", + "string-hash": "^1.1.3", + "text-mask-addons": "^3.8.0", + "tippy.js": "^6.3.7", + "uuid": "^8.3.2", + "vanilla-picker": "^2.12.1" + } + }, + "node_modules/formiojs/node_modules/autocompleter": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/autocompleter/-/autocompleter-6.1.3.tgz", + "integrity": "sha512-Pjb5R5r+S0/zDFudLP9a8CW7/xMc7O/uVCtaTf3f+RdNLAQQ5oUG018c3IRdDJMRVvT+OeZ1NYQoUH5GHlORKQ==" + }, + "node_modules/formiojs/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "dependencies": { + "map-cache": "^0.2.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fromentries": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.2.1.tgz", + "integrity": "sha512-Xu2Qh8yqYuDhQGOhD5iJGninErSfI9A3FrriD3tjUgV5VbJFeH8vfgZ9HnC6jWN80QDVNQK5vmxRAmEAp7Mevw==", + "dev": true + }, + "node_modules/fs-mkdirp-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", + "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.11", + "through2": "^2.0.3" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "deprecated": "The v1 package contains DANGEROUS / INSECURE binaries. Upgrade to safe fsevents v2", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/fuse.js": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-3.6.1.tgz", + "integrity": "sha512-hT9yh/tiinkmirKrlv4KWOjztdoZo1mx9Qh4KvWqC7isoXwdUY3PNWUxceF4/qO9R6riA2C29jdTOeQOIROjgw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.1", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", + "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "node_modules/get-func-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", + "integrity": "sha1-6td0q+5y4gQJQzoGY2YCPdaIekE=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob-stream": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", + "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=", + "dev": true, + "dependencies": { + "extend": "^3.0.0", + "glob": "^7.1.1", + "glob-parent": "^3.1.0", + "is-negated-glob": "^1.0.0", + "ordered-read-streams": "^1.0.0", + "pumpify": "^1.3.5", + "readable-stream": "^2.1.5", + "remove-trailing-separator": "^1.0.1", + "to-absolute-glob": "^2.0.0", + "unique-stream": "^2.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, + "node_modules/glob-watcher": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.5.tgz", + "integrity": "sha512-zOZgGGEHPklZNjZQaZ9f41i7F2YwE+tS5ZHrDhbBCk3stwahn5vQxnFmBJZHoYdusR6R1bLSXeGUy/BhctwKzw==", + "dev": true, + "dependencies": { + "anymatch": "^2.0.0", + "async-done": "^1.2.0", + "chokidar": "^2.0.0", + "is-negated-glob": "^1.0.0", + "just-debounce": "^1.0.0", + "normalize-path": "^3.0.0", + "object.defaults": "^1.1.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "dependencies": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/glogg": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz", + "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==", + "dev": true, + "dependencies": { + "sparkles": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + }, + "node_modules/growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true, + "engines": { + "node": ">=4.x" + } + }, + "node_modules/gulp": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz", + "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==", + "dev": true, + "dependencies": { + "glob-watcher": "^5.0.3", + "gulp-cli": "^2.2.0", + "undertaker": "^1.2.1", + "vinyl-fs": "^3.0.0" + }, + "bin": { + "gulp": "bin/gulp.js" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulp-insert": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/gulp-insert/-/gulp-insert-0.5.0.tgz", + "integrity": "sha1-MjE/E+SiPPWsylzl8MCAkjx3hgI=", + "dev": true, + "dependencies": { + "readable-stream": "^1.0.26-4", + "streamqueue": "0.0.6" + } + }, + "node_modules/gulp-insert/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "node_modules/gulp-insert/node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/gulp-insert/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "node_modules/gulp-rename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/gulp-rename/-/gulp-rename-2.0.0.tgz", + "integrity": "sha512-97Vba4KBzbYmR5VBs9mWmK+HwIf5mj+/zioxfZhOKeXtx5ZjBk57KFlePf5nxq9QsTtFl0ejnHE3zTC9MHXqyQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/gulp-template": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/gulp-template/-/gulp-template-5.0.0.tgz", + "integrity": "sha512-BsE+HrFZG0ItM0fBhRMfqWWR5MQ2W3O3ss1T3XdNqi4p9WCIFYjcdI1L5PikXMNUU93A4NoVLeWPwUmqGAKwGA==", + "dev": true, + "dependencies": { + "lodash": "^4.8.2", + "plugin-error": "^0.1.2", + "safe-buffer": "^5.1.1", + "through2": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/gulp/node_modules/gulp-cli": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.3.0.tgz", + "integrity": "sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A==", + "dev": true, + "dependencies": { + "ansi-colors": "^1.0.1", + "archy": "^1.0.0", + "array-sort": "^1.0.0", + "color-support": "^1.1.3", + "concat-stream": "^1.6.0", + "copy-props": "^2.0.1", + "fancy-log": "^1.3.2", + "gulplog": "^1.0.0", + "interpret": "^1.4.0", + "isobject": "^3.0.1", + "liftoff": "^3.1.0", + "matchdep": "^2.0.0", + "mute-stdout": "^1.0.0", + "pretty-hrtime": "^1.0.0", + "replace-homedir": "^1.0.0", + "semver-greatest-satisfied-range": "^1.1.0", + "v8flags": "^3.2.0", + "yargs": "^7.1.0" + }, + "bin": { + "gulp": "bin/gulp.js" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/gulplog": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", + "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", + "dev": true, + "dependencies": { + "glogg": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==" + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "dependencies": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hasha": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.0.tgz", + "integrity": "sha512-2W+jKdQbAdSIrggA8Q35Br8qKadTrqCTC8+XZvBWepKDK6m9XkX6Iz1a2yh2KP01kzAR/dpuMeUnocoLYDcskw==", + "dev": true, + "dependencies": { + "is-stream": "^2.0.0", + "type-fest": "^0.8.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "dependencies": { + "parse-passwd": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/i18next": { + "version": "21.8.2", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-21.8.2.tgz", + "integrity": "sha512-H/oQvA/OXcqurXHemlyDwdIzr9GHYg5/xBuDeFXTXJGMOJFH0ke1wgbsDjFFk2noD4cJfzicVPpUtp39Z+OzgQ==", + "funding": [ + { + "type": "individual", + "url": "https://locize.com" + }, + { + "type": "individual", + "url": "https://locize.com/i18next.html" + }, + { + "type": "individual", + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + } + ], + "dependencies": { + "@babel/runtime": "^7.17.2" + } + }, + "node_modules/idb": { + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/idb/-/idb-6.1.5.tgz", + "integrity": "sha512-IJtugpKkiVXQn5Y+LteyBCNk1N8xpGV3wWZk9EVtZWH8DYkjBn0bX1XnGP9RkyZF0sAcywa6unHqSWKe7q4LGw==" + }, + "node_modules/immutable": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.0.tgz", + "integrity": "sha512-0AOCmOip+xgJwEVTQj1EfiDDOkPmuyllDuTuEX+DDXUgapLAsBIfkg3sxCYyCEA8mQqZrrxPUGjcOQ2JS3WLkg==", + "dev": true + }, + "node_modules/import-local": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", + "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "dev": true, + "dependencies": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-arguments": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.0.tgz", + "integrity": "sha512-1Ij4lOMPl/xB5kBDn7I+b2ttPMKa8szhEIrXDuXQD/oe3HJLTLhqhgGspwgyGd6MOywBUqVvYicF72lkgDnIHg==", + "dependencies": { + "call-bind": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "node_modules/is-bigint": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz", + "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==" + }, + "node_modules/is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "dependencies": { + "binary-extensions": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.0.tgz", + "integrity": "sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA==", + "dependencies": { + "call-bind": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "node_modules/is-callable": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.1.tgz", + "integrity": "sha512-wliAfSzx6V+6WfMOmus1xy0XvSgf/dlStkvTfq7F0g4bOIW0PSUbnyse3NhDwdyYS1ozfUtAAySqTws3z9Eqgg==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-descriptor/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", + "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==" + }, + "node_modules/is-negated-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", + "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz", + "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz", + "integrity": "sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "dependencies": { + "has-symbols": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "dev": true, + "dependencies": { + "is-unc-path": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-set": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", + "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==" + }, + "node_modules/is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dependencies": { + "has-symbols": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.5.tgz", + "integrity": "sha512-S+GRDgJlR3PyEbsX/Fobd9cqpZBuvUS+8asRqYDMLCb2qMzt1oz5m5oxQCxOgUDxiWsOVNi4yaF+/uvdlHlYug==", + "dependencies": { + "available-typed-arrays": "^1.0.2", + "call-bind": "^1.0.2", + "es-abstract": "^1.18.0-next.2", + "foreach": "^2.0.5", + "has-symbols": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-typed-array/node_modules/es-abstract": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz", + "integrity": "sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==", + "dependencies": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "is-callable": "^1.2.3", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.2", + "is-string": "^1.0.5", + "object-inspect": "^1.9.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-typed-array/node_modules/is-callable": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", + "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-typed-array/node_modules/is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-typed-array/node_modules/is-regex": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz", + "integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==", + "dependencies": { + "call-bind": "^1.0.2", + "has-symbols": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-typed-array/node_modules/object-inspect": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.2.tgz", + "integrity": "sha512-gz58rdPpadwztRrPjZE9DZLOABUpTGdcANUgOwBFO1C+HZZhePoP83M65WGDmbpwFYJSWqavbl4SgDn4k8RYTA==" + }, + "node_modules/is-typed-array/node_modules/object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-typed-array/node_modules/string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "node_modules/is-typed-array/node_modules/string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "node_modules/is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "dev": true, + "dependencies": { + "unc-path-regex": "^0.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "node_modules/is-valid-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz", + "integrity": "sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", + "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==" + }, + "node_modules/is-weakset": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.1.tgz", + "integrity": "sha512-pi4vhbhVHGLxohUw7PhGsueT4vRGFoXhP7+RGN0jKIv9+8PWYCQTqtADngrxOm2g46hoH0+g8uZZBzMrvVGDmw==" + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/ismobilejs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ismobilejs/-/ismobilejs-1.1.1.tgz", + "integrity": "sha512-VaFW53yt8QO61k2WJui0dHf4SlL8lxBofUuUmwBo0ljPk0Drz2TiuDW4jo3wDcv41qy/SxrJ+VAzJ/qYqsmzRw==" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", + "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-hook": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", + "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", + "dev": true, + "dependencies": { + "append-transform": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/istanbul-lib-processinfo": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz", + "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==", + "dev": true, + "dependencies": { + "archy": "^1.0.0", + "cross-spawn": "^7.0.0", + "istanbul-lib-coverage": "^3.0.0-alpha.1", + "make-dir": "^3.0.0", + "p-map": "^3.0.0", + "rimraf": "^3.0.0", + "uuid": "^3.3.3" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", + "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-reports": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", + "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-logic-js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/json-logic-js/-/json-logic-js-2.0.1.tgz", + "integrity": "sha512-J3hhqM4IY66sL8qyzU7cwLmTAt3kA6ZsYxyuZBEwhcc+OYPTmAHc64fBTXHT6K5RwFeUqJUX1tfO7wpKsUx+9A==" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jstimezonedetect": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/jstimezonedetect/-/jstimezonedetect-1.0.7.tgz", + "integrity": "sha512-ARADHortktl9IZ1tr4GHwGPIAzgz3mLNCbR/YjWtRtc/O0o634O3NeFlpLjv95EvuDA5dc8z6yfgbS8nUc4zcQ==" + }, + "node_modules/just-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.0.0.tgz", + "integrity": "sha1-h/zPrv/AtozRnVX2cilD+SnqNeo=", + "dev": true + }, + "node_modules/just-extend": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", + "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", + "dev": true + }, + "node_modules/jwt-decode": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", + "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/last-run": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", + "integrity": "sha1-RblpQsF7HHnHchmCWbqUO+v4yls=", + "dev": true, + "dependencies": { + "default-resolution": "^2.0.0", + "es6-weak-map": "^2.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/lazystream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", + "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", + "dev": true, + "dependencies": { + "readable-stream": "^2.0.5" + }, + "engines": { + "node": ">= 0.6.3" + } + }, + "node_modules/lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "dependencies": { + "invert-kv": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lead": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", + "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=", + "dev": true, + "dependencies": { + "flush-write-stream": "^1.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/liftoff": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", + "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", + "dev": true, + "dependencies": { + "extend": "^3.0.0", + "findup-sync": "^3.0.0", + "fined": "^1.0.1", + "flagged-respawn": "^1.0.0", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.0", + "rechoir": "^0.6.2", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", + "dev": true + }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/loupe": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.4.tgz", + "integrity": "sha512-OvKfgCC2Ndby6aSTREl5aCCPTNIzlDfQZvZxNUrBrihDhL3xcrYegTblhmEiCrg2kKQz4XsFIaemE5BF4ybSaQ==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.0" + } + }, + "node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/make-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "dependencies": { + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matchdep": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", + "integrity": "sha1-xvNINKDY28OzfCfui7yyfHd1WC4=", + "dev": true, + "dependencies": { + "findup-sync": "^2.0.0", + "micromatch": "^3.0.4", + "resolve": "^1.4.0", + "stack-trace": "0.0.10" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/matchdep/node_modules/findup-sync": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", + "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "dev": true, + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^3.1.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/matchdep/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mime-db": { + "version": "1.47.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz", + "integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.30", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz", + "integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==", + "dependencies": { + "mime-db": "1.47.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "dependencies": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mixin-deep/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mocha": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", + "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==", + "dev": true, + "dependencies": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.3", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "4.2.1", + "ms": "2.1.3", + "nanoid": "3.3.1", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "workerpool": "6.2.0", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mocha/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/mocha/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/mocha/node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/mocha/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/mocha/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/mocha/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/mocha/node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/mocha/node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/mocha/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/mocha/node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/mocha/node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/mocha/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/mocha/node_modules/minimatch": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", + "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/mocha/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/mocha/node_modules/string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/mocha/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/mocha/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha/node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "engines": { + "node": "*" + } + }, + "node_modules/moment-timezone": { + "version": "0.5.43", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.43.tgz", + "integrity": "sha512-72j3aNyuIsDxdF1i7CEgV2FfxM1r6aaqJyLB2vwb33mXYyoyLly+F1zbWqhA3/bVIoJ4szlUoMbUnVdid32NUQ==", + "dependencies": { + "moment": "^2.29.4" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/mute-stdout": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz", + "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/nan": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", + "dev": true, + "optional": true + }, + "node_modules/nanoid": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", + "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/native-promise-only": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/native-promise-only/-/native-promise-only-0.8.1.tgz", + "integrity": "sha1-IKMYwwy0X3H+et+/eyHJnBRy7xE=" + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "dev": true + }, + "node_modules/nise": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/nise/-/nise-4.1.0.tgz", + "integrity": "sha512-eQMEmGN/8arp0xsvGoQ+B1qvSkR73B1nWSCh7nOt5neMCtwcQVYQGdzQMhcNscktTsWB54xnlSQFzOAPJD8nXA==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0", + "@sinonjs/fake-timers": "^6.0.0", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + } + }, + "node_modules/nise/node_modules/@sinonjs/fake-timers": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", + "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/node-fetch": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-preload": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", + "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", + "dev": true, + "dependencies": { + "process-on-spawn": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/node-releases": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/now-and-later": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", + "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==", + "dev": true, + "dependencies": { + "once": "^1.3.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nyc": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", + "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", + "dev": true, + "dependencies": { + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "caching-transform": "^4.0.0", + "convert-source-map": "^1.7.0", + "decamelize": "^1.2.0", + "find-cache-dir": "^3.2.0", + "find-up": "^4.1.0", + "foreground-child": "^2.0.0", + "get-package-type": "^0.1.0", + "glob": "^7.1.6", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-hook": "^3.0.0", + "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-processinfo": "^2.0.2", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "make-dir": "^3.0.0", + "node-preload": "^0.2.1", + "p-map": "^3.0.0", + "process-on-spawn": "^1.0.0", + "resolve-from": "^5.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "spawn-wrap": "^2.0.0", + "test-exclude": "^6.0.0", + "yargs": "^15.0.2" + }, + "bin": { + "nyc": "bin/nyc.js" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/nyc/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "dependencies": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/nyc/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/nyc/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/nyc/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/nyc/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/nyc/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "node_modules/nyc/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/nyc/node_modules/string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "node_modules/nyc/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/y18n": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", + "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", + "dev": true + }, + "node_modules/nyc/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "dependencies": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", + "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", + "dev": true + }, + "node_modules/object-is": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", + "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "dependencies": { + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.1.tgz", + "integrity": "sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.0", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.defaults": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", + "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", + "dev": true, + "dependencies": { + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", + "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", + "dev": true, + "dependencies": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.reduce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz", + "integrity": "sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60=", + "dev": true, + "dependencies": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/ordered-read-streams": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", + "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=", + "dev": true, + "dependencies": { + "readable-stream": "^2.0.1" + } + }, + "node_modules/os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "dev": true, + "dependencies": { + "lcid": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/os-shim": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz", + "integrity": "sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc=", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/package-hash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", + "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.15", + "hasha": "^5.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/parchment": { + "version": "2.0.0-dev.2", + "resolved": "https://registry.npmjs.org/parchment/-/parchment-2.0.0-dev.2.tgz", + "integrity": "sha512-4fgRny4pPISoML08Zp7poi52Dff3E2G1ORTi2D/acJ/RiROdDAMDB6VcQNfBcmehrX5Wixp6dxh6JjLyE5yUNQ==" + }, + "node_modules/parse-filepath": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", + "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", + "dev": true, + "dependencies": { + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "dependencies": { + "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" + }, + "node_modules/path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "dependencies": { + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-root": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", + "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", + "dev": true, + "dependencies": { + "path-root-regex": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-root-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", + "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "dev": true, + "dependencies": { + "isarray": "0.0.1" + } + }, + "node_modules/path-to-regexp/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "node_modules/path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/plugin-error": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz", + "integrity": "sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4=", + "dev": true, + "dependencies": { + "ansi-cyan": "^0.1.1", + "ansi-red": "^0.1.1", + "arr-diff": "^1.0.1", + "arr-union": "^2.0.1", + "extend-shallow": "^1.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/plugin-error/node_modules/arr-diff": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz", + "integrity": "sha1-aHwydYFjWI/vfeezb6vklesaOZo=", + "dev": true, + "dependencies": { + "arr-flatten": "^1.0.1", + "array-slice": "^0.2.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/plugin-error/node_modules/arr-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz", + "integrity": "sha1-IPnqtexw9cfSFbEHexw5Fh0pLH0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/plugin-error/node_modules/array-slice": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz", + "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/plugin-error/node_modules/extend-shallow": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz", + "integrity": "sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE=", + "dev": true, + "dependencies": { + "kind-of": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/plugin-error/node_modules/kind-of": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz", + "integrity": "sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss": { + "version": "8.4.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz", + "integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss/node_modules/nanoid": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", + "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/pre-commit": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/pre-commit/-/pre-commit-1.2.2.tgz", + "integrity": "sha1-287g7p3nI15X95xW186UZBpp7sY=", + "dev": true, + "dependencies": { + "cross-spawn": "^5.0.1", + "spawn-sync": "^1.0.15", + "which": "1.2.x" + } + }, + "node_modules/pre-commit/node_modules/cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "dependencies": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "node_modules/pre-commit/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pre-commit/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pre-commit/node_modules/which": { + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", + "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/process-on-spawn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", + "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", + "dev": true, + "dependencies": { + "fromentries": "^1.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "node_modules/pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "dependencies": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + } + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/quill": { + "version": "2.0.0-dev.4", + "resolved": "https://registry.npmjs.org/quill/-/quill-2.0.0-dev.4.tgz", + "integrity": "sha512-9WmMVCEIhf3lDdhzl+i+GBDeDl0BFi65waC4Im8Y4HudEJ9kEEb1lciAz9A8pcDmLMjiMbvz84lNt/U5OBS8Vg==", + "dependencies": { + "clone": "^2.1.2", + "deep-equal": "^2.0.2", + "eventemitter3": "^4.0.0", + "extend": "^3.0.2", + "parchment": "2.0.0-dev.2", + "quill-delta": "4.2.1" + } + }, + "node_modules/quill-delta": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-4.2.1.tgz", + "integrity": "sha512-Y2nksOj6Q+4hizre8n0dml76vLNGK4/y86EoI1d7rv6EL1bx7DPDYRmqQMPu1UqFQO/uQuVHQ3fOmm4ZSzWrfA==", + "dependencies": { + "deep-equal": "^1.0.1", + "extend": "^3.0.2", + "fast-diff": "1.2.0" + } + }, + "node_modules/quill-delta/node_modules/deep-equal": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", + "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "dependencies": { + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.1", + "is-regex": "^1.0.4", + "object-is": "^1.0.1", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.2.0" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "dependencies": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "dependencies": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/redux": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.0.tgz", + "integrity": "sha512-uI2dQN43zqLWCt6B/BMGRMY6db7TTY4qeHHfGeKb3EOhmOKjU3KdWvNLJyqaHRksv/ErdNH7cFZWg9jXtewy4g==", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" + }, + "node_modules/regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "dependencies": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regexp.prototype.flags": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", + "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", + "dev": true, + "dependencies": { + "es6-error": "^4.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/remove-bom-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", + "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5", + "is-utf8": "^0.2.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/remove-bom-stream": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz", + "integrity": "sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=", + "dev": true, + "dependencies": { + "remove-bom-buffer": "^3.0.0", + "safe-buffer": "^5.1.0", + "through2": "^2.0.3" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "node_modules/repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/replace-ext": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz", + "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/replace-homedir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz", + "integrity": "sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw=", + "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1", + "is-absolute": "^1.0.0", + "remove-trailing-separator": "^1.1.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, + "node_modules/resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" + }, + "node_modules/resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "dependencies": { + "path-parse": "^1.0.6" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-options": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz", + "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=", + "dev": true, + "dependencies": { + "value-or-function": "^3.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/rollup": { + "version": "3.21.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.21.5.tgz", + "integrity": "sha512-a4NTKS4u9PusbUJcfF4IMxuqjFzjm6ifj76P54a7cKnvVzJaG12BLVR+hgU2YDGHzyMMQNxLAZWuALsn8q2oQg==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "dependencies": { + "ret": "~0.1.10" + } + }, + "node_modules/sass": { + "version": "1.62.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.62.0.tgz", + "integrity": "sha512-Q4USplo4pLYgCi+XlipZCWUQz5pkg/ruSSgJ0WRDSb/+3z9tXUOkQ7QPYn4XrhZKYAK4HlpaQecRwKLJX6+DBg==", + "dev": true, + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass/node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/sass/node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/sass/node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sass/node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/sass/node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sass/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/sass/node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sass/node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/sass/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/sass/node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/schema-utils": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.2.tgz", + "integrity": "sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg==", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/semver-greatest-satisfied-range": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz", + "integrity": "sha1-E+jCZYq5aRywzXEJMkAoDTb3els=", + "dev": true, + "dependencies": { + "sver-compat": "^1.5.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "node_modules/set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-value/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "node_modules/side-channel/node_modules/object-inspect": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.2.tgz", + "integrity": "sha512-gz58rdPpadwztRrPjZE9DZLOABUpTGdcANUgOwBFO1C+HZZhePoP83M65WGDmbpwFYJSWqavbl4SgDn4k8RYTA==" + }, + "node_modules/signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "node_modules/signature_pad": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/signature_pad/-/signature_pad-2.3.2.tgz", + "integrity": "sha512-peYXLxOsIY6MES2TrRLDiNg2T++8gGbpP2yaC+6Ohtxr+a2dzoaqWosWDY9sWqTAAk6E/TyQO+LJw9zQwyu5kA==" + }, + "node_modules/sinon": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-12.0.1.tgz", + "integrity": "sha512-iGu29Xhym33ydkAT+aNQFBINakjq69kKO6ByPvTsm3yyIACfyQttRTP03aBP/I8GfhFmLzrnKwNNkr0ORb1udg==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.8.3", + "@sinonjs/fake-timers": "^8.1.0", + "@sinonjs/samsam": "^6.0.2", + "diff": "^5.0.0", + "nise": "^5.1.0", + "supports-color": "^7.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/sinon" + } + }, + "node_modules/sinon/node_modules/@sinonjs/fake-timers": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", + "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/sinon/node_modules/@sinonjs/samsam": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-6.0.2.tgz", + "integrity": "sha512-jxPRPp9n93ci7b8hMfJOFDPRLFYadN6FSpeROFTR4UNF4i5b+EK6m4QXPO46BDhFgRy1JuS87zAnFOzCUwMJcQ==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.6.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "node_modules/sinon/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/sinon/node_modules/nise": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.0.tgz", + "integrity": "sha512-W5WlHu+wvo3PaKLsJJkgPup2LrsXCcm7AWwyNZkUnn5rwPkuPBi3Iwk5SQtN0mv+K65k7nKKjwNQ30wg3wLAQQ==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0", + "@sinonjs/fake-timers": "^7.0.4", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + } + }, + "node_modules/sinon/node_modules/nise/node_modules/@sinonjs/fake-timers": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-7.1.2.tgz", + "integrity": "sha512-iQADsW4LBMISqZ6Ci1dupJL9pprqwcVFTcOsEmQOEhW+KLCVn/Y4Jrvg2k19fIHCp+iFprriYPTdRcQR8NbUPg==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/sinon/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "dependencies": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "dependencies": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "dependencies": { + "kind-of": "^3.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "dev": true, + "dependencies": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "node_modules/sparkles": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", + "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/spawn-sync": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz", + "integrity": "sha1-sAeZVX63+wyDdsKdROih6mfldHY=", + "dev": true, + "dependencies": { + "concat-stream": "^1.4.7", + "os-shim": "^0.1.2" + } + }, + "node_modules/spawn-wrap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", + "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", + "dev": true, + "dependencies": { + "foreground-child": "^2.0.0", + "is-windows": "^1.0.2", + "make-dir": "^3.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "which": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/spawn-wrap/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/spawn-wrap/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "dev": true + }, + "node_modules/split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "dependencies": { + "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "dependencies": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stream-exhaust": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", + "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==", + "dev": true + }, + "node_modules/stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", + "dev": true + }, + "node_modules/streamqueue": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/streamqueue/-/streamqueue-0.0.6.tgz", + "integrity": "sha1-ZvX17JTpuK8knkrsLdH3Qb/pTeM=", + "dev": true, + "dependencies": { + "readable-stream": "^1.0.26-2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/streamqueue/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "node_modules/streamqueue/node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/streamqueue/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-hash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", + "integrity": "sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs=" + }, + "node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trimend/node_modules/es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "dependencies": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trimstart/node_modules/es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "dependencies": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "dependencies": { + "is-utf8": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/supports-color/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/sver-compat": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz", + "integrity": "sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg=", + "dev": true, + "dependencies": { + "es6-iterator": "^2.0.1", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/terser": { + "version": "5.17.4", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.17.4.tgz", + "integrity": "sha512-jcEKZw6UPrgugz/0Tuk/PVyLAPfMBJf5clnGueo45wTweoV8yh7Q7PEkhkJ5uuUbC7zAxEcG3tqNr1bstkQ8nw==", + "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.8", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.8.tgz", + "integrity": "sha512-WiHL3ElchZMsK27P8uIUh4604IgJyAW47LVXGbEoB21DbQcZ+OuMpGjVYnEUaqcWM6dO8uS2qUbA7LSCWqvsbg==", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.17", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.16.8" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", + "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/terser-webpack-plugin/node_modules/serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-mask-addons": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/text-mask-addons/-/text-mask-addons-3.8.0.tgz", + "integrity": "sha1-F7Ye9mWk82gR8uofAaIjtL5hqyY=" + }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/through2-filter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", + "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", + "dev": true, + "dependencies": { + "through2": "~2.0.0", + "xtend": "~4.0.0" + } + }, + "node_modules/ticky": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ticky/-/ticky-1.0.1.tgz", + "integrity": "sha1-t8+nHnaPHJAAxJe5FRswlHxQ5G0=" + }, + "node_modules/time-stamp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", + "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tippy.js": { + "version": "6.3.7", + "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz", + "integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==", + "dependencies": { + "@popperjs/core": "^2.9.0" + } + }, + "node_modules/to-absolute-glob": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", + "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=", + "dev": true, + "dependencies": { + "is-absolute": "^1.0.0", + "is-negated-glob": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-object-path/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "dependencies": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-through": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", + "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=", + "dev": true, + "dependencies": { + "through2": "^2.0.3" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/ts-node": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.8.2.tgz", + "integrity": "sha512-LYdGnoGddf1D6v8REPtIH+5iq/gTDuZqv2/UJUU7tKjuEU8xVZorBM+buCGNjj+pGEud+sOoM4CX3/YzINpENA==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/ts-sinon": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ts-sinon/-/ts-sinon-2.0.2.tgz", + "integrity": "sha512-Eh6rXPQruACHPn+/e5HsIMaHZa17tGP/scGjUeW5eJ/Levn8hBV6zSP/6QkEDUP7wLkTyY0yeYikjpTzgC9Gew==", + "dev": true, + "dependencies": { + "@types/node": "^14.6.1", + "@types/sinon": "^9.0.5", + "@types/sinon-chai": "^3.2.4", + "sinon": "^9.0.3" + } + }, + "node_modules/ts-sinon/node_modules/@sinonjs/fake-timers": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", + "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/ts-sinon/node_modules/@types/node": { + "version": "14.14.43", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.43.tgz", + "integrity": "sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ==", + "dev": true + }, + "node_modules/ts-sinon/node_modules/@types/sinon": { + "version": "9.0.11", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-9.0.11.tgz", + "integrity": "sha512-PwP4UY33SeeVKodNE37ZlOsR9cReypbMJOhZ7BVE0lB+Hix3efCOxiJWiE5Ia+yL9Cn2Ch72EjFTRze8RZsNtg==", + "dev": true, + "dependencies": { + "@types/sinonjs__fake-timers": "*" + } + }, + "node_modules/ts-sinon/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/ts-sinon/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-sinon/node_modules/sinon": { + "version": "9.2.4", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.2.4.tgz", + "integrity": "sha512-zljcULZQsJxVra28qIAL6ow1Z9tpattkCTEJR4RBP3TGc00FcttsP5pK284Nas5WjMZU5Yzy3kAIp3B3KRf5Yg==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.8.1", + "@sinonjs/fake-timers": "^6.0.1", + "@sinonjs/samsam": "^5.3.1", + "diff": "^4.0.2", + "nise": "^4.0.4", + "supports-color": "^7.1.0" + } + }, + "node_modules/ts-sinon/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tslib": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", + "dev": true + }, + "node_modules/tslint": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", + "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^4.0.1", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.3", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.13.0", + "tsutils": "^2.29.0" + }, + "bin": { + "tslint": "bin/tslint" + }, + "engines": { + "node": ">=4.8.0" + } + }, + "node_modules/tslint/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + } + }, + "node_modules/type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typescript": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "dependencies": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + } + }, + "node_modules/unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/undertaker": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.3.0.tgz", + "integrity": "sha512-/RXwi5m/Mu3H6IHQGww3GNt1PNXlbeCuclF2QYR14L/2CHPz3DFZkvB5hZ0N/QUkiXWCACML2jXViIQEQc2MLg==", + "dev": true, + "dependencies": { + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "bach": "^1.0.0", + "collection-map": "^1.0.0", + "es6-weak-map": "^2.0.1", + "fast-levenshtein": "^1.0.0", + "last-run": "^1.1.0", + "object.defaults": "^1.0.0", + "object.reduce": "^1.0.0", + "undertaker-registry": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/undertaker-registry": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz", + "integrity": "sha1-XkvaMI5KiirlhPm5pDWaSZglzFA=", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "dependencies": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unique-stream": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", + "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", + "dev": true, + "dependencies": { + "json-stable-stringify-without-jsonify": "^1.0.1", + "through2-filter": "^3.0.0" + } + }, + "node_modules/unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "dependencies": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "dependencies": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "dependencies": { + "isarray": "1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "dev": true, + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "node_modules/use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/v8flags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", + "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", + "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/value-or-function": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz", + "integrity": "sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vanilla-picker": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/vanilla-picker/-/vanilla-picker-2.12.1.tgz", + "integrity": "sha512-2qrEP9VYylKXbyzXKsbu2dferBTvqnlsr29XjHwFE+/MEp0VNj6oEUESLDtKZ7DWzGdSv1x/+ujqFZF+KsO3cg==", + "dependencies": { + "@sphinxxxx/color-conversion": "^2.2.2" + } + }, + "node_modules/vinyl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz", + "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==", + "dev": true, + "dependencies": { + "clone": "^2.1.1", + "clone-buffer": "^1.0.0", + "clone-stats": "^1.0.0", + "cloneable-readable": "^1.0.0", + "remove-trailing-separator": "^1.0.1", + "replace-ext": "^1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vinyl-fs": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz", + "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==", + "dev": true, + "dependencies": { + "fs-mkdirp-stream": "^1.0.0", + "glob-stream": "^6.1.0", + "graceful-fs": "^4.0.0", + "is-valid-glob": "^1.0.0", + "lazystream": "^1.0.0", + "lead": "^1.0.0", + "object.assign": "^4.0.4", + "pumpify": "^1.3.5", + "readable-stream": "^2.3.3", + "remove-bom-buffer": "^3.0.0", + "remove-bom-stream": "^1.2.0", + "resolve-options": "^1.1.0", + "through2": "^2.0.0", + "to-through": "^2.0.0", + "value-or-function": "^3.0.0", + "vinyl": "^2.0.0", + "vinyl-sourcemap": "^1.1.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vinyl-sourcemap": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", + "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=", + "dev": true, + "dependencies": { + "append-buffer": "^1.0.2", + "convert-source-map": "^1.5.0", + "graceful-fs": "^4.1.6", + "normalize-path": "^2.1.1", + "now-and-later": "^2.0.0", + "remove-bom-buffer": "^3.0.0", + "vinyl": "^2.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vinyl-sourcemap/node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/vite": { + "version": "4.3.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz", + "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==", + "dev": true, + "dependencies": { + "esbuild": "^0.17.5", + "postcss": "^8.4.23", + "rollup": "^3.21.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/webpack": { + "version": "5.83.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.83.1.tgz", + "integrity": "sha512-TNsG9jDScbNuB+Lb/3+vYolPplCS3bbEaJf+Bj0Gw4DhP3ioAflBb1flcRt9zsWITyvOhM96wMQNRWlSX52DgA==", + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.0", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.14.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.2", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.7", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz", + "integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==", + "dev": true, + "dependencies": { + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^1.2.0", + "@webpack-cli/info": "^1.5.0", + "@webpack-cli/serve": "^1.7.0", + "colorette": "^2.0.14", + "commander": "^7.0.0", + "cross-spawn": "^7.0.3", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^2.2.0", + "rechoir": "^0.7.0", + "webpack-merge": "^5.7.3" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "4.x.x || 5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "@webpack-cli/migrate": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/@webpack-cli/configtest": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz", + "integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==", + "dev": true, + "peerDependencies": { + "webpack": "4.x.x || 5.x.x", + "webpack-cli": "4.x.x" + } + }, + "node_modules/webpack-cli/node_modules/@webpack-cli/info": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz", + "integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==", + "dev": true, + "dependencies": { + "envinfo": "^7.7.3" + }, + "peerDependencies": { + "webpack-cli": "4.x.x" + } + }, + "node_modules/webpack-cli/node_modules/@webpack-cli/serve": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz", + "integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==", + "dev": true, + "peerDependencies": { + "webpack-cli": "4.x.x" + }, + "peerDependenciesMeta": { + "webpack-dev-server": { + "optional": true + } + } + }, + "node_modules/webpack-cli/node_modules/colorette": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", + "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", + "dev": true + }, + "node_modules/webpack-cli/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/webpack-cli/node_modules/interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/webpack-cli/node_modules/rechoir": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.0.tgz", + "integrity": "sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q==", + "dev": true, + "dependencies": { + "resolve": "^1.9.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/webpack-merge": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.7.3.tgz", + "integrity": "sha512-6/JUQv0ELQ1igjGDzHkXbVDRxkfA57Zw7PfiupdLFJYrgFqY5ZP8xxbpp2lU3EPwYx89ht5Z/aDkD40hFCm5AA==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "node_modules/which-collection": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", + "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", + "dependencies": { + "is-map": "^2.0.1", + "is-set": "^2.0.1", + "is-weakmap": "^2.0.1", + "is-weakset": "^2.0.1" + } + }, + "node_modules/which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", + "dev": true + }, + "node_modules/which-typed-array": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.4.tgz", + "integrity": "sha512-49E0SpUe90cjpoc7BOJwyPHRqSAd12c10Qm2amdEZrJPCY2NDxaW01zHITrem+rnETY3dwrbH3UUrUwagfCYDA==", + "dependencies": { + "available-typed-arrays": "^1.0.2", + "call-bind": "^1.0.0", + "es-abstract": "^1.18.0-next.1", + "foreach": "^2.0.5", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.1", + "is-typed-array": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/which-typed-array/node_modules/es-abstract": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz", + "integrity": "sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==", + "dependencies": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "is-callable": "^1.2.3", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.2", + "is-string": "^1.0.5", + "object-inspect": "^1.9.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/which-typed-array/node_modules/is-callable": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", + "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/which-typed-array/node_modules/is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/which-typed-array/node_modules/is-regex": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz", + "integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==", + "dependencies": { + "call-bind": "^1.0.2", + "has-symbols": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/which-typed-array/node_modules/object-inspect": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.2.tgz", + "integrity": "sha512-gz58rdPpadwztRrPjZE9DZLOABUpTGdcANUgOwBFO1C+HZZhePoP83M65WGDmbpwFYJSWqavbl4SgDn4k8RYTA==" + }, + "node_modules/which-typed-array/node_modules/object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/which-typed-array/node_modules/string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "node_modules/which-typed-array/node_modules/string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "node_modules/wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "dev": true + }, + "node_modules/workerpool": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", + "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", + "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==", + "dev": true + }, + "node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "node_modules/yargs": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.1.tgz", + "integrity": "sha512-huO4Fr1f9PmiJJdll5kwoS2e4GqzGSsMT3PPMpOwoVkOK8ckqAewMTZyA6LXVQWflleb/Z8oPBEvNsMft0XE+g==", + "dev": true, + "dependencies": { + "camelcase": "^3.0.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "y18n": "^3.2.1", + "yargs-parser": "5.0.0-security.0" + } + }, + "node_modules/yargs-parser": { + "version": "5.0.0-security.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0-security.0.tgz", + "integrity": "sha512-T69y4Ps64LNesYxeYGYPvfoMTt/7y1XtfpIslUeK4um+9Hu7hlGoRtaDLvdXb7+/tfq4opVa2HRY5xGip022rQ==", + "dev": true, + "dependencies": { + "camelcase": "^3.0.0", + "object.assign": "^4.1.0" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser/node_modules/camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser/node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + } + } + } +} diff --git a/frontend/components/package.json b/frontend/components/package.json new file mode 100644 index 0000000..a0cb087 --- /dev/null +++ b/frontend/components/package.json @@ -0,0 +1,84 @@ +{ + "name": "@bcgov/formio", + "version": "1.0.0", + "description": "bcgov components for form.io", + "repository": { + "type": "git", + "url": "git+https://github.com/bcgov/common-hosted-form-service.git" + }, + "author": "Forminators <submit.digital@gov.bc.ca>", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/bcgov/common-hosted-form-service/issues" + }, + "homepage": "https://bcgov.github.io/common-hosted-form-service", + "contributors": [ + { + "name": "Jason Sherman", + "email": "jsherman@parcsystems.ca" + } + ], + "private": true, + "main": "lib/index.js", + "module": "node", + "scripts": { + "test:coverage": "nyc --reporter=text mocha --reporter spec './{,!(node_modules)/**/}*.spec.js'", + "test": "mocha --require ts-node/register --reporter spec './{,!(node_modules)/**/}*.spec.ts'", + "watch": "tsc -w", + "webpack:dev": "webpack", + "webpack:prod": "webpack --config webpack.prod.js", + "webpack:use": "webpack --config webpack.use.js", + "webpack": "npm run webpack:dev && npm run webpack:prod && npm run webpack:use", + "build": "tsc && gulp templates && npm run webpack && sass ./src/sass/contrib.scss ./dist/bcgov-formio-components.css", + "clean": "rm -rf coverage dist lib", + "purge": "rm -rf node_modules", + "lint": "tslint -p ." + }, + "pre-commit": [ + "lint", + "test" + ], + "files": [ + "dist", + "lib" + ], + "keywords": [ + "Form.io", + "components" + ], + "dependencies": { + "autocompleter": "^7.0.1", + "formiojs": "^4.14.6", + "lodash": "^4.17.21", + "native-promise-only": "^0.8.1", + "path-browserify": "^1.0.1", + "webpack": "^5.75.0" + }, + "devDependencies": { + "@types/chai": "^4.3.1", + "@types/ejs": "^3.1.1", + "@types/mocha": "^9.1.1", + "@types/node": "^16.11.8", + "@types/sinon": "^10.0.12", + "chai": "^4.3.6", + "glob-parent": "^6.0.2", + "gulp": "^4.0.2", + "gulp-insert": "^0.5.0", + "gulp-rename": "^2.0.0", + "gulp-template": "^5.0.0", + "mocha": "^9.1.3", + "nyc": "^15.0.1", + "pre-commit": "^1.2.2", + "sass": "^1.62.0", + "sinon": "^12.0.1", + "ts-node": "^10.8.2", + "ts-sinon": "^2.0.2", + "tslint": "^6.1.3", + "typescript": "^4.7.4", + "vite": "^4.3.5", + "webpack-cli": "^4.10.0" + }, + "overrides": { + "glob-parent": "$glob-parent" + } +} diff --git a/frontend/components/src/components/BCAddress/Component.form.ts b/frontend/components/src/components/BCAddress/Component.form.ts new file mode 100644 index 0000000..305a569 --- /dev/null +++ b/frontend/components/src/components/BCAddress/Component.form.ts @@ -0,0 +1,13 @@ +import baseEditForm from 'formiojs/components/_classes/component/Component.form'; +import AddressEditProvider from './editForm/Address.edit.provider'; + +export default function(...extend) { + return baseEditForm([ + { + label: 'Provider', + key: 'provider', + weight: 150, + components: AddressEditProvider, + }, + ], ...extend); +} diff --git a/frontend/components/src/components/BCAddress/Component.ts b/frontend/components/src/components/BCAddress/Component.ts new file mode 100644 index 0000000..9e4e32c --- /dev/null +++ b/frontend/components/src/components/BCAddress/Component.ts @@ -0,0 +1,95 @@ + +/* tslint:disable */ +import {Components} from 'formiojs'; +import { Constants } from '../Common/Constants'; +import editForm from './Component.form'; +import _ from 'lodash'; + +export const AddressComponentMode = { + Autocomplete: 'autocomplete', + Manual: 'manual', +}; + +const ParentComponent = (Components as any).components.address; + +const ID = 'bcaddress'; +const DISPLAY = 'BC Address'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + + return ParentComponent.schema({ + label: DISPLAY, + type: ID, + key: ID, + provider: 'custom', + providerOptions: { + queryProperty: 'addressString', + + url: import.meta.env.VITE_CHEFS_ADVANCE_GEO_ADDRESS_APIURL}, + + queryParameters:{"echo": false, + "brief": true, + "minScore": 55, + "onlyCivic": true, + "maxResults": 15, + "autocomplete": true, + "matchAccuracy": 100, + "matchPrecision": "occupant, unit, site, civic_number, intersection, block, street, locality, province", + "precisionPoints": 100,} + + }, ...extend); + } + + static get builderInfo() { + return { + title: DISPLAY, + group: 'advanced', + icon: 'address-book', + weight: 90, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } + + mergeSchema(component = {}) { + + let components = component['components']; + + if (components) { + return _.omit(component, 'components'); + } + + return component; + } + + public static editForm = editForm; + + async init(){ + super.init(); + } + + async attach(element) { + super.attach(element); + try { + + let { + providerOptions, + queryParameters, + } = this.component; + if(providerOptions) { + if(!providerOptions.params) { + providerOptions["params"]={} + } + if(queryParameters) { + providerOptions.params ={...providerOptions.params,...queryParameters} + } + } + + } catch (err) { + console.log(`This error is from Custom BC Address component in form.io: Failed to acquire configuration: ${err.message}`); + } + } + +} +export {}; diff --git a/frontend/components/src/components/BCAddress/editForm/Address.edit.provider.ts b/frontend/components/src/components/BCAddress/editForm/Address.edit.provider.ts new file mode 100644 index 0000000..9e7f51d --- /dev/null +++ b/frontend/components/src/components/BCAddress/editForm/Address.edit.provider.ts @@ -0,0 +1,48 @@ +import _ from 'lodash'; + +export default [ + { + type: 'textfield', + input: true, + defaultValue: 'features', + key: 'providerOptions.responseProperty', + label: 'Response Property', + placeholder: 'Enter Response Property', + weight: 30, + tooltip: 'The property within the response data, where iterable addresses reside. For example: results.', + }, + { + type: 'textfield', + input: true, + defaultValue: 'properties.fullAddress', + key: 'providerOptions.displayValueProperty', + label: 'Display Value Property', + placeholder: 'Display Value Property', + weight: 40, + tooltip: 'The property of each address in the response to use as the display value.', + }, + { + type: 'textarea', + input: true, + key: 'queryParameters', + label: 'Params', + placeholder: '{ ... }', + weight: 50, + rows: 5, + editor: 'ace', + as: 'json', + tooltip: 'Additional query params can be specified here in a way of JSON object.', + }, + { + type: 'textarea', + input: true, + key: 'manualModeViewString', + label: 'Manual Mode View String', + placeholder: 'Enter Manual Mode View String', + description: '"address" variable references component value, "data" - submission data and "component" - address component schema.', + weight: 60, + rows: 5, + editor: 'ace', + tooltip: 'Specify template which should be when quering view string for the component value entered in manual mode. This string is used in table view, CSV export and email rendering. When left blank combined value of all components joined with comma will be used.', + }, +]; diff --git a/frontend/components/src/components/Common/Advanced.edit.api.ts b/frontend/components/src/components/Common/Advanced.edit.api.ts new file mode 100644 index 0000000..1cfd08c --- /dev/null +++ b/frontend/components/src/components/Common/Advanced.edit.api.ts @@ -0,0 +1,4 @@ +import ComponentEditApi from 'formiojs/components/_classes/component/editForm/Component.edit.api'; +export default [ + ...ComponentEditApi +]; \ No newline at end of file diff --git a/frontend/components/src/components/Common/Advanced.edit.conditional.ts b/frontend/components/src/components/Common/Advanced.edit.conditional.ts new file mode 100644 index 0000000..ef3ca4f --- /dev/null +++ b/frontend/components/src/components/Common/Advanced.edit.conditional.ts @@ -0,0 +1,4 @@ +import ComponentEditConditional from 'formiojs/components/_classes/component/editForm/Component.edit.conditional'; +export default [ + ...ComponentEditConditional +]; \ No newline at end of file diff --git a/frontend/components/src/components/Common/Advanced.edit.data.ts b/frontend/components/src/components/Common/Advanced.edit.data.ts new file mode 100644 index 0000000..1e6e0d0 --- /dev/null +++ b/frontend/components/src/components/Common/Advanced.edit.data.ts @@ -0,0 +1,3 @@ +import ComponentEditData from 'formiojs/components/_classes/component/editForm/Component.edit.data'; +import TextFieldEditData from 'formiojs/components/textfield/editForm/TextField.edit.data'; +export default [...ComponentEditData, ...TextFieldEditData]; \ No newline at end of file diff --git a/frontend/components/src/components/Common/Advanced.edit.display.ts b/frontend/components/src/components/Common/Advanced.edit.display.ts new file mode 100644 index 0000000..166eec2 --- /dev/null +++ b/frontend/components/src/components/Common/Advanced.edit.display.ts @@ -0,0 +1,379 @@ +import _widgets from 'formiojs/widgets'; + +export default [ + { + weight: 10, + type: 'textfield', + input: true, + key: 'label', + label: 'Label', + placeholder: 'Field Label', + tooltip: 'The label for this field that will appear next to it.', + validate: { + required: true + } + }, { + type: 'select', + input: true, + key: 'labelPosition', + label: 'Label Position', + tooltip: 'Position for the label for this field.', + weight: 20, + defaultValue: 'top', + dataSrc: 'values', + data: { + values: [{ + label: 'Top', + value: 'top' + }, { + label: 'Left (Left-aligned)', + value: 'left-left' + }, { + label: 'Left (Right-aligned)', + value: 'left-right' + }, { + label: 'Right (Left-aligned)', + value: 'right-left' + }, { + label: 'Right (Right-aligned)', + value: 'right-right' + }, { + label: 'Bottom', + value: 'bottom' + }] + } + }, { + type: 'number', + input: true, + key: 'labelWidth', + label: 'Label Width', + tooltip: 'The width of label on line in percentages.', + clearOnHide: false, + weight: 30, + placeholder: '30', + suffix: '%', + validate: { + min: 0, + max: 100 + }, + conditional: { + json: { + and: [{ + '!==': [{ + var: 'data.labelPosition' + }, 'top'] + }, { + '!==': [{ + var: 'data.labelPosition' + }, 'bottom'] + }] + } + } + }, { + type: 'number', + input: true, + key: 'labelMargin', + label: 'Label Margin', + tooltip: 'The width of label margin on line in percentages.', + clearOnHide: false, + weight: 30, + placeholder: '3', + suffix: '%', + validate: { + min: 0, + max: 100 + }, + conditional: { + json: { + and: [{ + '!==': [{ + var: 'data.labelPosition' + }, 'top'] + }, { + '!==': [{ + var: 'data.labelPosition' + }, 'bottom'] + }] + } + } + }, { + weight: 100, + type: 'textfield', + input: true, + key: 'placeholder', + label: 'Placeholder', + placeholder: 'Placeholder', + tooltip: 'The placeholder text that will appear when this field is empty.' + }, { + weight: 200, + type: 'textarea', + input: true, + key: 'description', + label: 'Description', + placeholder: 'Description for this field.', + tooltip: 'The description is text that will appear below the input field.', + editor: 'ace', + as: 'html', + wysiwyg: { + minLines: 3, + isUseWorkerDisabled: true + } + }, { + weight: 300, + type: 'textarea', + input: true, + key: 'tooltip', + label: 'Tooltip', + placeholder: 'To add a tooltip to this field, enter text here.', + tooltip: 'Adds a tooltip to the side of this field.', + editor: 'ace', + as: 'html', + wysiwyg: { + minLines: 3, + isUseWorkerDisabled: true + } + }, + { + weight: 320, + type: 'textfield', + input: true, + key: 'prefix', + label: 'Prefix' + }, { + weight: 330, + type: 'textfield', + input: true, + key: 'suffix', + label: 'Suffix', + }, + + { + weight: 400, + type: 'select', + input: true, + key: 'widget.type', + label: 'Widget', + placeholder: 'Select a widget', + tooltip: 'The widget is the display UI used to input the value of the field.', + defaultValue: 'input', + onChange(context) { + context.data.widget = context.default.pick(context.data.widget, 'type'); + }, + dataSrc: 'values', + data: { + values: [{ + label: 'Input Field', + value: 'input' + }, { + label: 'Calendar Picker', + value: 'calendar' + }] + }, + }, + { + weight: 405, + type: 'textarea', + key: 'widget', + label: 'Widget Settings', + refreshOn: 'wiget.type', + clearOnHide: false, + input: true, + rows: 5, + editor: 'ace', + as: 'json', + customConditional: function customConditional(context) { + return context.data.widget.type !== 'input'; + } + }, + { + weight: 410, + type: 'textfield', + input: true, + key: 'inputMask', + label: 'Input Mask', + tooltip: 'An input mask helps the user with input by ensuring a predefined format.<br><br>9: numeric<br>a: alphabetical<br>*: alphanumeric<br><br>Example telephone mask: (999) 999-9999<br><br>See the <a target=\'_blank\' href=\'https://github.com/RobinHerbots/jquery.inputmask\'>jquery.inputmask documentation</a> for more information.</a>', + customConditional: function customConditional(context) { + return !context.data.allowMultipleMasks; + } + }, + { + weight: 410, + type: 'textfield', + input: true, + key: 'displayMask', + label: 'Display Mask', + tooltip: 'A display mask helps to display the input in a readable way, this won\'t affect the value which will be saved (to affect both view and saved value, delete Display Mask and use Input Mask).<br><br>9: numeric<br>a: alphabetical<br>*: alphanumeric<br><br>Example telephone mask: (999) 999-9999<br><br>See the <a target=\'_blank\' href=\'https://github.com/RobinHerbots/jquery.inputmask\'>jquery.inputmask documentation</a> for more information.</a>', + customConditional: function customConditional(context) { + return !context.data.allowMultipleMasks; + } + }, { + weight: 411, + type: 'textfield', + input: true, + key: 'inputMaskPlaceholderChar', + label: 'Input Mask Placeholder Char', + tooltip: 'You can specify a char which will be used as a placeholder in the field. <br>E.g., \u02CD<br>Make note that placeholder char will be replaced by a space if it is used inside the mask', + validation: { + maxLength: 1 + }, + customConditional: function customConditional(context) { + return context.data.inputMask || context.data.displayMask; + } + }, + { + weight: 413, + type: 'checkbox', + input: true, + key: 'allowMultipleMasks', + label: 'Allow Multiple Masks' + }, + { + weight: 408, + type: 'textfield', + input: true, + key: 'customClass', + label: 'Custom CSS Class', + placeholder: 'Custom CSS Class', + tooltip: 'Custom CSS class to add to this component.' + }, { + weight: 600, + type: 'textfield', + input: true, + key: 'tabindex', + label: 'Tab Index', + placeholder: '0', + tooltip: 'Sets the tabindex attribute of this component to override the tab order of the form. See the <a href=\'https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex\'>MDN documentation</a> on tabindex for more information.' + }, + { + weight: 700, + type: 'textfield', + input: true, + key: 'autocomplete', + label: 'Autocomplete', + placeholder: 'on', + tooltip: 'Indicates whether input elements can by default have their values automatically completed by the browser. See the <a href=\'https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete\'>MDN documentation</a> on autocomplete for more information.' + }, + { + weight: 1100, + type: 'checkbox', + label: 'Hidden', + tooltip: 'A hidden field is still a part of the form, but is hidden from view.', + key: 'hidden', + input: true + }, { + weight: 1200, + type: 'checkbox', + label: 'Hide Label', + tooltip: 'Hide the label (title, if no label) of this component. This allows you to show the label in the form builder, but not when it is rendered.', + key: 'hideLabel', + input: true + }, { + weight: 1200, + type: 'checkbox', + label: 'Show Word Counter', + tooltip: 'Show a live count of the number of words.', + key: 'showWordCount', + input: true + }, { + weight: 1201, + type: 'checkbox', + label: 'Show Character Counter', + tooltip: 'Show a live count of the number of characters.', + key: 'showCharCount', + input: true + }, + { + weight: 1300, + type: 'checkbox', + label: 'Hide Input', + tooltip: 'Hide the input in the browser. This does not encrypt on the server. Do not use for passwords.', + key: 'mask', + input: true + },{ + weight: 1350, + type: 'checkbox', + label: 'Initial Focus', + tooltip: 'Make this field the initially focused element on this form.', + key: 'autofocus', + input: true + }, { + weight: 1350, + type: 'checkbox', + input: true, + key: 'spellcheck', + defaultValue: true, + label: 'Allow Spellcheck' + }, + // { + // weight: 1370, + // type: 'checkbox', + // label: 'Show Label in DataGrid', + // tooltip: 'Show the label when in a Datagrid.', + // key: 'dataGridLabel', + // input: true, + // customConditional: function customConditional(context) { + // var _context$instance$opt, _context$instance$opt2; + // return (_context$instance$opt = context.instance.options) === null || _context$instance$opt === void 0 ? void 0 : (_context$instance$opt2 = _context$instance$opt.flags) === null || _context$instance$opt2 === void 0 ? void 0 : _context$instance$opt2.inDataGrid; + // } + // }, + { + weight: 1400, + type: 'checkbox', + label: 'Disabled', + tooltip: 'Disable the form input.', + key: 'disabled', + input: true + }, { + weight: 1500, + type: 'checkbox', + label: 'Table View', + tooltip: 'Shows this value within the table view of the submissions.', + key: 'tableView', + input: true + }, { + weight: 1600, + type: 'checkbox', + label: 'Modal Edit', + tooltip: 'Opens up a modal to edit the value of this component.', + key: 'modalEdit', + input: true + }, { + type: 'number', + input: true, + key: 'rows', + label: 'Rows', + weight: 210, + tooltip: 'This allows control over how many rows are visible in the text area.', + placeholder: 'Enter the amount of rows' + }, { + type: 'checkbox', + input: true, + key: 'autoExpand', + label: 'Auto Expand', + tooltip: 'This will make the TextArea auto expand it\'s height as the user is typing into the area.', + weight: 415 + }, { + type: 'select', + input: true, + key: 'editor', + label: 'Editor', + tooltip: 'Select the type of WYSIWYG editor to use for this text area.', + dataSrc: 'values', + data: { + values: [{ + label: 'None', + value: '' + }, { + label: 'ACE', + value: 'ace' + }, { + label: 'CKEditor', + value: 'ckeditor' + }, { + label: 'Quill', + value: 'quill' + }] + }, + weight: 415 + }, + ]; diff --git a/frontend/components/src/components/Common/Advanced.edit.layout.ts b/frontend/components/src/components/Common/Advanced.edit.layout.ts new file mode 100644 index 0000000..62cfab5 --- /dev/null +++ b/frontend/components/src/components/Common/Advanced.edit.layout.ts @@ -0,0 +1,4 @@ +import ComponentEditLayout from 'formiojs/components/_classes/component/editForm/Component.edit.layout'; +export default [ + ...ComponentEditLayout +]; \ No newline at end of file diff --git a/frontend/components/src/components/Common/Advanced.edit.logic.ts b/frontend/components/src/components/Common/Advanced.edit.logic.ts new file mode 100644 index 0000000..a86c237 --- /dev/null +++ b/frontend/components/src/components/Common/Advanced.edit.logic.ts @@ -0,0 +1,4 @@ +import ComponentEditLogic from 'formiojs/components/_classes/component/editForm/Component.edit.logic'; +export default [ + ...ComponentEditLogic +]; \ No newline at end of file diff --git a/frontend/components/src/components/Common/Advanced.edit.validation.ts b/frontend/components/src/components/Common/Advanced.edit.validation.ts new file mode 100644 index 0000000..471521e --- /dev/null +++ b/frontend/components/src/components/Common/Advanced.edit.validation.ts @@ -0,0 +1,49 @@ +import ComponentEditValidation from 'formiojs/components/_classes/component/editForm/Component.edit.validation'; +import TextFieldEditValidation from 'formiojs/components/textfield/editForm/TextField.edit.validation'; +import UseForCopy from './UseForCopy'; + +const kickbox = { + type: 'panel', + label: 'Kickbox', + title: 'Kickbox', + weight: 102, + key: 'kickbox', + components: [{ + type: 'checkbox', + label: 'Enable', + tooltip: 'Enable Kickbox validation for this email field.', + description: 'Validate this email using the Kickbox email validation service.', + key: 'kickbox.enabled' + }] + } + +export default [kickbox, UseForCopy, ...ComponentEditValidation, ...TextFieldEditValidation]; + + + + +// const neededposition = [ +// 'validate.isUseForCopy', +// 'validateOn', +// 'validate.required', +// 'unique', +// 'kickbox', +// 'validate.minLength', +// 'validate.maxLength', +// 'validate.minWords', +// 'validate.maxWords', +// 'validate.pattern', +// 'errorLabel', +// 'validate.customMessage', +// 'errors', +// 'custom-validation-js', +// 'json-validation-json' +// ]; + +// var newPosition = []; +// neededposition.map((posKey) => { +// [kickbox,UseForCopy,...TextFieldEditValidation,...ComponentEditValidation].findIndex((comp) => { +// if(comp.key === posKey){newPosition.push(comp);} +// }); +// }) +// export default newPosition; \ No newline at end of file diff --git a/frontend/components/src/components/Common/Constants.ts b/frontend/components/src/components/Common/Constants.ts new file mode 100644 index 0000000..969ac7b --- /dev/null +++ b/frontend/components/src/components/Common/Constants.ts @@ -0,0 +1,4 @@ +export abstract class Constants { + static readonly DEFAULT_HELP_LINK: string = 'https://github.com/bcgov/common-hosted-form-service/wiki'; + static readonly ADV: string = ''; +} diff --git a/frontend/components/src/components/Common/Evaluator.ts b/frontend/components/src/components/Common/Evaluator.ts new file mode 100644 index 0000000..4f7d02a --- /dev/null +++ b/frontend/components/src/components/Common/Evaluator.ts @@ -0,0 +1,6 @@ +const Evaluator = { + noeval: false, + protectedEval: false, // This property can be customized only by plugins +}; + +export default Evaluator; diff --git a/frontend/components/src/components/Common/Simple.edit.api.ts b/frontend/components/src/components/Common/Simple.edit.api.ts new file mode 100644 index 0000000..baaed9a --- /dev/null +++ b/frontend/components/src/components/Common/Simple.edit.api.ts @@ -0,0 +1,14 @@ +export default [ + { + weight: 0, + type: 'textfield', + input: true, + key: 'key', + label: 'Property Name', + tooltip: 'The name of this field in the API endpoint.', + validate: { + pattern: '(\\w|\\w[\\w-.]*\\w)', + patternMessage: 'The property name must only contain alphanumeric characters, underscores, dots and dashes and should not be ended by dash or dot.' + } + }, +]; diff --git a/frontend/components/src/components/Common/Simple.edit.conditional.ts b/frontend/components/src/components/Common/Simple.edit.conditional.ts new file mode 100644 index 0000000..ffe2be1 --- /dev/null +++ b/frontend/components/src/components/Common/Simple.edit.conditional.ts @@ -0,0 +1,58 @@ +import { getContextComponents } from 'formiojs/utils/utils'; +import EditFormUtils from './utils'; +/* eslint-disable quotes, max-len */ +export default [ + { + type: 'panel', + title: 'Simple', + key: 'simple-conditional', + theme: 'default', + components: [ + { + type: 'select', + input: true, + label: 'This component should Display:', + key: 'conditional.show', + dataSrc: 'values', + data: { + values: [ + { label: 'True', value: 'true' }, + { label: 'False', value: 'false' } + ] + } + }, + { + type: 'select', + input: true, + label: 'When the form component:', + key: 'conditional.when', + dataSrc: 'custom', + valueProperty: 'value', + data: { + custom(context) { + return getContextComponents(context); + } + } + }, + { + type: 'textfield', + input: true, + label: 'Has the value:', + key: 'conditional.eq' + } + ] + }, + EditFormUtils.javaScriptValue( + 'Advanced Conditions', + 'customConditional', + 'conditional.json', + 110, + '<p>You must assign the <strong>show</strong> variable a boolean result.</p>' + + '<p><strong>Note: Advanced Conditional logic will override the results of the Simple Conditional logic.</strong></p>' + + '<h5>Example</h5><pre>show = !!data.showMe;</pre>', + '<p><a href="http://formio.github.io/formio.js/app/examples/conditions.html" target="_blank">Click here for an example</a></p>', + '', + '' + ) +]; +/* eslint-enable quotes, max-len */ diff --git a/frontend/components/src/components/Common/Simple.edit.data.ts b/frontend/components/src/components/Common/Simple.edit.data.ts new file mode 100644 index 0000000..0da4f9d --- /dev/null +++ b/frontend/components/src/components/Common/Simple.edit.data.ts @@ -0,0 +1,21 @@ +/* eslint-disable max-len */ +export default [ + { + weight: 0, + type: 'checkbox', + label: 'Multiple Values', + tooltip: 'Allows multiple values to be entered for this field.', + key: 'multiple', + input: true + }, + { + type: 'textfield', + label: 'Default Value', + key: 'defaultValue', + weight: 5, + placeholder: 'Default Value', + tooltip: 'The will be the value for this field, before user interaction. Having a default value will override the placeholder text.', + input: true + }, +]; +/* eslint-enable max-len */ diff --git a/frontend/components/src/components/Common/Simple.edit.display.ts b/frontend/components/src/components/Common/Simple.edit.display.ts new file mode 100644 index 0000000..169c107 --- /dev/null +++ b/frontend/components/src/components/Common/Simple.edit.display.ts @@ -0,0 +1,26 @@ +export default [ + { + key: 'tableView', + ignore: true + }, + { + key: 'hidden', + ignore: true + }, + { + key: 'autofocus', + ignore: true + }, + { + key: 'tabindex', + ignore: true + }, + { + key: 'modalEdit', + ignore: true + }, + { + key: 'customClass', + ignore: true + }, +]; diff --git a/frontend/components/src/components/Common/Simple.edit.validation.ts b/frontend/components/src/components/Common/Simple.edit.validation.ts new file mode 100644 index 0000000..110d021 --- /dev/null +++ b/frontend/components/src/components/Common/Simple.edit.validation.ts @@ -0,0 +1,23 @@ +import UseForCopy from './UseForCopy'; +/* eslint-disable quotes, max-len */ +export default [ + UseForCopy, + { + weight: 10, + type: 'checkbox', + label: 'Required', + tooltip: 'A required field must be filled in before the form can be submitted.', + key: 'validate.required', + input: true + }, + { + weight: 200, + key: 'validate.customMessage', + label: 'Custom Error Message', + placeholder: 'Custom Error Message', + type: 'textfield', + tooltip: 'Error message displayed if any error occurred.', + input: true + } +]; +/* eslint-enable quotes, max-len */ diff --git a/frontend/components/src/components/Common/UseForCopy.ts b/frontend/components/src/components/Common/UseForCopy.ts new file mode 100644 index 0000000..2703093 --- /dev/null +++ b/frontend/components/src/components/Common/UseForCopy.ts @@ -0,0 +1,11 @@ +const UseForCopy = { + weight: 10, + type: 'checkbox', + defaultValue: false, + label: 'Allow value propagation', + tooltip: 'Enabling this checkbox will allow this field to be duplicated in new submission.', + key: 'validate.isUseForCopy', + input: true +}; + +export default UseForCopy; diff --git a/frontend/components/src/components/Common/function.ts b/frontend/components/src/components/Common/function.ts new file mode 100644 index 0000000..89bc3fa --- /dev/null +++ b/frontend/components/src/components/Common/function.ts @@ -0,0 +1,16 @@ +export function reArrangeComponents(neededposition=[], components=[]) { + const newPosition = []; + // tslint:disable-next-line: no-unused-expression + neededposition.length && neededposition.map((posKey) => { + components.findIndex((comp) => { + if(comp.key === posKey){ + newPosition.push(comp); + } + }); +}); + + return Array.from(new Set(newPosition.map(a => a.key))) + .map(key => { + return newPosition.find(a => a.key === key) + }); +} \ No newline at end of file diff --git a/frontend/components/src/components/Common/utils.ts b/frontend/components/src/components/Common/utils.ts new file mode 100644 index 0000000..0ffe280 --- /dev/null +++ b/frontend/components/src/components/Common/utils.ts @@ -0,0 +1,140 @@ +import _ from 'lodash'; +import Evaluator from './Evaluator'; +const EditFormUtils = { + sortAndFilterComponents(components) { + return _.filter(_.sortBy(components, 'weight'), (item) => !item.ignore); + }, + unifyComponents(objValue, srcValue) { + if (objValue.key && srcValue.key) { + if (objValue.skipMerge || srcValue.skipMerge) { + return false; + } + if (objValue.key === srcValue.key) { + // Create complete objects by including missing keys. + _.each(objValue, (value, prop) => { + if (objValue.overrideEditForm || !srcValue.hasOwnProperty(prop)) { + srcValue[prop] = value; + } + }); + _.each(srcValue, (value, prop) => { + if (srcValue.overrideEditForm || !objValue.hasOwnProperty(prop)) { + objValue[prop] = value; + } + }); + + if (objValue.components) { + srcValue.components = EditFormUtils.sortAndFilterComponents( + _.unionWith(objValue.components, srcValue.components, EditFormUtils.unifyComponents) + ); + } + return true; + } + else { + return false; + } + } + return _.isEqual(objValue, srcValue); + }, + logicVariablesTable(additional) { + additional = additional || ''; + return { + type: 'htmlelement', + tag: 'div', + /* eslint-disable prefer-template */ + content: '<p>The following variables are available in all scripts.</p>' + + '<table class="table table-bordered table-condensed table-striped">' + + additional + + '<tr><th>token</th><td>The decoded JWT token for the authenticated user.</td></tr>' + + '<tr><th>user</th><td>The current logged in user</td></tr>' + + '<tr><th>form</th><td>The complete form JSON object</td></tr>' + + '<tr><th>submission</th><td>The complete submission object.</td></tr>' + + '<tr><th>data</th><td>The complete submission data object.</td></tr>' + + '<tr><th>row</th><td>Contextual "row" data, used within DataGrid, EditGrid, and Container components</td></tr>' + + '<tr><th>component</th><td>The current component JSON</td></tr>' + + '<tr><th>instance</th><td>The current component instance.</td></tr>' + + '<tr><th>value</th><td>The current value of the component.</td></tr>' + + '<tr><th>moment</th><td>The moment.js library for date manipulation.</td></tr>' + + '<tr><th>_</th><td>An instance of <a href="https://lodash.com/docs/" target="_blank">Lodash</a>.</td></tr>' + + '<tr><th>utils</th><td>An instance of the <a href="http://formio.github.io/formio.js/docs/identifiers.html#utils" target="_blank">FormioUtils</a> object.</td></tr>' + + '<tr><th>util</th><td>An alias for "utils".</td></tr>' + + '</table><br/>' + /* eslint-enable prefer-template */ + }; + }, + javaScriptValue(title, property, propertyJSON, weight, exampleHTML, exampleJSON, additionalParams = '', excludeJSONLogic) { + const components = [ + this.logicVariablesTable(additionalParams), + { + type: 'panel', + title: 'JavaScript', + collapsible: true, + collapsed: false, + style: { 'margin-bottom': '10px' }, + key: `${property}-js`, + customConditional() { + return !Evaluator.noeval || Evaluator.protectedEval; + }, + components: [ + { + type: 'textarea', + key: property, + rows: 5, + editor: 'ace', + hideLabel: true, + as: 'javascript', + input: true + }, + { + type: 'htmlelement', + tag: 'div', + content: `<p>Enter custom javascript code.</p>${exampleHTML}` + } + ] + }, + { + type: 'panel', + title: 'JSONLogic', + collapsible: true, + collapsed: true, + key: `${property}-json`, + components: [ + { + type: 'htmlelement', + tag: 'div', + /* eslint-disable prefer-template */ + content: '<p>Execute custom logic using <a href="http://jsonlogic.com/" target="_blank">JSONLogic</a>.</p>' + + '<p>Full <a href="https://lodash.com/docs" target="_blank">Lodash</a> support is provided using an "_" before each operation, such as <code>{"_sum": {var: "data.a"}}</code></p>' + + exampleJSON + /* eslint-enable prefer-template */ + }, + { + type: 'textarea', + key: propertyJSON, + rows: 5, + editor: 'ace', + hideLabel: true, + as: 'json', + input: true + } + ] + } + ]; + + if (excludeJSONLogic) { + components.splice(2, 1); + } + + return { + type: 'panel', + title: `${title}`, + theme: 'default', + collapsible: true, + collapsed: true, + key: `${property}Panel`, + weight: `${weight}`, + components + }; + } +}; + +export default EditFormUtils; diff --git a/frontend/components/src/components/OrgBook/Component.form.ts b/frontend/components/src/components/OrgBook/Component.form.ts new file mode 100644 index 0000000..4b40f7c --- /dev/null +++ b/frontend/components/src/components/OrgBook/Component.form.ts @@ -0,0 +1,22 @@ +import baseEditForm from 'formiojs/components/_classes/component/Component.form'; + +import EditData from './editForm/Orgbook.edit.data'; +import EditDisplay from './editForm/Orgbook.edit.display'; +import EditValidation from './editForm/Orgbook.edit.validation'; + +export default function(...extend) { + return baseEditForm([ + { + key: 'display', + components: EditDisplay + }, + { + key: 'data', + components: EditData + }, + { + key: 'validation', + components: EditValidation + } + ], ...extend); +} diff --git a/frontend/components/src/components/OrgBook/Component.ts b/frontend/components/src/components/OrgBook/Component.ts new file mode 100644 index 0000000..8ae9d2e --- /dev/null +++ b/frontend/components/src/components/OrgBook/Component.ts @@ -0,0 +1,130 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const SelectComponent = (Components as any).components.select; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'orgbook'; +export default class Component extends (SelectComponent as any) { + static schema(...extend) { + return SelectComponent.schema({ + type: ID, + label: 'Registered Business Name', + key: ID, + idPath: 'id', + dataSrc: 'url', + data: { + values: [], + json: '', + url: 'https://orgbook.gov.bc.ca/api/v3/search/autocomplete', + resource: '', + custom: '' + }, + limit: 100, + logic: [], + filter: 'latest=true&inactive=false&revoked=false', + dataType: 'string', + template: '{{ item.value }}', + placeholder: 'Start typing to search BC Registered Businesses database', + searchField: 'q', + selectValues: 'results', + valueProperty: 'value', + selectFields: '', + searchThreshold: 3, + minSearch: 3, + hidden: false, + prefix: '', + suffix: '', + unique: false, + widget: '', + dbIndex: false, + overlay: { + top: '', + left: '', + page: '', + style: '', + width: '', + height: '' + }, + tooltip: '', + disabled: false, + lazyLoad: true, + multiple: false, + redrawOn: '', + tabindex: '', + validate: { + json: '', + custom: '', + select: false, + unique: false, + multiple: false, + required: false, + customMessage: '', + customPrivate: false, + strictDateValidation: false + }, + autofocus: false, + encrypted: false, + hideLabel: false, + indexeddb: { + filter: {} + }, + modalEdit: false, + protected: false, + refreshOn: '', + tableView: false, + attributes: {}, + errorLabel: '', + persistent: true, + properties: {}, + validateOn: '', + clearOnHide: true, + conditional: { + eq: '', + json: '', + show: null, + when: null + }, + customClass: '', + description: '', + fuseOptions: { + include: 'score', + threshold: 0.3 + }, + authenticate: false, + defaultValue: '', + disableLimit: false, + customOptions: { + duplicateItemsAllowed: false + }, + labelPosition: 'top', + readOnlyValue: true, + searchEnabled: true, + showCharCount: false, + showWordCount: false, + uniqueOptions: false, + calculateValue: '', + clearOnRefresh: false, + calculateServer: false, + selectThreshold: 0.3, + customConditional: '', + allowMultipleMasks: false, + customDefaultValue: '', + allowCalculateOverride: false + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: 'Business Name Search', + group: 'advanced', + icon: 'database', + weight: 70, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/OrgBook/editForm/Orgbook.edit.data.ts b/frontend/components/src/components/OrgBook/editForm/Orgbook.edit.data.ts new file mode 100644 index 0000000..cf5d7c0 --- /dev/null +++ b/frontend/components/src/components/OrgBook/editForm/Orgbook.edit.data.ts @@ -0,0 +1,168 @@ +export default [ + { + type: 'textfield', + input: true, + key: 'data.url', + weight: 10, + label: 'Org. Book URL', + placeholder: 'Org. Book URL', + tooltip: 'Org. Book URL that returns a JSON to use as the data source.', + }, + { + type: 'checkbox', + input: true, + label: 'Lazy Load Data', + key: 'lazyLoad', + tooltip: 'When set, this will not fire off the request to the URL until this control is within focus. This can improve performance if you have many Select dropdowns on your form where the API\'s will only fire when the control is activated.', + weight: 11, + }, + { + type: 'textfield', + input: true, + label: 'Data Path', + key: 'selectValues', + weight: 12, + description: 'The object path to the iterable items.', + tooltip: 'The property within the source data, where iterable items reside. For example: results', + }, + { + type: 'select', + input: true, + label: 'Storage Type', + key: 'dataType', + clearOnHide: true, + tooltip: 'The type to store the data. String will store the Business Name, Object will store the object.', + weight: 12, + template: '<span>{{ item.label }}</span>', + dataSrc: 'values', + data: { + values: [ + { label: 'String', value: 'string' }, + { label: 'Object', value: 'object' }, + ], + }, + onChange(context) { + if (context && context.flags && context.flags.modified) { + const dataTypeProp = context.instance.data.dataType; + const valueProp = dataTypeProp === 'object' ? '' : 'names[0].text'; + context.instance.root.getComponent('valueProperty').setValue(valueProp); + } + }, + }, + { + type: 'textfield', + input: true, + key: 'idPath', + weight: 12, + label: 'ID Path', + placeholder: 'id', + tooltip: 'Path to the select option id.' + }, + { + type: 'textfield', + input: true, + label: 'Value Property', + key: 'valueProperty', + skipMerge: true, + clearOnHide: false, + weight: 13, + description: "The selected item's property to save.", + tooltip: 'The property of each item in the data source to use as the select value. If not specified, the item itself will be used.', + }, + { + type: 'textfield', + input: true, + key: 'searchField', + label: 'Search Query Name', + weight: 16, + description: 'Name of URL query parameter (for Org Book, it is \'q\')', + tooltip: 'The name of the search querystring parameter used when sending a request to filter results with. The server at the URL must handle this query parameter.', + }, + { + type: 'number', + input: true, + key: 'minSearch', + weight: 17, + label: 'Minimum Search Length', + tooltip: 'The minimum amount of characters they must type before a search is made.', + defaultValue: 3, + }, + { + type: 'textfield', + input: true, + key: 'filter', + label: 'Filter Query', + weight: 18, + description: 'The filter query for results.', + tooltip: 'Use this to provide additional filtering using query parameters.', + }, + { + type: 'number', + input: true, + key: 'limit', + label: 'Limit', + weight: 18, + defaultValue: 100, + description: 'Maximum number of items to view per page of results.', + tooltip: 'Use this to limit the number of items to request or view.', + }, + { + type: 'textarea', + input: true, + key: 'template', + label: 'Item Template', + editor: 'ace', + as: 'html', + rows: 3, + weight: 18, + tooltip: 'The HTML template for the result data items.', + allowCalculateOverride: true, + calculateValue:(context) => { + if (!context.data.template) { + if (context.instance && context.instance._currentForm.options.editComponent) { + return context.instance._currentForm.options.editComponent.template; + } + } + + return context.data.template; + } + }, + { + type: 'checkbox', + input: true, + weight: 21, + key: 'searchEnabled', + label: 'Enable Static Search', + defaultValue: true, + tooltip: 'When checked, the select dropdown will allow for searching within the static list of items provided.', + }, + { + label: 'Search Threshold', + mask: false, + tableView: true, + alwaysEnabled: false, + type: 'number', + input: true, + key: 'selectThreshold', + validate: { + min: 0, + customMessage: '', + json: '', + max: 1, + }, + delimiter: false, + requireDecimal: false, + encrypted: false, + defaultValue: 0.3, + weight: 22, + tooltip: 'At what point does the match algorithm give up. A threshold of 0.0 requires a perfect match, a threshold of 1.0 would match anything.', + }, + { + type: 'checkbox', + input: true, + weight: 27, + key: 'readOnlyValue', + label: 'Read Only Value', + tooltip: 'Check this if you would like to show just the value when in Read Only mode.', + }, +]; diff --git a/frontend/components/src/components/OrgBook/editForm/Orgbook.edit.display.ts b/frontend/components/src/components/OrgBook/editForm/Orgbook.edit.display.ts new file mode 100644 index 0000000..a7c553c --- /dev/null +++ b/frontend/components/src/components/OrgBook/editForm/Orgbook.edit.display.ts @@ -0,0 +1,4 @@ +import common from '../../Common/Simple.edit.display'; +export default [ + ...common, +]; diff --git a/frontend/components/src/components/OrgBook/editForm/Orgbook.edit.validation.ts b/frontend/components/src/components/OrgBook/editForm/Orgbook.edit.validation.ts new file mode 100644 index 0000000..d6d1738 --- /dev/null +++ b/frontend/components/src/components/OrgBook/editForm/Orgbook.edit.validation.ts @@ -0,0 +1 @@ +export default []; diff --git a/frontend/components/src/components/SimpleAddressAdvanced/Component.form.ts b/frontend/components/src/components/SimpleAddressAdvanced/Component.form.ts new file mode 100644 index 0000000..a482776 --- /dev/null +++ b/frontend/components/src/components/SimpleAddressAdvanced/Component.form.ts @@ -0,0 +1,17 @@ +import baseEditForm from 'formiojs/components/address/Address.form'; +import EditValidation from './editForm/Component.edit.validation'; + +export default function(...extend) { + return baseEditForm([ + { + key: 'validation', + ignore: true + }, + { + label: 'Validation', + key: 'customValidation', + weight: 15, + components: EditValidation + }, + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleAddressAdvanced/Component.ts b/frontend/components/src/components/SimpleAddressAdvanced/Component.ts new file mode 100644 index 0000000..b8d2005 --- /dev/null +++ b/frontend/components/src/components/SimpleAddressAdvanced/Component.ts @@ -0,0 +1,33 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.address; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simpleaddressadvanced'; + +const DISPLAY = 'Address'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'advanced', + icon: 'home', + weight: 770, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleAddressAdvanced/editForm/Component.edit.validation.ts b/frontend/components/src/components/SimpleAddressAdvanced/editForm/Component.edit.validation.ts new file mode 100644 index 0000000..231eb49 --- /dev/null +++ b/frontend/components/src/components/SimpleAddressAdvanced/editForm/Component.edit.validation.ts @@ -0,0 +1,18 @@ +import common from '../../Common/Advanced.edit.validation'; +import {reArrangeComponents} from '../../Common/function'; + +const neededposition = [ + 'validate.isUseForCopy', + 'validate.required', + 'unique', + 'validateOn', + 'errorLabel', + 'validate.customMessage', + 'custom-validation-js', + 'json-validation-json', + 'errors', + ]; + + const newPosition = reArrangeComponents(neededposition,common); + + export default newPosition; \ No newline at end of file diff --git a/frontend/components/src/components/SimpleBCAddress/Component.form.ts b/frontend/components/src/components/SimpleBCAddress/Component.form.ts new file mode 100644 index 0000000..305a569 --- /dev/null +++ b/frontend/components/src/components/SimpleBCAddress/Component.form.ts @@ -0,0 +1,13 @@ +import baseEditForm from 'formiojs/components/_classes/component/Component.form'; +import AddressEditProvider from './editForm/Address.edit.provider'; + +export default function(...extend) { + return baseEditForm([ + { + label: 'Provider', + key: 'provider', + weight: 150, + components: AddressEditProvider, + }, + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleBCAddress/Component.ts b/frontend/components/src/components/SimpleBCAddress/Component.ts new file mode 100644 index 0000000..b9b03cc --- /dev/null +++ b/frontend/components/src/components/SimpleBCAddress/Component.ts @@ -0,0 +1,98 @@ + +/* tslint:disable */ +import {Components} from 'formiojs'; +import { Constants } from '../Common/Constants'; +import editForm from './Component.form'; +import _ from 'lodash'; + +export const AddressComponentMode = { + Autocomplete: 'autocomplete', + Manual: 'manual', +}; + +const ParentComponent = (Components as any).components.address; + +const ID = 'simplebcaddress'; +const DISPLAY = 'Simple BC Address'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + + return ParentComponent.schema({ + label: DISPLAY, + type: ID, + key: ID, + provider: 'custom', + providerOptions: { + queryProperty: 'addressString', + url:import.meta.env.VITE_CHEFS_ADVANCE_GEO_ADDRESS_APIURL}, + + queryParameters:{"echo": false, + "brief": true, + "minScore": 55, + "onlyCivic": true, + "maxResults": 15, + "autocomplete": true, + "matchAccuracy": 100, + "matchPrecision": "occupant, unit, site, civic_number, intersection, block, street, locality, province", + "precisionPoints": 100,} + + }, ...extend); + } + + static get builderInfo() { + return { + title: DISPLAY, + group: 'advanced', + icon: 'address-book', + weight: 90, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema(), + + }; + } + + public static editForm = editForm; + + async init(){ + super.init(); + } + + async attach(element) { + super.attach(element); + try { + + let { + providerOptions, + queryParameters, + + } = this.component; + + if(providerOptions) { + if(!providerOptions.params) { + providerOptions["params"]={} + } + if(queryParameters) { + providerOptions.params ={...providerOptions.params,...queryParameters} + } + } + + } catch (err) { + console.log(`This error is from Custom BC Address component in form.io: Failed to acquire configuration: ${err.message}`); + } + } + + mergeSchema(component = {}) { + + let components = component['components']; + + if (components) { + return _.omit(component, 'components'); + } + + return component; + } + + +} +export {}; diff --git a/frontend/components/src/components/SimpleBCAddress/editForm/Address.edit.provider.ts b/frontend/components/src/components/SimpleBCAddress/editForm/Address.edit.provider.ts new file mode 100644 index 0000000..9e7f51d --- /dev/null +++ b/frontend/components/src/components/SimpleBCAddress/editForm/Address.edit.provider.ts @@ -0,0 +1,48 @@ +import _ from 'lodash'; + +export default [ + { + type: 'textfield', + input: true, + defaultValue: 'features', + key: 'providerOptions.responseProperty', + label: 'Response Property', + placeholder: 'Enter Response Property', + weight: 30, + tooltip: 'The property within the response data, where iterable addresses reside. For example: results.', + }, + { + type: 'textfield', + input: true, + defaultValue: 'properties.fullAddress', + key: 'providerOptions.displayValueProperty', + label: 'Display Value Property', + placeholder: 'Display Value Property', + weight: 40, + tooltip: 'The property of each address in the response to use as the display value.', + }, + { + type: 'textarea', + input: true, + key: 'queryParameters', + label: 'Params', + placeholder: '{ ... }', + weight: 50, + rows: 5, + editor: 'ace', + as: 'json', + tooltip: 'Additional query params can be specified here in a way of JSON object.', + }, + { + type: 'textarea', + input: true, + key: 'manualModeViewString', + label: 'Manual Mode View String', + placeholder: 'Enter Manual Mode View String', + description: '"address" variable references component value, "data" - submission data and "component" - address component schema.', + weight: 60, + rows: 5, + editor: 'ace', + tooltip: 'Specify template which should be when quering view string for the component value entered in manual mode. This string is used in table view, CSV export and email rendering. When left blank combined value of all components joined with comma will be used.', + }, +]; diff --git a/frontend/components/src/components/SimpleButtonAdvanced/Component.form.ts b/frontend/components/src/components/SimpleButtonAdvanced/Component.form.ts new file mode 100644 index 0000000..d8733b2 --- /dev/null +++ b/frontend/components/src/components/SimpleButtonAdvanced/Component.form.ts @@ -0,0 +1,3 @@ +import baseEditForm from 'formiojs/components/button/Button.form'; + +export default baseEditForm; diff --git a/frontend/components/src/components/SimpleButtonAdvanced/Component.ts b/frontend/components/src/components/SimpleButtonAdvanced/Component.ts new file mode 100644 index 0000000..ea63323 --- /dev/null +++ b/frontend/components/src/components/SimpleButtonAdvanced/Component.ts @@ -0,0 +1,33 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.button; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simplebuttonadvanced'; + +const DISPLAY = 'Button'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'advanced', + icon: 'stop', + weight: 845, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleButtonReset/Component.form.ts b/frontend/components/src/components/SimpleButtonReset/Component.form.ts new file mode 100644 index 0000000..7b2d92d --- /dev/null +++ b/frontend/components/src/components/SimpleButtonReset/Component.form.ts @@ -0,0 +1,48 @@ +import baseEditForm from 'formiojs/components/_classes/component/Component.form'; + +import EditDisplay from './editForm/Component.edit.display'; + +import SimpleApi from '../Common/Simple.edit.api'; +import SimpleConditional from '../Common/Simple.edit.conditional'; + +export default function(...extend) { + return baseEditForm([ + EditDisplay, + { + key: 'data', + ignore: true, + }, + { + key: 'api', + ignore: true + }, + { + key: 'layout', + ignore: true + }, + { + key: 'conditional', + ignore: true + }, + { + key: 'validation', + ignore: true + }, + { + key: 'logic', + ignore: true + }, + { + label: 'API', + key: 'customAPI', + weight: 30, + components: SimpleApi + }, + { + label: 'Conditional', + key: 'customConditional', + weight: 40, + components: SimpleConditional + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleButtonReset/Component.ts b/frontend/components/src/components/SimpleButtonReset/Component.ts new file mode 100644 index 0000000..bdfd1dd --- /dev/null +++ b/frontend/components/src/components/SimpleButtonReset/Component.ts @@ -0,0 +1,41 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.button; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simplebtnreset'; +const DISPLAY = 'Reset Button'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: 'Reset', + key: 'submit', + size: 'md', + leftIcon: '', + rightIcon: '', + block: false, + action: 'reset', + persistent: false, + disableOnInvalid: false, + theme: 'secondary', + dataGridLabel: true + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'simple', + icon: 'undo', + weight: 31, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleButtonReset/editForm/Component.edit.display.ts b/frontend/components/src/components/SimpleButtonReset/editForm/Component.edit.display.ts new file mode 100644 index 0000000..5030bbb --- /dev/null +++ b/frontend/components/src/components/SimpleButtonReset/editForm/Component.edit.display.ts @@ -0,0 +1,35 @@ +import common from '../../Common/Simple.edit.display'; +export default { + key: 'display', + components: [ + ...common, + { + key: 'refreshOnChange', + ignore: true + }, + { + key: 'className', + ignore: true, + }, + { + key: 'labelPosition', + ignore: true, + }, + { + key: 'placeholder', + ignore: true, + }, + { + key: 'hideLabel', + ignore: true, + }, + { + type: 'checkbox', + key: 'block', + label: 'Block Button', + input: true, + weight: 155, + tooltip: 'This control should span the full width of the bounding container.', + }, + ] +} diff --git a/frontend/components/src/components/SimpleButtonSubmit/Component.form.ts b/frontend/components/src/components/SimpleButtonSubmit/Component.form.ts new file mode 100644 index 0000000..7b2d92d --- /dev/null +++ b/frontend/components/src/components/SimpleButtonSubmit/Component.form.ts @@ -0,0 +1,48 @@ +import baseEditForm from 'formiojs/components/_classes/component/Component.form'; + +import EditDisplay from './editForm/Component.edit.display'; + +import SimpleApi from '../Common/Simple.edit.api'; +import SimpleConditional from '../Common/Simple.edit.conditional'; + +export default function(...extend) { + return baseEditForm([ + EditDisplay, + { + key: 'data', + ignore: true, + }, + { + key: 'api', + ignore: true + }, + { + key: 'layout', + ignore: true + }, + { + key: 'conditional', + ignore: true + }, + { + key: 'validation', + ignore: true + }, + { + key: 'logic', + ignore: true + }, + { + label: 'API', + key: 'customAPI', + weight: 30, + components: SimpleApi + }, + { + label: 'Conditional', + key: 'customConditional', + weight: 40, + components: SimpleConditional + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleButtonSubmit/Component.ts b/frontend/components/src/components/SimpleButtonSubmit/Component.ts new file mode 100644 index 0000000..0e4a789 --- /dev/null +++ b/frontend/components/src/components/SimpleButtonSubmit/Component.ts @@ -0,0 +1,41 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.button; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simplebtnsubmit'; +const DISPLAY = 'Submit Button'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: 'Submit', + key: 'submit', + size: 'md', + leftIcon: '', + rightIcon: '', + block: false, + action: 'submit', + persistent: false, + disableOnInvalid: true, + theme: 'primary', + dataGridLabel: true + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'simple', + icon: 'paper-plane', + weight: 30, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleButtonSubmit/editForm/Component.edit.display.ts b/frontend/components/src/components/SimpleButtonSubmit/editForm/Component.edit.display.ts new file mode 100644 index 0000000..54a6552 --- /dev/null +++ b/frontend/components/src/components/SimpleButtonSubmit/editForm/Component.edit.display.ts @@ -0,0 +1,43 @@ +import common from '../../Common/Simple.edit.display'; +export default { + key: 'display', + components: [ + ...common, + { + key: 'refreshOnChange', + ignore: true + }, + { + key: 'className', + ignore: true, + }, + { + key: 'labelPosition', + ignore: true, + }, + { + key: 'placeholder', + ignore: true, + }, + { + key: 'hideLabel', + ignore: true, + }, + { + type: 'checkbox', + key: 'block', + label: 'Block Button', + input: true, + weight: 155, + tooltip: 'This control should span the full width of the bounding container.', + }, + { + type: 'checkbox', + key: 'disableOnInvalid', + label: 'Disable on Form Invalid', + tooltip: 'This will disable this field if the form is invalid.', + input: true, + weight: 620, + }, + ] +} diff --git a/frontend/components/src/components/SimpleCheckbox/Component.form.ts b/frontend/components/src/components/SimpleCheckbox/Component.form.ts new file mode 100644 index 0000000..1ff7d07 --- /dev/null +++ b/frontend/components/src/components/SimpleCheckbox/Component.form.ts @@ -0,0 +1,58 @@ +import baseEditForm from 'formiojs/components/_classes/component/Component.form'; + +import EditDisplay from './editForm/Component.edit.display'; +import EditValidation from './editForm/Component.edit.validation'; + +import SimpleApi from '../Common/Simple.edit.api'; +import SimpleConditional from '../Common/Simple.edit.conditional'; + +export default function(...extend) { + return baseEditForm([ + { + key: 'display', + components: EditDisplay + }, + { + key: 'data', + ignore: true, + }, + { + key: 'api', + ignore: true + }, + { + key: 'layout', + ignore: true + }, + { + key: 'conditional', + ignore: true + }, + { + key: 'validation', + ignore: true + }, + { + key: 'logic', + ignore: true + }, + { + label: 'API', + key: 'customAPI', + weight: 30, + components: SimpleApi + }, + { + label: 'Validation', + key: 'customValidation', + weight: 20, + components: EditValidation + }, + { + label: 'Conditional', + key: 'customConditional', + weight: 40, + components: SimpleConditional + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleCheckbox/Component.ts b/frontend/components/src/components/SimpleCheckbox/Component.ts new file mode 100644 index 0000000..78da409 --- /dev/null +++ b/frontend/components/src/components/SimpleCheckbox/Component.ts @@ -0,0 +1,37 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.checkbox; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simplecheckbox'; +const DISPLAY = 'Checkbox'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + inputType: 'checkbox', + dataGridLabel: true, + labelPosition: 'right', + value: '', + name: '' + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'simple', + icon: 'check-square', + weight: 4, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleCheckbox/editForm/Component.edit.display.ts b/frontend/components/src/components/SimpleCheckbox/editForm/Component.edit.display.ts new file mode 100644 index 0000000..4a0f0fd --- /dev/null +++ b/frontend/components/src/components/SimpleCheckbox/editForm/Component.edit.display.ts @@ -0,0 +1,28 @@ +import common from '../../Common/Simple.edit.display'; +export default [ + ...common, + { + key: 'refreshOnChange', + ignore: true + }, + { + key: 'className', + ignore: true, + }, + { + key: 'prefix', + ignore: true + }, + { + key: 'suffix', + ignore: true + }, + { + key: 'labelPosition', + ignore: true, + }, + { + key: 'placeholder', + ignore: true, + }, +]; diff --git a/frontend/components/src/components/SimpleCheckbox/editForm/Component.edit.validation.ts b/frontend/components/src/components/SimpleCheckbox/editForm/Component.edit.validation.ts new file mode 100644 index 0000000..1cec573 --- /dev/null +++ b/frontend/components/src/components/SimpleCheckbox/editForm/Component.edit.validation.ts @@ -0,0 +1,4 @@ +import common from '../../Common/Simple.edit.validation'; +export default [ + ...common, +]; diff --git a/frontend/components/src/components/SimpleCheckboxAdvanced/Component.form.ts b/frontend/components/src/components/SimpleCheckboxAdvanced/Component.form.ts new file mode 100644 index 0000000..8f7643c --- /dev/null +++ b/frontend/components/src/components/SimpleCheckboxAdvanced/Component.form.ts @@ -0,0 +1,17 @@ +import baseEditForm from 'formiojs/components/checkbox/Checkbox.form'; +import EditValidation from './editForm/Component.edit.validation'; + +export default function(...extend) { + return baseEditForm([ + { + key: 'validation', + ignore: true + }, + { + label: 'Validation', + key: 'customValidation', + weight: 15, + components: EditValidation + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleCheckboxAdvanced/Component.ts b/frontend/components/src/components/SimpleCheckboxAdvanced/Component.ts new file mode 100644 index 0000000..7127e8b --- /dev/null +++ b/frontend/components/src/components/SimpleCheckboxAdvanced/Component.ts @@ -0,0 +1,32 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.checkbox; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simplecheckboxadvanced'; +const DISPLAY = 'Checkbox'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'advanced', + icon: 'check-square', + weight: 780, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleCheckboxAdvanced/editForm/Component.edit.validation.ts b/frontend/components/src/components/SimpleCheckboxAdvanced/editForm/Component.edit.validation.ts new file mode 100644 index 0000000..190b6c0 --- /dev/null +++ b/frontend/components/src/components/SimpleCheckboxAdvanced/editForm/Component.edit.validation.ts @@ -0,0 +1,18 @@ +import common from '../../Common/Advanced.edit.validation'; +import validationComponents from 'formiojs/components/checkbox/editForm/Checkbox.edit.validation'; +import {reArrangeComponents} from '../../Common/function'; + +const neededposition = [ + 'validate.isUseForCopy', + 'validate.required', + 'errorLabel', + 'validate.customMessage', + 'custom-validation-js', + 'json-validation-json', + 'errors', + ]; + + const newPosition = reArrangeComponents(neededposition,[...validationComponents,...common]); + + + export default newPosition; \ No newline at end of file diff --git a/frontend/components/src/components/SimpleCheckboxes/Component.form.ts b/frontend/components/src/components/SimpleCheckboxes/Component.form.ts new file mode 100644 index 0000000..dde1ea2 --- /dev/null +++ b/frontend/components/src/components/SimpleCheckboxes/Component.form.ts @@ -0,0 +1,62 @@ +import radioEditForm from 'formiojs/components/radio/Radio.form'; + +import EditData from './editForm/Component.edit.data'; +import EditDisplay from './editForm/Component.edit.display'; +import EditValidation from './editForm/Component.edit.validation'; + +import SimpleApi from '../Common/Simple.edit.api'; +import SimpleConditional from '../Common/Simple.edit.conditional'; + +export default function(...extend) { + return radioEditForm([ + EditDisplay, + { + key: 'data', + ignore: true + }, + { + key: 'api', + ignore: true + }, + { + key: 'layout', + ignore: true + }, + { + key: 'conditional', + ignore: true + }, + { + key: 'validation', + ignore: true + }, + { + key: 'logic', + ignore: true + }, + { + label: 'Data', + key: 'customData', + weight: 10, + components: EditData + }, + { + label: 'Validation', + key: 'customValidation', + weight: 20, + components: EditValidation + }, + { + label: 'API', + key: 'customAPI', + weight: 30, + components: SimpleApi + }, + { + label: 'Conditional', + key: 'customConditional', + weight: 40, + components: SimpleConditional + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleCheckboxes/Component.ts b/frontend/components/src/components/SimpleCheckboxes/Component.ts new file mode 100644 index 0000000..45b6c09 --- /dev/null +++ b/frontend/components/src/components/SimpleCheckboxes/Component.ts @@ -0,0 +1,35 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.selectboxes; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simplecheckboxes'; +const DISPLAY = 'Checkbox Group'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + inline: false, + values: [{ label: '', value: '' }], + fieldSet: false + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'simple', + icon: 'plus-square', + weight: 5, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleCheckboxes/editForm/Component.edit.data.ts b/frontend/components/src/components/SimpleCheckboxes/editForm/Component.edit.data.ts new file mode 100644 index 0000000..a9d335d --- /dev/null +++ b/frontend/components/src/components/SimpleCheckboxes/editForm/Component.edit.data.ts @@ -0,0 +1,65 @@ +import BuilderUtils from 'formiojs/utils/builder'; +import _ from 'lodash'; + +export default [ + { + type: 'textfield', + label: 'Default Value', + key: 'defaultValue', + weight: 5, + placeholder: 'Default Value', + tooltip: 'The will be the value for this field, before user interaction. Having a default value will override the placeholder text.', + input: true + }, + { + type: 'datagrid', + input: true, + label: 'Values', + key: 'values', + tooltip: 'The values that can be picked for this field. Values are text submitted with the form data. Labels are text that appears next to the radio buttons on the form.', + weight: 10, + reorder: true, + defaultValue: [{ label: '', value: '' }], + components: [ + { + weight: 160, + label: 'Label', + key: 'label', + input: true, + type: 'textfield', + }, + { + weight: 170, + label: 'Value', + key: 'value', + input: true, + type: 'textfield', + allowCalculateOverride: true, + calculateValue: { _camelCase: [{ var: 'row.label' }] }, + validate: { + required: true + } + }, + { + type: 'select', + input: true, + weight: 180, + label: 'Shortcut', + key: 'shortcut', + tooltip: 'The shortcut key for this option.', + dataSrc: 'custom', + valueProperty: 'value', + customDefaultValue: () => '', + template: '{{ item.label }}', + data: { + custom(context) { + return BuilderUtils.getAvailableShortcuts( + _.get(context, 'instance.options.editForm', {}), + _.get(context, 'instance.options.editComponent', {}) + ); + }, + }, + }, + ], + }, +]; diff --git a/frontend/components/src/components/SimpleCheckboxes/editForm/Component.edit.display.ts b/frontend/components/src/components/SimpleCheckboxes/editForm/Component.edit.display.ts new file mode 100644 index 0000000..b463e8a --- /dev/null +++ b/frontend/components/src/components/SimpleCheckboxes/editForm/Component.edit.display.ts @@ -0,0 +1,28 @@ +import common from '../../Common/Simple.edit.display'; +export default { + key: 'display', + components: + [ + ...common, + { + key: 'refreshOnChange', + ignore: true + }, + { + key: 'className', + ignore: true, + }, + { + key: 'attrs', + ignore: true + }, + { + key: 'widget', + ignore: true + }, + { + key: 'uniqueOptions', + ignore: true + }, + ] +} diff --git a/frontend/components/src/components/SimpleCheckboxes/editForm/Component.edit.validation.ts b/frontend/components/src/components/SimpleCheckboxes/editForm/Component.edit.validation.ts new file mode 100644 index 0000000..5a327db --- /dev/null +++ b/frontend/components/src/components/SimpleCheckboxes/editForm/Component.edit.validation.ts @@ -0,0 +1,37 @@ +import common from '../../Common/Simple.edit.validation'; + +export default [ + ...common, + { + type: 'number', + input: true, + key: 'validate.minSelectedCount', + label: 'Minimum checked number', + tooltip: 'Minimum checkboxes required before form can be submitted.', + weight: 250 + }, + { + type: 'number', + input: true, + key: 'validate.maxSelectedCount', + label: 'Maximum checked number', + tooltip: 'Maximum checkboxes possible before form can be submitted.', + weight: 250 + }, + { + type: 'textfield', + input: true, + key: 'minSelectedCountMessage', + label: 'Minimum checked error message', + tooltip: 'Error message displayed if minimum number of items not checked.', + weight: 250 + }, + { + type: 'textfield', + input: true, + key: 'maxSelectedCountMessage', + label: 'Maximum checked error message', + tooltip: 'Error message displayed if maximum number of items checked.', + weight: 250 + } +]; diff --git a/frontend/components/src/components/SimpleColumns2/Component.form.ts b/frontend/components/src/components/SimpleColumns2/Component.form.ts new file mode 100644 index 0000000..ee54219 --- /dev/null +++ b/frontend/components/src/components/SimpleColumns2/Component.form.ts @@ -0,0 +1,53 @@ +import baseEditForm from 'formiojs/components/_classes/component/Component.form'; +import EditDisplay from './editForm/Component.edit.display'; +import SimpleApi from '../Common/Simple.edit.api'; +import SimpleConditional from '../Common/Simple.edit.conditional'; + +export default function(...extend) { + return baseEditForm([ + { + key: 'display', + components: EditDisplay + }, + { + key: 'data', + ignore: true, + }, + { + key: 'api', + ignore: true + }, + { + key: 'layout', + ignore: true + }, + { + key: 'conditional', + ignore: true + }, + { + key: 'validation', + ignore: true + }, + { + key: 'logic', + ignore: true + }, + { + key: 'modalEdit', + ignore: true + }, + { + label: 'API', + key: 'customAPI', + weight: 30, + components: SimpleApi + }, + { + label: 'Conditional', + key: 'customConditional', + weight: 40, + components: SimpleConditional + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleColumns2/Component.ts b/frontend/components/src/components/SimpleColumns2/Component.ts new file mode 100644 index 0000000..500842b --- /dev/null +++ b/frontend/components/src/components/SimpleColumns2/Component.ts @@ -0,0 +1,42 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.columns; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simplecols2'; +const DISPLAY = 'Columns - 2'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + columns: [ + { components: [], width: 6, offset: 0, push: 0, pull: 0, size: 'md' }, + { components: [], width: 6, offset: 0, push: 0, pull: 0, size: 'md' } + ], + clearOnHide: false, + input: false, + tableView: false, + persistent: false, + autoAdjust: false, + hideOnChildrenHidden: false + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'simple', + icon: 'columns', + weight: 50, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleColumns2/editForm/Component.edit.display.ts b/frontend/components/src/components/SimpleColumns2/editForm/Component.edit.display.ts new file mode 100644 index 0000000..73bf442 --- /dev/null +++ b/frontend/components/src/components/SimpleColumns2/editForm/Component.edit.display.ts @@ -0,0 +1,44 @@ +import common from '../../Common/Simple.edit.display'; +export default [ + ...common, + { + key: 'labelPosition', + ignore: true + }, + { + key: 'placeholder', + ignore: true + }, + { + key: 'description', + ignore: true + }, + { + key: 'tooltip', + ignore: true + }, + { + key: 'disabled', + ignore: true + }, + { + key: 'hideLabel', + ignore: true + }, + { + weight: 160, + type: 'checkbox', + label: 'Auto adjust columns', + tooltip: 'Will automatically adjust columns based on if nested components are hidden.', + key: 'autoAdjust', + input: true + }, + { + weight: 161, + type: 'checkbox', + label: 'Hide Column when Children Hidden', + key: 'hideOnChildrenHidden', + tooltip: 'Check this if you would like to hide any column when the children within that column are also hidden', + input: true + } +]; diff --git a/frontend/components/src/components/SimpleColumns3/Component.form.ts b/frontend/components/src/components/SimpleColumns3/Component.form.ts new file mode 100644 index 0000000..7b2d92d --- /dev/null +++ b/frontend/components/src/components/SimpleColumns3/Component.form.ts @@ -0,0 +1,48 @@ +import baseEditForm from 'formiojs/components/_classes/component/Component.form'; + +import EditDisplay from './editForm/Component.edit.display'; + +import SimpleApi from '../Common/Simple.edit.api'; +import SimpleConditional from '../Common/Simple.edit.conditional'; + +export default function(...extend) { + return baseEditForm([ + EditDisplay, + { + key: 'data', + ignore: true, + }, + { + key: 'api', + ignore: true + }, + { + key: 'layout', + ignore: true + }, + { + key: 'conditional', + ignore: true + }, + { + key: 'validation', + ignore: true + }, + { + key: 'logic', + ignore: true + }, + { + label: 'API', + key: 'customAPI', + weight: 30, + components: SimpleApi + }, + { + label: 'Conditional', + key: 'customConditional', + weight: 40, + components: SimpleConditional + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleColumns3/Component.ts b/frontend/components/src/components/SimpleColumns3/Component.ts new file mode 100644 index 0000000..4d4945c --- /dev/null +++ b/frontend/components/src/components/SimpleColumns3/Component.ts @@ -0,0 +1,43 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.columns; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simplecols3'; +const DISPLAY = 'Columns - 3'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + columns: [ + { components: [], width: 4, offset: 0, push: 0, pull: 0, size: 'md' }, + { components: [], width: 4, offset: 0, push: 0, pull: 0, size: 'md' }, + { components: [], width: 4, offset: 0, push: 0, pull: 0, size: 'md' } + ], + clearOnHide: false, + input: false, + tableView: false, + persistent: false, + autoAdjust: false, + hideOnChildrenHidden: false + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'simple', + icon: 'columns', + weight: 51, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleColumns3/editForm/Component.edit.display.ts b/frontend/components/src/components/SimpleColumns3/editForm/Component.edit.display.ts new file mode 100644 index 0000000..cc2e172 --- /dev/null +++ b/frontend/components/src/components/SimpleColumns3/editForm/Component.edit.display.ts @@ -0,0 +1,47 @@ +import common from '../../Common/Simple.edit.display'; +export default { + key: 'display', + components: [ + ...common, + { + key: 'labelPosition', + ignore: true + }, + { + key: 'placeholder', + ignore: true + }, + { + key: 'description', + ignore: true + }, + { + key: 'tooltip', + ignore: true + }, + { + key: 'disabled', + ignore: true + }, + { + key: 'hideLabel', + ignore: true + }, + { + weight: 160, + type: 'checkbox', + label: 'Auto adjust columns', + tooltip: 'Will automatically adjust columns based on if nested components are hidden.', + key: 'autoAdjust', + input: true + }, + { + weight: 161, + type: 'checkbox', + label: 'Hide Column when Children Hidden', + key: 'hideOnChildrenHidden', + tooltip: 'Check this if you would like to hide any column when the children within that column are also hidden', + input: true + } + ] +} diff --git a/frontend/components/src/components/SimpleColumns4/Component.form.ts b/frontend/components/src/components/SimpleColumns4/Component.form.ts new file mode 100644 index 0000000..7b2d92d --- /dev/null +++ b/frontend/components/src/components/SimpleColumns4/Component.form.ts @@ -0,0 +1,48 @@ +import baseEditForm from 'formiojs/components/_classes/component/Component.form'; + +import EditDisplay from './editForm/Component.edit.display'; + +import SimpleApi from '../Common/Simple.edit.api'; +import SimpleConditional from '../Common/Simple.edit.conditional'; + +export default function(...extend) { + return baseEditForm([ + EditDisplay, + { + key: 'data', + ignore: true, + }, + { + key: 'api', + ignore: true + }, + { + key: 'layout', + ignore: true + }, + { + key: 'conditional', + ignore: true + }, + { + key: 'validation', + ignore: true + }, + { + key: 'logic', + ignore: true + }, + { + label: 'API', + key: 'customAPI', + weight: 30, + components: SimpleApi + }, + { + label: 'Conditional', + key: 'customConditional', + weight: 40, + components: SimpleConditional + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleColumns4/Component.ts b/frontend/components/src/components/SimpleColumns4/Component.ts new file mode 100644 index 0000000..adf9da1 --- /dev/null +++ b/frontend/components/src/components/SimpleColumns4/Component.ts @@ -0,0 +1,44 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.columns; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simplecols4'; +const DISPLAY = 'Columns - 4'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + columns: [ + { components: [], width: 3, offset: 0, push: 0, pull: 0, size: 'sm' }, + { components: [], width: 3, offset: 0, push: 0, pull: 0, size: 'sm' }, + { components: [], width: 3, offset: 0, push: 0, pull: 0, size: 'sm' }, + { components: [], width: 3, offset: 0, push: 0, pull: 0, size: 'sm' } + ], + clearOnHide: false, + input: false, + tableView: false, + persistent: false, + autoAdjust: false, + hideOnChildrenHidden: false + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'simple', + icon: 'columns', + weight: 52, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleColumns4/editForm/Component.edit.display.ts b/frontend/components/src/components/SimpleColumns4/editForm/Component.edit.display.ts new file mode 100644 index 0000000..dae87a5 --- /dev/null +++ b/frontend/components/src/components/SimpleColumns4/editForm/Component.edit.display.ts @@ -0,0 +1,48 @@ +import common from '../../Common/Simple.edit.display'; + +export default { + key: 'display', + components: [ + ...common, + { + key: 'labelPosition', + ignore: true + }, + { + key: 'placeholder', + ignore: true + }, + { + key: 'description', + ignore: true + }, + { + key: 'tooltip', + ignore: true + }, + { + key: 'disabled', + ignore: true + }, + { + key: 'hideLabel', + ignore: true + }, + { + weight: 160, + type: 'checkbox', + label: 'Auto adjust columns', + tooltip: 'Will automatically adjust columns based on if nested components are hidden.', + key: 'autoAdjust', + input: true + }, + { + weight: 161, + type: 'checkbox', + label: 'Hide Column when Children Hidden', + key: 'hideOnChildrenHidden', + tooltip: 'Check this if you would like to hide any column when the children within that column are also hidden', + input: true + } + ] +} diff --git a/frontend/components/src/components/SimpleContent/Component.form.ts b/frontend/components/src/components/SimpleContent/Component.form.ts new file mode 100644 index 0000000..7740e21 --- /dev/null +++ b/frontend/components/src/components/SimpleContent/Component.form.ts @@ -0,0 +1,63 @@ +import baseEditForm from 'formiojs/components/_classes/component/Component.form'; + +import SimpleApi from '../Common/Simple.edit.api'; +import SimpleConditional from '../Common/Simple.edit.conditional'; + +export default function(...extend) { + const editForm = baseEditForm([ + { + key: 'display', + ignore: true + }, + { + key: 'data', + ignore: true + }, + { + key: 'validation', + ignore: true + }, + { + key: 'api', + ignore: true + }, + { + key: 'conditional', + ignore: true + }, + { + key: 'layout', + ignore: true + }, + { + key: 'logic', + ignore: true + }, + { + label: 'API', + key: 'customAPI', + weight: 30, + components: SimpleApi + }, + { + label: 'Conditional', + key: 'customConditional', + weight: 40, + components: SimpleConditional + } + ], ...extend); + // Add content as full width above the settings. + editForm.components = [{ + weight: 0, + type: 'textarea', + editor: 'ckeditor', + label: 'Content', + hideLabel: true, + input: true, + key: 'html', + as: 'html', + rows: 3, + tooltip: 'The HTML template for the result data items.', + }].concat(editForm.components); + return editForm; +} diff --git a/frontend/components/src/components/SimpleContent/Component.ts b/frontend/components/src/components/SimpleContent/Component.ts new file mode 100644 index 0000000..e8a46d1 --- /dev/null +++ b/frontend/components/src/components/SimpleContent/Component.ts @@ -0,0 +1,34 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.content; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simplecontent'; +const DISPLAY = 'Text/Images'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + input: false, + html: '' + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'simple', + icon: 'pencil-square-o', + weight: 40, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleCurrencyAdvanced/Component.form.ts b/frontend/components/src/components/SimpleCurrencyAdvanced/Component.form.ts new file mode 100644 index 0000000..20c65eb --- /dev/null +++ b/frontend/components/src/components/SimpleCurrencyAdvanced/Component.form.ts @@ -0,0 +1,17 @@ +import baseEditForm from 'formiojs/components/currency/Currency.form'; +import EditValidation from './editForm/Component.edit.validation'; + +export default function(...extend) { + return baseEditForm([ + { + key: 'validation', + ignore: true + }, + { + label: 'Validation', + key: 'customValidation', + weight: 15, + components: EditValidation + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleCurrencyAdvanced/Component.ts b/frontend/components/src/components/SimpleCurrencyAdvanced/Component.ts new file mode 100644 index 0000000..8a65287 --- /dev/null +++ b/frontend/components/src/components/SimpleCurrencyAdvanced/Component.ts @@ -0,0 +1,33 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.currency; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simplecurrencyadvanced'; + +const DISPLAY = 'Currency'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'advanced', + icon: 'usd', + weight: 830, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleCurrencyAdvanced/editForm/Component.edit.validation.ts b/frontend/components/src/components/SimpleCurrencyAdvanced/editForm/Component.edit.validation.ts new file mode 100644 index 0000000..3de8c14 --- /dev/null +++ b/frontend/components/src/components/SimpleCurrencyAdvanced/editForm/Component.edit.validation.ts @@ -0,0 +1,19 @@ +import common from '../../Common/Advanced.edit.validation'; +import {reArrangeComponents} from '../../Common/function'; + +const neededposition = [ + 'validate.isUseForCopy', + 'validateOn', + 'validate.required', + 'unique', + 'errorLabel', + 'validate.customMessage', + 'custom-validation-js', + 'json-validation-json', + 'errors', + ]; + + const newPosition = reArrangeComponents(neededposition,[...common]); + + + export default newPosition; \ No newline at end of file diff --git a/frontend/components/src/components/SimpleDateTime/Component.form.ts b/frontend/components/src/components/SimpleDateTime/Component.form.ts new file mode 100644 index 0000000..bda335a --- /dev/null +++ b/frontend/components/src/components/SimpleDateTime/Component.form.ts @@ -0,0 +1,80 @@ +import baseEditForm from 'formiojs/components/_classes/component/Component.form'; + +import EditData from './editForm/Component.edit.data'; +import EditDisplay from './editForm/Component.edit.display'; + +import EditDate from './editForm/Component.edit.date'; +import EditTime from './editForm/Component.edit.time'; + +import SimpleApi from '../Common/Simple.edit.api'; +import SimpleConditional from '../Common/Simple.edit.conditional'; +import SimpleValidation from '../Common/Simple.edit.validation'; + +export default function(...extend) { + return baseEditForm([ + { + key: 'display', + components: EditDisplay + }, + { + key: 'data', + ignore: true, + }, + { + key: 'api', + ignore: true + }, + { + key: 'layout', + ignore: true + }, + { + key: 'conditional', + ignore: true + }, + { + key: 'validation', + ignore: true + }, + { + key: 'logic', + ignore: true + }, + { + label: 'Data', + key: 'customData', + weight: 10, + components: EditData + }, + { + label: 'Validation', + key: 'customValidation', + weight: 20, + components: SimpleValidation + }, + { + label: 'API', + key: 'customAPI', + weight: 30, + components: SimpleApi + }, + { + label: 'Conditional', + key: 'customConditional', + weight: 40, + components: SimpleConditional + }, + { + label: 'Date', + key: 'date', + weight: 1, + components: EditDate + }, + { + label: 'Time', + key: 'time', + weight: 2, + components: EditTime + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleDateTime/Component.ts b/frontend/components/src/components/SimpleDateTime/Component.ts new file mode 100644 index 0000000..6d5485b --- /dev/null +++ b/frontend/components/src/components/SimpleDateTime/Component.ts @@ -0,0 +1,73 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.datetime; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simpledatetime'; +const DISPLAY = 'Date / Time'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema( + { + type: ID, + label: DISPLAY, + key: ID, + format: 'yyyy-MM-dd hh:mm a', + useLocaleSettings: false, + allowInput: true, + enableDate: true, + enableTime: false, + defaultValue: '', + defaultDate: '', + displayInTimezone: 'viewer', + timezone: '', + datepickerMode: 'day', + datePicker: { + showWeeks: true, + startingDay: 0, + initDate: '', + minMode: 'day', + maxMode: 'year', + yearRows: 4, + yearColumns: 5, + minDate: null, + maxDate: null, + }, + timePicker: { + hourStep: 1, + minuteStep: 1, + showMeridian: true, + readonlyInput: false, + mousewheel: true, + arrowkeys: true, + }, + customOptions: {}, + }, + ...extend + ); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'simple', + icon: 'calendar', + weight: 20, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema(), + }; + } + + constructor(component, options, data) { + super(component, options, data); + // if enableTime is set to false, manually add time fields since it get removed later on through Form IO + if (!this.component.enableTime) { + this.component.format = this.component.format.concat(' hh:mm a'); + } + } +} diff --git a/frontend/components/src/components/SimpleDateTime/editForm/Component.edit.data.ts b/frontend/components/src/components/SimpleDateTime/editForm/Component.edit.data.ts new file mode 100644 index 0000000..be19704 --- /dev/null +++ b/frontend/components/src/components/SimpleDateTime/editForm/Component.edit.data.ts @@ -0,0 +1,4 @@ +import common from '../../Common/Simple.edit.data'; +export default [ + ...common, +]; diff --git a/frontend/components/src/components/SimpleDateTime/editForm/Component.edit.date.ts b/frontend/components/src/components/SimpleDateTime/editForm/Component.edit.date.ts new file mode 100644 index 0000000..14c5296 --- /dev/null +++ b/frontend/components/src/components/SimpleDateTime/editForm/Component.edit.date.ts @@ -0,0 +1,34 @@ +export default [ + { + type: 'datetime', + input: true, + key: 'datePicker.minDate', + label: 'Minimum allowed date', + weight: 10, + tooltip: 'Set the minimum allowed date.' + }, + { + type: 'datetime', + input: true, + key: 'datePicker.maxDate', + label: 'Maximum allowed Date', + weight: 20, + tooltip: 'Set the maximum allowed date.', + }, + { + type: 'checkbox', + input: true, + key: 'datePicker.disableWeekends', + label: 'Disable weekends', + tooltip: 'Check to disable weekends', + weight: 23 + }, + { + type: 'checkbox', + input: true, + key: 'datePicker.disableWeekdays', + label: 'Disable weekdays', + tooltip: 'Check to disable weekdays', + weight: 23 + } +]; diff --git a/frontend/components/src/components/SimpleDateTime/editForm/Component.edit.display.ts b/frontend/components/src/components/SimpleDateTime/editForm/Component.edit.display.ts new file mode 100644 index 0000000..b8e3d9b --- /dev/null +++ b/frontend/components/src/components/SimpleDateTime/editForm/Component.edit.display.ts @@ -0,0 +1,36 @@ +import common from '../../Common/Simple.edit.display'; +export default [ + ...common, + { + key: 'refreshOnChange', + ignore: true + }, + { + key: 'className', + ignore: true, + }, + { + key: 'prefix', + ignore: true + }, + { + key: 'suffix', + ignore: true + }, + { + key: 'inputMask', + ignore: true + }, + { + key: 'allowMultipleMasks', + ignore: true + }, + { + key: 'showWordCount', + ignore: true, + }, + { + key: 'showCharCount', + ignore: true, + }, +]; diff --git a/frontend/components/src/components/SimpleDateTime/editForm/Component.edit.time.ts b/frontend/components/src/components/SimpleDateTime/editForm/Component.edit.time.ts new file mode 100644 index 0000000..7629a78 --- /dev/null +++ b/frontend/components/src/components/SimpleDateTime/editForm/Component.edit.time.ts @@ -0,0 +1,34 @@ +export default [ + { + type: 'checkbox', + input: true, + key: 'enableTime', + label: 'Enable Time Input', + tooltip: 'Enables time input for this field.', + weight: 30 + }, + { + type: 'number', + input: true, + key: 'timePicker.hourStep', + label: 'Hour Step Size', + tooltip: 'The number of hours to increment/decrement in the time picker.', + weight: 10 + }, + { + type: 'number', + input: true, + key: 'timePicker.minuteStep', + label: 'Minute Step Size', + tooltip: 'The number of minutes to increment/decrement in the time picker.', + weight: 20 + }, + { + type: 'checkbox', + input: true, + key: 'timePicker.showMeridian', + label: '12 Hour Time (AM/PM)', + tooltip: 'Display time in 12 hour time with AM/PM.', + weight: 30 + } +]; diff --git a/frontend/components/src/components/SimpleDateTimeAdvanced/Component.form.ts b/frontend/components/src/components/SimpleDateTimeAdvanced/Component.form.ts new file mode 100644 index 0000000..6d298d4 --- /dev/null +++ b/frontend/components/src/components/SimpleDateTimeAdvanced/Component.form.ts @@ -0,0 +1,17 @@ +import baseEditForm from 'formiojs/components/datetime/DateTime.form'; +import EditValidation from './editForm/Component.edit.validation'; + +export default function(...extend) { + return baseEditForm([ + { + key: 'validation', + ignore: true + }, + { + label: 'Validation', + key: 'customValidation', + weight: 15, + components: EditValidation + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleDateTimeAdvanced/Component.ts b/frontend/components/src/components/SimpleDateTimeAdvanced/Component.ts new file mode 100644 index 0000000..e71ce65 --- /dev/null +++ b/frontend/components/src/components/SimpleDateTimeAdvanced/Component.ts @@ -0,0 +1,33 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.datetime; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simpledatetimeadvanced'; + +const DISPLAY = 'Date / Time'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'advanced', + icon: 'calendar', + weight: 776, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleDateTimeAdvanced/editForm/Component.edit.validation.ts b/frontend/components/src/components/SimpleDateTimeAdvanced/editForm/Component.edit.validation.ts new file mode 100644 index 0000000..0c0a4e0 --- /dev/null +++ b/frontend/components/src/components/SimpleDateTimeAdvanced/editForm/Component.edit.validation.ts @@ -0,0 +1,24 @@ +import common from '../../Common/Advanced.edit.validation'; +import validationComponents from 'formiojs/components/datetime/editForm/DateTime.edit.validation'; +import {reArrangeComponents} from '../../Common/function'; + +const neededposition = [ + 'validate.isUseForCopy', + 'validateOn', + 'validate.required', + 'enableMinDateInput', + 'datePicker.minDate', + 'enableMaxDateInput', + 'datePicker.maxDate', + 'unique', + 'errorLabel', + 'validate.customMessage', + 'custom-validation-js', + 'json-validation-json', + 'errors', + ]; + + const newPosition = reArrangeComponents(neededposition,[...validationComponents,...common]); + + + export default newPosition; \ No newline at end of file diff --git a/frontend/components/src/components/SimpleDay/Component.form.ts b/frontend/components/src/components/SimpleDay/Component.form.ts new file mode 100644 index 0000000..f145a27 --- /dev/null +++ b/frontend/components/src/components/SimpleDay/Component.form.ts @@ -0,0 +1,87 @@ +import baseEditForm from 'formiojs/components/_classes/component/Component.form'; + +import EditData from './editForm/Component.edit.data'; +import EditDisplay from './editForm/Component.edit.display'; +import EditValidation from './editForm/Component.edit.validation'; + +import EditDay from './editForm/Component.edit.day'; +import EditMonth from './editForm/Component.edit.month'; +import EditYear from './editForm/Component.edit.year'; + +import SimpleApi from '../Common/Simple.edit.api'; +import SimpleConditional from '../Common/Simple.edit.conditional'; + +export default function(...extend) { + return baseEditForm([ + { + key: 'display', + components: EditDisplay + }, + { + key: 'data', + ignore: true, + }, + { + key: 'api', + ignore: true + }, + { + key: 'layout', + ignore: true + }, + { + key: 'conditional', + ignore: true + }, + { + key: 'validation', + ignore: true + }, + { + key: 'logic', + ignore: true + }, + { + label: 'Data', + key: 'customData', + weight: 10, + components: EditData + }, + { + label: 'Validation', + key: 'customValidation', + weight: 20, + components: EditValidation + }, + { + label: 'API', + key: 'customAPI', + weight: 30, + components: SimpleApi + }, + { + label: 'Conditional', + key: 'customConditional', + weight: 40, + components: SimpleConditional + }, + { + key: 'day', + label: 'Day', + weight: 3, + components: EditDay + }, + { + key: 'month', + label: 'Month', + weight: 3, + components: EditMonth + }, + { + key: 'year', + label: 'Year', + weight: 3, + components: EditYear + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleDay/Component.ts b/frontend/components/src/components/SimpleDay/Component.ts new file mode 100644 index 0000000..6e4b636 --- /dev/null +++ b/frontend/components/src/components/SimpleDay/Component.ts @@ -0,0 +1,50 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.day; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simpleday'; +const DISPLAY = 'Day'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + fields: { + day: { + type: 'number', + placeholder: '', + required: false + }, + month: { + type: 'select', + placeholder: '', + required: false + }, + year: { + type: 'number', + placeholder: '', + required: false + } + }, + dayFirst: false, + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'simple', + icon: 'calendar', + weight: 21, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleDay/editForm/Component.edit.data.ts b/frontend/components/src/components/SimpleDay/editForm/Component.edit.data.ts new file mode 100644 index 0000000..9c1859e --- /dev/null +++ b/frontend/components/src/components/SimpleDay/editForm/Component.edit.data.ts @@ -0,0 +1,11 @@ +export default [ + { + type: 'textfield', + label: 'Default Value', + key: 'defaultValue', + weight: 5, + placeholder: 'Default Value', + tooltip: 'The will be the value for this field, before user interaction. Having a default value will override the placeholder text.', + input: true + }, +]; diff --git a/frontend/components/src/components/SimpleDay/editForm/Component.edit.day.ts b/frontend/components/src/components/SimpleDay/editForm/Component.edit.day.ts new file mode 100644 index 0000000..22525ef --- /dev/null +++ b/frontend/components/src/components/SimpleDay/editForm/Component.edit.day.ts @@ -0,0 +1,46 @@ +export default [ + { + wieght: 200, + type: 'select', + datasrc: 'values', + key: 'fields.day.type', + label: 'Type', + data: { + values: [ + { + label: 'Number', + value: 'number' + }, + { + label: 'Select', + value: 'select' + }, + ] + } + }, + { + weight: 210, + type: 'textfield', + input: true, + key: 'fields.day.placeholder', + label: 'Placeholder', + placeholder: 'Day Placeholder', + tooltip: 'The placeholder text that will appear when Day field is empty.' + }, + { + weight: 215, + type: 'checkbox', + label: 'Hidden', + tooltip: 'Hide the Day part of the component.', + key: 'fields.day.hide', + input: true + }, + { + weight: 214, + type: 'checkbox', + label: 'Day First', + tooltip: 'Display the Day field before the Month field.', + key: 'dayFirst', + input: true + }, +]; diff --git a/frontend/components/src/components/SimpleDay/editForm/Component.edit.display.ts b/frontend/components/src/components/SimpleDay/editForm/Component.edit.display.ts new file mode 100644 index 0000000..92c3993 --- /dev/null +++ b/frontend/components/src/components/SimpleDay/editForm/Component.edit.display.ts @@ -0,0 +1,83 @@ +import common from '../../Common/Simple.edit.display'; +export default [ + ...common, + { + key: 'refreshOnChange', + ignore: true + }, + { + key: 'className', + ignore: true, + }, + { + key: 'prefix', + ignore: true + }, + { + key: 'suffix', + ignore: true + }, + { + key: 'inputMask', + ignore: true + }, + { + key: 'allowMultipleMasks', + ignore: true + }, + { + key: 'showWordCount', + ignore: true, + }, + { + key: 'showCharCount', + ignore: true, + }, + { + key: 'labelPosition', + ignore: true + }, + { + key: 'useLocaleSettings', + ignore: true + }, + { + weight: 15, + type: 'checkbox', + label: 'Hide Input Labels', + tooltip: 'Hide the labels of component inputs. This allows you to show the labels in the form builder, but not when it is rendered.', + key: 'hideInputLabels', + input: true + }, + { + type: 'select', + input: true, + key: 'inputsLabelPosition', + label: 'Inputs Label Position', + tooltip: 'Position for the labels for inputs for this field.', + weight: 40, + defaultValue: 'top', + dataSrc: 'values', + data: { + values: [ + { label: 'Top', value: 'top' }, + { label: 'Left', value: 'left' }, + { label: 'Right', value: 'right' }, + { label: 'Bottom', value: 'bottom' } + ] + } + }, + { + key: 'placeholder', + ignore: true + }, + { + weight: 213, + type: 'checkbox', + label: 'Use Locale Settings', + tooltip: 'Use locale settings to display day.', + key: 'useLocaleSettings', + input: true + }, + +]; diff --git a/frontend/components/src/components/SimpleDay/editForm/Component.edit.month.ts b/frontend/components/src/components/SimpleDay/editForm/Component.edit.month.ts new file mode 100644 index 0000000..5d8f609 --- /dev/null +++ b/frontend/components/src/components/SimpleDay/editForm/Component.edit.month.ts @@ -0,0 +1,38 @@ +export default [ + { + wieght: 200, + type: 'select', + datasrc: 'values', + key: 'fields.month.type', + label: 'Type of input', + data: { + values: [ + { + label: 'Number', + value: 'number' + }, + { + label: 'Select', + value: 'select' + }, + ] + } + }, + { + weight: 210, + type: 'textfield', + input: true, + key: 'fields.month.placeholder', + label: 'Placeholder', + placeholder: 'Month Placeholder', + tooltip: 'The placeholder text that will appear when Month field is empty.' + }, + { + weight: 215, + type: 'checkbox', + label: 'Hidden', + tooltip: 'Hide the Month part of the component.', + key: 'fields.month.hide', + input: true + }, +]; diff --git a/frontend/components/src/components/SimpleDay/editForm/Component.edit.validation.ts b/frontend/components/src/components/SimpleDay/editForm/Component.edit.validation.ts new file mode 100644 index 0000000..45a1a08 --- /dev/null +++ b/frontend/components/src/components/SimpleDay/editForm/Component.edit.validation.ts @@ -0,0 +1,46 @@ +import common from '../../Common/Simple.edit.validation'; +export default [ + ...common, + { + weight: 10, + type: 'checkbox', + label: 'Require Month', + tooltip: 'A required field must be filled in before the form can be submitted.', + key: 'fields.month.required', + input: true + }, + { + weight: 0, + type: 'checkbox', + label: 'Require Day', + tooltip: 'A required field must be filled in before the form can be submitted.', + key: 'fields.day.required', + input: true + }, + { + weight: 20, + type: 'checkbox', + label: 'Require Year', + tooltip: 'A required field must be filled in before the form can be submitted.', + key: 'fields.year.required', + input: true + }, + { + weight: 40, + type: 'textfield', + label: 'Minimum Day', + placeholder: 'yyyy-MM-dd', + tooltip: 'A minimum date that can be set. You can also use Moment.js functions. For example: \n \n moment().subtract(10, \'days\')', + key: 'minDate', + input: true, + }, + { + weight: 30, + type: 'textfield', + label: 'Maximum Day', + placeholder: 'yyyy-MM-dd', + tooltip: 'A maximum day that can be set. You can also use Moment.js functions. For example: \n \n moment().add(10, \'days\')', + key: 'maxDate', + input: true, + }, +]; diff --git a/frontend/components/src/components/SimpleDay/editForm/Component.edit.year.ts b/frontend/components/src/components/SimpleDay/editForm/Component.edit.year.ts new file mode 100644 index 0000000..e3ca7ff --- /dev/null +++ b/frontend/components/src/components/SimpleDay/editForm/Component.edit.year.ts @@ -0,0 +1,56 @@ +export default [ + { + wieght: 200, + type: 'select', + datasrc: 'values', + key: 'fields.year.type', + label: 'Type of input', + data: { + values: [ + { + label: 'Number', + value: 'number' + }, + { + label: 'Select', + value: 'select' + }, + ] + } + }, + { + weight: 203, + type: 'number', + input: true, + key: 'fields.year.minYear', + label: 'Minimum Year', + placeholder: '1900', + tooltip: 'The minimum year that can be entered.' + }, + { + weight: 204, + type: 'number', + input: true, + key: 'fields.year.maxYear', + label: 'Maximum Year', + placeholder: '2030', + tooltip: 'The maximum year that can be entered.' + }, + { + weight: 210, + type: 'textfield', + input: true, + key: 'fields.year.placeholder', + label: 'Placeholder', + placeholder: 'Year Placeholder', + tooltip: 'The placeholder text that will appear when Year field is empty.' + }, + { + weight: 215, + type: 'checkbox', + label: 'Hidden', + tooltip: 'Hide the Year part of the component.', + key: 'fields.year.hide', + input: true + }, +]; diff --git a/frontend/components/src/components/SimpleDayAdvanced/Component.form.ts b/frontend/components/src/components/SimpleDayAdvanced/Component.form.ts new file mode 100644 index 0000000..d248035 --- /dev/null +++ b/frontend/components/src/components/SimpleDayAdvanced/Component.form.ts @@ -0,0 +1,17 @@ +import baseEditForm from 'formiojs/components/day/Day.form'; +import EditValidation from './editForm/Component.edit.validation'; + +export default function(...extend) { + return baseEditForm([ + { + key: 'validation', + ignore: true + }, + { + label: 'Validation', + key: 'customValidation', + weight: 15, + components: EditValidation + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleDayAdvanced/Component.ts b/frontend/components/src/components/SimpleDayAdvanced/Component.ts new file mode 100644 index 0000000..f2c8387 --- /dev/null +++ b/frontend/components/src/components/SimpleDayAdvanced/Component.ts @@ -0,0 +1,31 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.day; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simpledayadvanced'; +const DISPLAY = 'Day'; +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'advanced', + icon: 'calendar', + weight: 790, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleDayAdvanced/editForm/Component.edit.validation.ts b/frontend/components/src/components/SimpleDayAdvanced/editForm/Component.edit.validation.ts new file mode 100644 index 0000000..ae5cbcc --- /dev/null +++ b/frontend/components/src/components/SimpleDayAdvanced/editForm/Component.edit.validation.ts @@ -0,0 +1,24 @@ +import common from '../../Common/Advanced.edit.validation'; +import validationComponents from 'formiojs/components/day/editForm/Day.edit.validation'; +import {reArrangeComponents} from '../../Common/function'; + +const neededposition = [ + 'validate.isUseForCopy', + 'validateOn', + 'fields.day.required', + 'fields.month.required', + 'fields.year.required', + 'maxDate', + 'minDate', + 'unique', + 'errorLabel', + 'validate.customMessage', + 'custom-validation-js', + 'json-validation-json', + 'errors', + ]; + + const newPosition = reArrangeComponents(neededposition,[...validationComponents,...common]); + + + export default newPosition; \ No newline at end of file diff --git a/frontend/components/src/components/SimpleEmail/Component.form.ts b/frontend/components/src/components/SimpleEmail/Component.form.ts new file mode 100644 index 0000000..7017d0c --- /dev/null +++ b/frontend/components/src/components/SimpleEmail/Component.form.ts @@ -0,0 +1,62 @@ +import baseEditForm from 'formiojs/components/_classes/component/Component.form'; + +import EditData from './editForm/Component.edit.data'; +import EditDisplay from './editForm/Component.edit.display'; + +import SimpleApi from '../Common/Simple.edit.api'; +import SimpleConditional from '../Common/Simple.edit.conditional'; +import SimpleValidation from '../Common/Simple.edit.validation'; + +export default function(...extend) { + return baseEditForm([ + EditDisplay, + { + key: 'data', + ignore: true, + }, + { + key: 'api', + ignore: true + }, + { + key: 'layout', + ignore: true + }, + { + key: 'conditional', + ignore: true + }, + { + key: 'validation', + ignore: true + }, + { + key: 'logic', + ignore: true + }, + { + label: 'Data', + key: 'customData', + weight: 10, + components: EditData + }, + { + label: 'Validation', + key: 'customValidation', + weight: 20, + components: SimpleValidation + }, + { + label: 'API', + key: 'customAPI', + weight: 30, + components: SimpleApi + }, + { + label: 'Conditional', + key: 'customConditional', + weight: 40, + components: SimpleConditional + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleEmail/Component.ts b/frontend/components/src/components/SimpleEmail/Component.ts new file mode 100644 index 0000000..4e5e7d3 --- /dev/null +++ b/frontend/components/src/components/SimpleEmail/Component.ts @@ -0,0 +1,33 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.email; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simpleemail'; +const DISPLAY = 'Email'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + inputType: 'email' + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'simple', + icon: 'at', + weight: 12, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleEmail/editForm/Component.edit.data.ts b/frontend/components/src/components/SimpleEmail/editForm/Component.edit.data.ts new file mode 100644 index 0000000..a0439fd --- /dev/null +++ b/frontend/components/src/components/SimpleEmail/editForm/Component.edit.data.ts @@ -0,0 +1,26 @@ +import common from '../../Common/Simple.edit.data'; +export default [ + ...common, + { + weight: 200, + type: 'radio', + label: 'Text Case', + key: 'case', + tooltip: 'When data is entered, you can change the case of the value.', + input: true, + values: [ + { + value: 'mixed', + label: 'Mixed (Allow upper and lower case)' + }, + { + value: 'uppercase', + label: 'Uppercase' + }, + { + value: 'lowercase', + label: 'Lowercase' + } + ] + } +]; diff --git a/frontend/components/src/components/SimpleEmail/editForm/Component.edit.display.ts b/frontend/components/src/components/SimpleEmail/editForm/Component.edit.display.ts new file mode 100644 index 0000000..47b34a0 --- /dev/null +++ b/frontend/components/src/components/SimpleEmail/editForm/Component.edit.display.ts @@ -0,0 +1,39 @@ +import common from '../../Common/Simple.edit.display'; +export default { + key: 'display', + components: [ + ...common, + { + key: 'refreshOnChange', + ignore: true + }, + { + key: 'className', + ignore: true, + }, + { + key: 'prefix', + ignore: true + }, + { + key: 'suffix', + ignore: true + }, + { + key: 'inputMask', + ignore: true + }, + { + key: 'allowMultipleMasks', + ignore: true + }, + { + key: 'showWordCount', + ignore: true, + }, + { + key: 'showCharCount', + ignore: true, + }, + ] +} diff --git a/frontend/components/src/components/SimpleEmailAdvanced/Component.form.ts b/frontend/components/src/components/SimpleEmailAdvanced/Component.form.ts new file mode 100644 index 0000000..f553a47 --- /dev/null +++ b/frontend/components/src/components/SimpleEmailAdvanced/Component.form.ts @@ -0,0 +1,17 @@ +import baseEditForm from 'formiojs/components/email/Email.form'; +import EditValidation from './editForm/Component.edit.validation'; + +export default function(...extend) { + return baseEditForm([ + { + key: 'validation', + ignore: true + }, + { + label: 'Validation', + key: 'customValidation', + weight: 20, + components: EditValidation + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleEmailAdvanced/Component.ts b/frontend/components/src/components/SimpleEmailAdvanced/Component.ts new file mode 100644 index 0000000..cefaa38 --- /dev/null +++ b/frontend/components/src/components/SimpleEmailAdvanced/Component.ts @@ -0,0 +1,33 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.email; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simpleemailadvanced'; +const DISPLAY = 'Email'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + inputType: 'email' + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'advanced', + icon: 'at', + weight: 720, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleEmailAdvanced/editForm/Component.edit.validation.ts b/frontend/components/src/components/SimpleEmailAdvanced/editForm/Component.edit.validation.ts new file mode 100644 index 0000000..0bfa02c --- /dev/null +++ b/frontend/components/src/components/SimpleEmailAdvanced/editForm/Component.edit.validation.ts @@ -0,0 +1,21 @@ +import common from '../../Common/Advanced.edit.validation'; +import {reArrangeComponents} from '../../Common/function'; + +const neededposition = [ + 'validate.isUseForCopy', + 'validateOn', + 'validate.required', + 'unique', + 'kickbox', + 'validate.minLength', + 'validate.maxLength', + 'validate.pattern', + 'errorLabel', + 'validate.customMessage', + 'errors', + 'custom-validation-js', + 'json-validation-json' + ]; + + const newPosition = reArrangeComponents(neededposition,common); + export default newPosition; \ No newline at end of file diff --git a/frontend/components/src/components/SimpleFieldSet/Component.form.ts b/frontend/components/src/components/SimpleFieldSet/Component.form.ts new file mode 100644 index 0000000..7b2d92d --- /dev/null +++ b/frontend/components/src/components/SimpleFieldSet/Component.form.ts @@ -0,0 +1,48 @@ +import baseEditForm from 'formiojs/components/_classes/component/Component.form'; + +import EditDisplay from './editForm/Component.edit.display'; + +import SimpleApi from '../Common/Simple.edit.api'; +import SimpleConditional from '../Common/Simple.edit.conditional'; + +export default function(...extend) { + return baseEditForm([ + EditDisplay, + { + key: 'data', + ignore: true, + }, + { + key: 'api', + ignore: true + }, + { + key: 'layout', + ignore: true + }, + { + key: 'conditional', + ignore: true + }, + { + key: 'validation', + ignore: true + }, + { + key: 'logic', + ignore: true + }, + { + label: 'API', + key: 'customAPI', + weight: 30, + components: SimpleApi + }, + { + label: 'Conditional', + key: 'customConditional', + weight: 40, + components: SimpleConditional + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleFieldSet/Component.ts b/frontend/components/src/components/SimpleFieldSet/Component.ts new file mode 100644 index 0000000..c7da807 --- /dev/null +++ b/frontend/components/src/components/SimpleFieldSet/Component.ts @@ -0,0 +1,36 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.fieldset; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simplefieldset'; +const DISPLAY = 'Field Set'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + legend: '', + components: [], + input: false, + persistent: false + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'simple', + icon: 'th-large', + weight: 55, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleFieldSet/editForm/Component.edit.display.ts b/frontend/components/src/components/SimpleFieldSet/editForm/Component.edit.display.ts new file mode 100644 index 0000000..dac9221 --- /dev/null +++ b/frontend/components/src/components/SimpleFieldSet/editForm/Component.edit.display.ts @@ -0,0 +1,61 @@ +export default { + key: 'display', + components: [ + { + key: 'labelPosition', + ignore: true + }, + { + key: 'placeholder', + ignore: true + }, + { + key: 'description', + ignore: true + }, + { + key: 'tooltip', + ignore: true + }, + { + key: 'autofocus', + ignore: true + }, + { + key: 'tabindex', + ignore: true + }, + { + key: 'disabled', + ignore: true + }, + { + key: 'tableView', + ignore: true + }, + { + key: 'hideLabel', + ignore: true + }, + { + key: 'modalEdit', + ignore: true + }, + { + key: 'label', + hidden: true, + calculateValue(context) { + return context.data.legend; + } + }, + { + weight: 1, + type: 'textfield', + input: true, + key: 'legend', + label: 'Caption', + placeholder: 'Caption', + tooltip: 'The caption for this Fieldset.' + }, + ] +} diff --git a/frontend/components/src/components/SimpleFile/Component.form.ts b/frontend/components/src/components/SimpleFile/Component.form.ts new file mode 100644 index 0000000..63842f8 --- /dev/null +++ b/frontend/components/src/components/SimpleFile/Component.form.ts @@ -0,0 +1,72 @@ +import baseEditForm from 'formiojs/components/_classes/component/Component.form'; + +import EditData from './editForm/Component.edit.data'; +import EditDisplay from './editForm/Component.edit.display'; +import EditFile from './editForm/Component.edit.file'; + +import SimpleApi from '../Common/Simple.edit.api'; +import SimpleConditional from '../Common/Simple.edit.conditional'; +import SimpleValidation from '../Common/Simple.edit.validation'; + +export default function(...extend) { + return baseEditForm([ + { + key: 'display', + components: EditDisplay + }, + { + key: 'data', + ignore: true, + }, + { + key: 'api', + ignore: true + }, + { + key: 'layout', + ignore: true + }, + { + key: 'conditional', + ignore: true + }, + { + key: 'validation', + ignore: true + }, + { + key: 'logic', + ignore: true + }, + { + label: 'File', + key: 'file', + weight: 10, + components: EditFile + }, + { + label: 'Data', + key: 'customData', + weight: 15, + components: EditData + }, + { + label: 'Validation', + key: 'customValidation', + weight: 20, + components: SimpleValidation + }, + { + label: 'API', + key: 'customAPI', + weight: 30, + components: SimpleApi + }, + { + label: 'Conditional', + key: 'customConditional', + weight: 40, + components: SimpleConditional + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleFile/Component.ts b/frontend/components/src/components/SimpleFile/Component.ts new file mode 100644 index 0000000..8b48526 --- /dev/null +++ b/frontend/components/src/components/SimpleFile/Component.ts @@ -0,0 +1,212 @@ +/* tslint:disable */ +import {Components, Utils} from 'formiojs'; +const ParentComponent = (Components as any).components.file; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; +import uniqueName = Utils.uniqueName; + +const ID = 'simplefile'; +const DISPLAY = 'File Upload'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + storage: 'chefs', + url: '/files', + fileKey: 'files', + fileNameTemplate: '{{fileName}}', + image: false, + webcam: false, + webcamSize: 320, + privateDownload: false, + imageSize: '200', + filePattern: '*', + fileMinSize: '0KB', + fileMaxSize: '1GB', + uploadOnly: false, + customClass: 'formio-component-file' + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'simple', + icon: 'file', + weight: 13, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } + + // we will read these in from runtime + private _enabled: boolean; + + constructor(...args) { + super(...args); + try { + if (this.options && this.options.componentOptions) { + // componentOptions are passed in from the viewer, basically runtime configuration + const opts = this.options.componentOptions[ID]; + this.component.options = {...this.component.options, ...opts}; + // the config.uploads object will say what size our server can handle and what path to use. + if (opts.config && opts.config.uploads) { + const remSlash = (s) => s.replace(/^\s*\/*\s*|\s*\/*\s*$/gm, ''); + + const cfg = opts.config; + const uploads = cfg.uploads; + + this.component.fileMinSize = uploads.fileMinSize; + this.component.fileMaxSize = uploads.fileMaxSize; + // set the default url to be for uploads. + this.component.url = `/${remSlash(cfg.basePath)}/${remSlash(cfg.apiPath)}/${remSlash(uploads.path)}`; + // no idea what to do with this yet... + this._enabled = uploads.enabled; + } + } + } catch (e) {}; + } + + deleteFile(fileInfo) { + const { options = {} } = this.component; + const Provider = Formio.Providers.getProvider('storage', this.component.storage); + if (Provider) { + const provider = new Provider(this); + if (fileInfo && provider && typeof provider.deleteFile === 'function') { + provider.deleteFile(fileInfo, options) + } + } + } + + upload(files) { + // Only allow one upload if not multiple. + if (!this.component.multiple) { + files = Array.prototype.slice.call(files, 0, 1); + } + if (this.component.storage && files && files.length) { + // files is not really an array and does not have a forEach method, so fake it. + Array.prototype.forEach.call(files, (file) => { + const fileName = uniqueName(file.name, this.component.fileNameTemplate, this.evalContext()); + const fileUpload = { + originalName: file.name, + name: fileName, + size: file.size, + status: 'info', + message: this.t('Starting upload'), + }; + + // Check file pattern + if (this.component.filePattern && !this.validatePattern(file, this.component.filePattern)) { + fileUpload.status = 'error'; + fileUpload.message = this.t('File is the wrong type; it must be {{ pattern }}', { + pattern: this.component.filePattern, + }); + } + + // Check file minimum size + if (this.component.fileMinSize && !this.validateMinSize(file, this.component.fileMinSize)) { + fileUpload.status = 'error'; + fileUpload.message = this.t('File is too small; it must be at least {{ size }}', { + size: this.component.fileMinSize, + }); + } + + // Check file maximum size + if (this.component.fileMaxSize && !this.validateMaxSize(file, this.component.fileMaxSize)) { + fileUpload.status = 'error'; + fileUpload.message = this.t('File is too big; it must be at most {{ size }}', { + size: this.component.fileMaxSize, + }); + } + + // Get a unique name for this file to keep file collisions from occurring. + const dir = this.interpolate(this.component.dir || ''); + const { fileService } = this; + if (!fileService) { + fileUpload.status = 'error'; + fileUpload.message = this.t('File Service not provided.'); + } + + this.statuses.push(fileUpload); + this.redraw(); + + if (fileUpload.status !== 'error') { + if (this.component.privateDownload) { + file.private = true; + } + const { storage, options = {} } = this.component; + const url = this.interpolate(this.component.url); + let groupKey = null; + let groupPermissions = null; + + //Iterate through form components to find group resource if one exists + this.root.everyComponent((element) => { + if (element.component?.submissionAccess || element.component?.defaultPermission) { + groupPermissions = !element.component.submissionAccess ? [ + { + type: element.component.defaultPermission, + roles: [], + }, + ] : element.component.submissionAccess; + + groupPermissions.forEach((permission) => { + groupKey = ['admin', 'write', 'create'].includes(permission.type) ? element.component.key : null; + }); + } + }); + + const fileKey = this.component.fileKey || 'file'; + const groupResourceId = groupKey ? this.currentForm.submission.data[groupKey]._id : null; + fileService.uploadFile(storage, file, fileName, dir, (evt) => { + fileUpload.status = 'progress'; + // @ts-ignore + fileUpload.progress = parseInt(100.0 * evt.loaded / evt.total); + delete fileUpload.message; + this.redraw(); + }, url, options, fileKey, groupPermissions, groupResourceId) + .then((fileInfo) => { + const index = this.statuses.indexOf(fileUpload); + if (index !== -1) { + this.statuses.splice(index, 1); + } + fileInfo.originalName = file.name; + if (!this.hasValue()) { + this.dataValue = []; + } + this.dataValue.push(fileInfo); + this.redraw(); + this.triggerChange(); + }) + .catch((response) => { + fileUpload.status = 'error'; + // grab the detail out our api-problem response. + fileUpload.message = response.detail; + // @ts-ignore + delete fileUpload.progress; + this.redraw(); + }); + } + }); + } + } + + getFile(fileInfo) { + const { options = {} } = this.component; + const { fileService } = this; + if (!fileService) { + return alert('File Service not provided'); + } + fileService.downloadFile(fileInfo, options) + .catch((response) => { + // Is alert the best way to do this? + // User is expecting an immediate notification due to attempting to download a file. + alert(response); + }); + } +} diff --git a/frontend/components/src/components/SimpleFile/editForm/Component.edit.data.ts b/frontend/components/src/components/SimpleFile/editForm/Component.edit.data.ts new file mode 100644 index 0000000..6727188 --- /dev/null +++ b/frontend/components/src/components/SimpleFile/editForm/Component.edit.data.ts @@ -0,0 +1,10 @@ +export default [ + { + weight: 0, + type: 'checkbox', + label: 'Multiple Values', + tooltip: 'Allows multiple values to be entered for this field.', + key: 'multiple', + input: true + }, +]; diff --git a/frontend/components/src/components/SimpleFile/editForm/Component.edit.display.ts b/frontend/components/src/components/SimpleFile/editForm/Component.edit.display.ts new file mode 100644 index 0000000..fded672 --- /dev/null +++ b/frontend/components/src/components/SimpleFile/editForm/Component.edit.display.ts @@ -0,0 +1,40 @@ +import common from '../../Common/Simple.edit.display'; +export default [ + ...common, + { + key: 'placeholder', + ignore: true + }, + { + key: 'refreshOnChange', + ignore: true + }, + { + key: 'className', + ignore: true, + }, + { + key: 'prefix', + ignore: true + }, + { + key: 'suffix', + ignore: true + }, + { + key: 'inputMask', + ignore: true + }, + { + key: 'allowMultipleMasks', + ignore: true + }, + { + key: 'showWordCount', + ignore: true, + }, + { + key: 'showCharCount', + ignore: true, + }, +]; diff --git a/frontend/components/src/components/SimpleFile/editForm/Component.edit.file.ts b/frontend/components/src/components/SimpleFile/editForm/Component.edit.file.ts new file mode 100644 index 0000000..5064c66 --- /dev/null +++ b/frontend/components/src/components/SimpleFile/editForm/Component.edit.file.ts @@ -0,0 +1,33 @@ +export default [ + { + type: 'datagrid', + input: true, + label: 'File Types', + key: 'fileTypes', + tooltip: 'Specify file types to classify the uploads. This is useful if you allow multiple types of uploads but want to allow the user to specify which type of file each is.', + weight: 11, + components: [ + { + label: 'Label', + key: 'label', + input: true, + type: 'textfield' + }, + { + label: 'Value', + key: 'value', + input: true, + type: 'textfield' + } + ] + }, + { + type: 'textfield', + input: true, + key: 'filePattern', + label: 'File Pattern', + placeholder: '.pdf,.jpg', + tooltip: 'See <a href=\'https://github.com/danialfarid/ng-file-upload#full-reference\' target=\'_blank\'>https://github.com/danialfarid/ng-file-upload#full-reference</a> for how to specify file patterns.', + weight: 50 + } +]; diff --git a/frontend/components/src/components/SimpleHeading/Component.form.ts b/frontend/components/src/components/SimpleHeading/Component.form.ts new file mode 100644 index 0000000..6184f07 --- /dev/null +++ b/frontend/components/src/components/SimpleHeading/Component.form.ts @@ -0,0 +1,33 @@ +import baseEditForm from 'formiojs/components/_classes/component/Component.form'; + +import EditDisplay from './editForm/Component.edit.display'; + +export default function(...extend) { + return baseEditForm([ + { + key: 'display', + components: EditDisplay + + }, + { + key: 'data', + ignore: true + }, + { + key: 'validation', + ignore: true + }, + { + key: 'api', + ignore: true + }, + { + key: 'conditional', + ignore: true + }, + { + key: 'layout', + ignore: true + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleHeading/Component.ts b/frontend/components/src/components/SimpleHeading/Component.ts new file mode 100644 index 0000000..01b9154 --- /dev/null +++ b/frontend/components/src/components/SimpleHeading/Component.ts @@ -0,0 +1,38 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.htmlelement; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simpleheading'; +const DISPLAY = 'Heading'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + tag: 'h1', + headingSize: 'h1', + attrs: [], + content: '', + input: false, + persistent: false + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'simple', + icon: 'header', + weight: 41, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleHeading/editForm/Component.edit.display.ts b/frontend/components/src/components/SimpleHeading/editForm/Component.edit.display.ts new file mode 100644 index 0000000..065c1a4 --- /dev/null +++ b/frontend/components/src/components/SimpleHeading/editForm/Component.edit.display.ts @@ -0,0 +1,101 @@ +export default [ + { + key: 'label', + ignore: true, + }, + { + key: 'labelPosition', + ignore: true + }, + { + key: 'placeholder', + ignore: true + }, + { + key: 'description', + ignore: true + }, + { + key: 'tooltip', + ignore: true + }, + { + key: 'hideLabel', + ignore: true + }, + { + key: 'autofocus', + ignore: true + }, + { + key: 'disabled', + ignore: true + }, + { + key: 'tabindex', + ignore: true + }, + { + key: 'tableView', + ignore: true + }, + { + key: 'hidden', + ignore: true + }, + { + key: 'modalEdit', + ignore: true + }, + { + key: 'refreshOnChange', + ignore: true + }, + { + key: 'className', + ignore: 'true', + }, + { + key: 'attrs', + ignore: true + }, + { + type: 'radio', + input: true, + label: 'Heading Size', + key: 'tag', + clearOnHide: true, + tooltip: 'The size of the heading font.', + weight: 70, + inline: true, + defaultValue: 'h1', + values: [ + { label: 'Largest', value: 'h1' }, + { label: 'Larger', value: 'h2' }, + { label: 'Large', value: 'h3' }, + { label: 'Small', value: 'h4' }, + { label: 'Smaller', value: 'h5' }, + { label: 'Smallest', value: 'h6' }, + ] + }, + { + type: 'textfield', + input: true, + label: 'Heading', + tooltip: 'The heading to display.', + key: 'content', + placeholder: 'Your heading here', + weight: 0, + validate: { + required: true + } + }, + { + weight: 85, + type: 'checkbox', + label: 'Refresh On Change', + tooltip: 'Rerender the field whenever a value on the form changes.', + key: 'refreshOnChange', + input: true + }, +]; diff --git a/frontend/components/src/components/SimpleNumber/Component.form.ts b/frontend/components/src/components/SimpleNumber/Component.form.ts new file mode 100644 index 0000000..d82d83b --- /dev/null +++ b/frontend/components/src/components/SimpleNumber/Component.form.ts @@ -0,0 +1,62 @@ +import baseEditForm from 'formiojs/components/_classes/component/Component.form'; + +import EditData from './editForm/Component.edit.data'; +import EditDisplay from './editForm/Component.edit.display'; +import EditValidation from './editForm/Component.edit.validation'; + +import SimpleApi from '../Common/Simple.edit.api'; +import SimpleConditional from '../Common/Simple.edit.conditional'; + +export default function(...extend) { + return baseEditForm([ + EditDisplay, + { + key: 'data', + ignore: true, + }, + { + key: 'api', + ignore: true + }, + { + key: 'layout', + ignore: true + }, + { + key: 'conditional', + ignore: true + }, + { + key: 'validation', + ignore: true + }, + { + key: 'logic', + ignore: true + }, + { + label: 'Data', + key: 'customData', + weight: 10, + components: EditData + }, + { + label: 'Validation', + key: 'customValidation', + weight: 20, + components: EditValidation + }, + { + label: 'API', + key: 'customAPI', + weight: 30, + components: SimpleApi + }, + { + label: 'Conditional', + key: 'customConditional', + weight: 40, + components: SimpleConditional + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleNumber/Component.ts b/frontend/components/src/components/SimpleNumber/Component.ts new file mode 100644 index 0000000..986e5d7 --- /dev/null +++ b/frontend/components/src/components/SimpleNumber/Component.ts @@ -0,0 +1,38 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.number; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simplenumber'; +const DISPLAY = 'Number'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + validate: { + min: '', + max: '', + step: 'any', + integer: '' + } + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'simple', + icon: 'hashtag', + weight: 10, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleNumber/editForm/Component.edit.data.ts b/frontend/components/src/components/SimpleNumber/editForm/Component.edit.data.ts new file mode 100644 index 0000000..8a8a7af --- /dev/null +++ b/frontend/components/src/components/SimpleNumber/editForm/Component.edit.data.ts @@ -0,0 +1,28 @@ +import common from '../../Common/Simple.edit.data'; +export default [ + ...common, + { + type: 'checkbox', + input: true, + weight: 70, + key: 'delimiter', + label: 'Use Thousands Separator', + tooltip: 'Separate thousands by local delimiter.' + }, + { + type: 'number', + input: true, + weight: 80, + key: 'decimalLimit', + label: 'Decimal Places', + tooltip: 'The maximum number of decimal places.' + }, + { + type: 'checkbox', + input: true, + weight: 90, + key: 'requireDecimal', + label: 'Require Decimal', + tooltip: 'Always show decimals, even if trailing zeros.' + }, +]; diff --git a/frontend/components/src/components/SimpleNumber/editForm/Component.edit.display.ts b/frontend/components/src/components/SimpleNumber/editForm/Component.edit.display.ts new file mode 100644 index 0000000..47b34a0 --- /dev/null +++ b/frontend/components/src/components/SimpleNumber/editForm/Component.edit.display.ts @@ -0,0 +1,39 @@ +import common from '../../Common/Simple.edit.display'; +export default { + key: 'display', + components: [ + ...common, + { + key: 'refreshOnChange', + ignore: true + }, + { + key: 'className', + ignore: true, + }, + { + key: 'prefix', + ignore: true + }, + { + key: 'suffix', + ignore: true + }, + { + key: 'inputMask', + ignore: true + }, + { + key: 'allowMultipleMasks', + ignore: true + }, + { + key: 'showWordCount', + ignore: true, + }, + { + key: 'showCharCount', + ignore: true, + }, + ] +} diff --git a/frontend/components/src/components/SimpleNumber/editForm/Component.edit.validation.ts b/frontend/components/src/components/SimpleNumber/editForm/Component.edit.validation.ts new file mode 100644 index 0000000..3ca403a --- /dev/null +++ b/frontend/components/src/components/SimpleNumber/editForm/Component.edit.validation.ts @@ -0,0 +1,22 @@ +import common from '../../Common/Simple.edit.validation'; +export default [ + ...common, + { + type: 'number', + label: 'Minimum Value', + key: 'validate.min', + input: true, + placeholder: 'Minimum Value', + tooltip: 'The minimum value this field must have before the form can be submitted.', + weight: 150 + }, + { + type: 'number', + label: 'Maximum Value', + key: 'validate.max', + input: true, + placeholder: 'Maximum Value', + tooltip: 'The maximum value this field can have before the form can be submitted.', + weight: 160 + } +]; diff --git a/frontend/components/src/components/SimpleNumberAdvanced/Component.form.ts b/frontend/components/src/components/SimpleNumberAdvanced/Component.form.ts new file mode 100644 index 0000000..7c81333 --- /dev/null +++ b/frontend/components/src/components/SimpleNumberAdvanced/Component.form.ts @@ -0,0 +1,17 @@ +import baseEditForm from 'formiojs/components/number/Number.form'; +import EditValidation from './editForm/Component.edit.validation'; + +export default function(...extend) { + return baseEditForm([ + { + key: 'validation', + ignore: true + }, + { + label: 'Validation', + key: 'customValidation', + weight: 15, + components: EditValidation + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleNumberAdvanced/Component.ts b/frontend/components/src/components/SimpleNumberAdvanced/Component.ts new file mode 100644 index 0000000..82293e2 --- /dev/null +++ b/frontend/components/src/components/SimpleNumberAdvanced/Component.ts @@ -0,0 +1,38 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.number; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simplenumberadvanced'; +const DISPLAY = 'Number'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + validate: { + min: '', + max: '', + step: 'any', + integer: '' + } + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'advanced', + icon: 'hashtag', + weight: 750, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleNumberAdvanced/editForm/Component.edit.validation.ts b/frontend/components/src/components/SimpleNumberAdvanced/editForm/Component.edit.validation.ts new file mode 100644 index 0000000..cafced9 --- /dev/null +++ b/frontend/components/src/components/SimpleNumberAdvanced/editForm/Component.edit.validation.ts @@ -0,0 +1,20 @@ +import common from '../../Common/Advanced.edit.validation'; +import NumberEditValidation from 'formiojs/components/number/editForm/Number.edit.validation'; +import {reArrangeComponents} from '../../Common/function'; + +const neededposition = [ + 'validate.isUseForCopy', + 'validateOn', + 'validate.required', + 'validate.min', + 'validate.max', + 'errorLabel', + 'validate.customMessage', + 'errors', + 'custom-validation-js', + 'json-validation-json' + ]; + + const newPosition = reArrangeComponents(neededposition,[...NumberEditValidation, ...common]); + + export default newPosition; \ No newline at end of file diff --git a/frontend/components/src/components/SimplePanel/Component.form.ts b/frontend/components/src/components/SimplePanel/Component.form.ts new file mode 100644 index 0000000..3e0f61d --- /dev/null +++ b/frontend/components/src/components/SimplePanel/Component.form.ts @@ -0,0 +1,48 @@ +import nestedComponentForm from 'formiojs/components/_classes/nested/NestedComponent.form'; + +import EditDisplay from './editForm/Component.edit.display'; + +import SimpleApi from '../Common/Simple.edit.api'; +import SimpleConditional from '../Common/Simple.edit.conditional'; + +export default function(...extend) { + return nestedComponentForm([ + EditDisplay, + { + key: 'data', + ignore: true, + }, + { + key: 'api', + ignore: true + }, + { + key: 'layout', + ignore: true + }, + { + key: 'conditional', + ignore: true + }, + { + key: 'validation', + ignore: true + }, + { + key: 'logic', + ignore: true + }, + { + label: 'API', + key: 'customAPI', + weight: 30, + components: SimpleApi + }, + { + label: 'Conditional', + key: 'customConditional', + weight: 40, + components: SimpleConditional + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimplePanel/Component.ts b/frontend/components/src/components/SimplePanel/Component.ts new file mode 100644 index 0000000..c5775ff --- /dev/null +++ b/frontend/components/src/components/SimplePanel/Component.ts @@ -0,0 +1,42 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.panel; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simplepanel'; +const DISPLAY = 'Panel'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + title: 'Panel', + theme: 'default', + breadcrumb: 'default', + components: [], + clearOnHide: false, + input: false, + tableView: false, + persistent: false, + collapsible: false, + collapsed: false + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'simple', + icon: 'list-alt', + weight: 54, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimplePanel/editForm/Component.edit.display.ts b/frontend/components/src/components/SimplePanel/editForm/Component.edit.display.ts new file mode 100644 index 0000000..8a72f39 --- /dev/null +++ b/frontend/components/src/components/SimplePanel/editForm/Component.edit.display.ts @@ -0,0 +1,90 @@ +import common from '../../Common/Simple.edit.display'; + +export default { + key: 'display', + components: [ + ...common, + { + key: 'labelPosition', + ignore: true + }, + { + key: 'placeholder', + ignore: true + }, + { + key: 'description', + ignore: true + }, + { + key: 'tooltip', + ignore: true + }, + { + key: 'disabled', + ignore: true + }, + { + key: 'hideLabel', + ignore: true + }, + { + key: 'modalEdit', + ignore: true + }, + { + key: 'label', + hidden: true, + calculateValue(context) { + return context.data.legend; + } + }, + { + weight: 1, + type: 'textfield', + input: true, + placeholder: 'Panel Title', + label: 'Title', + key: 'title', + tooltip: 'The title text that appears in the header of this panel.' + }, + { + weight: 650, + type: 'checkbox', + label: 'Collapsible', + tooltip: 'If checked, this will turn this Panel into a collapsible panel.', + key: 'collapsible', + input: true + }, + { + weight: 651, + type: 'checkbox', + label: 'Initially Collapsed', + tooltip: 'Determines the initial collapsed state of this Panel.', + key: 'collapsed', + input: true, + conditional: { + json: { '===': [{ var: 'data.collapsible' }, true] } + } + }, + { + type: 'select', + key: 'theme', + label: 'Theme', + input: true, + tooltip: 'The color theme of this button.', + dataSrc: 'values', + weight: 140, + data: { + values: [ + { label: 'Primary', value: 'primary' }, + { label: 'Secondary', value: 'secondary' }, + { label: 'Info', value: 'info' }, + { label: 'Success', value: 'success' }, + { label: 'Danger', value: 'danger' }, + { label: 'Warning', value: 'warning' }, + ], + }, + }, + ] +} diff --git a/frontend/components/src/components/SimpleParagraph/Component.form.ts b/frontend/components/src/components/SimpleParagraph/Component.form.ts new file mode 100644 index 0000000..6184f07 --- /dev/null +++ b/frontend/components/src/components/SimpleParagraph/Component.form.ts @@ -0,0 +1,33 @@ +import baseEditForm from 'formiojs/components/_classes/component/Component.form'; + +import EditDisplay from './editForm/Component.edit.display'; + +export default function(...extend) { + return baseEditForm([ + { + key: 'display', + components: EditDisplay + + }, + { + key: 'data', + ignore: true + }, + { + key: 'validation', + ignore: true + }, + { + key: 'api', + ignore: true + }, + { + key: 'conditional', + ignore: true + }, + { + key: 'layout', + ignore: true + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleParagraph/Component.ts b/frontend/components/src/components/SimpleParagraph/Component.ts new file mode 100644 index 0000000..057497e --- /dev/null +++ b/frontend/components/src/components/SimpleParagraph/Component.ts @@ -0,0 +1,37 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.htmlelement; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simpleparagraph'; +const DISPLAY = 'Paragraph'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + tag: 'p', + attrs: [], + content: '', + input: false, + persistent: false + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'simple', + icon: 'paragraph', + weight: 42, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleParagraph/editForm/Component.edit.display.ts b/frontend/components/src/components/SimpleParagraph/editForm/Component.edit.display.ts new file mode 100644 index 0000000..8f999c2 --- /dev/null +++ b/frontend/components/src/components/SimpleParagraph/editForm/Component.edit.display.ts @@ -0,0 +1,82 @@ +export default [ + { + key: 'label', + ignore: true, + }, + { + key: 'labelPosition', + ignore: true + }, + { + key: 'placeholder', + ignore: true + }, + { + key: 'description', + ignore: true + }, + { + key: 'tooltip', + ignore: true + }, + { + key: 'hideLabel', + ignore: true + }, + { + key: 'autofocus', + ignore: true + }, + { + key: 'disabled', + ignore: true + }, + { + key: 'tabindex', + ignore: true + }, + { + key: 'tableView', + ignore: true + }, + { + key: 'hidden', + ignore: true + }, + { + key: 'modalEdit', + ignore: true + }, + { + key: 'refreshOnChange', + ignore: true + }, + { + key: 'className', + ignore: 'true', + }, + { + key: 'attrs', + ignore: true + }, + { + type: 'textarea', + input: true, + editor: 'ace', + rows: 10, + as: 'html', + label: 'Content', + tooltip: 'The content of this Paragraph.', + defaultValue: 'Content', + key: 'content', + weight: 80 + }, + { + weight: 85, + type: 'checkbox', + label: 'Refresh On Change', + tooltip: 'Rerender the field whenever a value on the form changes.', + key: 'refreshOnChange', + input: true + }, +]; diff --git a/frontend/components/src/components/SimplePasswordAdvanced/Component.form.ts b/frontend/components/src/components/SimplePasswordAdvanced/Component.form.ts new file mode 100644 index 0000000..9ddb5c1 --- /dev/null +++ b/frontend/components/src/components/SimplePasswordAdvanced/Component.form.ts @@ -0,0 +1,17 @@ +import baseEditForm from 'formiojs/components/password/Password.form'; +import EditValidation from './editForm/Component.edit.validation'; + +export default function(...extend) { + return baseEditForm([ + { + key: 'validation', + ignore: true + }, + { + label: 'Validation', + key: 'customValidation', + weight: 20, + components: EditValidation + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimplePasswordAdvanced/Component.ts b/frontend/components/src/components/SimplePasswordAdvanced/Component.ts new file mode 100644 index 0000000..1450861 --- /dev/null +++ b/frontend/components/src/components/SimplePasswordAdvanced/Component.ts @@ -0,0 +1,35 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.password; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simplepasswordadvanced'; +const DISPLAY = 'Password'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + inputType: 'password', + protected: true, + tableView: false + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'advanced', + icon: 'asterisk', + weight: 775, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimplePasswordAdvanced/editForm/Component.edit.validation.ts b/frontend/components/src/components/SimplePasswordAdvanced/editForm/Component.edit.validation.ts new file mode 100644 index 0000000..d5e2adc --- /dev/null +++ b/frontend/components/src/components/SimplePasswordAdvanced/editForm/Component.edit.validation.ts @@ -0,0 +1,20 @@ +import common from '../../Common/Advanced.edit.validation'; +import {reArrangeComponents} from '../../Common/function'; + +const neededposition = [ + 'validate.isUseForCopy', + 'validateOn', + 'validate.required', + 'validate.minLength', + 'validate.maxLength', + 'validate.pattern', + 'errorLabel', + 'validate.customMessage', + 'custom-validation-js', + 'json-validation-json', + 'errors', + ]; + + const newPosition = reArrangeComponents(neededposition,common); + + export default newPosition; diff --git a/frontend/components/src/components/SimplePhoneNumber/Component.form.ts b/frontend/components/src/components/SimplePhoneNumber/Component.form.ts new file mode 100644 index 0000000..7017d0c --- /dev/null +++ b/frontend/components/src/components/SimplePhoneNumber/Component.form.ts @@ -0,0 +1,62 @@ +import baseEditForm from 'formiojs/components/_classes/component/Component.form'; + +import EditData from './editForm/Component.edit.data'; +import EditDisplay from './editForm/Component.edit.display'; + +import SimpleApi from '../Common/Simple.edit.api'; +import SimpleConditional from '../Common/Simple.edit.conditional'; +import SimpleValidation from '../Common/Simple.edit.validation'; + +export default function(...extend) { + return baseEditForm([ + EditDisplay, + { + key: 'data', + ignore: true, + }, + { + key: 'api', + ignore: true + }, + { + key: 'layout', + ignore: true + }, + { + key: 'conditional', + ignore: true + }, + { + key: 'validation', + ignore: true + }, + { + key: 'logic', + ignore: true + }, + { + label: 'Data', + key: 'customData', + weight: 10, + components: EditData + }, + { + label: 'Validation', + key: 'customValidation', + weight: 20, + components: SimpleValidation + }, + { + label: 'API', + key: 'customAPI', + weight: 30, + components: SimpleApi + }, + { + label: 'Conditional', + key: 'customConditional', + weight: 40, + components: SimpleConditional + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimplePhoneNumber/Component.ts b/frontend/components/src/components/SimplePhoneNumber/Component.ts new file mode 100644 index 0000000..198c24a --- /dev/null +++ b/frontend/components/src/components/SimplePhoneNumber/Component.ts @@ -0,0 +1,35 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.phoneNumber; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simplephonenumber'; +const DISPLAY = 'Phone Number'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + inputType: 'tel', + inputFormat: 'plain', + inputMask: '(999) 999-9999' + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'simple', + icon: 'phone-square', + weight: 11, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimplePhoneNumber/editForm/Component.edit.data.ts b/frontend/components/src/components/SimplePhoneNumber/editForm/Component.edit.data.ts new file mode 100644 index 0000000..be19704 --- /dev/null +++ b/frontend/components/src/components/SimplePhoneNumber/editForm/Component.edit.data.ts @@ -0,0 +1,4 @@ +import common from '../../Common/Simple.edit.data'; +export default [ + ...common, +]; diff --git a/frontend/components/src/components/SimplePhoneNumber/editForm/Component.edit.display.ts b/frontend/components/src/components/SimplePhoneNumber/editForm/Component.edit.display.ts new file mode 100644 index 0000000..719b46b --- /dev/null +++ b/frontend/components/src/components/SimplePhoneNumber/editForm/Component.edit.display.ts @@ -0,0 +1,35 @@ +import common from '../../Common/Simple.edit.display'; +export default { + key: 'display', + components: [ + ...common, + { + key: 'refreshOnChange', + ignore: true + }, + { + key: 'className', + ignore: true, + }, + { + key: 'prefix', + ignore: true + }, + { + key: 'suffix', + ignore: true + }, + { + key: 'placeholder', + ignore: true + }, + { + weight: 410, + type: 'textfield', + input: true, + key: 'inputMask', + label: 'Input Mask', + tooltip: 'An input mask helps the user with input by ensuring a predefined format.<br><br>9: numeric<br>a: alphabetical<br>*: alphanumeric<br><br>Example telephone mask: (999) 999-9999<br><br>See the <a target=\'_blank\' href=\'https://github.com/RobinHerbots/jquery.inputmask\'>jquery.inputmask documentation</a> for more information.</a>', + } + ] +} diff --git a/frontend/components/src/components/SimplePhoneNumberAdvanced/Component.form.ts b/frontend/components/src/components/SimplePhoneNumberAdvanced/Component.form.ts new file mode 100644 index 0000000..410b5c1 --- /dev/null +++ b/frontend/components/src/components/SimplePhoneNumberAdvanced/Component.form.ts @@ -0,0 +1,17 @@ +import baseEditForm from 'formiojs/components/phonenumber/PhoneNumber.form'; +import EditValidation from './editForm/Component.edit.validation'; + +export default function(...extend) { + return baseEditForm([ + { + key: 'validation', + ignore: true + }, + { + label: 'Validation', + key: 'customValidation', + weight: 15, + components: EditValidation + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimplePhoneNumberAdvanced/Component.ts b/frontend/components/src/components/SimplePhoneNumberAdvanced/Component.ts new file mode 100644 index 0000000..0f0c808 --- /dev/null +++ b/frontend/components/src/components/SimplePhoneNumberAdvanced/Component.ts @@ -0,0 +1,35 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.phoneNumber; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simplephonenumberadvanced'; +const DISPLAY = 'Phone Number'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + inputType: 'tel', + inputFormat: 'plain', + inputMask: '(999) 999-9999' + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'advanced', + icon: 'phone-square', + weight: 760, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimplePhoneNumberAdvanced/editForm/Component.edit.validation.ts b/frontend/components/src/components/SimplePhoneNumberAdvanced/editForm/Component.edit.validation.ts new file mode 100644 index 0000000..c98357a --- /dev/null +++ b/frontend/components/src/components/SimplePhoneNumberAdvanced/editForm/Component.edit.validation.ts @@ -0,0 +1,18 @@ +import common from '../../Common/Advanced.edit.validation'; +import {reArrangeComponents} from '../../Common/function'; + +const neededposition = [ + 'validate.isUseForCopy', + 'validateOn', + 'validate.required', + 'unique', + 'errorLabel', + 'validate.customMessage', + 'custom-validation-js', + 'json-validation-json', + 'errors' + ]; + + const newPosition = reArrangeComponents(neededposition,common); + + export default newPosition; \ No newline at end of file diff --git a/frontend/components/src/components/SimpleRadioAdvanced/Component.form.ts b/frontend/components/src/components/SimpleRadioAdvanced/Component.form.ts new file mode 100644 index 0000000..96c22ce --- /dev/null +++ b/frontend/components/src/components/SimpleRadioAdvanced/Component.form.ts @@ -0,0 +1,17 @@ +import baseEditForm from 'formiojs/components/radio/Radio.form'; +import EditValidation from './editForm/Component.edit.validation'; + +export default function(...extend) { + return baseEditForm([ + { + key: 'validation', + ignore: true + }, + { + label: 'Validation', + key: 'customValidation', + weight: 15, + components: EditValidation + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleRadioAdvanced/Component.ts b/frontend/components/src/components/SimpleRadioAdvanced/Component.ts new file mode 100644 index 0000000..235200c --- /dev/null +++ b/frontend/components/src/components/SimpleRadioAdvanced/Component.ts @@ -0,0 +1,31 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.radio; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simpleradioadvanced'; +const DISPLAY = 'Radio'; +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'advanced', + icon: 'dot-circle-o', + weight: 840, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleRadioAdvanced/editForm/Component.edit.validation.ts b/frontend/components/src/components/SimpleRadioAdvanced/editForm/Component.edit.validation.ts new file mode 100644 index 0000000..d343daf --- /dev/null +++ b/frontend/components/src/components/SimpleRadioAdvanced/editForm/Component.edit.validation.ts @@ -0,0 +1,20 @@ +import common from '../../Common/Advanced.edit.validation'; +import {reArrangeComponents} from '../../Common/function'; +import validationComponents from 'formiojs/components/radio/editForm/Radio.edit.validation'; + +const neededposition = [ + 'validate.isUseForCopy', + 'validate.required', + 'validate.onlyAvailableItems', + 'errorLabel', + 'validate.customMessage', + 'custom-validation-js', + 'json-validation-json', + 'errors', + ]; + + + const newPosition = reArrangeComponents(neededposition,[...validationComponents,...common]); + + + export default newPosition; \ No newline at end of file diff --git a/frontend/components/src/components/SimpleRadios/Component.form.ts b/frontend/components/src/components/SimpleRadios/Component.form.ts new file mode 100644 index 0000000..dde1ea2 --- /dev/null +++ b/frontend/components/src/components/SimpleRadios/Component.form.ts @@ -0,0 +1,62 @@ +import radioEditForm from 'formiojs/components/radio/Radio.form'; + +import EditData from './editForm/Component.edit.data'; +import EditDisplay from './editForm/Component.edit.display'; +import EditValidation from './editForm/Component.edit.validation'; + +import SimpleApi from '../Common/Simple.edit.api'; +import SimpleConditional from '../Common/Simple.edit.conditional'; + +export default function(...extend) { + return radioEditForm([ + EditDisplay, + { + key: 'data', + ignore: true + }, + { + key: 'api', + ignore: true + }, + { + key: 'layout', + ignore: true + }, + { + key: 'conditional', + ignore: true + }, + { + key: 'validation', + ignore: true + }, + { + key: 'logic', + ignore: true + }, + { + label: 'Data', + key: 'customData', + weight: 10, + components: EditData + }, + { + label: 'Validation', + key: 'customValidation', + weight: 20, + components: EditValidation + }, + { + label: 'API', + key: 'customAPI', + weight: 30, + components: SimpleApi + }, + { + label: 'Conditional', + key: 'customConditional', + weight: 40, + components: SimpleConditional + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleRadios/Component.ts b/frontend/components/src/components/SimpleRadios/Component.ts new file mode 100644 index 0000000..aebc671 --- /dev/null +++ b/frontend/components/src/components/SimpleRadios/Component.ts @@ -0,0 +1,35 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.radio; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simpleradios'; +const DISPLAY = 'Radio Group'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + inline: false, + values: [{ label: '', value: '' }], + fieldSet: false + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'simple', + icon: 'dot-circle-o', + weight: 6, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleRadios/editForm/Component.edit.data.ts b/frontend/components/src/components/SimpleRadios/editForm/Component.edit.data.ts new file mode 100644 index 0000000..2c059e0 --- /dev/null +++ b/frontend/components/src/components/SimpleRadios/editForm/Component.edit.data.ts @@ -0,0 +1,65 @@ +import BuilderUtils from 'formiojs/utils/builder'; +import _ from 'lodash'; + +export default [ + { + type: 'textfield', + label: 'Default Value', + key: 'defaultValue', + weight: 5, + placeholder: 'Default Value', + tooltip: 'The will be the value for this field, before user interaction. Having a default value will override the placeholder text.', + input: true + }, + { + type: 'datagrid', + input: true, + label: 'Values', + key: 'values', + tooltip: 'The values that can be picked for this field. Values are text submitted with the form data. Labels are text that appears next to the radio buttons on the form.', + weight: 10, + reorder: true, + defaultValue: [{ label: '', value: '' }], + components: [ + { + weight: 160, + label: 'Label', + key: 'label', + input: true, + type: 'textfield', + }, + { + weight: 170, + label: 'Value', + key: 'value', + input: true, + type: 'textfield', + allowCalculateOverride: true, + calculateValue: { _camelCase: [{ var: 'row.label' }] }, + validate: { + required: true + } + }, + { + type: 'select', + input: true, + weight: 180, + label: 'Shortcut', + key: 'shortcut', + tooltip: 'The shortcut key for this option.', + dataSrc: 'custom', + valueProperty: 'value', + customDefaultValue: () => '', + template: '{{ item.label }}', + data: { + custom(context) { + return BuilderUtils.getAvailableShortcuts( + _.get(context, 'instance.options.editForm', {}), + _.get(context, 'instance.options.editComponent', {}) + ); + }, + }, + }, + ], + }, +]; diff --git a/frontend/components/src/components/SimpleRadios/editForm/Component.edit.display.ts b/frontend/components/src/components/SimpleRadios/editForm/Component.edit.display.ts new file mode 100644 index 0000000..23b996c --- /dev/null +++ b/frontend/components/src/components/SimpleRadios/editForm/Component.edit.display.ts @@ -0,0 +1,27 @@ +import common from '../../Common/Simple.edit.display'; +export default { + key: 'display', + components: [ + ...common, + { + key: 'refreshOnChange', + ignore: true + }, + { + key: 'className', + ignore: true, + }, + { + key: 'attrs', + ignore: true + }, + { + key: 'widget', + ignore: true + }, + { + key: 'uniqueOptions', + ignore: true + }, + ] +} diff --git a/frontend/components/src/components/SimpleRadios/editForm/Component.edit.validation.ts b/frontend/components/src/components/SimpleRadios/editForm/Component.edit.validation.ts new file mode 100644 index 0000000..5798dd2 --- /dev/null +++ b/frontend/components/src/components/SimpleRadios/editForm/Component.edit.validation.ts @@ -0,0 +1,5 @@ +import common from '../../Common/Simple.edit.validation'; + +export default [ + ...common +]; diff --git a/frontend/components/src/components/SimpleSelect/Component.form.ts b/frontend/components/src/components/SimpleSelect/Component.form.ts new file mode 100644 index 0000000..8c68023 --- /dev/null +++ b/frontend/components/src/components/SimpleSelect/Component.form.ts @@ -0,0 +1,62 @@ +import baseEditForm from 'formiojs/components/_classes/component/Component.form'; + +import EditData from './editForm/Component.edit.data'; +import EditDisplay from './editForm/Component.edit.display'; +import EditValidation from './editForm/Component.edit.validation'; + +import SimpleApi from '../Common/Simple.edit.api'; +import SimpleConditional from '../Common/Simple.edit.conditional'; + +export default function(...extend) { + return baseEditForm([ + EditDisplay, + { + key: 'data', + ignore: true + }, + { + key: 'api', + ignore: true + }, + { + key: 'layout', + ignore: true + }, + { + key: 'conditional', + ignore: true + }, + { + key: 'validation', + ignore: true + }, + { + key: 'logic', + ignore: true + }, + { + label: 'Data', + key: 'customData', + weight: 10, + components: EditData + }, + { + label: 'Validation', + key: 'customValidation', + weight: 20, + components: EditValidation + }, + { + label: 'API', + key: 'customAPI', + weight: 30, + components: SimpleApi + }, + { + label: 'Conditional', + key: 'customConditional', + weight: 40, + components: SimpleConditional + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleSelect/Component.ts b/frontend/components/src/components/SimpleSelect/Component.ts new file mode 100644 index 0000000..bc075cc --- /dev/null +++ b/frontend/components/src/components/SimpleSelect/Component.ts @@ -0,0 +1,63 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.select; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simpleselect'; +const DISPLAY = 'Select List'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + dataSrc: 'values', + dataType: 'auto', + widget: 'choicesjs', + idPath: 'id', + data: { + values: [], + json: '', + url: '', + resource: '', + custom: '' + }, + clearOnRefresh: false, + limit: 100, + valueProperty: '', + lazyLoad: true, + filter: '', + searchEnabled: true, + searchField: '', + minSearch: 0, + readOnlyValue: false, + authenticate: false, + template: '<span>{{ item.label }}</span>', + selectFields: '', + searchThreshold: 0.3, + uniqueOptions: false, + tableView: true, + fuseOptions: { + include: 'score', + threshold: 0.3, + }, + customOptions: {} + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'simple', + icon: 'list', + weight: 3, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleSelect/editForm/Component.edit.data.ts b/frontend/components/src/components/SimpleSelect/editForm/Component.edit.data.ts new file mode 100644 index 0000000..b169dd8 --- /dev/null +++ b/frontend/components/src/components/SimpleSelect/editForm/Component.edit.data.ts @@ -0,0 +1,30 @@ +import common from '../../Common/Simple.edit.data'; +export default [ + ...common, + { + type: 'datagrid', + input: true, + label: 'Select List Items', + key: 'data.values', + tooltip: 'Values to use in the list. Labels are shown in the select field. Values are the corresponding values saved with the submission.', + weight: 10, + reorder: true, + defaultValue: [{ label: '', value: '' }], + components: [ + { + label: 'Label', + key: 'label', + input: true, + type: 'textfield', + }, + { + label: 'Value', + key: 'value', + input: true, + type: 'textfield', + allowCalculateOverride: true, + calculateValue: { _camelCase: [{ var: 'row.label' }] }, + }, + ], + } +]; diff --git a/frontend/components/src/components/SimpleSelect/editForm/Component.edit.display.ts b/frontend/components/src/components/SimpleSelect/editForm/Component.edit.display.ts new file mode 100644 index 0000000..23b996c --- /dev/null +++ b/frontend/components/src/components/SimpleSelect/editForm/Component.edit.display.ts @@ -0,0 +1,27 @@ +import common from '../../Common/Simple.edit.display'; +export default { + key: 'display', + components: [ + ...common, + { + key: 'refreshOnChange', + ignore: true + }, + { + key: 'className', + ignore: true, + }, + { + key: 'attrs', + ignore: true + }, + { + key: 'widget', + ignore: true + }, + { + key: 'uniqueOptions', + ignore: true + }, + ] +} diff --git a/frontend/components/src/components/SimpleSelect/editForm/Component.edit.validation.ts b/frontend/components/src/components/SimpleSelect/editForm/Component.edit.validation.ts new file mode 100644 index 0000000..1cec573 --- /dev/null +++ b/frontend/components/src/components/SimpleSelect/editForm/Component.edit.validation.ts @@ -0,0 +1,4 @@ +import common from '../../Common/Simple.edit.validation'; +export default [ + ...common, +]; diff --git a/frontend/components/src/components/SimpleSelectAdvanced/Component.form.ts b/frontend/components/src/components/SimpleSelectAdvanced/Component.form.ts new file mode 100644 index 0000000..6051b28 --- /dev/null +++ b/frontend/components/src/components/SimpleSelectAdvanced/Component.form.ts @@ -0,0 +1,17 @@ +import baseEditForm from 'formiojs/components/select/Select.form'; +import EditValidation from './editForm/Component.edit.validation'; + +export default function(...extend) { + return baseEditForm([ + { + key: 'validation', + ignore: true + }, + { + label: 'Validation', + key: 'customValidation', + weight: 15, + components: EditValidation + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleSelectAdvanced/Component.ts b/frontend/components/src/components/SimpleSelectAdvanced/Component.ts new file mode 100644 index 0000000..352f35c --- /dev/null +++ b/frontend/components/src/components/SimpleSelectAdvanced/Component.ts @@ -0,0 +1,32 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.select; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simpleselectadvanced'; +const DISPLAY = 'Select'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'advanced', + icon: 'th-list', + weight: 820, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleSelectAdvanced/editForm/Component.edit.validation.ts b/frontend/components/src/components/SimpleSelectAdvanced/editForm/Component.edit.validation.ts new file mode 100644 index 0000000..0809cc2 --- /dev/null +++ b/frontend/components/src/components/SimpleSelectAdvanced/editForm/Component.edit.validation.ts @@ -0,0 +1,37 @@ +import common from '../../Common/Advanced.edit.validation'; +import validationComponents from 'formiojs/components/select/editForm/Select.edit.validation'; +import {reArrangeComponents} from '../../Common/function'; + +const neededposition = [ + 'validate.isUseForCopy', + 'validateOn', + 'validate.required', + 'validate.onlyAvailableItems', + 'unique', + 'errorLabel', + 'validate.customMessage', + 'custom-validation-js', + 'json-validation-json', + 'errors', + ]; + + const componentSpecific = { + weight: 52, + type: 'checkbox', + label: 'Allow only available values', + tooltip: 'Check this if you would like to perform a validation check to ensure the selected value is an available option (only for synchronous values).', + key: 'validate.onlyAvailableItems', + input: true, + conditional: { + json: { + in: [{ + var: 'data.dataSrc' + }, ['values', 'json', 'custom']] + } + } + } + + const newPosition = reArrangeComponents(neededposition,[componentSpecific, ...validationComponents,...common]); + + + export default newPosition; \ No newline at end of file diff --git a/frontend/components/src/components/SimpleSelectBoxesAdvanced/Component.form.ts b/frontend/components/src/components/SimpleSelectBoxesAdvanced/Component.form.ts new file mode 100644 index 0000000..faabe40 --- /dev/null +++ b/frontend/components/src/components/SimpleSelectBoxesAdvanced/Component.form.ts @@ -0,0 +1,17 @@ +import baseEditForm from 'formiojs/components/selectboxes/SelectBoxes.form'; +import EditValidation from './editForm/Component.edit.validation'; + +export default function(...extend) { + return baseEditForm([ + { + key: 'validation', + ignore: true + }, + { + label: 'Validation', + key: 'customValidation', + weight: 15, + components: EditValidation + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleSelectBoxesAdvanced/Component.ts b/frontend/components/src/components/SimpleSelectBoxesAdvanced/Component.ts new file mode 100644 index 0000000..037d373 --- /dev/null +++ b/frontend/components/src/components/SimpleSelectBoxesAdvanced/Component.ts @@ -0,0 +1,32 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.selectboxes; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simpleselectboxesadvanced'; +const DISPLAY = 'Select Boxes'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'advanced', + icon: 'plus-square', + weight: 810, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleSelectBoxesAdvanced/editForm/Component.edit.validation.ts b/frontend/components/src/components/SimpleSelectBoxesAdvanced/editForm/Component.edit.validation.ts new file mode 100644 index 0000000..4e510da --- /dev/null +++ b/frontend/components/src/components/SimpleSelectBoxesAdvanced/editForm/Component.edit.validation.ts @@ -0,0 +1,39 @@ +import common from '../../Common/Advanced.edit.validation'; +import validationComponents from 'formiojs/components/selectboxes/editForm/SelectBoxes.edit.validation'; +import {reArrangeComponents} from '../../Common/function'; + +const neededposition = [ + 'validate.isUseForCopy', + 'validate.required', + 'validate.onlyAvailableItems', + 'errorLabel', + 'validate.customMessage', + 'validate.minSelectedCount', + 'validate.maxSelectedCount', + 'minSelectedCountMessage', + 'maxSelectedCountMessage', + 'custom-validation-js', + 'json-validation-json', + 'errors', + ]; + + const componentSpecific = { + weight: 52, + type: 'checkbox', + label: 'Allow only available values', + tooltip: 'Check this if you would like to perform a validation check to ensure the selected value is an available option (only for synchronous values).', + key: 'validate.onlyAvailableItems', + input: true, + conditional: { + json: { + in: [{ + var: 'data.dataSrc' + }, ['values', 'json', 'custom']] + } + } + } + + const newPosition = reArrangeComponents(neededposition,[componentSpecific, ...validationComponents,...common]); + + + export default newPosition; \ No newline at end of file diff --git a/frontend/components/src/components/SimpleSignatureAdvanced/Component.form.ts b/frontend/components/src/components/SimpleSignatureAdvanced/Component.form.ts new file mode 100644 index 0000000..59ba98f --- /dev/null +++ b/frontend/components/src/components/SimpleSignatureAdvanced/Component.form.ts @@ -0,0 +1,17 @@ +import baseEditForm from 'formiojs/components/signature/Signature.form'; +import EditValidation from './editForm/Component.edit.validation'; + +export default function(...extend) { + return baseEditForm([ + { + key: 'validation', + ignore: true + }, + { + label: 'Validation', + key: 'customValidation', + weight: 15, + components: EditValidation + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleSignatureAdvanced/Component.ts b/frontend/components/src/components/SimpleSignatureAdvanced/Component.ts new file mode 100644 index 0000000..ea3842f --- /dev/null +++ b/frontend/components/src/components/SimpleSignatureAdvanced/Component.ts @@ -0,0 +1,32 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.signature; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simplesignatureadvanced'; +const DISPLAY = 'Signature'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'advanced', + icon: 'pencil', + weight: 860, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleSignatureAdvanced/editForm/Component.edit.validation.ts b/frontend/components/src/components/SimpleSignatureAdvanced/editForm/Component.edit.validation.ts new file mode 100644 index 0000000..c47db42 --- /dev/null +++ b/frontend/components/src/components/SimpleSignatureAdvanced/editForm/Component.edit.validation.ts @@ -0,0 +1,18 @@ +import common from '../../Common/Advanced.edit.validation'; +import {reArrangeComponents} from '../../Common/function'; + +const neededposition = [ + 'validate.isUseForCopy', + 'validate.required', + 'errorLabel', + 'validate.customMessage', + 'custom-validation-js', + 'json-validation-json', + 'errors', + ]; + + + const newPosition = reArrangeComponents(neededposition,[...common]); + + + export default newPosition; \ No newline at end of file diff --git a/frontend/components/src/components/SimpleSurveyAdvanced/Component.form.ts b/frontend/components/src/components/SimpleSurveyAdvanced/Component.form.ts new file mode 100644 index 0000000..33e1c6a --- /dev/null +++ b/frontend/components/src/components/SimpleSurveyAdvanced/Component.form.ts @@ -0,0 +1,17 @@ +import baseEditForm from 'formiojs/components/survey/Survey.form'; +import EditValidation from './editForm/Component.edit.validation'; + +export default function(...extend) { + return baseEditForm([ + { + key: 'validation', + ignore: true + }, + { + label: 'Validation', + key: 'customValidation', + weight: 15, + components: EditValidation + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleSurveyAdvanced/Component.ts b/frontend/components/src/components/SimpleSurveyAdvanced/Component.ts new file mode 100644 index 0000000..048e7eb --- /dev/null +++ b/frontend/components/src/components/SimpleSurveyAdvanced/Component.ts @@ -0,0 +1,32 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.survey; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simplesurveyadvanced'; +const DISPLAY = 'Survey'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'advanced', + icon: 'list', + weight: 850, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleSurveyAdvanced/editForm/Component.edit.validation.ts b/frontend/components/src/components/SimpleSurveyAdvanced/editForm/Component.edit.validation.ts new file mode 100644 index 0000000..181cb57 --- /dev/null +++ b/frontend/components/src/components/SimpleSurveyAdvanced/editForm/Component.edit.validation.ts @@ -0,0 +1,19 @@ +import common from '../../Common/Advanced.edit.validation'; +import {reArrangeComponents} from '../../Common/function'; + +const neededposition = [ + 'validate.isUseForCopy', + 'validate.required', + 'unique', + 'errorLabel', + 'validate.customMessage', + 'custom-validation-js', + 'json-validation-json', + 'errors', + ]; + + + const newPosition = reArrangeComponents(neededposition,[...common]); + + + export default newPosition; \ No newline at end of file diff --git a/frontend/components/src/components/SimpleTabs/Component.form.ts b/frontend/components/src/components/SimpleTabs/Component.form.ts new file mode 100644 index 0000000..3e0f61d --- /dev/null +++ b/frontend/components/src/components/SimpleTabs/Component.form.ts @@ -0,0 +1,48 @@ +import nestedComponentForm from 'formiojs/components/_classes/nested/NestedComponent.form'; + +import EditDisplay from './editForm/Component.edit.display'; + +import SimpleApi from '../Common/Simple.edit.api'; +import SimpleConditional from '../Common/Simple.edit.conditional'; + +export default function(...extend) { + return nestedComponentForm([ + EditDisplay, + { + key: 'data', + ignore: true, + }, + { + key: 'api', + ignore: true + }, + { + key: 'layout', + ignore: true + }, + { + key: 'conditional', + ignore: true + }, + { + key: 'validation', + ignore: true + }, + { + key: 'logic', + ignore: true + }, + { + label: 'API', + key: 'customAPI', + weight: 30, + components: SimpleApi + }, + { + label: 'Conditional', + key: 'customConditional', + weight: 40, + components: SimpleConditional + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleTabs/Component.ts b/frontend/components/src/components/SimpleTabs/Component.ts new file mode 100644 index 0000000..17fcf89 --- /dev/null +++ b/frontend/components/src/components/SimpleTabs/Component.ts @@ -0,0 +1,41 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.tabs; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simpletabs'; +const DISPLAY = 'Tabs'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + persistent: false, + tableView: false, + components: [ + { + label: 'Tab 1', + key: 'tab1', + components: [], + }, + ], + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'simple', + icon: 'folder-o', + weight: 53, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleTabs/editForm/Component.edit.display.ts b/frontend/components/src/components/SimpleTabs/editForm/Component.edit.display.ts new file mode 100644 index 0000000..ac03ee9 --- /dev/null +++ b/frontend/components/src/components/SimpleTabs/editForm/Component.edit.display.ts @@ -0,0 +1,55 @@ +import common from '../../Common/Simple.edit.display'; +export default { + key: 'display', + components: [ + ...common, + { + key: 'labelPosition', + ignore: true + }, + { + key: 'placeholder', + ignore: true + }, + { + key: 'description', + ignore: true + }, + { + key: 'tooltip', + ignore: true + }, + { + key: 'disabled', + ignore: true + }, + { + key: 'hideLabel', + ignore: true + }, + { + key: 'components', + type: 'datagrid', + input: true, + label: 'Tabs', + weight: 50, + reorder: true, + components: [ + { + type: 'textfield', + input: true, + key: 'label', + label: 'Label' + }, + { + type: 'textfield', + input: true, + key: 'key', + label: 'Key', + allowCalculateOverride: true, + calculateValue: { _camelCase: [{ var: 'row.label' }] } + } + ] + } + ] +} diff --git a/frontend/components/src/components/SimpleTagsAdvanced/Component.form.ts b/frontend/components/src/components/SimpleTagsAdvanced/Component.form.ts new file mode 100644 index 0000000..f368dc0 --- /dev/null +++ b/frontend/components/src/components/SimpleTagsAdvanced/Component.form.ts @@ -0,0 +1,17 @@ +import baseEditForm from 'formiojs/components/tags/Tags.form'; +import EditValidation from './editForm/Component.edit.validation'; + +export default function(...extend) { + return baseEditForm([ + { + key: 'validation', + ignore: true + }, + { + label: 'Validation', + key: 'customValidation', + weight: 15, + components: EditValidation + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleTagsAdvanced/Component.ts b/frontend/components/src/components/SimpleTagsAdvanced/Component.ts new file mode 100644 index 0000000..2946802 --- /dev/null +++ b/frontend/components/src/components/SimpleTagsAdvanced/Component.ts @@ -0,0 +1,35 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.tags; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simpletagsadvanced'; +const DISPLAY = 'Tags'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + delimeter: ',', + storeas: 'string', + maxTags: 0 + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'advanced', + icon: 'tags', + weight: 765, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleTagsAdvanced/editForm/Component.edit.validation.ts b/frontend/components/src/components/SimpleTagsAdvanced/editForm/Component.edit.validation.ts new file mode 100644 index 0000000..231eb49 --- /dev/null +++ b/frontend/components/src/components/SimpleTagsAdvanced/editForm/Component.edit.validation.ts @@ -0,0 +1,18 @@ +import common from '../../Common/Advanced.edit.validation'; +import {reArrangeComponents} from '../../Common/function'; + +const neededposition = [ + 'validate.isUseForCopy', + 'validate.required', + 'unique', + 'validateOn', + 'errorLabel', + 'validate.customMessage', + 'custom-validation-js', + 'json-validation-json', + 'errors', + ]; + + const newPosition = reArrangeComponents(neededposition,common); + + export default newPosition; \ No newline at end of file diff --git a/frontend/components/src/components/SimpleTextArea/Component.form.ts b/frontend/components/src/components/SimpleTextArea/Component.form.ts new file mode 100644 index 0000000..d82d83b --- /dev/null +++ b/frontend/components/src/components/SimpleTextArea/Component.form.ts @@ -0,0 +1,62 @@ +import baseEditForm from 'formiojs/components/_classes/component/Component.form'; + +import EditData from './editForm/Component.edit.data'; +import EditDisplay from './editForm/Component.edit.display'; +import EditValidation from './editForm/Component.edit.validation'; + +import SimpleApi from '../Common/Simple.edit.api'; +import SimpleConditional from '../Common/Simple.edit.conditional'; + +export default function(...extend) { + return baseEditForm([ + EditDisplay, + { + key: 'data', + ignore: true, + }, + { + key: 'api', + ignore: true + }, + { + key: 'layout', + ignore: true + }, + { + key: 'conditional', + ignore: true + }, + { + key: 'validation', + ignore: true + }, + { + key: 'logic', + ignore: true + }, + { + label: 'Data', + key: 'customData', + weight: 10, + components: EditData + }, + { + label: 'Validation', + key: 'customValidation', + weight: 20, + components: EditValidation + }, + { + label: 'API', + key: 'customAPI', + weight: 30, + components: SimpleApi + }, + { + label: 'Conditional', + key: 'customConditional', + weight: 40, + components: SimpleConditional + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleTextArea/Component.ts b/frontend/components/src/components/SimpleTextArea/Component.ts new file mode 100644 index 0000000..33990bc --- /dev/null +++ b/frontend/components/src/components/SimpleTextArea/Component.ts @@ -0,0 +1,42 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.textarea; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simpletextarea'; +const DISPLAY = 'Multi-line Text'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + rows: 3, + wysiwyg: false, + editor: '', + spellcheck: true, + fixedSize: true, + inputFormat: 'plain', + validate: { + minWords: '', + maxWords: '' + } + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'simple', + icon: 'font', + weight: 2, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleTextArea/editForm/Component.edit.data.ts b/frontend/components/src/components/SimpleTextArea/editForm/Component.edit.data.ts new file mode 100644 index 0000000..5c79d4e --- /dev/null +++ b/frontend/components/src/components/SimpleTextArea/editForm/Component.edit.data.ts @@ -0,0 +1,41 @@ +export default [ + { + weight: 0, + type: 'checkbox', + label: 'Multiple Values', + tooltip: 'Allows multiple values to be entered for this field.', + key: 'multiple', + input: true + }, + { + type: 'textfield', + label: 'Default Value', + key: 'defaultValue', + weight: 5, + placeholder: 'Default Value', + tooltip: 'The will be the value for this field, before user interaction. Having a default value will override the placeholder text.', + input: true + }, + { + weight: 200, + type: 'radio', + label: 'Text Case', + key: 'case', + tooltip: 'When data is entered, you can change the case of the value.', + input: true, + values: [ + { + value: 'mixed', + label: 'Mixed (Allow upper and lower case)' + }, + { + value: 'uppercase', + label: 'Uppercase' + }, + { + value: 'lowercase', + label: 'Lowercase' + } + ] + } +]; diff --git a/frontend/components/src/components/SimpleTextArea/editForm/Component.edit.display.ts b/frontend/components/src/components/SimpleTextArea/editForm/Component.edit.display.ts new file mode 100644 index 0000000..a667dbe --- /dev/null +++ b/frontend/components/src/components/SimpleTextArea/editForm/Component.edit.display.ts @@ -0,0 +1,112 @@ +import common from '../../Common/Simple.edit.display'; +export default { + key: 'display', + components: [ + ...common, + { + key: 'refreshOnChange', + ignore: true + }, + { + key: 'className', + ignore: true, + }, + { + key: 'prefix', + ignore: true + }, + { + key: 'suffix', + ignore: true + }, + { + key: 'inputMask', + ignore: true + }, + { + key: 'allowMultipleMasks', + ignore: true + }, + { + key: 'mask', + ignore: true + }, + { + type: 'number', + input: true, + key: 'rows', + label: 'Rows', + weight: 210, + tooltip: 'This allows control over how many rows are visible in the text area.', + placeholder: 'Enter the amount of rows' + }, + { + weight: 1350, + type: 'checkbox', + input: true, + key: 'spellcheck', + defaultValue: true, + label: 'Allow Spellcheck' + }, + { + key: 'editor', + ignore: true + }, + { + type: 'checkbox', + input: true, + key: 'autoExpand', + label: 'Auto Expand', + tooltip: 'This will make the TextArea auto expand it\'s height as the user is typing into the area.', + weight: 415 + }, + { + weight: 1200, + type: 'checkbox', + label: 'Show Word Counter', + tooltip: 'Show a live count of the number of words.', + key: 'showWordCount', + input: true + }, + { + weight: 1201, + type: 'checkbox', + label: 'Show Character Counter', + tooltip: 'Show a live count of the number of characters.', + key: 'showCharCount', + input: true + }, + { + key: 'isUploadEnabled', + ignore: true + }, + { + key: 'uploadStorage', + ignore: true + }, + { + key: 'uploadUrl', + ignore: true + }, + { + key: 'uploadOptions', + ignore: true + }, + { + key: 'uploadDir', + ignore: true + }, + { + key: 'fileKey', + ignore: true + }, + { + key: 'as', + ignore: true + }, + { + key: 'wysiwyg', + ignore: true + } + ] +} diff --git a/frontend/components/src/components/SimpleTextArea/editForm/Component.edit.validation.ts b/frontend/components/src/components/SimpleTextArea/editForm/Component.edit.validation.ts new file mode 100644 index 0000000..33c6c62 --- /dev/null +++ b/frontend/components/src/components/SimpleTextArea/editForm/Component.edit.validation.ts @@ -0,0 +1,40 @@ +import common from '../../Common/Simple.edit.validation'; +export default [ + ...common, + { + weight: 110, + key: 'validate.minLength', + label: 'Minimum Length', + placeholder: 'Minimum Length', + type: 'number', + tooltip: 'The minimum length requirement this field must meet.', + input: true + }, + { + weight: 120, + key: 'validate.maxLength', + label: 'Maximum Length', + placeholder: 'Maximum Length', + type: 'number', + tooltip: 'The maximum length requirement this field must meet.', + input: true + }, + { + weight: 125, + key: 'validate.minWords', + label: 'Minimum Word Length', + placeholder: 'Minimum Word Length', + type: 'number', + tooltip: 'The minimum amount of words that can be added to this field.', + input: true + }, + { + weight: 126, + key: 'validate.maxWords', + label: 'Maximum Word Length', + placeholder: 'Maximum Word Length', + type: 'number', + tooltip: 'The maximum amount of words that can be added to this field.', + input: true + }, +]; diff --git a/frontend/components/src/components/SimpleTextAreaAdvanced/Component.form.ts b/frontend/components/src/components/SimpleTextAreaAdvanced/Component.form.ts new file mode 100644 index 0000000..c0fe74f --- /dev/null +++ b/frontend/components/src/components/SimpleTextAreaAdvanced/Component.form.ts @@ -0,0 +1,17 @@ +import baseEditForm from 'formiojs/components/textarea/TextArea.form'; +import EditValidation from './editForm/Component.edit.validation'; + +export default function(...extend) { + return baseEditForm([ + { + key: 'validation', + ignore: true + }, + { + label: 'Validation', + key: 'customValidation', + weight: 20, + components: EditValidation + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleTextAreaAdvanced/Component.ts b/frontend/components/src/components/SimpleTextAreaAdvanced/Component.ts new file mode 100644 index 0000000..c5a8d36 --- /dev/null +++ b/frontend/components/src/components/SimpleTextAreaAdvanced/Component.ts @@ -0,0 +1,42 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.textarea; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simpletextareaadvanced'; +const DISPLAY = 'Text Area'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + rows: 3, + wysiwyg: false, + editor: '', + spellcheck: true, + fixedSize: true, + inputFormat: 'plain', + validate: { + minWords: '', + maxWords: '' + } + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'advanced', + icon: 'font', + weight: 730, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleTextAreaAdvanced/editForm/Component.edit.validation.ts b/frontend/components/src/components/SimpleTextAreaAdvanced/editForm/Component.edit.validation.ts new file mode 100644 index 0000000..e1f5157 --- /dev/null +++ b/frontend/components/src/components/SimpleTextAreaAdvanced/editForm/Component.edit.validation.ts @@ -0,0 +1,23 @@ +import common from '../../Common/Advanced.edit.validation'; +import {reArrangeComponents} from '../../Common/function'; + +const neededposition = [ + 'validate.isUseForCopy', + 'validateOn', + 'validate.required', + 'unique', + 'validate.minLength', + 'validate.maxLength', + 'validate.minWords', + 'validate.maxWords', + 'validate.pattern', + 'errorLabel', + 'validate.customMessage', + 'errors', + 'custom-validation-js', + 'json-validation-json' + ]; + + const newPosition = reArrangeComponents(neededposition,common); + + export default newPosition; \ No newline at end of file diff --git a/frontend/components/src/components/SimpleTextField/Component.form.ts b/frontend/components/src/components/SimpleTextField/Component.form.ts new file mode 100644 index 0000000..d82d83b --- /dev/null +++ b/frontend/components/src/components/SimpleTextField/Component.form.ts @@ -0,0 +1,62 @@ +import baseEditForm from 'formiojs/components/_classes/component/Component.form'; + +import EditData from './editForm/Component.edit.data'; +import EditDisplay from './editForm/Component.edit.display'; +import EditValidation from './editForm/Component.edit.validation'; + +import SimpleApi from '../Common/Simple.edit.api'; +import SimpleConditional from '../Common/Simple.edit.conditional'; + +export default function(...extend) { + return baseEditForm([ + EditDisplay, + { + key: 'data', + ignore: true, + }, + { + key: 'api', + ignore: true + }, + { + key: 'layout', + ignore: true + }, + { + key: 'conditional', + ignore: true + }, + { + key: 'validation', + ignore: true + }, + { + key: 'logic', + ignore: true + }, + { + label: 'Data', + key: 'customData', + weight: 10, + components: EditData + }, + { + label: 'Validation', + key: 'customValidation', + weight: 20, + components: EditValidation + }, + { + label: 'API', + key: 'customAPI', + weight: 30, + components: SimpleApi + }, + { + label: 'Conditional', + key: 'customConditional', + weight: 40, + components: SimpleConditional + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleTextField/Component.ts b/frontend/components/src/components/SimpleTextField/Component.ts new file mode 100644 index 0000000..1dab5de --- /dev/null +++ b/frontend/components/src/components/SimpleTextField/Component.ts @@ -0,0 +1,46 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.textfield; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simpletextfield'; +const DISPLAY = 'Text Field'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + mask: false, + inputType: 'text', + inputFormat: 'plain', + inputMask: '', + tableView: false, + spellcheck: true, + widget: { + type: 'input' + }, + validate: { + minLength: '', + maxLength: '', + pattern: '' + } + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'simple', + icon: 'terminal', + weight: 1, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleTextField/editForm/Component.edit.data.ts b/frontend/components/src/components/SimpleTextField/editForm/Component.edit.data.ts new file mode 100644 index 0000000..9c28c59 --- /dev/null +++ b/frontend/components/src/components/SimpleTextField/editForm/Component.edit.data.ts @@ -0,0 +1,25 @@ +import common from '../../Common/Simple.edit.data'; +export default [ + ...common, + { + weight: 200, + type: 'radio', + label: 'Text Case', + key: 'case', + tooltip: 'When data is entered, you can change the case of the value.', + input: true, + values: [ + { + value: 'mixed', + label: 'Mixed (Allow upper and lower case)' + }, + { + value: 'uppercase', + label: 'Uppercase' + },{ + value: 'lowercase', + label: 'Lowercase' + } + ] + } +]; diff --git a/frontend/components/src/components/SimpleTextField/editForm/Component.edit.display.ts b/frontend/components/src/components/SimpleTextField/editForm/Component.edit.display.ts new file mode 100644 index 0000000..6a3c34c --- /dev/null +++ b/frontend/components/src/components/SimpleTextField/editForm/Component.edit.display.ts @@ -0,0 +1,108 @@ +import common from '../../Common/Simple.edit.display'; +export default + { + key: 'display', + components: [ + ...common, + { + key: 'refreshOnChange', + ignore: true + }, + { + key: 'className', + ignore: true, + }, + { + key: 'widget', + ignore: true + }, + { + key: 'widget.type', + ignore: true + }, + { + key: 'prefix', + ignore: true + }, + { + key: 'suffix', + ignore: true + }, + { + weight: 410, + type: 'textfield', + input: true, + key: 'inputMask', + label: 'Input Mask', + tooltip: 'An input mask helps the user with input by ensuring a predefined format.<br><br>9: numeric<br>a: alphabetical<br>*: alphanumeric<br><br>Example telephone mask: (999) 999-9999<br><br>See the <a target=\'_blank\' href=\'https://github.com/RobinHerbots/jquery.inputmask\'>jquery.inputmask documentation</a> for more information.</a>', + customConditional(context) { + return !context.data.allowMultipleMasks; + } + }, + { + weight: 413, + type: 'checkbox', + input: true, + key: 'allowMultipleMasks', + label: 'Allow Multiple Masks' + }, + { + weight: 1350, + type: 'checkbox', + input: true, + key: 'spellcheck', + defaultValue: true, + label: 'Allow Spellcheck' + }, + { + weight: 417, + type: 'datagrid', + input: true, + key: 'inputMasks', + label: 'Input Masks', + customConditional(context) { + return context.data.allowMultipleMasks === true; + }, + reorder: true, + components: [ + { + type: 'textfield', + key: 'label', + label: 'Label', + input: true + }, + { + type: 'textfield', + key: 'mask', + label: 'Mask', + input: true + } + ] + }, + { + key: 'autocomplete', + ignore: true, + }, + { + weight: 1300, + key: 'mask', + ignore: true + }, + { + weight: 1200, + type: 'checkbox', + label: 'Show Word Counter', + tooltip: 'Show a live count of the number of words.', + key: 'showWordCount', + input: true + }, + { + weight: 1201, + type: 'checkbox', + label: 'Show Character Counter', + tooltip: 'Show a live count of the number of characters.', + key: 'showCharCount', + input: true + } + ] + } diff --git a/frontend/components/src/components/SimpleTextField/editForm/Component.edit.validation.ts b/frontend/components/src/components/SimpleTextField/editForm/Component.edit.validation.ts new file mode 100644 index 0000000..e0ac0d5 --- /dev/null +++ b/frontend/components/src/components/SimpleTextField/editForm/Component.edit.validation.ts @@ -0,0 +1,22 @@ +import common from '../../Common/Simple.edit.validation'; +export default [ + ...common, + { + weight: 110, + key: 'validate.minLength', + label: 'Minimum Length', + placeholder: 'Minimum Length', + type: 'number', + tooltip: 'The minimum length requirement this field must meet.', + input: true + }, + { + weight: 120, + key: 'validate.maxLength', + label: 'Maximum Length', + placeholder: 'Maximum Length', + type: 'number', + tooltip: 'The maximum length requirement this field must meet.', + input: true + } +]; diff --git a/frontend/components/src/components/SimpleTextFieldAdvanced/Component.form.ts b/frontend/components/src/components/SimpleTextFieldAdvanced/Component.form.ts new file mode 100644 index 0000000..4f2c188 --- /dev/null +++ b/frontend/components/src/components/SimpleTextFieldAdvanced/Component.form.ts @@ -0,0 +1,28 @@ +import baseEditForm from 'formiojs/components/textfield/TextField.form'; +import EditValidation from './editForm/Component.edit.validation'; +import EditDisplay from './editForm/Component.edit.display'; + +export default function(...extend) { + return baseEditForm([ + { + key: 'display', + ignore: true + }, + { + key: 'validation', + ignore: true + }, + { + label: 'Display', + key: 'customDisplay', + weight: 5, + components: EditDisplay + }, + { + label: 'Validation', + key: 'customValidation', + weight: 15, + components: EditValidation + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleTextFieldAdvanced/Component.ts b/frontend/components/src/components/SimpleTextFieldAdvanced/Component.ts new file mode 100644 index 0000000..29120fa --- /dev/null +++ b/frontend/components/src/components/SimpleTextFieldAdvanced/Component.ts @@ -0,0 +1,32 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.textfield; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simpletextfieldadvanced'; +const DISPLAY = 'Text Field'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'advanced', + icon: 'terminal', + weight: 710, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleTextFieldAdvanced/editForm/Component.edit.display.ts b/frontend/components/src/components/SimpleTextFieldAdvanced/editForm/Component.edit.display.ts new file mode 100644 index 0000000..a1a52db --- /dev/null +++ b/frontend/components/src/components/SimpleTextFieldAdvanced/editForm/Component.edit.display.ts @@ -0,0 +1,38 @@ +import common from '../../Common/Advanced.edit.display'; + +import {reArrangeComponents} from '../../Common/function'; + +const neededposition = [ + 'label', + 'labelPosition', + 'labelWidth', + 'labelMargin', + 'placeholder', + 'description', + 'tooltip', + 'prefix', + 'suffix', + 'widget.type', + 'widget', + 'inputMask', + 'displayMask', + 'inputMaskPlaceholderChar', + 'allowMultipleMasks', + 'customClass', + 'tabindex', + 'autocomplete', + 'hidden', + 'hideLabel', + 'showWordCount', + 'showCharCount', + 'mask', + 'autofocus', + 'spellcheck', + 'disabled', + 'tableView', + 'modalEdit' + ]; + + const newPosition = reArrangeComponents(neededposition,common); + + export default newPosition; diff --git a/frontend/components/src/components/SimpleTextFieldAdvanced/editForm/Component.edit.validation.ts b/frontend/components/src/components/SimpleTextFieldAdvanced/editForm/Component.edit.validation.ts new file mode 100644 index 0000000..e1f5157 --- /dev/null +++ b/frontend/components/src/components/SimpleTextFieldAdvanced/editForm/Component.edit.validation.ts @@ -0,0 +1,23 @@ +import common from '../../Common/Advanced.edit.validation'; +import {reArrangeComponents} from '../../Common/function'; + +const neededposition = [ + 'validate.isUseForCopy', + 'validateOn', + 'validate.required', + 'unique', + 'validate.minLength', + 'validate.maxLength', + 'validate.minWords', + 'validate.maxWords', + 'validate.pattern', + 'errorLabel', + 'validate.customMessage', + 'errors', + 'custom-validation-js', + 'json-validation-json' + ]; + + const newPosition = reArrangeComponents(neededposition,common); + + export default newPosition; \ No newline at end of file diff --git a/frontend/components/src/components/SimpleTime/Component.form.ts b/frontend/components/src/components/SimpleTime/Component.form.ts new file mode 100644 index 0000000..7017d0c --- /dev/null +++ b/frontend/components/src/components/SimpleTime/Component.form.ts @@ -0,0 +1,62 @@ +import baseEditForm from 'formiojs/components/_classes/component/Component.form'; + +import EditData from './editForm/Component.edit.data'; +import EditDisplay from './editForm/Component.edit.display'; + +import SimpleApi from '../Common/Simple.edit.api'; +import SimpleConditional from '../Common/Simple.edit.conditional'; +import SimpleValidation from '../Common/Simple.edit.validation'; + +export default function(...extend) { + return baseEditForm([ + EditDisplay, + { + key: 'data', + ignore: true, + }, + { + key: 'api', + ignore: true + }, + { + key: 'layout', + ignore: true + }, + { + key: 'conditional', + ignore: true + }, + { + key: 'validation', + ignore: true + }, + { + key: 'logic', + ignore: true + }, + { + label: 'Data', + key: 'customData', + weight: 10, + components: EditData + }, + { + label: 'Validation', + key: 'customValidation', + weight: 20, + components: SimpleValidation + }, + { + label: 'API', + key: 'customAPI', + weight: 30, + components: SimpleApi + }, + { + label: 'Conditional', + key: 'customConditional', + weight: 40, + components: SimpleConditional + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleTime/Component.ts b/frontend/components/src/components/SimpleTime/Component.ts new file mode 100644 index 0000000..36f5114 --- /dev/null +++ b/frontend/components/src/components/SimpleTime/Component.ts @@ -0,0 +1,37 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.time; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simpletime'; +const DISPLAY = 'Time'; + +const defaultDataFormat = 'HH:mm:ss'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + inputType: 'time', + format: 'HH:mm', + dataFormat: defaultDataFormat, + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'simple', + icon: 'clock-o', + weight: 22, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleTime/editForm/Component.edit.data.ts b/frontend/components/src/components/SimpleTime/editForm/Component.edit.data.ts new file mode 100644 index 0000000..73ef7e6 --- /dev/null +++ b/frontend/components/src/components/SimpleTime/editForm/Component.edit.data.ts @@ -0,0 +1,21 @@ +export default [ + { + type: 'textfield', + label: 'Default Value', + key: 'defaultValue', + weight: 5, + placeholder: 'Default Value', + tooltip: 'The will be the value for this field, before user interaction. Having a default value will override the placeholder text.', + input: true + }, + { + type: 'textfield', + input: true, + key: 'dataFormat', + label: 'Data Format', + placeholder: 'HH:mm:ss', + tooltip: 'The moment.js format for saving the value of this field.', + weight: 25, + }, + +]; diff --git a/frontend/components/src/components/SimpleTime/editForm/Component.edit.display.ts b/frontend/components/src/components/SimpleTime/editForm/Component.edit.display.ts new file mode 100644 index 0000000..8562fe6 --- /dev/null +++ b/frontend/components/src/components/SimpleTime/editForm/Component.edit.display.ts @@ -0,0 +1,53 @@ +export default { + key: 'display', + components: [ + { + key: 'tableView', + ignore: true + }, + { + key: 'hidden', + ignore: true + }, + { + key: 'modalEdit', + ignore: true + }, + { + key: 'refreshOnChange', + ignore: true + }, + { + key: 'className', + ignore: true, + }, + { + key: 'prefix', + ignore: true + }, + { + key: 'suffix', + ignore: true + }, + { + key: 'inputMask', + ignore: true + }, + { + key: 'allowMultipleMasks', + ignore: true + }, + { + key: 'showWordCount', + ignore: true, + }, + { + key: 'showCharCount', + ignore: true, + }, + { + key: 'labelPosition', + ignore: true + } + ] +} diff --git a/frontend/components/src/components/SimpleTimeAdvanced/Component.form.ts b/frontend/components/src/components/SimpleTimeAdvanced/Component.form.ts new file mode 100644 index 0000000..a60a51d --- /dev/null +++ b/frontend/components/src/components/SimpleTimeAdvanced/Component.form.ts @@ -0,0 +1,17 @@ +import baseEditForm from 'formiojs/components/time/Time.form'; +import EditValidation from './editForm/Component.edit.validation'; + +export default function(...extend) { + return baseEditForm([ + { + key: 'validation', + ignore: true + }, + { + label: 'Validation', + key: 'customValidation', + weight: 15, + components: EditValidation + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleTimeAdvanced/Component.ts b/frontend/components/src/components/SimpleTimeAdvanced/Component.ts new file mode 100644 index 0000000..18d79a9 --- /dev/null +++ b/frontend/components/src/components/SimpleTimeAdvanced/Component.ts @@ -0,0 +1,32 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.time; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simpletimeadvanced'; +const DISPLAY = 'Time'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'advanced', + icon: 'clock-o', + weight: 800, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleTimeAdvanced/editForm/Component.edit.validation.ts b/frontend/components/src/components/SimpleTimeAdvanced/editForm/Component.edit.validation.ts new file mode 100644 index 0000000..f1c2655 --- /dev/null +++ b/frontend/components/src/components/SimpleTimeAdvanced/editForm/Component.edit.validation.ts @@ -0,0 +1,19 @@ +import common from '../../Common/Advanced.edit.validation'; +import {reArrangeComponents} from '../../Common/function'; + +const neededposition = [ + 'validate.isUseForCopy', + 'validate.required', + 'unique', + 'validateOn', + 'errorLabel', + 'validate.customMessage', + 'custom-validation-js', + 'json-validation-json', + 'errors', + ]; + + const newPosition = reArrangeComponents(neededposition,common); + + + export default newPosition; \ No newline at end of file diff --git a/frontend/components/src/components/SimpleUrlAdvanced/Component.form.ts b/frontend/components/src/components/SimpleUrlAdvanced/Component.form.ts new file mode 100644 index 0000000..64554ff --- /dev/null +++ b/frontend/components/src/components/SimpleUrlAdvanced/Component.form.ts @@ -0,0 +1,17 @@ +import baseEditForm from 'formiojs/components/url/Url.form'; +import EditValidation from './editForm/Component.edit.validation'; + +export default function(...extend) { + return baseEditForm([ + { + key: 'validation', + ignore: true + }, + { + label: 'Validation', + key: 'customValidation', + weight: 15, + components: EditValidation + } + ], ...extend); +} diff --git a/frontend/components/src/components/SimpleUrlAdvanced/Component.ts b/frontend/components/src/components/SimpleUrlAdvanced/Component.ts new file mode 100644 index 0000000..6af4295 --- /dev/null +++ b/frontend/components/src/components/SimpleUrlAdvanced/Component.ts @@ -0,0 +1,33 @@ +/* tslint:disable */ +import { Components } from 'formiojs'; +const ParentComponent = (Components as any).components.url; +import editForm from './Component.form'; + +import { Constants } from '../Common/Constants'; + +const ID = 'simpleurladvanced'; +const DISPLAY = 'Url'; + +export default class Component extends (ParentComponent as any) { + static schema(...extend) { + return ParentComponent.schema({ + type: ID, + label: DISPLAY, + key: ID, + inputType: 'url' + }, ...extend); + } + + public static editForm = editForm; + + static get builderInfo() { + return { + title: DISPLAY, + group: 'advanced', + icon: 'link', + weight: 740, + documentation: Constants.DEFAULT_HELP_LINK, + schema: Component.schema() + }; + } +} diff --git a/frontend/components/src/components/SimpleUrlAdvanced/editForm/Component.edit.validation.ts b/frontend/components/src/components/SimpleUrlAdvanced/editForm/Component.edit.validation.ts new file mode 100644 index 0000000..5d34335 --- /dev/null +++ b/frontend/components/src/components/SimpleUrlAdvanced/editForm/Component.edit.validation.ts @@ -0,0 +1,21 @@ +import common from '../../Common/Advanced.edit.validation'; +import {reArrangeComponents} from '../../Common/function'; + +const neededposition = [ + 'validate.isUseForCopy', + 'validateOn', + 'validate.required', + 'unique', + 'validate.minLength', + 'validate.maxLength', + 'validate.pattern', + 'errorLabel', + 'validate.customMessage', + 'errors', + 'custom-validation-js', + 'json-validation-json' + ]; + + const newPosition = reArrangeComponents(neededposition,common); + + export default newPosition; \ No newline at end of file diff --git a/frontend/components/src/components/index.ts b/frontend/components/src/components/index.ts new file mode 100644 index 0000000..8361f59 --- /dev/null +++ b/frontend/components/src/components/index.ts @@ -0,0 +1,97 @@ +import orgbook from './OrgBook/Component'; +import simplebtnreset from './SimpleButtonReset/Component'; +import simplebtnsubmit from './SimpleButtonSubmit/Component'; +import simplecheckbox from './SimpleCheckbox/Component'; +import simplecheckboxes from './SimpleCheckboxes/Component'; +import simplecols2 from './SimpleColumns2/Component'; +import simplecols3 from './SimpleColumns3/Component'; +import simplecols4 from './SimpleColumns4/Component'; +import simplecontent from './SimpleContent/Component'; +import simpledatetime from './SimpleDateTime/Component'; +import simpleday from './SimpleDay/Component'; +import simpleemail from './SimpleEmail/Component'; +import simplefieldset from './SimpleFieldSet/Component'; +import simplefile from './SimpleFile/Component'; +import simpleheading from './SimpleHeading/Component'; +import simplenumber from './SimpleNumber/Component'; +import simplepanel from './SimplePanel/Component'; +import simpleparagraph from './SimpleParagraph/Component'; +import simplephonenumber from './SimplePhoneNumber/Component'; +import simpleradios from './SimpleRadios/Component'; +import simpleselect from './SimpleSelect/Component'; +import simpletabs from './SimpleTabs/Component'; +import simpletextarea from './SimpleTextArea/Component'; +import simpletextfield from './SimpleTextField/Component'; +import simpletime from './SimpleTime/Component'; +import simpletextfieldadvanced from './SimpleTextFieldAdvanced/Component'; +import simpleemailadvanced from './SimpleEmailAdvanced/Component'; +import simpletextareaadvanced from './SimpleTextAreaAdvanced/Component'; +import simplenumberadvanced from './SimpleNumberAdvanced/Component'; +import simpleurladvanced from './SimpleUrlAdvanced/Component'; +import simplephonenumberadvanced from './SimplePhoneNumberAdvanced/Component'; +import simpletagsadvanced from './SimpleTagsAdvanced/Component'; +import simpleaddressadvanced from './SimpleAddressAdvanced/Component'; +import simplepasswordadvanced from './SimplePasswordAdvanced/Component'; +import simpledatetimeadvanced from './SimpleDateTimeAdvanced/Component'; +import simplecheckboxadvanced from './SimpleCheckboxAdvanced/Component'; +import simpledayadvanced from './SimpleDayAdvanced/Component'; +import simpletimeadvanced from './SimpleTimeAdvanced/Component'; +import simpleselectboxesadvanced from './SimpleSelectBoxesAdvanced/Component'; +import simpleselectadvanced from './SimpleSelectAdvanced/Component'; +import simplecurrencyadvanced from './SimpleCurrencyAdvanced/Component'; +import simpleradioadvanced from './SimpleRadioAdvanced/Component'; +import simplesurveyadvanced from './SimpleSurveyAdvanced/Component'; +import simplesignatureadvanced from './SimpleSignatureAdvanced/Component'; +import simplebuttonadvanced from './SimpleButtonAdvanced/Component'; +import bcaddress from './BCAddress/Component'; +import simplebcaddress from './SimpleBCAddress/Component'; + +export default { + orgbook, + simplebtnreset, + simplebtnsubmit, + simplecheckbox, + simplecheckboxes, + simplecols2, + simplecols3, + simplecols4, + simplecontent, + simpledatetime, + simpleday, + simpleemail, + simplefieldset, + simplefile, + simpleheading, + simplenumber, + simplepanel, + simpleparagraph, + simplephonenumber, + simpleradios, + simpleselect, + simpletabs, + simpletextarea, + simpletextfield, + simpletime, + simpletextfieldadvanced, + simpleemailadvanced, + simpletextareaadvanced, + simplenumberadvanced, + simpleurladvanced, + simplephonenumberadvanced, + simpletagsadvanced, + simpleaddressadvanced, + simplepasswordadvanced, + simpledatetimeadvanced, + simplecheckboxadvanced, + simpledayadvanced, + simpletimeadvanced, + simpleselectboxesadvanced, + simpleselectadvanced, + simplecurrencyadvanced, + simpleradioadvanced, + simplesurveyadvanced, + simplesignatureadvanced, + simplebuttonadvanced, + bcaddress, + simplebcaddress +}; diff --git a/frontend/components/src/ejs.d.ts b/frontend/components/src/ejs.d.ts new file mode 100644 index 0000000..9d886f2 --- /dev/null +++ b/frontend/components/src/ejs.d.ts @@ -0,0 +1,6 @@ +declare module '*.ejs' { + const value: string; + export default value +} + +declare var Formio: any; diff --git a/frontend/components/src/index.ts b/frontend/components/src/index.ts new file mode 100644 index 0000000..06cc315 --- /dev/null +++ b/frontend/components/src/index.ts @@ -0,0 +1,10 @@ +import './overrides/editform/utils'; + +import components from './components'; +// @ts-ignore +import providers from './providers'; + +export default { + components, + providers, +}; diff --git a/frontend/components/src/overrides/editform/utils.ts b/frontend/components/src/overrides/editform/utils.ts new file mode 100644 index 0000000..8b604f9 --- /dev/null +++ b/frontend/components/src/overrides/editform/utils.ts @@ -0,0 +1,22 @@ +import EditFormUtils from 'formiojs/components/_classes/component/editForm/utils'; + +const originalLogicVariablesTable = EditFormUtils.logicVariablesTable; + +// decorate this function to include global updates to evalContext. +function logicVariablesTable(additional = '') { + // Avoid this showing up twice in the table (don't see a currently supported better way to override this atm) + // https://github.com/formio/formio.js/blob/3ee8def5e873c1bb957cee856926bcd76dc2e52a/src/components/_classes/component/editForm/Component.edit.data.js#L109 + if ( + additional === + '<tr><th>token</th><td>The decoded JWT token for the authenticated user.</td></tr>' + ) { + additional = ''; + } + + const customEval = + '<tr><th>token</th><td>The decoded JWT token for the authenticated user.</td></tr>' + + '<tr><th>user</th><td>The currently logged in user</td></tr>'; + return originalLogicVariablesTable(additional + customEval); +} + +EditFormUtils.logicVariablesTable = logicVariablesTable; diff --git a/frontend/components/src/providers/index.ts b/frontend/components/src/providers/index.ts new file mode 100644 index 0000000..866184a --- /dev/null +++ b/frontend/components/src/providers/index.ts @@ -0,0 +1,5 @@ +import storage from './storage'; + +export default { + storage, +}; diff --git a/frontend/components/src/providers/storage/chefs.ts b/frontend/components/src/providers/storage/chefs.ts new file mode 100644 index 0000000..8e41595 --- /dev/null +++ b/frontend/components/src/providers/storage/chefs.ts @@ -0,0 +1,177 @@ +/* tslint:disable */ +import NativePromise from 'native-promise-only'; + +const chefs = function Provider(formio) { + const addHeaders = (xhr, options) => { + if (options) { + if (options.headers) { + Object.keys(options.headers).forEach(k => { + const v = options.headers[k]; + xhr.setRequestHeader(k, v); + }); + } + + // Allow manual setting of any supplied headers above, but need to get the latest + // token from the containing app to deal with expiries and override auth + if (options.chefsToken) { + xhr.setRequestHeader('Authorization', options.chefsToken()) + } + } + }; + + const xhrRequest = (url, name, query, data, options, onprogress) => { + return new NativePromise((resolve, reject) => { + const xhr = new XMLHttpRequest(); + const json = (typeof data === 'string'); + const fd = new FormData(); + if (typeof onprogress === 'function') { + xhr.upload.onprogress = onprogress; + } + + if (!json) { + for (const key in data) { + fd.append(key, data[key]); + } + } + + xhr.onload = () => { + if (xhr.status >= 200 && xhr.status < 300) { + // Need to test if xhr.response is decoded or not. + let respData = {}; + try { + respData = (typeof xhr.response === 'string') ? JSON.parse(xhr.response) : {}; + // @ts-ignore + respData = (respData && respData.data) ? respData.data : respData; + } + catch (err) { + respData = {}; + } + + // Get the url of the file. + // @ts-ignore + let respUrl = respData.hasOwnProperty('url') ? respData.url : `${xhr.responseURL}/${name}`; + + // If they provide relative url, then prepend the url. + if (respUrl && respUrl[0] === '/') { + respUrl = `${url}${respUrl}`; + } + resolve({ url: respUrl, data: respData }); + } + else { + reject(xhr.response || 'Unable to upload file'); + } + }; + + xhr.onerror = () => reject(xhr); + xhr.onabort = () => reject(xhr); + + let requestUrl = url + (url.indexOf('?') > -1 ? '&' : '?'); + for (const key in query) { + requestUrl += `${key}=${query[key]}&`; + } + if (requestUrl[requestUrl.length - 1] === '&') { + requestUrl = requestUrl.substr(0, requestUrl.length - 1); + } + + xhr.open('POST', requestUrl); + if (json) { + xhr.setRequestHeader('Content-Type', 'application/json'); + } + const token = formio.getToken(); + if (token) { + xhr.setRequestHeader('x-jwt-token', token); + } + + addHeaders(xhr, options); + + //Overrides previous request props + if (options) { + const parsedOptions = typeof options === 'string' ? JSON.parse(options) : options; + for (const prop in parsedOptions) { + xhr[prop] = parsedOptions[prop]; + } + } + xhr.send(json ? data : fd); + }); + }; + + return { + title: 'CHEFS', + name: 'chefs', + uploadFile(file, name, dir, progressCallback, url, options, fileKey) { + const uploadRequest = function (form) { + return xhrRequest(url, name, {}, { + [fileKey]: file, + name, + dir + }, options, progressCallback).then(response => { + response.data = response.data || {}; + return { + storage: 'chefs', + name: response.data.originalname, + url: `${url}/${response.data.id}`, + size: response.data.size, + type: response.data.mimetype, + data: { id: response.data.id } + }; + }); + }; + if (file.private && formio.formId) { + return formio.loadForm().then((form) => uploadRequest(form)); + } + else { + // @ts-ignore + return uploadRequest(); + } + }, + deleteFile(fileInfo, options) { + return new NativePromise((resolve, reject) => { + const xhr = new XMLHttpRequest(); + xhr.open('DELETE', fileInfo.url, true); + addHeaders(xhr, options); + xhr.onload = () => { + if (xhr.status >= 200 && xhr.status < 300) { + resolve('File deleted'); + } + else { + reject(xhr.response || 'Unable to delete file'); + } + }; + xhr.send(null); + }); + }, + downloadFile(file, options) { + return new NativePromise((resolve, reject) => { + const xhr = new XMLHttpRequest(); + xhr.open('GET', file.url, true); + addHeaders(xhr, options); + xhr.responseType = 'blob'; + xhr.onload = function (event) { + const blob = xhr.response; + let fileName; + const contentType = xhr.getResponseHeader('content-type'); + + // IE/EDGE doesn't send all response headers + if (xhr.getResponseHeader('content-disposition')) { + const contentDisposition = xhr.getResponseHeader('content-disposition'); + fileName = contentDisposition.substring(contentDisposition.indexOf('=') + 1); + } else { + fileName = 'unnamed.' + contentType.substring(contentType.indexOf('/') + 1); + } + + const url = window.URL.createObjectURL(blob); + let el = document.createElement('a'); + el.href = url; + el.download = fileName; + el.click(); + window.URL.revokeObjectURL(url); + el.remove(); + }; + xhr.send(); + }); + } + }; +}; + +chefs.title = 'CHEFS'; +export default chefs; diff --git a/frontend/components/src/providers/storage/index.ts b/frontend/components/src/providers/storage/index.ts new file mode 100644 index 0000000..c5e0dd8 --- /dev/null +++ b/frontend/components/src/providers/storage/index.ts @@ -0,0 +1,5 @@ +import chefs from './chefs'; + +export default { + chefs, +}; diff --git a/frontend/cypress/support/e2e.ts b/frontend/components/src/sass/contrib.scss similarity index 100% rename from frontend/cypress/support/e2e.ts rename to frontend/components/src/sass/contrib.scss diff --git a/frontend/components/src/use.ts b/frontend/components/src/use.ts new file mode 100644 index 0000000..7982b12 --- /dev/null +++ b/frontend/components/src/use.ts @@ -0,0 +1,4 @@ +import { Formio } from 'formiojs'; +import BcGovFormioComponents from './index'; +(Formio as any).use(BcGovFormioComponents); +export default BcGovFormioComponents; diff --git a/frontend/components/tsconfig.json b/frontend/components/tsconfig.json new file mode 100644 index 0000000..7d7740f --- /dev/null +++ b/frontend/components/tsconfig.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "target": "esnext", + "preserveConstEnums": true, + "outDir": "lib", + "noImplicitAny": false, + "sourceMap": false, + "declaration": true, + "rootDir": "src", + "module": "esnext", + "moduleResolution": "node", + "lib": [ + "esnext", + "dom" + ], + "types": ["vite/client"] + }, + "include": [ + "src/*.ts", + "src/*.ejs", + "src/**/*.ts", + "src/**/*.ejs" + ], + "exclude": [ + "node_modules", + "**/*.spec.ts" + ] +} diff --git a/frontend/components/tslint.json b/frontend/components/tslint.json new file mode 100644 index 0000000..88ff638 --- /dev/null +++ b/frontend/components/tslint.json @@ -0,0 +1,26 @@ +{ + "defaultSeverity": "error", + "extends": [ + "tslint:recommended" + ], + "jsRules": {}, + "rules": { + "quotemark": [true, "single", "avoid-escape", "avoid-template"], + "one-line": [false, "check-catch", "check-finally", "check-else"], + "object-literal-sort-keys": false, + "no-shadowed-variable": false, + "variable-name": { + "options": [ + "allow-leading-underscore", + "allow-pascal-case", + "ban-keywords" + ] + }, + "max-classes-per-file": [false] + }, + "rulesDirectory": [], + "exclude": [ + "lib", + "node_modules" + ] +} diff --git a/frontend/components/webpack.config.js b/frontend/components/webpack.config.js new file mode 100644 index 0000000..c82fc57 --- /dev/null +++ b/frontend/components/webpack.config.js @@ -0,0 +1,17 @@ +const path = require('path'); + +module.exports = { + entry: path.join(path.resolve(__dirname, 'lib'), 'index.js'), + output: { + library: 'BcGovFormioComponents', + libraryTarget: 'umd', + libraryExport: 'default', + path: path.resolve(__dirname, 'dist'), + filename: 'bcgov-formio-components.js', + }, + mode: 'development', + performance: { hints: false }, + externals: { + formiojs: 'Formio' + } +}; diff --git a/frontend/components/webpack.prod.js b/frontend/components/webpack.prod.js new file mode 100644 index 0000000..24c4128 --- /dev/null +++ b/frontend/components/webpack.prod.js @@ -0,0 +1,4 @@ +const config = require('./webpack.config.js'); +config.mode = 'production'; +config.output.filename = 'bcgov-formio-components.min.js'; +module.exports = config; diff --git a/frontend/components/webpack.use.js b/frontend/components/webpack.use.js new file mode 100644 index 0000000..c9e6a8f --- /dev/null +++ b/frontend/components/webpack.use.js @@ -0,0 +1,6 @@ +const path = require('path'); +const config = require('./webpack.config.js'); +config.entry = path.join(path.resolve(__dirname, 'lib'), 'use.js'), +config.mode = 'production'; +config.output.filename = 'bcgov-formio-components.use.min.js'; +module.exports = config; diff --git a/frontend/cypress.config.ts b/frontend/cypress.config.ts deleted file mode 100644 index 732c2df..0000000 --- a/frontend/cypress.config.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { defineConfig } from "cypress"; - -export default defineConfig({ - e2e: { - baseUrl: 'https://quickstart-openshift-test-frontend.apps.silver.devops.gov.bc.ca/', - setupNodeEvents(on, config) { - // implement node event listeners here - }, - experimentalStudio: true, - experimentalWebKitSupport: true, - }, -}); diff --git a/frontend/cypress/e2e/home-page.cy.ts b/frontend/cypress/e2e/home-page.cy.ts deleted file mode 100644 index 3d7864d..0000000 --- a/frontend/cypress/e2e/home-page.cy.ts +++ /dev/null @@ -1,8 +0,0 @@ -/// <reference types="cypress" /> -describe("Home page visit", () => { - - it("visit landing page", () => { - cy.visit("/"); - cy.contains("Quickstart OpenShift"); - }); -}); diff --git a/frontend/cypress/e2e/user-table.cy.ts b/frontend/cypress/e2e/user-table.cy.ts deleted file mode 100644 index bc40487..0000000 --- a/frontend/cypress/e2e/user-table.cy.ts +++ /dev/null @@ -1,30 +0,0 @@ -/// <reference types="cypress" /> -describe("User Table", () => { - beforeEach(() => { - cy.visit("/"); - }); - - it("renders the table", () => { - cy.get("h6.MuiTypography-root").should("exist").should(($div) => { - // access the native DOM element - expect($div.get(0).innerText).to.eq('User List') - }); - cy.get("th.MuiTableCell-root:nth-child(2) > span:nth-child(1) > button:nth-child(1) > div:nth-child(1) > div:nth-child(1)").should("exist").should(($div) => { - // access the native DOM element - expect($div.get(0).innerText).to.eq('ID'); - }); - cy.get("th.MuiTableCell-root:nth-child(3) > span:nth-child(1) > button:nth-child(1)").should("exist").should(($div) => { - // access the native DOM element - expect($div.get(0).innerText).to.eq('NAME'); - }); - cy.get("th.MuiTableCell-root:nth-child(4) > span:nth-child(1) > button:nth-child(1) > div:nth-child(1) > div:nth-child(1)").should("exist").should(($div) => { - // access the native DOM element - expect($div.get(0).innerText).to.eq('EMAIL'); - }); - cy.get(".MuiTableBody-root").should("exist").should(($div) => { - // access the native DOM element - console.info($div.get(0)) - expect($div.get(0).childNodes.length).to.eq(5); - }); - }); -}); diff --git a/frontend/cypress/support/index.ts b/frontend/cypress/support/index.ts deleted file mode 100644 index 551c38a..0000000 --- a/frontend/cypress/support/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -declare namespace Cypress { -} diff --git a/frontend/index.html b/frontend/index.html deleted file mode 100644 index 5d1983c..0000000 --- a/frontend/index.html +++ /dev/null @@ -1,17 +0,0 @@ -<!DOCTYPE html> -<html lang="en"> - <head> - <meta charset="utf-8" /> - <meta name="Description" content="Quickstart OpenShift" /> - <meta http-equiv="X-UA-Compatible" content="IE=edge" /> - <meta name="theme-color" content="#003366" /> - <meta name="viewport" content="width=device-width,initial-scale=1.0" /> - <link rel="preload" href="https://fonts.googleapis.com/css?family=Material+Icons" as="style" /> - <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Material+Icons" /> - <title>QuickStart OpenShift - - -
- - - diff --git a/frontend/openshift/README.md b/frontend/openshift/README.md new file mode 100644 index 0000000..97d3b05 --- /dev/null +++ b/frontend/openshift/README.md @@ -0,0 +1,234 @@ +# Application on Openshift + +This application is deployed on Openshift. This readme will outline how to setup and configure an Openshift project to get the application to a deployable state. This document assumes a working knowledge of Kubernetes/Openshift container orchestration concepts (i.e. buildconfigs, deployconfigs, imagestreams, secrets, configmaps, routes, networkpolicies, etc) and Red Hat SSO authentication. + +Our CI/CD pipelines are orchestrated by [GitHub Actions](../.github/workflows). + +## Table of Contents + +- [Openshift Deployment Prerequisites](#openshift-deployment-prerequisites) +- [Environment Setup - ConfigMaps and Secrets](#environment-setup---configmaps-and-secrets) +- [Deployment](#deployment) +- [Templates](#templates) +- [Pull Request Cleanup](#pull-request-cleanup) +- [Appendix - Supporting Deployments](#appendix---supporting-deployments) + +## Openshift Deployment Prerequisites + +We assume you are logged into OpenShift and are in the repo's `/openshift` local directory. We will run the scripts from there. + +### Add Default Kubernetes Network Policies + +Before deploying, ensure that you have the Network Policy `allow-from-openshift-ingress` by running the following: + +```sh +export NAMESPACE= +oc apply -n $NAMESPACE -f allow-from-openshift-ingress.np.yaml +``` + +## Environment Setup - ConfigMaps and Secrets + +There are some requirements in the target Openshift namespace/project which are **outside** of the CI/CD pipeline process. This application requires that a few Secrets as well as ConfigMaps are already present in the environment before it is able to function as intended. Otherwise the pipeline will fail the deployment by design. + +In order to prepare an environment, you will need to ensure that all of the following configmaps and secrets are populated. This is achieved by executing the following commands as a project administrator of the targeted environment. Note that this must be repeated on _each_ of the target deployment namespace/projects (i.e. `dev`, `test` and `prod`) as that they are independent of each other. Deployments will fail otherwise. Refer to [custom-environment-variables](../app/config/custom-environment-variables.json) for the direct mapping of environment variables to the app. + +### ConfigMaps + +_Note:_ Replace anything in angle brackets with the appropriate value. + +_Note 2:_ The Keycloak Public Key can be found in the Keycloak Admin Panel under `Realm Settings` > `Keys`. Look for the Public key button (normally under RS256 row), and click to see the key. The key should begin with a pattern of `MIIBIjANB...`. + +```sh +export APP_NAME= +export NAMESPACE= +export PUBLIC_KEY= +export REPO_NAME=common-hosted-form-service +export SSO_REALM= +export STORAGE_BUCKET= + +oc create -n $NAMESPACE configmap $APP_NAME-frontend-config \ + --from-literal=FRONTEND_APIPATH=api/v1 \ + --from-literal=VITE_FRONTEND_BASEPATH=/app \ + --from-literal=FRONTEND_ENV=dev \ + --from-literal=FRONTEND_KC_REALM=$SSO_REALM \ + --from-literal=FRONTEND_KC_SERVERURL=https://dev.loginproxy.gov.bc.ca/auth +``` + +```sh +oc create -n $NAMESPACE configmap $APP_NAME-sc-config \ + --from-literal=SC_CS_CHES_ENDPOINT=https://ches-dev.api.gov.bc.ca/api \ + --from-literal=SC_CS_CDOGS_ENDPOINT=https://cdogs-dev.api.gov.bc.ca/api \ + --from-literal=SC_CS_CHES_TOKEN_ENDPOINT=https://dev.loginproxy.gov.bc.ca/auth/realms/comsvcauth/protocol/openid-connect/token + --from-literal=SC_CS_CDOGS_TOKEN_ENDPOINT=https://dev.loginproxy.gov.bc.ca/auth/realms/comsvcauth/protocol/openid-connect/token +``` + +```sh +oc create -n $NAMESPACE configmap $APP_NAME-server-config \ + --from-literal=SERVER_APIPATH=/api/v1 \ + --from-literal=SERVER_BASEPATH=/app \ + --from-literal=SERVER_BODYLIMIT=30mb \ + --from-literal=SERVER_KC_PUBLICKEY=$PUBLIC_KEY \ + --from-literal=SERVER_KC_REALM=$SSO_REALM \ + --from-literal=SERVER_KC_SERVERURL=https://dev.loginproxy.gov.bc.ca/auth \ + --from-literal=SERVER_LOGLEVEL=http \ + --from-literal=SERVER_PORT=8080 +``` + +_Note:_ We use the Common Services Object Storage for CHEFS. You will need to contact them to have your storage bucket created. + +```sh +oc create -n $NAMESPACE configmap $APP_NAME-files-config \ + --from-literal=FILES_UPLOADS_DIR= \ + --from-literal=FILES_UPLOADS_ENABLED=true \ + --from-literal=FILES_UPLOADS_FILECOUNT=1 \ + --from-literal=FILES_UPLOADS_FILEKEY=files \ + --from-literal=FILES_UPLOADS_FILEMAXSIZE=25MB \ + --from-literal=FILES_UPLOADS_FILEMINSIZE=0KB \ + --from-literal=FILES_UPLOADS_PATH=files \ + --from-literal=FILES_PERMANENT=objectStorage \ + --from-literal=FILES_LOCALSTORAGE_PATH= \ + --from-literal=FILES_OBJECTSTORAGE_BUCKET=$STORAGE_BUCKET \ + --from-literal=FILES_OBJECTSTORAGE_ENDPOINT=https://commonservices.objectstore.gov.bc.ca \ + --from-literal=FILES_OBJECTSTORAGE_KEY=chefs/dev/ \ +``` + +### Secrets + +```sh +export NAMESPACE= +export APP_NAME= + +export username= +export password= + +oc create -n $NAMESPACE secret generic $APP_NAME-keycloak-secret \ + --type=kubernetes.io/basic-auth \ + --from-literal=username=$username \ + --from-literal=password=$password +``` + +```sh +export ches_client_id= +export ches_client_secret= +export cdogs_client_id= +export cdogs_client_secret= + +oc create -n $NAMESPACE secret generic $APP_NAME-sc-cs-secret \ + --type=Opaque \ + --from-literal=ches_client_id=$ches_client_id \ + --from-literal=ches_client_secret=$ches_client_secret \ + --from-literal=cdogs_client_id=$cdogs_client_id \ + --from-literal=cdogs_client_secret=$cdogs_client_secret +``` + +```sh +export username= +export password= + +oc create -n $NAMESPACE secret generic $APP_NAME-objectstorage-secret \ + --type=kubernetes.io/basic-auth \ + --from-literal=username=$username \ + --from-literal=password=$password +``` + +## Deployment + +This application is currently designed as a single application pod deployment. It will host a static frontend containing all of the Vue.js resources and assets, and a Node.js backend which serves the API that the frontend requires. We are currently leveraging Openshift Routes with path based filtering to forward incoming traffic to the right deployment service. + +### Frontend + +The frontend temporarily installs dependencies needed to generate the static assets that will appear in the `/app/frontend/dist` folder. These contents will be picked up by the application and hosted appropriately. + +### Application + +The backend is a standard [Node](https://nodejs.org)/[Express](https://expressjs.com) server. It handles the JWT based authentication via OIDC authentication flow, and exposes the API to authorized users. This deployment container is built up on top of an Alpine Node image. The resulting container after build is what is deployed. + +## Templates + +The CI/CD pipeline heavily leverages Openshift Templates to push environment variables, settings, and contexts to Openshift. Files ending with `.dc.yaml` specify the components required for deployment. + +### Deployment Configurations + +Deployment configurations will emit and handle the deployment lifecycles of running containers based off of the previously built images. They generally contain a deploymentconfig, a service, and a route. Before our application is deployed, Patroni (a Highly Available Postgres Cluster implementation) needs to be deployed. Refer to any `patroni*` templates and their [official documentation](https://patroni.readthedocs.io/en/latest/) for more details. + +Our application template takes in the following required parameters: + +| Name | Description | +| ---------- | ------------------------------------------------------------------- | +| REPO_NAME | Application repository name | +| JOB_NAME | Job identifier (i.e. 'pr-5' OR 'master') | +| NAMESPACE | which namespace/"environment" are we deploying to? dev, test, prod? | +| APP_NAME | short name for the application | +| ROUTE_HOST | base domain for the publicly accessible URL | +| ROUTE_PATH | base path for the publicly accessible URL | + +The CI/CD pipeline will deploy to Openshift. To deploy manually: + +```sh +export NAMESPACE= +export APP_NAME= + +oc process -n $NAMESPACE -f openshift/app.dc.yaml -p REPO_NAME=common-hosted-form-service -p JOB_NAME=master -p NAMESPACE=$NAMESPACE -p APP_NAME=$APP_NAME -p ROUTE_HOST=$APP_NAME-dev.apps.silver.devops.gov.bc.ca -p ROUTE_PATH=master -o yaml | oc apply -n $NAMESPACE -f - +``` + +Due to the triggers that are set in the deploymentconfig, the deployment will begin automatically. However, you can deploy manually by use the following command for example: + +```sh +oc rollout -n $NAMESPACE latest dc/-master +``` + +## Pull Request Cleanup + +When a PR is closed the CI/CD pipeline will automatically clean up the resources created by the deployment. To manually clear all resources for a specific PR, run the following two commands to delete all relevant resources from the Openshift project (replacing `PRNUMBER` with the appropriate number): + +```sh +export NAMESPACE= +export APP_NAME= + +oc delete all,secret,networkpolicy,rolebinding -n $NAMESPACE --selector app=$APP_NAME-pr- +oc delete all,svc,cm,sa,role,secret -n $NAMESPACE --selector cluster-name=pr- +``` + +The first command will clear out all related executable resources for the application, while the second command will clear out the remaining Patroni cluster resources associated with that PR. + +## Appendix - Supporting Deployments + +There will be instances where this application will need supporting modifications or deployment such as databases and business analytics tools. Below is a list of initial reference points for other Openshift templates that could be leveraged and bolted onto the existing CI/CD pipeline if applicable. + +### Metabase + +- [Overview & Templates](https://github.com/bcgov/common-service-showcase/wiki/Metabase) + +### Redash + +- [Overview & Templates](redash) + +### Patroni (HA Postgres) + +Refer to the `patroni.dc.yaml` and `patroni.secret.yaml` files found below for a Highly Available Patroni cluster statefulset: + +- [Templates](https://github.com/bcgov/nr-get-token/tree/master/openshift) + +#### Database Backup + +- [Documentation & Templates](https://github.com/bcgov/common-service-showcase/wiki/Database-Backup) + +After backups are made a verification job should be run to restore the backup into a temporary database and check that tables are created and data is written. This is not a full verification to ensure all data integrity, but it is an automatable first step. + +Using the `backup-cronjon-verify.yaml` file from the `redash` directory: + +```sh +export NAMESPACE= +export PVC= + +oc process -f backup-cronjob-verify.yaml \ + -p BACKUP_JOB_CONFIG=backup-postgres-config \ + -p DATABASE_DEPLOYMENT_NAME=patroni-master-secret \ + -p DATABASE_PASSWORD_KEY_NAME=app-db-password \ + -p DATABASE_USER_KEY_NAME=app-db-username \ + -p JOB_NAME=backup-postgres-verify \ + -p JOB_PERSISTENT_STORAGE_NAME=$PVC \ + -p SCHEDULE="0 9 * * *" \ + -p TAG_NAME=2.6.1 \ + | oc -n $NAMESPACE apply -f - +``` diff --git a/frontend/openshift/allow-from-openshift-ingress.np.yaml b/frontend/openshift/allow-from-openshift-ingress.np.yaml new file mode 100644 index 0000000..f54b1da --- /dev/null +++ b/frontend/openshift/allow-from-openshift-ingress.np.yaml @@ -0,0 +1,14 @@ +kind: NetworkPolicy +apiVersion: networking.k8s.io/v1 +metadata: + name: allow-from-openshift-ingress +spec: + podSelector: {} + ingress: + - from: + - namespaceSelector: + matchLabels: + network.openshift.io/policy-group: ingress + policyTypes: + - Ingress +status: {} diff --git a/frontend/openshift/app.cm.yaml b/frontend/openshift/app.cm.yaml new file mode 100644 index 0000000..0aa4d0e --- /dev/null +++ b/frontend/openshift/app.cm.yaml @@ -0,0 +1,37 @@ +--- +apiVersion: template.openshift.io/v1 +kind: Template +labels: + app.kubernetes.io/component: app + app.kubernetes.io/instance: "${APP_NAME}-${JOB_NAME}" + app.kubernetes.io/managed-by: github + app.kubernetes.io/name: nodejs + app.kubernetes.io/part-of: "${APP_NAME}-${JOB_NAME}" + app: "${APP_NAME}-${JOB_NAME}" + template: "chefs-app-cm-template" +metadata: + name: "chefs-app-cm" +objects: + - apiVersion: v1 + kind: ConfigMap + metadata: + name: "${APP_NAME}-service-config" + data: + SERVER_HOST: ${SERVER_HOST} +parameters: + - name: APP_NAME + description: Application name + displayName: Application name + required: true + - name: JOB_NAME + description: Job identifier (i.e. 'pr-5' OR 'master') + displayName: Job Branch Name + required: true + - name: SERVER_HOST + description: Server domain to be used by end users + displayName: Application name + required: true + - name: NAMESPACE + description: Target namespace reference (i.e. 'wfezkf-dev') + displayName: Target Namespace + required: true diff --git a/frontend/openshift/app.cronjob.yaml b/frontend/openshift/app.cronjob.yaml new file mode 100644 index 0000000..4bca4ba --- /dev/null +++ b/frontend/openshift/app.cronjob.yaml @@ -0,0 +1,85 @@ +--- +apiVersion: template.openshift.io/v1 +kind: Template +labels: + app.kubernetes.io/component: app + app.kubernetes.io/instance: "${APP_NAME}-${JOB_NAME}" + app.kubernetes.io/managed-by: github + app.kubernetes.io/name: nodejs + app.kubernetes.io/part-of: "${APP_NAME}-${JOB_NAME}" + app: "${APP_NAME}-${JOB_NAME}" + template: "chefs-app-cronjob-template" +metadata: + name: "chefs-app-cronjob" +objects: + - apiVersion: networking.k8s.io/v1 + kind: NetworkPolicy + metadata: + name: "allow-${APP_NAME}-cronjob-${JOB_NAME}-to-${APP_NAME}-app-${JOB_NAME}" + spec: + # Allow cronjob to talk to chefs add via service + ingress: + - from: + - podSelector: + matchLabels: + type: trigger + workload: mailcronjob + ports: + - port: 8080 + protocol: TCP + podSelector: + matchLabels: + app: "${APP_NAME}-${JOB_NAME}" + deploymentconfig: "${APP_NAME}-app-${JOB_NAME}" + role: app + - apiVersion: batch/v1 + kind: CronJob + metadata: + name: "${APP_NAME}-cronjob-${JOB_NAME}" + spec: + schedule: "0 8 * * *" + concurrencyPolicy: "Replace" + startingDeadlineSeconds: 200 + suspend: false + successfulJobsHistoryLimit: 3 + failedJobsHistoryLimit: 1 + jobTemplate: + spec: + template: + metadata: + labels: + parent: "cronjobpi" + workload: mailcronjob + type: trigger + spec: + containers: + - name: my-container + image: docker.io/curlimages/curl:8.1.0 + env: + - name: APITOKEN + valueFrom: + secretKeyRef: + name: "chefs-${JOB_NAME}-secret" + key: mailapitoken + command: + - /bin/sh + - -ec + - 'curl -v -X GET -ks -H "apikey: $APITOKEN" -H "Content-Type: application/json" "http://${APP_NAME}-app-${JOB_NAME}:8080${ROUTE_PATH}/api/v1/public/reminder"||exit 0' + restartPolicy: OnFailure +parameters: + - name: APP_NAME + description: Application name + displayName: Application name + required: true + - name: ROUTE_PATH + description: Configure the route path (ex. /pr-5 or /app), also used for VITE_FRONTEND_BASEPATH + displayName: Route path + required: true + - name: JOB_NAME + description: Job identifier (i.e. 'pr-5' OR 'master') + displayName: Job Branch Name + required: true + - name: NAMESPACE + description: Target namespace reference (i.e. 'wfezkf-dev') + displayName: Target Namespace + required: true diff --git a/frontend/openshift/app.dc.yaml b/frontend/openshift/app.dc.yaml new file mode 100644 index 0000000..0f77451 --- /dev/null +++ b/frontend/openshift/app.dc.yaml @@ -0,0 +1,361 @@ +--- +apiVersion: template.openshift.io/v1 +kind: Template +labels: + app.kubernetes.io/component: app + app.kubernetes.io/instance: "${APP_NAME}-${JOB_NAME}" + app.kubernetes.io/managed-by: kubectl + app.kubernetes.io/name: nodejs + app.kubernetes.io/part-of: "${APP_NAME}-${JOB_NAME}" + app: "${APP_NAME}-${JOB_NAME}" + template: "${REPO_NAME}-app-dc-template" +metadata: + name: "${REPO_NAME}-app-dc" +objects: + - apiVersion: networking.k8s.io/v1 + kind: NetworkPolicy + metadata: + name: "allow-${APP_NAME}-app-${JOB_NAME}-to-patroni-${JOB_NAME}-cluster" + spec: + # Allow app to talk to Patroni cluster + ingress: + - from: + - podSelector: + matchLabels: + app: "${APP_NAME}-${JOB_NAME}" + deploymentconfig: "${APP_NAME}-app-${JOB_NAME}" + role: app + ports: + - port: 5432 + protocol: TCP + podSelector: + matchLabels: + cluster-name: "${JOB_NAME}" + statefulset: "patroni-${JOB_NAME}" + role: master + - apiVersion: networking.k8s.io/v1 + kind: NetworkPolicy + metadata: + name: "allow-pre-hook-to-patroni-${JOB_NAME}-cluster" + spec: + # Allow app pre-hook pods to talk to Patroni cluster + ingress: + - from: + - podSelector: + matchLabels: + openshift.io/deployer-pod.type: hook-pre + ports: + - port: 5432 + protocol: TCP + podSelector: + matchLabels: + cluster-name: "${JOB_NAME}" + statefulset: "patroni-${JOB_NAME}" + role: master + - apiVersion: v1 + kind: DeploymentConfig + metadata: + annotations: + app.openshift.io/connects-to: '[{"apiVersion":"apps/v1","kind":"StatefulSet","name":"patroni-${JOB_NAME}"}]' + name: "${APP_NAME}-app-${JOB_NAME}" + spec: + replicas: 2 + revisionHistoryLimit: 10 + selector: + app: "${APP_NAME}-${JOB_NAME}" + deploymentconfig: "${APP_NAME}-app-${JOB_NAME}" + role: app + strategy: + type: Rolling + resources: {} + rollingParams: + timeoutSeconds: 600 + pre: + failurePolicy: Retry + execNewPod: + command: + - npm + - run + - migrate + containerName: "app" + env: + - name: NODE_ENV + value: production + - name: DB_DATABASE + valueFrom: + secretKeyRef: + key: app-db-name + name: "patroni-${JOB_NAME}-secret" + - name: DB_HOST + value: "patroni-${JOB_NAME}" + - name: DB_USERNAME + valueFrom: + secretKeyRef: + key: app-db-username + name: "patroni-${JOB_NAME}-secret" + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + key: app-db-password + name: "patroni-${JOB_NAME}-secret" + - name: SERVER_BASEPATH + value: "${ROUTE_PATH}" + template: + metadata: + labels: + app: "${APP_NAME}-${JOB_NAME}" + deploymentconfig: "${APP_NAME}-app-${JOB_NAME}" + role: app + spec: + containers: + - name: app + image: "${IMAGE_REGISTRY}/${IMAGE_NAMESPACE}/${REPO_NAME}:${IMAGE_TAG}" + imagePullPolicy: IfNotPresent + livenessProbe: + httpGet: + path: "${ROUTE_PATH}/api" + port: 8080 + scheme: HTTP + initialDelaySeconds: 10 + timeoutSeconds: 3 + failureThreshold: 3 + ports: + - containerPort: 8080 + protocol: TCP + readinessProbe: + httpGet: + path: "${ROUTE_PATH}/api" + port: 8080 + scheme: HTTP + initialDelaySeconds: 10 + timeoutSeconds: 3 + failureThreshold: 1 + resources: + requests: + cpu: "${CPU_REQUEST}" + memory: "${MEMORY_REQUEST}" + limits: + cpu: "${CPU_LIMIT}" + memory: "${MEMORY_LIMIT}" + env: + - name: NODE_ENV + value: production + - name: DB_DATABASE + valueFrom: + secretKeyRef: + key: app-db-name + name: "patroni-${JOB_NAME}-secret" + - name: DB_HOST + value: "patroni-${JOB_NAME}" + - name: DB_USERNAME + valueFrom: + secretKeyRef: + key: app-db-username + name: "patroni-${JOB_NAME}-secret" + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + key: app-db-password + name: "patroni-${JOB_NAME}-secret" + - name: FRONTEND_BASEPATH + value: "${ROUTE_PATH}" + - name: VITE_FRONTEND_BASEPATH + value: "${ROUTE_PATH}" + - name: VITE_CONTACT + valueFrom: + secretKeyRef: + key: email + name: "${APP_NAME}-contact-secret" + + - name: VITE_HOWTOURL + valueFrom: + secretKeyRef: + key: howtovideourl + name: "${APP_NAME}-landingpagevideourls-secret" + - name: VITE_CHEFSTOURURL + valueFrom: + secretKeyRef: + key: chefstourvideourl + name: "${APP_NAME}-landingpagevideourls-secret" + - name: VITE_CHEFS_GEO_ADDRESS_APIURL + valueFrom: + secretKeyRef: + key: chefsgeoaddressapiurl + name: "${APP_NAME}-bcgeoaddress-secret" + - name: VITE_CHEFS_ADVANCE_GEO_ADDRESS_APIURL + valueFrom: + secretKeyRef: + key: chefsadvancegeoaddressapiurl + name: "${APP_NAME}-bcgeoaddress-secret" + - name: VITE_BC_GEO_ADDRESS_APIURL + valueFrom: + secretKeyRef: + key: bcgeoaddressapiurl + name: "${APP_NAME}-bcgeoaddress-secret" + - name: SERVER_BASEPATH + value: "${ROUTE_PATH}" + - name: SERVER_KC_CLIENTID + valueFrom: + secretKeyRef: + key: username + name: "${APP_NAME}-keycloak-secret" + - name: SERVER_KC_CLIENTSECRET + valueFrom: + secretKeyRef: + key: password + name: "${APP_NAME}-keycloak-secret" + - name: SC_CS_CHES_CLIENT_ID + valueFrom: + secretKeyRef: + key: ches_client_id + name: "${APP_NAME}-sc-cs-secret" + - name: SC_CS_CHES_CLIENT_SECRET + valueFrom: + secretKeyRef: + key: ches_client_secret + name: "${APP_NAME}-sc-cs-secret" + - name: SC_CS_CDOGS_CLIENT_ID + valueFrom: + secretKeyRef: + key: cdogs_client_id + name: "${APP_NAME}-sc-cs-secret" + - name: SC_CS_CDOGS_CLIENT_SECRET + valueFrom: + secretKeyRef: + key: cdogs_client_secret + name: "${APP_NAME}-sc-cs-secret" + - name: FILES_OBJECTSTORAGE_ACCESSKEYID + valueFrom: + secretKeyRef: + key: username + name: "${APP_NAME}-objectstorage-secret" + - name: FILES_OBJECTSTORAGE_SECRETACCESSKEY + valueFrom: + secretKeyRef: + key: password + name: "${APP_NAME}-objectstorage-secret" + - name: APITOKEN + valueFrom: + secretKeyRef: + key: mailapitoken + name: "chefs-${JOB_NAME}-secret" + # - name: SERVER_LOGFILE + # value: "/var/log/app.log" + envFrom: + - configMapRef: + name: "${APP_NAME}-frontend-config" + - configMapRef: + name: "${APP_NAME}-sc-config" + - configMapRef: + name: "${APP_NAME}-server-config" + - configMapRef: + name: "${APP_NAME}-service-config" + - configMapRef: + name: "${APP_NAME}-files-config" + - configMapRef: + name: "${APP_NAME}-custombcaddressformiocomponent-config" + restartPolicy: Always + terminationGracePeriodSeconds: 30 + volumes: + - name: log-storage + emptyDir: {} + test: false + triggers: + - type: ConfigChange + # - imageChangeParams: + # automatic: true + # containerNames: + # - app + # from: + # kind: ImageStreamTag + # name: "${REPO_NAME}-app:${JOB_NAME}" + # namespace: "${NAMESPACE}" + # type: ImageChange + - apiVersion: v1 + kind: Service + metadata: + name: "${APP_NAME}-app-${JOB_NAME}" + spec: + ports: + - name: 8080-tcp + port: 8080 + protocol: TCP + targetPort: 8080 + selector: + app: "${APP_NAME}-${JOB_NAME}" + deploymentconfig: "${APP_NAME}-app-${JOB_NAME}" + role: app + sessionAffinity: None + - apiVersion: v1 + kind: Route + metadata: + name: "${APP_NAME}-app-${JOB_NAME}" + spec: + host: "${ROUTE_HOST}" + path: "${ROUTE_PATH}" + port: + targetPort: 8080-tcp + tls: + insecureEdgeTerminationPolicy: Redirect + termination: edge + to: + kind: Service + name: "${APP_NAME}-app-${JOB_NAME}" + weight: 100 + wildcardPolicy: None +parameters: + - name: APP_NAME + description: Application name + displayName: Application name + required: true + - name: ROUTE_HOST + description: The host the route will use to expose service outside cluster + displayName: Route host + required: true + - name: ROUTE_PATH + description: Configure the route path (ex. /pr-5 or /app), also used for VITE_FRONTEND_BASEPATH + displayName: Route path + required: true + - name: JOB_NAME + description: Job identifier (i.e. 'pr-5' OR 'master') + displayName: Job Branch Name + required: true + - name: IMAGE_REGISTRY + description: The container registry + displayName: Docker Image Registry + required: true + value: ghcr.io + - name: IMAGE_NAMESPACE + description: The image namespace + displayName: Docker Image Namespace + required: true + value: bcgov + - name: IMAGE_TAG + description: The specific image tag to deploy + displayName: Docker Image Tag + required: true + value: latest + - name: NAMESPACE + description: Target namespace reference (i.e. 'wfezkf-dev') + displayName: Target Namespace + required: true + - name: REPO_NAME + description: Application repository name + displayName: Repository Name + required: true + - name: CPU_LIMIT + description: Limit Peak CPU per pod (in millicores ex. 1000m) + displayName: CPU Limit + value: 250m + - name: CPU_REQUEST + description: Requested CPU per pod (in millicores ex. 500m) + displayName: CPU Request + value: 50m + - name: MEMORY_LIMIT + description: Limit Peak Memory per pod (in gigabytes Gi or megabytes Mi ex. 2Gi) + displayName: Memory Limit + value: 1Gi + - name: MEMORY_REQUEST + description: Requested Memory per pod (in gigabytes Gi or megabytes Mi ex. 500Mi) + displayName: Memory Request + value: 256Mi diff --git a/frontend/openshift/app.dev.param b/frontend/openshift/app.dev.param new file mode 100644 index 0000000..e69de29 diff --git a/frontend/openshift/app.prod.param b/frontend/openshift/app.prod.param new file mode 100644 index 0000000..12f76a4 --- /dev/null +++ b/frontend/openshift/app.prod.param @@ -0,0 +1,3 @@ +CPU_LIMIT=1500m +CPU_REQUEST=250m +MEMORY_LIMIT=2Gi diff --git a/frontend/openshift/app.secret.yaml b/frontend/openshift/app.secret.yaml new file mode 100644 index 0000000..11d5172 --- /dev/null +++ b/frontend/openshift/app.secret.yaml @@ -0,0 +1,40 @@ +--- +apiVersion: template.openshift.io/v1 +kind: Template +metadata: + annotations: + description: Application secrets generation + openshift.io/display-name: CHEFS application secrets + openshift.io/long-description: This template creates secrets to be used by CHEFS app. + tags: chefs + name: chefs-app-secret +labels: + app.kubernetes.io/instance: "${INSTANCE}" + app.kubernetes.io/component: app + app.kubernetes.io/name: chefs + app.kubernetes.io/managed-by: template + app.kubernetes.io/version: "12" + cluster-name: "${INSTANCE}" +objects: + - apiVersion: v1 + kind: Secret + metadata: + name: "${NAME}-${INSTANCE}-secret" + stringData: + mailapitoken: "${MAIL_API_TOKEN}" +parameters: + - name: NAME + description: The name of the application for labelling all artifacts. + displayName: Application Name + required: true + value: chefs + - name: INSTANCE + description: The name of this instance of the application + displayName: Application Instance Name + required: true + - name: MAIL_API_TOKEN + description: The token used to protect mail notification API endpoint + displayName: Mail API token + generate: expression + from: "[a-zA-Z0-9]{32}" + required: true diff --git a/frontend/openshift/app.test.param b/frontend/openshift/app.test.param new file mode 100644 index 0000000..e69de29 diff --git a/frontend/openshift/patroni-ephemeral.dc.yaml b/frontend/openshift/patroni-ephemeral.dc.yaml new file mode 100644 index 0000000..960c8ef --- /dev/null +++ b/frontend/openshift/patroni-ephemeral.dc.yaml @@ -0,0 +1,365 @@ +--- +apiVersion: template.openshift.io/v1 +kind: Template +metadata: + annotations: + description: Patroni Postgresql database cluster, with ephemeral storage. + iconClass: icon-postgresql + openshift.io/display-name: Patroni Postgresql (Ephemeral) + openshift.io/long-description: + This template deploys a patroni postgresql HA cluster + with ephemeral storage. + tags: postgresql + name: patroni-pgsql-ephemeral +labels: + app: "${APP_NAME}-${INSTANCE}" + app.kubernetes.io/instance: "${INSTANCE}" + app.kubernetes.io/component: database + app.kubernetes.io/name: patroni + app.kubernetes.io/managed-by: template + app.kubernetes.io/part-of: "${APP_NAME}-${INSTANCE}" + app.kubernetes.io/version: "12" + app.openshift.io/runtime: postgresql + cluster-name: "${INSTANCE}" +objects: + - apiVersion: networking.k8s.io/v1 + kind: NetworkPolicy + metadata: + name: "allow-patroni-${INSTANCE}-to-patroni-${INSTANCE}-cluster" + spec: + # Allow Patroni pods to talk to its cluster + ingress: + - from: + - podSelector: + matchLabels: + cluster-name: "${INSTANCE}" + statefulset: "patroni-${INSTANCE}" + ports: + - port: 5432 + protocol: TCP + - port: 8008 + protocol: TCP + podSelector: + matchLabels: + cluster-name: "${INSTANCE}" + statefulset: "patroni-${INSTANCE}" + - apiVersion: v1 + kind: Service + metadata: + name: "${NAME}-${INSTANCE}" + spec: + ports: + - port: 5432 + protocol: TCP + targetPort: 5432 + selector: + cluster-name: "${INSTANCE}" + role: master + app.kubernetes.io/name: patroni + sessionAffinity: None + type: ClusterIP + - apiVersion: v1 + kind: Service + metadata: + name: "${NAME}-${INSTANCE}-readonly" + spec: + ports: + - port: 5432 + protocol: TCP + targetPort: 5432 + selector: + cluster-name: "${INSTANCE}" + role: replica + app.kubernetes.io/name: patroni + sessionAffinity: None + type: ClusterIP + - apiVersion: apps/v1 + kind: StatefulSet + metadata: + name: "${NAME}-${INSTANCE}" + spec: + podManagementPolicy: OrderedReady + replicas: ${{REPLICAS}} + revisionHistoryLimit: 10 + selector: + matchLabels: + statefulset: "${NAME}-${INSTANCE}" + serviceName: "${NAME}-${INSTANCE}" + template: + metadata: + labels: + cluster-name: "${INSTANCE}" + statefulset: "${NAME}-${INSTANCE}" + app.kubernetes.io/name: patroni + spec: + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: statefulset + operator: In + values: + - ${NAME}-${INSTANCE} + topologyKey: "kubernetes.io/hostname" + containers: + - name: postgresql + image: "${IMAGE_REGISTRY}/${IMAGE_STREAM_NAMESPACE}/${IMAGE_STREAM_TAG}" + imagePullPolicy: Always + env: + - name: APP_DATABASE + valueFrom: + secretKeyRef: + key: app-db-name + name: "${NAME}-${INSTANCE}-secret" + - name: APP_USER + valueFrom: + secretKeyRef: + key: app-db-username + name: "${NAME}-${INSTANCE}-secret" + - name: APP_PASSWORD + valueFrom: + secretKeyRef: + key: app-db-password + name: "${NAME}-${INSTANCE}-secret" + - name: POD_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: PATRONI_KUBERNETES_LABELS + value: '{"cluster-name": "${INSTANCE}", "app.kubernetes.io/name": "patroni"}' + - name: PATRONI_KUBERNETES_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: PATRONI_SUPERUSER_USERNAME + valueFrom: + secretKeyRef: + key: superuser-username + name: "${NAME}-${INSTANCE}-secret" + - name: PATRONI_SUPERUSER_PASSWORD + valueFrom: + secretKeyRef: + key: superuser-password + name: "${NAME}-${INSTANCE}-secret" + - name: PATRONI_REPLICATION_USERNAME + valueFrom: + secretKeyRef: + key: replication-username + name: "${NAME}-${INSTANCE}-secret" + - name: PATRONI_REPLICATION_PASSWORD + valueFrom: + secretKeyRef: + key: replication-password + name: "${NAME}-${INSTANCE}-secret" + - name: PATRONI_LOG_LEVEL + value: WARNING + - name: PATRONI_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: PATRONI_POSTGRESQL_DATA_DIR + value: "/home/postgres/pgdata/pgroot/data" + - name: PATRONI_POSTGRESQL_PGPASS + value: "/tmp/pgpass" + - name: PATRONI_POSTGRESQL_LISTEN + value: 0.0.0.0:5432 + - name: PATRONI_RESTAPI_LISTEN + value: 0.0.0.0:8008 + - name: PATRONI_SCOPE + value: "${INSTANCE}" + - name: POSTGRESQL_MAX_CONNECTIONS + value: "500" + - name: POSTGRESQL_MAX_PREPARED_TRANSACTIONS + value: "500" + lifecycle: + preStop: + exec: + command: + - /usr/bin/env + - bash + - -c + - | + # switch leader pod if the current pod is the leader + if curl --fail http://localhost:8008/read-write; then + patronictl switchover --force + fi + livenessProbe: + exec: + command: + - /usr/bin/env + - bash + - -c + - | + set -Eeuo pipefail && curl -s localhost:8008/liveness | jq -e ". | select(.state == \"running\")" + initialDelaySeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + ports: + - containerPort: 8008 + protocol: TCP + - containerPort: 5432 + protocol: TCP + readinessProbe: + exec: + command: + - /usr/bin/env + - bash + - -c + - | + set -Eeuo pipefail && df "${PATRONI_POSTGRESQL_DATA_DIR:-/home/postgres/pgdata}" --output=pcent | tail -n 1 | awk '{if ($1+0 > 90) exit 1; else exit 0;}' && pg_isready -q && curl -s localhost:8008/readiness | jq -e ". | select(.state == \"running\")" + initialDelaySeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + resources: + requests: + cpu: ${CPU_REQUEST} + memory: ${MEMORY_REQUEST} + limits: + cpu: ${CPU_LIMIT} + memory: ${MEMORY_LIMIT} + terminationMessagePath: "/dev/termination-log" + terminationMessagePolicy: File + volumeMounts: + - mountPath: "/home/postgres/pgdata" + name: postgresql + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: + allowPrivilegeEscalation: true + serviceAccountName: "${NAME}-${INSTANCE}" + volumes: + - name: postgresql + emptyDir: {} + updateStrategy: + type: RollingUpdate + - apiVersion: v1 + kind: ServiceAccount + metadata: + name: "${NAME}-${INSTANCE}" + - apiVersion: rbac.authorization.k8s.io/v1 + kind: Role + metadata: + name: "${NAME}-${INSTANCE}" + rules: + - apiGroups: + - "" + resources: + - services + verbs: + - create + - get + - list + - patch + - update + - watch + - delete + - apiGroups: + - "" + resources: + - configmaps + verbs: + - create + - get + - list + - patch + - update + - watch + - delete + - apiGroups: + - "" + resources: + - endpoints + verbs: + - get + - patch + - update + - create + - list + - watch + - delete + - apiGroups: + - "" + resources: + - pods + verbs: + - get + - list + - patch + - update + - watch + - apiVersion: rbac.authorization.k8s.io/v1 + kind: RoleBinding + metadata: + name: "${NAME}-${INSTANCE}" + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: "${NAME}-${INSTANCE}" + subjects: + - kind: ServiceAccount + name: "${NAME}-${INSTANCE}" +parameters: + - name: APP_NAME + description: The name of the application which will use this database. + displayName: Application client name + required: true + - name: NAME + description: The name of the application for labelling all artifacts. + displayName: Application Name + required: true + value: patroni + - name: INSTANCE + description: The name of this instance of the application + displayName: Application Instance Name + required: true + - name: NAMESPACE + description: Target namespace reference (i.e. 'k8vopl-dev') + displayName: Target Namespace + required: true + - name: REPLICAS + description: The number of StatefulSet replicas to use. + displayName: Replicas + required: true + value: "2" + - name: IMAGE_REGISTRY + description: The base OpenShift docker registry + displayName: Docker Image Registry + required: true + value: artifacts.developer.gov.bc.ca + - name: IMAGE_STREAM_NAMESPACE + description: + The OpenShift Namespace where the patroni and postgresql ImageStream + resides. + displayName: ImageStream Namespace + required: true + value: bcgov-docker-local + - name: IMAGE_STREAM_TAG + description: Patroni ImageTag + displayName: ImageStream Tag + required: true + value: patroni-postgres:2.0.1-12.4-latest + - name: CPU_REQUEST + description: Starting amount of CPU the container can use. + displayName: CPU Request + required: true + value: "50m" + - name: CPU_LIMIT + description: Maximum amount of CPU the container can use. + displayName: CPU Limit + required: true + value: "500m" + - name: MEMORY_REQUEST + description: Starting amount of memory the container can use. + displayName: Memory Request + required: true + value: 256Mi + - name: MEMORY_LIMIT + description: Maximum amount of memory the container can use. + displayName: Memory Limit + required: true + value: 512Mi diff --git a/frontend/openshift/patroni.dc.yaml b/frontend/openshift/patroni.dc.yaml new file mode 100644 index 0000000..c937e94 --- /dev/null +++ b/frontend/openshift/patroni.dc.yaml @@ -0,0 +1,386 @@ +--- +apiVersion: template.openshift.io/v1 +kind: Template +metadata: + annotations: + description: Patroni Postgresql database cluster, with persistent storage. + iconClass: icon-postgresql + openshift.io/display-name: Patroni Postgresql (Persistent) + openshift.io/long-description: + This template deploys a patroni postgresql HA cluster + with persistent storage. + tags: postgresql + name: patroni-pgsql-persistent +labels: + app: "${NAME}-${INSTANCE}" + app.kubernetes.io/instance: "${INSTANCE}" + app.kubernetes.io/component: database + app.kubernetes.io/name: patroni + app.kubernetes.io/managed-by: template + app.kubernetes.io/part-of: "${NAME}-${INSTANCE}" + app.kubernetes.io/version: "12" + app.openshift.io/runtime: postgresql + cluster-name: "${INSTANCE}" +objects: + - apiVersion: networking.k8s.io/v1 + kind: NetworkPolicy + metadata: + name: "allow-patroni-${INSTANCE}-to-patroni-${INSTANCE}-cluster" + spec: + # Allow Patroni pods to talk to its cluster + ingress: + - from: + - podSelector: + matchLabels: + cluster-name: "${INSTANCE}" + statefulset: "patroni-${INSTANCE}" + ports: + - port: 5432 + protocol: TCP + - port: 8008 + protocol: TCP + podSelector: + matchLabels: + cluster-name: "${INSTANCE}" + statefulset: "patroni-${INSTANCE}" + - apiVersion: v1 + kind: Service + metadata: + name: "${NAME}-${INSTANCE}" + spec: + ports: + - port: 5432 + protocol: TCP + targetPort: 5432 + selector: + cluster-name: "${INSTANCE}" + role: master + app.kubernetes.io/name: patroni + sessionAffinity: None + type: ClusterIP + - apiVersion: v1 + kind: Service + metadata: + name: "${NAME}-${INSTANCE}-readonly" + spec: + ports: + - port: 5432 + protocol: TCP + targetPort: 5432 + selector: + cluster-name: "${INSTANCE}" + role: replica + app.kubernetes.io/name: patroni + sessionAffinity: None + type: ClusterIP + - apiVersion: apps/v1 + kind: StatefulSet + metadata: + name: "${NAME}-${INSTANCE}" + spec: + podManagementPolicy: OrderedReady + replicas: ${{REPLICAS}} + revisionHistoryLimit: 10 + selector: + matchLabels: + statefulset: "${NAME}-${INSTANCE}" + serviceName: "${NAME}-${INSTANCE}" + template: + metadata: + labels: + cluster-name: "${INSTANCE}" + statefulset: "${NAME}-${INSTANCE}" + app.kubernetes.io/name: patroni + spec: + affinity: + podAntiAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + - labelSelector: + matchExpressions: + - key: statefulset + operator: In + values: + - ${NAME}-${INSTANCE} + topologyKey: "kubernetes.io/hostname" + containers: + - name: postgresql + image: "${IMAGE_REGISTRY}/${IMAGE_STREAM_NAMESPACE}/${IMAGE_STREAM_TAG}" + imagePullPolicy: Always + env: + - name: APP_DATABASE + valueFrom: + secretKeyRef: + key: app-db-name + name: "${NAME}-${INSTANCE}-secret" + - name: APP_USER + valueFrom: + secretKeyRef: + key: app-db-username + name: "${NAME}-${INSTANCE}-secret" + - name: APP_PASSWORD + valueFrom: + secretKeyRef: + key: app-db-password + name: "${NAME}-${INSTANCE}-secret" + - name: POD_IP + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: status.podIP + - name: PATRONI_KUBERNETES_LABELS + value: '{"cluster-name": "${INSTANCE}", "app.kubernetes.io/name": "patroni"}' + - name: PATRONI_KUBERNETES_NAMESPACE + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + - name: PATRONI_SUPERUSER_USERNAME + valueFrom: + secretKeyRef: + key: superuser-username + name: "${NAME}-${INSTANCE}-secret" + - name: PATRONI_SUPERUSER_PASSWORD + valueFrom: + secretKeyRef: + key: superuser-password + name: "${NAME}-${INSTANCE}-secret" + - name: PATRONI_REPLICATION_USERNAME + valueFrom: + secretKeyRef: + key: replication-username + name: "${NAME}-${INSTANCE}-secret" + - name: PATRONI_REPLICATION_PASSWORD + valueFrom: + secretKeyRef: + key: replication-password + name: "${NAME}-${INSTANCE}-secret" + - name: PATRONI_LOG_LEVEL + value: WARNING + - name: PATRONI_NAME + valueFrom: + fieldRef: + apiVersion: v1 + fieldPath: metadata.name + - name: PATRONI_POSTGRESQL_DATA_DIR + value: "/home/postgres/pgdata/pgroot/data" + - name: PATRONI_POSTGRESQL_PGPASS + value: "/tmp/pgpass" + - name: PATRONI_POSTGRESQL_LISTEN + value: 0.0.0.0:5432 + - name: PATRONI_RESTAPI_LISTEN + value: 0.0.0.0:8008 + - name: PATRONI_SCOPE + value: "${INSTANCE}" + - name: POSTGRESQL_MAX_CONNECTIONS + value: "500" + - name: POSTGRESQL_MAX_PREPARED_TRANSACTIONS + value: "500" + lifecycle: + preStop: + exec: + command: + - /usr/bin/env + - bash + - -c + - | + # switch leader pod if the current pod is the leader + if curl --fail http://localhost:8008/read-write; then + patronictl switchover --force + fi + livenessProbe: + exec: + command: + - /usr/bin/env + - bash + - -c + - | + set -Eeuo pipefail && curl -s localhost:8008/liveness | jq -e ". | select(.state == \"running\")" + initialDelaySeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + ports: + - containerPort: 8008 + protocol: TCP + - containerPort: 5432 + protocol: TCP + readinessProbe: + exec: + command: + - /usr/bin/env + - bash + - -c + - | + set -Eeuo pipefail && df "${PATRONI_POSTGRESQL_DATA_DIR:-/home/postgres/pgdata}" --output=pcent | tail -n 1 | awk '{if ($1+0 > 90) exit 1; else exit 0;}' && pg_isready -q && curl -s localhost:8008/readiness | jq -e ". | select(.state == \"running\")" + initialDelaySeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + resources: + requests: + cpu: ${CPU_REQUEST} + memory: ${MEMORY_REQUEST} + limits: + cpu: ${CPU_LIMIT} + memory: ${MEMORY_LIMIT} + terminationMessagePath: "/dev/termination-log" + terminationMessagePolicy: File + volumeMounts: + - mountPath: "/home/postgres/pgdata" + name: postgresql + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: + allowPrivilegeEscalation: true + serviceAccountName: "${NAME}-${INSTANCE}" + volumes: + - name: postgresql + persistentVolumeClaim: + claimName: postgresql + updateStrategy: + type: RollingUpdate + volumeClaimTemplates: + - metadata: + annotations: + volume.beta.kubernetes.io/storage-class: "${STORAGE_CLASS}" + labels: + app: "${NAME}-${INSTANCE}" + name: postgresql + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: "${PVC_SIZE}" + storageClassName: "${STORAGE_CLASS}" + - apiVersion: v1 + kind: ServiceAccount + metadata: + name: "${NAME}-${INSTANCE}" + - apiVersion: rbac.authorization.k8s.io/v1 + kind: Role + metadata: + name: "${NAME}-${INSTANCE}" + rules: + - apiGroups: + - "" + resources: + - services + verbs: + - create + - get + - list + - patch + - update + - watch + - delete + - apiGroups: + - "" + resources: + - configmaps + verbs: + - create + - get + - list + - patch + - update + - watch + - delete + - apiGroups: + - "" + resources: + - endpoints + verbs: + - get + - patch + - update + - create + - list + - watch + - delete + - apiGroups: + - "" + resources: + - pods + verbs: + - get + - list + - patch + - update + - watch + - apiVersion: rbac.authorization.k8s.io/v1 + kind: RoleBinding + metadata: + name: "${NAME}-${INSTANCE}" + roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: "${NAME}-${INSTANCE}" + subjects: + - kind: ServiceAccount + name: "${NAME}-${INSTANCE}" +parameters: + - name: NAME + description: The name of the application for labelling all artifacts. + displayName: Application Name + required: true + value: patroni + - name: INSTANCE + description: The name of this instance of the application + displayName: Application Instance Name + required: true + - name: NAMESPACE + description: Target namespace reference (i.e. 'k8vopl-dev') + displayName: Target Namespace + required: true + - name: REPLICAS + description: The number of StatefulSet replicas to use. + displayName: Replicas + required: true + value: "3" + - name: IMAGE_REGISTRY + description: The base OpenShift docker registry + displayName: Docker Image Registry + required: true + value: artifacts.developer.gov.bc.ca + - name: IMAGE_STREAM_NAMESPACE + description: + The OpenShift Namespace where the patroni and postgresql ImageStream + resides. + displayName: ImageStream Namespace + required: true + value: bcgov-docker-local + - name: IMAGE_STREAM_TAG + description: Patroni ImageTag + displayName: ImageStream Tag + required: true + value: patroni-postgres:2.0.1-12.4-latest + - name: CPU_REQUEST + description: Starting amount of CPU the container can use. + displayName: CPU Request + required: true + value: "50m" + - name: CPU_LIMIT + description: Maximum amount of CPU the container can use. + displayName: CPU Limit + required: true + value: "1" + - name: MEMORY_REQUEST + description: Starting amount of memory the container can use. + displayName: Memory Request + required: true + value: 256Mi + - name: MEMORY_LIMIT + description: Maximum amount of memory the container can use. + displayName: Memory Limit + required: true + value: 512Mi + - name: PVC_SIZE + description: The size of the persistent volume to create. + displayName: Persistent Volume Size + required: true + value: 2Gi + - name: STORAGE_CLASS + description: The type of the persistent volume to create. + displayName: Persistent Volume Class + required: true + value: netapp-block-standard diff --git a/frontend/openshift/patroni.dev.param b/frontend/openshift/patroni.dev.param new file mode 100644 index 0000000..e69de29 diff --git a/frontend/openshift/patroni.prod.param b/frontend/openshift/patroni.prod.param new file mode 100644 index 0000000..682ec04 --- /dev/null +++ b/frontend/openshift/patroni.prod.param @@ -0,0 +1,3 @@ +CPU_LIMIT=2 +MEMORY_LIMIT=2048Mi +MEMORY_REQUEST=1536Mi diff --git a/frontend/openshift/patroni.secret.yaml b/frontend/openshift/patroni.secret.yaml new file mode 100644 index 0000000..34c26f4 --- /dev/null +++ b/frontend/openshift/patroni.secret.yaml @@ -0,0 +1,79 @@ +--- +apiVersion: template.openshift.io/v1 +kind: Template +metadata: + annotations: + description: Patroni Postgresql database cluster secret generator + iconClass: icon-postgresql + openshift.io/display-name: Patroni Postgresql + openshift.io/long-description: This template creates a patroni postgresql secret. + tags: postgresql + name: patroni-pgsql-secret +labels: + app.kubernetes.io/instance: "${INSTANCE}" + app.kubernetes.io/component: database + app.kubernetes.io/name: patroni + app.kubernetes.io/managed-by: template + app.kubernetes.io/version: "12" + cluster-name: "${INSTANCE}" +objects: + - apiVersion: v1 + kind: Secret + metadata: + name: "${NAME}-${INSTANCE}-secret" + stringData: + replication-username: "${PATRONI_REPLICATION_USERNAME}" + replication-password: "${PATRONI_REPLICATION_PASSWORD}" + superuser-username: "${PATRONI_SUPERUSER_USERNAME}" + superuser-password: "${PATRONI_SUPERUSER_PASSWORD}" + app-db-name: "${APP_DB_NAME}" + app-db-username: "${APP_DB_USERNAME}" + app-db-password: "${APP_DB_PASSWORD}" +parameters: + - name: NAME + description: The name of the application for labelling all artifacts. + displayName: Application Name + required: true + value: patroni + - name: INSTANCE + description: The name of this instance of the application + displayName: Application Instance Name + required: true + - name: APP_DB_NAME + description: Name of the application database + displayName: Application Database Name + required: true + value: app + - name: APP_DB_USERNAME + description: Username of the application database + displayName: Application Database Username + required: true + value: app + - name: APP_DB_PASSWORD + description: Password of the application database + displayName: Application Database Password + generate: expression + from: "[a-zA-Z0-9]{32}" + required: true + - name: PATRONI_SUPERUSER_USERNAME + description: Username of the superuser account for initialization. + displayName: Superuser Username + required: true + value: postgres + - name: PATRONI_SUPERUSER_PASSWORD + description: Password of the superuser account for initialization. + displayName: Superuser Passsword + generate: expression + from: "[a-zA-Z0-9]{32}" + required: true + - name: PATRONI_REPLICATION_USERNAME + description: Username of the replication account for initialization. + displayName: Replication Username + required: true + value: replication + - name: PATRONI_REPLICATION_PASSWORD + description: Password of the replication account for initialization. + displayName: Repication Passsword + generate: expression + from: "[a-zA-Z0-9]{32}" + required: true diff --git a/frontend/openshift/patroni.test.param b/frontend/openshift/patroni.test.param new file mode 100644 index 0000000..e69de29 diff --git a/frontend/openshift/redash/README.md b/frontend/openshift/redash/README.md new file mode 100644 index 0000000..d723f51 --- /dev/null +++ b/frontend/openshift/redash/README.md @@ -0,0 +1,157 @@ +# Redash Data Visualization + +CHEFS uses [Redash](https://redash.io) to visualize forms metadata and display it in dashboards. + +## Install Pre-requisites + +The Redash Helm Chart doesn't work well in OpenShift due to the accounts it is trying to use for PostgreSQL and Redis. Install our own versions of them: + +```sh +oc process -f secrets.yaml | oc -n a12c97-tools apply -f - +oc process -f postgresql.deploy.yaml | oc -n a12c97-tools apply -f - +oc process -f redis.deploy.yaml | oc -n a12c97-tools apply -f - +oc process -f redash.route.yaml | oc -n a12c97-tools apply -f - +``` + +Set up the PostgreSQL backup as a CronJob using the [backup-container](https://github.com/BCDevOps/backup-container): + +```sh +oc process -f backup-cronjob.yaml \ + -p DATABASE_DEPLOYMENT_NAME=chefs-redash-postgresql \ + -p DATABASE_NAME=redash \ + -p DATABASE_PASSWORD_KEY_NAME=POSTGRES_PASSWORD \ + -p DATABASE_SERVICE_NAME=chefs-redash-postgresql \ + -p DATABASE_USER_KEY_NAME=POSTGRES_USER \ + -p JOB_NAME=backup-chefs-redash-postgres \ + -p JOB_PERSISTENT_STORAGE_NAME=backup-chefs-redash-postgresql \ + -p MONTHLY_BACKUPS=3 \ + -p SCHEDULE="0 8 * * *" \ + -p TAG_NAME=2.6.1 \ + -p WEEKLY_BACKUPS=8 \ + | oc -n a12c97-tools apply -f - +``` + +Verify the backup using another cron job. The file `backup-cronjob-verify.yaml` has been lightly modified from `backup-cronjob.yaml` in the `backup-container` repo. + +```sh +oc process -f backup-cronjob-verify.yaml \ + -p BACKUP_JOB_CONFIG=backup-chefs-redash-postgres-config \ + -p DATABASE_DEPLOYMENT_NAME=chefs-redash-postgresql \ + -p DATABASE_PASSWORD_KEY_NAME=POSTGRES_PASSWORD \ + -p DATABASE_USER_KEY_NAME=POSTGRES_USER \ + -p JOB_NAME=backup-chefs-redash-postgres-verify \ + -p JOB_PERSISTENT_STORAGE_NAME=backup-chefs-redash-postgresql \ + -p SCHEDULE="0 9 * * *" \ + -p TAG_NAME=2.6.1 \ + | oc -n a12c97-tools apply -f - +``` + +## Install Redash + +The [Redash Helm Chart](https://github.com/getredash/contrib-helm-chart) is an easy way to install Redash. + +Add the chart repository to Helm: + +```sh +helm repo add redash https://getredash.github.io/contrib-helm-chart/ +``` + +Set up the configuration file: + +```sh +cat > my-values.yaml <<- EOM +redash: + cookieSecret: $(openssl rand -base64 32) + externalRedisSecret: chefs-redash-redis + secretKey: $(openssl rand -base64 32) +postgresql: + enabled: false +externalPostgreSQL: postgresql://:@chefs-redash-postgresql:5432/redash +redis: + enabled: false +externalRedis: redis://chefs-redash-redis:6379/redash +EOM +``` + +For the `externalPostgreSQL` database connection setting replace the `` and `` placeholders using values from the `redash-postgresql` secret. + +> Note: The error `[CRITICAL] WORKER TIMEOUT` happens in the `chefs-redash` pod because it can't spin up fast enough. It will get restarted by the probes and never starts. Before you run the following command, load up the Deployments in the OpenShift console and be prepared to reduce `chefs-redash` to 0 pods. + +Install Redash: + +```sh +helm -n a12c97-tools upgrade --install -f my-values.yaml chefs redash/redash +``` + +Edit the `chefs-redash` Deployment and change the `initialDelaySeconds` for both the `liveness` and `readiness` probes to `60` seconds. Then spin it up to a single pod. It's a good idea to tune the CPU and memory requests and limits to values that correspond to what the pods tend to run at (they will vary). + +If you ever need to uninstall Redash: + +```sh +helm -n a12c97-tools delete chefs +``` + +## Data Sources + +Network policies are created to allow Redash to access the readonly database replicas: + +```sh +oc process -f patroni.networkpolicy.yaml | oc -n a12c97-dev apply -f - +oc process -f patroni.networkpolicy.yaml | oc -n a12c97-test apply -f - +oc process -f patroni.networkpolicy.yaml | oc -n a12c97-prod apply -f - +``` + +## Redash Configuration + +Redash should be up and running. Log in and create the Users, Data Sources, Queries, Visualizations, and Dashboards that you need. + +### SAML Authentication with Red Hat SSO (Keycloak) + +To integrate Redash with SSO, go into `Settings` and in the `General` tab's `SAML` section: + +1. For `SAML Enabled` choose `Enabled (Dynamic)` +1. Set `SAML Metadata URL` to `https://loginproxy.gov.bc.ca/auth/realms/chefs/protocol/saml/descriptor` +1. Set `SAML Entity ID` to `unused` (or any value) as there is a bug in v10 of Redash and the `SAML Entity ID` value is overwritten by the Redash callback URL. This will be handled when setting up the client in SSO. +1. Set `SAML NameID Format` to `urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress` + +### Redash Client in SSO + +In SSO create a new `Client` and: + +1. Set `Client ID` to `https://chefs-redash.apps.silver.devops.gov.bc.ca/saml/callback?org_slug=default` to deal with the v10 bug +1. Set `Client Protocol` to `saml` +1. Set `Client SAML Endpoint` also to `https://chefs-redash.apps.silver.devops.gov.bc.ca/saml/callback?org_slug=default` +1. Click `Save` + +After creating the client, do the following configuration: + +1. Set `Sign Assertions` to `On` +1. Set `Canonicalization Method` to `EXCLUSIVE_WITH_COMMENTS` +1. Set `Client Signature Required` to `Off` +1. Set `Name ID Format` to `email` +1. Set `Valid Redirect URIs` to `https://chefs-redash.apps.silver.devops.gov.bc.ca/*` +1. Click `Save` + +In the `Mappers` click `Add Builtin` and add `X500 givenName` and `X500 surname`. + +Edit `x500 givenName` and + +1. Set `Friendly Name` to `FirstName` +1. Set `SAML Attribute Name` to `FirstName` + +Edit `x500 surname` and + +1. Set `Friendly Name` to `LastName` +1. Set `SAML Attribute Name` to `LastName` + +## Custom Image + +The Redash v10.0.0b50363 image used by the Helm chart contains security vulnerabilities, particularly in the `pysaml2` package. Create a buildconfig with a Dockerfile: + +``` +FROM docker.io/redash/redash:10.1.0.b50633 +USER root +RUN pip install --upgrade pysaml2==6.5.0 +``` + +Use the new image for the five Redash deployments by replacing `redash/redash:10.0.0.b50363` with `image-registry.openshift-image-registry.svc:5000/a12c97-tools/redash:10.1.0-patched`. diff --git a/frontend/openshift/redash/backup-cronjob-verify.yaml b/frontend/openshift/redash/backup-cronjob-verify.yaml new file mode 100644 index 0000000..326f858 --- /dev/null +++ b/frontend/openshift/redash/backup-cronjob-verify.yaml @@ -0,0 +1,240 @@ +--- +kind: "Template" +apiVersion: "template.openshift.io/v1" +metadata: + name: "{$JOB_NAME}-cronjob-template" + annotations: + description: "Scheduled Task to perform a Database Backup" + tags: "cronjob,backup" +parameters: + - name: "BACKUP_JOB_CONFIG" + displayName: "Backup Job Config File Name" + description: "Name of the backup job's config file." + value: "backup-postgres-config" + required: true + - name: "JOB_NAME" + displayName: "Job Name" + description: "Name of the Scheduled Job to Create." + value: "backup-postgres-verify" + required: true + - name: "JOB_PERSISTENT_STORAGE_NAME" + displayName: "Backup Persistent Storage Name" + description: "Pre-Created PVC to use for backup target" + value: "bk-devex-von-tools-a9vlgd1jpsg1" + required: true + - name: "SCHEDULE" + displayName: "Cron Schedule" + description: "Cron Schedule to Execute the Job (using local cluster system TZ)" + # Currently targeting 1:00 AM Daily + value: "0 1 * * *" + required: true + - name: "SOURCE_IMAGE_NAME" + displayName: "Source Image Name" + description: "The name of the image to use for this resource." + required: true + value: "backup-container" + - name: "IMAGE_REGISTRY" + description: "The base OpenShift docker registry" + displayName: "Docker Image Registry" + required: true + # Set value to "docker-registry.default.svc:5000" if using OCP3 + value: "docker.io" + - name: "IMAGE_NAMESPACE" + displayName: "Image Namespace" + description: "The namespace of the OpenShift project containing the imagestream for the application." + required: true + value: "bcgovimages" + - name: "TAG_NAME" + displayName: "Environment TAG name" + description: "The TAG name for this environment, e.g., dev, test, prod" + required: true + value: "dev" + - name: "DATABASE_SERVICE_NAME" + displayName: "Database Service Name" + description: "The name of the database service." + required: true + value: "postgresql" + - name: "DATABASE_DEFAULT_PORT" + displayName: "Database Service Port" + description: "The configured port for the database service" + required: true + value: "5432" + - name: "DATABASE_NAME" + displayName: "Database Name" + description: "The name of the database." + required: true + value: "MyDatabase" + - name: "DATABASE_DEPLOYMENT_NAME" + displayName: "Database Deployment Name" + description: "The name associated to the database deployment resources. In particular, this is used to wire up the credentials associated to the database." + required: true + value: "postgresql" + - name: DATABASE_USER_KEY_NAME + displayName: Database User Key Name + description: + The database user key name stored in database deployment resources specified + by DATABASE_DEPLOYMENT_NAME. + required: true + value: database-user + - name: DATABASE_PASSWORD_KEY_NAME + displayName: Database Password Key Name + description: + The database password key name stored in database deployment resources + specified by DATABASE_DEPLOYMENT_NAME. + required: true + value: database-password + - name: "BACKUP_STRATEGY" + displayName: "Backup Strategy" + description: "The strategy to use for backups; for example daily, or rolling." + required: true + value: "rolling" + - name: "BACKUP_DIR" + displayName: "The root backup directory" + description: "The name of the root backup directory" + required: true + value: "/backups/" + - name: "NUM_BACKUPS" + displayName: "The number of backup files to be retained" + description: "The number of backup files to be retained. Used for the `daily` backup strategy. Ignored when using the `rolling` backup strategy." + required: false + value: "5" + - name: "DAILY_BACKUPS" + displayName: "Number of Daily Backups to Retain" + description: "The number of daily backup files to be retained. Used for the `rolling` backup strategy." + required: false + value: "7" + - name: "WEEKLY_BACKUPS" + displayName: "Number of Weekly Backups to Retain" + description: "The number of weekly backup files to be retained. Used for the `rolling` backup strategy." + required: false + value: "4" + - name: "MONTHLY_BACKUPS" + displayName: "Number of Monthly Backups to Retain" + description: "The number of monthly backup files to be retained. Used for the `rolling` backup strategy." + required: false + value: "1" + - name: "JOB_SERVICE_ACCOUNT" + displayName: "Service Account Name" + description: "Name of the Service Account To Exeucte the Job As." + value: "default" + required: true + - name: "SUCCESS_JOBS_HISTORY_LIMIT" + displayName: "Successful Job History Limit" + description: "The number of successful jobs that will be retained" + value: "5" + required: true + - name: "FAILED_JOBS_HISTORY_LIMIT" + displayName: "Failed Job History Limit" + description: "The number of failed jobs that will be retained" + value: "2" + required: true + - name: "JOB_BACKOFF_LIMIT" + displayName: "Job Backoff Limit" + description: "The number of attempts to try for a successful job outcome" + value: "0" + required: false +objects: + - kind: "CronJob" + apiVersion: "batch/v1" + metadata: + name: "${JOB_NAME}" + labels: + template: "${JOB_NAME}-cronjob" + cronjob: "${JOB_NAME}" + spec: + schedule: "${SCHEDULE}" + concurrencyPolicy: "Forbid" + successfulJobsHistoryLimit: "${{SUCCESS_JOBS_HISTORY_LIMIT}}" + failedJobsHistoryLimit: "${{FAILED_JOBS_HISTORY_LIMIT}}" + jobTemplate: + metadata: + labels: + template: "${JOB_NAME}-job" + cronjob: "${JOB_NAME}" + spec: + backoffLimit: ${{JOB_BACKOFF_LIMIT}} + template: + metadata: + labels: + template: "${JOB_NAME}-job" + cronjob: "${JOB_NAME}" + spec: + containers: + - name: "${JOB_NAME}-cronjob" + image: "${IMAGE_REGISTRY}/${IMAGE_NAMESPACE}/${SOURCE_IMAGE_NAME}:${TAG_NAME}" + # image: backup + command: + - "/bin/bash" + - "-c" + - "/backup.sh -v all" + volumeMounts: + - mountPath: "${BACKUP_DIR}" + name: "backup" + env: + - name: BACKUP_DIR + value: "${BACKUP_DIR}" + - name: BACKUP_STRATEGY + valueFrom: + configMapKeyRef: + name: "${BACKUP_JOB_CONFIG}" + key: BACKUP_STRATEGY + - name: NUM_BACKUPS + valueFrom: + configMapKeyRef: + name: "${BACKUP_JOB_CONFIG}" + key: RETENTION.NUM_BACKUPS + optional: true + - name: DAILY_BACKUPS + valueFrom: + configMapKeyRef: + name: "${BACKUP_JOB_CONFIG}" + key: RETENTION.DAILY_BACKUPS + optional: true + - name: WEEKLY_BACKUPS + valueFrom: + configMapKeyRef: + name: "${BACKUP_JOB_CONFIG}" + key: RETENTION.WEEKLY_BACKUPS + optional: true + - name: MONTHLY_BACKUPS + valueFrom: + configMapKeyRef: + name: "${BACKUP_JOB_CONFIG}" + key: RETENTION.MONTHLY_BACKUPS + optional: true + - name: DATABASE_SERVICE_NAME + valueFrom: + configMapKeyRef: + name: "${BACKUP_JOB_CONFIG}" + key: DATABASE_SERVICE_NAME + - name: DEFAULT_PORT + valueFrom: + configMapKeyRef: + name: "${BACKUP_JOB_CONFIG}" + key: DEFAULT_PORT + optional: true + - name: POSTGRESQL_DATABASE + valueFrom: + configMapKeyRef: + name: "${BACKUP_JOB_CONFIG}" + key: POSTGRESQL_DATABASE + - name: DATABASE_USER + valueFrom: + secretKeyRef: + name: "${DATABASE_DEPLOYMENT_NAME}" + key: "${DATABASE_USER_KEY_NAME}" + - name: DATABASE_PASSWORD + valueFrom: + secretKeyRef: + name: "${DATABASE_DEPLOYMENT_NAME}" + key: "${DATABASE_PASSWORD_KEY_NAME}" + volumes: + - name: backup + persistentVolumeClaim: + claimName: "${JOB_PERSISTENT_STORAGE_NAME}" + restartPolicy: "Never" + terminationGracePeriodSeconds: 30 + activeDeadlineSeconds: 1600 + dnsPolicy: "ClusterFirst" + serviceAccountName: "${JOB_SERVICE_ACCOUNT}" + serviceAccount: "${JOB_SERVICE_ACCOUNT}" diff --git a/frontend/openshift/redash/patroni.networkpolicy.yaml b/frontend/openshift/redash/patroni.networkpolicy.yaml new file mode 100644 index 0000000..08c9c59 --- /dev/null +++ b/frontend/openshift/redash/patroni.networkpolicy.yaml @@ -0,0 +1,42 @@ +--- +kind: Template +apiVersion: template.openshift.io/v1 +labels: + app.kubernetes.io/component: server + app.kubernetes.io/instance: ${NAME} + app.kubernetes.io/managed-by: kubectl + app.kubernetes.io/name: redash + app.kubernetes.io/part-of: redash +metadata: + name: ${NAME} +objects: + - kind: NetworkPolicy + apiVersion: networking.k8s.io/v1 + metadata: + name: allow-${NAME}-a12c97-tools-to-patroni-master-readonly + spec: + podSelector: + matchLabels: + cluster-name: master + role: replica + statefulset: patroni-master + ingress: + - ports: + - protocol: TCP + port: 5432 + from: + - podSelector: + matchLabels: + app.kubernetes.io/name: redash + namespaceSelector: + matchLabels: + environment: tools + name: a12c97 + policyTypes: + - Ingress +parameters: + - name: NAME + displayName: Name + description: The name assigned to all of the objects defined in this template. + required: true + value: chefs-redash diff --git a/frontend/openshift/redash/postgresql.deploy.yaml b/frontend/openshift/redash/postgresql.deploy.yaml new file mode 100644 index 0000000..9d0a676 --- /dev/null +++ b/frontend/openshift/redash/postgresql.deploy.yaml @@ -0,0 +1,191 @@ +--- +kind: Template +apiVersion: template.openshift.io/v1 +labels: + app.kubernetes.io/component: database + app.kubernetes.io/instance: ${NAME}-postgresql + app.kubernetes.io/managed-by: kubectl + app.kubernetes.io/name: postgresql + app.kubernetes.io/part-of: redash +metadata: + name: ${NAME} +objects: + - kind: DeploymentConfig + apiVersion: v1 + metadata: + name: ${NAME}-postgresql + spec: + replicas: 1 + revisionHistoryLimit: 10 + selector: + app.kubernetes.io/instance: ${NAME}-postgresql + strategy: + activeDeadlineSeconds: 21600 + recreateParams: + timeoutSeconds: 600 + type: Recreate + template: + metadata: + labels: + app.kubernetes.io/component: database + app.kubernetes.io/instance: ${NAME}-postgresql + app.kubernetes.io/managed-by: kubectl + app.kubernetes.io/name: postgresql + app.kubernetes.io/part-of: redash + spec: + containers: + - env: + - name: POSTGRESQL_DATABASE + valueFrom: + secretKeyRef: + key: POSTGRES_DATABASE + name: ${NAME}-postgresql + - name: POSTGRESQL_PASSWORD + valueFrom: + secretKeyRef: + key: POSTGRES_PASSWORD + name: ${NAME}-postgresql + - name: POSTGRESQL_USER + valueFrom: + secretKeyRef: + key: POSTGRES_USER + name: ${NAME}-postgresql + image: ${IMAGE_REGISTRY}/openshift/postgresql:9.6 + imagePullPolicy: Always + livenessProbe: + tcpSocket: + port: 5432 + initialDelaySeconds: 30 + timeoutSeconds: 1 + periodSeconds: 10 + successThreshold: 1 + failureThreshold: 3 + name: ${NAME}-postgresql + ports: + - containerPort: 5432 + protocol: TCP + readinessProbe: + exec: + command: + - /bin/bash + - "-c" + - pg_isready -h localhost -p 5432 + failureThreshold: 3 + initialDelaySeconds: 20 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 15 + resources: + limits: + memory: ${POSTGRESQL_MEMORY_LIMIT} + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + volumeMounts: + - name: ${NAME}-postgresql-volume + mountPath: /var/lib/pgsql/data + volumes: + - name: ${NAME}-postgresql-volume + persistentVolumeClaim: + claimName: ${NAME}-postgresql + restartPolicy: Always + terminationGracePeriodSeconds: 30 + dnsPolicy: ClusterFirst + securityContext: {} + schedulerName: default-scheduler + triggers: + - type: ConfigChange + - kind: NetworkPolicy + apiVersion: networking.k8s.io/v1 + metadata: + name: allow-${NAME}-to-postgresql + spec: + podSelector: + matchLabels: + app.kubernetes.io/instance: ${NAME}-postgresql + ingress: + - ports: + - protocol: TCP + port: 5432 + from: + - podSelector: + matchLabels: + app.kubernetes.io/instance: chefs + policyTypes: + - Ingress + - kind: NetworkPolicy + apiVersion: networking.k8s.io/v1 + metadata: + name: allow-backup-${NAME}-postgres-to-${NAME}-postgresql + spec: + podSelector: + matchLabels: + app.kubernetes.io/instance: ${NAME}-postgresql + ingress: + - ports: + - protocol: TCP + port: 5432 + from: + - podSelector: + matchLabels: + cronjob: backup-${NAME}-postgres + policyTypes: + - Ingress + - kind: PersistentVolumeClaim + apiVersion: v1 + metadata: + name: ${NAME}-postgresql + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: ${POSTGRESQL_VOLUME_CAPACITY} + storageClassName: netapp-file-standard + - kind: PersistentVolumeClaim + apiVersion: v1 + metadata: + name: backup-${NAME}-postgresql + spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: 1Gi + storageClassName: netapp-file-backup + - kind: Service + apiVersion: v1 + metadata: + name: ${NAME}-postgresql + spec: + ports: + - name: 5432-tcp + port: 5432 + protocol: TCP + targetPort: 5432 + selector: + app.kubernetes.io/instance: ${NAME}-postgresql + type: ClusterIP + sessionAffinity: None + status: + loadBalancer: {} +parameters: + - name: NAME + displayName: Name + description: The name assigned to all of the objects defined in this template. + required: true + value: chefs-redash + - name: POSTGRESQL_MEMORY_LIMIT + displayName: PostgreSQL Memory Limit + description: The memory limit for PostgreSQL + required: true + value: 512Mi + - name: POSTGRESQL_VOLUME_CAPACITY + displayName: PostgreSQL Volume Capacity + description: The volume capacity for PostgreSQL + required: true + value: 4Gi + - name: IMAGE_REGISTRY + description: The base docker registry + displayName: Docker Image Registry + required: true + value: image-registry.openshift-image-registry.svc:5000 diff --git a/frontend/openshift/redash/redash.route.yaml b/frontend/openshift/redash/redash.route.yaml new file mode 100644 index 0000000..8db0667 --- /dev/null +++ b/frontend/openshift/redash/redash.route.yaml @@ -0,0 +1,34 @@ +--- +kind: Template +apiVersion: template.openshift.io/v1 +labels: + app.kubernetes.io/component: server + app.kubernetes.io/instance: ${NAME} + app.kubernetes.io/managed-by: kubectl + app.kubernetes.io/name: redash + app.kubernetes.io/part-of: redash +metadata: + name: ${NAME} +objects: + - kind: Route + apiVersion: route.openshift.io/v1 + metadata: + name: ${NAME} + spec: + host: ${NAME}.apps.silver.devops.gov.bc.ca + port: + targetPort: http + tls: + insecureEdgeTerminationPolicy: Redirect + termination: edge + to: + kind: Service + name: ${NAME} + weight: 100 + wildcardPolicy: None +parameters: + - name: NAME + displayName: Name + description: The name assigned to all of the objects defined in this template. + required: true + value: chefs-redash diff --git a/frontend/openshift/redash/redis.deploy.yaml b/frontend/openshift/redash/redis.deploy.yaml new file mode 100644 index 0000000..4a1b36f --- /dev/null +++ b/frontend/openshift/redash/redis.deploy.yaml @@ -0,0 +1,138 @@ +--- +kind: Template +apiVersion: template.openshift.io/v1 +labels: + app.kubernetes.io/component: database + app.kubernetes.io/instance: ${NAME}-redis + app.kubernetes.io/managed-by: kubectl + app.kubernetes.io/name: redis + app.kubernetes.io/part-of: redash +metadata: + name: ${NAME} +objects: + - kind: DeploymentConfig + apiVersion: v1 + metadata: + name: ${NAME}-redis + spec: + replicas: 1 + revisionHistoryLimit: 10 + selector: + app.kubernetes.io/instance: ${NAME}-redis + strategy: + type: Recreate + template: + metadata: + labels: + app.kubernetes.io/component: database + app.kubernetes.io/instance: ${NAME}-redis + app.kubernetes.io/managed-by: kubectl + app.kubernetes.io/name: redis + app.kubernetes.io/part-of: redash + spec: + containers: + - env: + - name: REDIS_PASSWORD + valueFrom: + secretKeyRef: + key: REDIS_PASSWORD + name: ${NAME}-redis + image: redis:7.0.11-alpine + imagePullPolicy: Always + name: ${NAME}-redis + ports: + - containerPort: 6379 + protocol: TCP + readinessProbe: + failureThreshold: 3 + initialDelaySeconds: 5 + periodSeconds: 10 + successThreshold: 1 + tcpSocket: + port: 6379 + timeoutSeconds: 1 + resources: + limits: + memory: ${REDIS_MEMORY_LIMIT} + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + volumeMounts: + - name: ${NAME}-redis-volume + mountPath: /data + volumes: + - name: ${NAME}-redis-volume + persistentVolumeClaim: + claimName: ${NAME}-redis + restartPolicy: Always + terminationGracePeriodSeconds: 30 + dnsPolicy: ClusterFirst + securityContext: {} + schedulerName: default-scheduler + triggers: + - type: ConfigChange + - kind: PersistentVolumeClaim + apiVersion: v1 + metadata: + name: ${NAME}-redis + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: ${REDIS_VOLUME_CAPACITY} + storageClassName: netapp-file-standard + - kind: Service + apiVersion: v1 + metadata: + name: ${NAME}-redis + spec: + ports: + - name: 6379-tcp + port: 6379 + protocol: TCP + targetPort: 6379 + selector: + app.kubernetes.io/instance: ${NAME}-redis + type: ClusterIP + sessionAffinity: None + status: + loadBalancer: {} + - kind: NetworkPolicy + apiVersion: networking.k8s.io/v1 + metadata: + name: allow-${NAME}-to-redis + spec: + podSelector: + matchLabels: + app.kubernetes.io/instance: ${NAME}-redis + ingress: + - ports: + - protocol: TCP + port: 6379 + from: + - podSelector: + matchLabels: + app.kubernetes.io/instance: chefs + policyTypes: + - Ingress +parameters: + - name: NAME + displayName: Name + description: The name assigned to all of the objects defined in this template. + required: true + value: chefs-redash + - name: REDIS_MEMORY_LIMIT + displayName: Redis Memory Limit + description: The memory limit for Redis + required: true + value: 512Mi + - name: REDIS_VOLUME_CAPACITY + displayName: Redis Volume Capacity + description: The volume capacity for Redis + required: true + value: 2Gi + - name: IMAGE_REGISTRY + description: The base docker registry + displayName: Docker Image Registry + required: true + value: image-registry.openshift-image-registry.svc:5000 diff --git a/frontend/openshift/redash/secrets.yaml b/frontend/openshift/redash/secrets.yaml new file mode 100644 index 0000000..aeff185 --- /dev/null +++ b/frontend/openshift/redash/secrets.yaml @@ -0,0 +1,108 @@ +--- +kind: Template +apiVersion: template.openshift.io/v1 +labels: + app: "${NAME}" + app.kubernetes.io/component: "${NAME}" + app.kubernetes.io/instance: "${NAME}" + app.kubernetes.io/managed-by: template + app.kubernetes.io/name: redash + app.kubernetes.io/part-of: "${NAME}" + template: "${NAME}-secret-template" +metadata: + name: "${NAME}-secret" +objects: + - kind: Secret + apiVersion: v1 + metadata: + name: "${NAME}-admin" + stringData: + REDASH_ADMIN_PASSWORD: ${REDASH_ADMIN_PASSWORD} + REDASH_ADMIN_USERNAME: ${REDASH_ADMIN_USERNAME} + - kind: Secret + apiVersion: v1 + metadata: + name: "${NAME}-config" + stringData: + REDASH_COOKIE_SECRET: ${REDASH_COOKIE_SECRET} + REDASH_SECRET_KEY: ${REDASH_SECRET_KEY} + - kind: Secret + apiVersion: v1 + metadata: + name: "${NAME}-postgresql" + labels: + app: ${NAME} + annotations: + description: Database credentials and name. + template.openshift.io/expose-database_name: "${.data['POSTGRES_DATABASE']}" + template.openshift.io/expose-password: "${.data['POSTGRES_PASSWORD']}" + template.openshift.io/expose-username: "${.data['POSTGRES_USER']}" + stringData: + POSTGRES_DATABASE: ${POSTGRES_DATABASE} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_USER: ${POSTGRES_USER} + - kind: Secret + apiVersion: v1 + metadata: + name: "${NAME}-redis" + stringData: + REDIS_PASSWORD: ${REDIS_PASSWORD} +parameters: + - name: NAME + displayName: Name + description: The name assigned to all of the objects defined in this template. + required: true + value: chefs-redash + - name: REDASH_ADMIN_USERNAME + displayName: Redash Administrator Username + description: The username for the Redash administrator account + required: true + value: submit.digital@gov.bc.ca + - name: REDASH_ADMIN_PASSWORD + displayName: Redash Administrator Password + description: The password for the Redash administrator account + from: "[a-zA-Z0-9]{32}" + generate: expression + required: true + - name: REDASH_COOKIE_SECRET + displayName: Redash Cookie Secret + description: A reference to Redash cookie secret + from: "[a-zA-Z0-9]{32}" + generate: expression + required: true + - name: REDASH_SECRET_KEY + displayName: Redash Secret Key + description: A reference to Redash secret key + from: "[a-zA-Z0-9]{32}" + generate: expression + required: true + - name: POSTGRES_NONROOT_GROUP + displayName: PostgreSQL non-root group + description: A group for non-root users + generate: expression + from: "group[A-Z0-9]{3}" + required: true + - name: POSTGRES_USER + displayName: PostgreSQL Username + from: "user[A-Z0-9]{3}" + generate: expression + required: true + - name: POSTGRES_PASSWORD + displayName: PostgreSQL Password + description: + A minimum 16 character password that is generated in the target database, + and then copied over into this field. + generate: expression + from: "[a-zA-Z0-9]{16}" + required: true + - name: POSTGRES_DATABASE + displayName: PostgreSQL Database Name + description: The database that will be used by Redash + value: "redash" + required: true + - name: REDIS_PASSWORD + displayName: Redis Password + description: Password for Redis that will be used by Redash + from: "[a-zA-Z0-9]{16}" + generate: expression + required: true diff --git a/frontend/package-lock.json b/frontend/package-lock.json deleted file mode 100644 index 173081b..0000000 --- a/frontend/package-lock.json +++ /dev/null @@ -1,10340 +0,0 @@ -{ - "name": "quickstart-openshift-react-frontend", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "quickstart-openshift-react-frontend", - "version": "1.0.0", - "dependencies": { - "@emotion/react": "^11.11.0", - "@emotion/styled": "^11.11.0", - "@mui/icons-material": "^5.11.16", - "@mui/material": "^5.13.1", - "@vitejs/plugin-react": "^4.0.0", - "axios": "^1.4.0", - "mui-datatables": "^4.3.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-router": "^6.12.1", - "react-router-dom": "^6.12.1", - "vite": "^4.4.11", - "vite-tsconfig-paths": "^4.2.0" - }, - "devDependencies": { - "@faker-js/faker": "^8.0.2", - "@testing-library/cypress": "^10.0.0", - "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.4.3", - "@types/mui-datatables": "^4.3.5", - "@types/react": "^18.2.6", - "@types/react-dom": "^18.2.4", - "@vitest/coverage-v8": "^0.34.0", - "@vitest/ui": "^0.34.6", - "cypress": "^13.0.0", - "cypress-file-upload": "^5.0.8", - "cypress-plugin-api": "^2.11.1", - "eslint": "^8.41.0", - "eslint-config-prettier": "^9.0.0", - "eslint-config-standard-with-typescript": "^40.0.0", - "eslint-import-resolver-alias": "^1.1.2", - "eslint-import-resolver-typescript": "^3.5.5", - "eslint-plugin-cypress": "^2.13.3", - "eslint-plugin-html": "^7.1.0", - "eslint-plugin-import": "^2.27.5", - "eslint-plugin-prettier": "^5.0.0", - "eslint-plugin-promise": "^6.1.1", - "eslint-plugin-react": "^7.32.2", - "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-tsdoc": "^0.2.17", - "eslint-plugin-yaml": "^0.5.0", - "history": "^5.3.0", - "jsdom": "^22.1.0", - "msw": "^2.0.1", - "prettier": "^3.0.0", - "typescript": "^5.1.3", - "vitest": "^0.34.6" - } - }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@adobe/css-tools": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.2.tgz", - "integrity": "sha512-DA5a1C0gD/pLOvhv33YMrbf2FK3oUzwNl9oOJqE4XVjuEtt6XIakRcsd7eLiOSPkp1kTRQGICTA8cKra/vFbjw==", - "dev": true - }, - "node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.4.tgz", - "integrity": "sha512-r1IONyb6Ia+jYR2vvIDhdWdlTGhqbBoFqLTQidzZ4kepUFH15ejXvFHxCVbtl7BOXIudsIubf4E81xeA3h3IXA==", - "dependencies": { - "@babel/highlight": "^7.23.4", - "chalk": "^2.4.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/code-frame/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/code-frame/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/code-frame/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.3.tgz", - "integrity": "sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.3.tgz", - "integrity": "sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew==", - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.3", - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.23.2", - "@babel/parser": "^7.23.3", - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.3", - "@babel/types": "^7.23.3", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.4.tgz", - "integrity": "sha512-esuS49Cga3HcThFNebGhlgsrVLkvhqvYDTzgjfFFlHJcIfLe5jFmRRfCQ1KuBfc4Jrtn3ndLgKWAKjBE+IraYQ==", - "dependencies": { - "@babel/types": "^7.23.4", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", - "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", - "dependencies": { - "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.15", - "browserslist": "^4.21.9", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", - "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", - "dependencies": { - "@babel/types": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", - "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", - "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.20" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", - "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", - "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.4.tgz", - "integrity": "sha512-HfcMizYz10cr3h29VqyfGL6ZWIjTwWfvYBMsBVGwpcbhNGe3wQ1ZXZRPzZoAHhd9OqHadHqjQ89iVKINXnbzuw==", - "dependencies": { - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.4", - "@babel/types": "^7.23.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", - "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", - "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/parser": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.4.tgz", - "integrity": "sha512-vf3Xna6UEprW+7t6EtOmFpHNAuxw3xqPZghy+brsnusscJRW5BMUzzHZc5ICjULee81WeUV2jjakG09MDglJXQ==", - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.23.3.tgz", - "integrity": "sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.23.3.tgz", - "integrity": "sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g==", - "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.4.tgz", - "integrity": "sha512-2Yv65nlWnWlSpe3fXEyX5i7fx5kIKo4Qbcj+hMO0odwaneFjfXw5fdum+4yL20O0QiaHpia0cYQ9xpNMqrBwHg==", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/runtime-corejs3": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.23.4.tgz", - "integrity": "sha512-zQyB4MJGM+rvd4pM58n26kf3xbiitw9MHzL8oLiBMKb8MCtVDfV5nDzzJWWzLMtbvKI9wN6XwJYl479qF4JluQ==", - "dependencies": { - "core-js-pure": "^3.30.2", - "regenerator-runtime": "^0.14.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", - "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.4.tgz", - "integrity": "sha512-IYM8wSUwunWTB6tFC2dkKZhxbIjHoWemdK+3f8/wq8aKhbUscxD5MX72ubd90fxvFknaLPeGw5ycU84V1obHJg==", - "dependencies": { - "@babel/code-frame": "^7.23.4", - "@babel/generator": "^7.23.4", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.4", - "@babel/types": "^7.23.4", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.23.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.4.tgz", - "integrity": "sha512-7uIFwVYpoplT5jp/kVv6EF93VaJ8H+Yn5IczYiaAi98ajzjfoZfslet/e0sLh+wVBjb2qqIut1b0S26VSafsSQ==", - "dependencies": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "node_modules/@bundled-es-modules/cookie": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@bundled-es-modules/cookie/-/cookie-2.0.0.tgz", - "integrity": "sha512-Or6YHg/kamKHpxULAdSqhGqnWFneIXu1NKvvfBBzKGwpVsYuFIQ5aBPHDnnoR3ghW1nvSkALd+EF9iMtY7Vjxw==", - "dev": true, - "dependencies": { - "cookie": "^0.5.0" - } - }, - "node_modules/@bundled-es-modules/js-levenshtein": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@bundled-es-modules/js-levenshtein/-/js-levenshtein-2.0.1.tgz", - "integrity": "sha512-DERMS3yfbAljKsQc0U2wcqGKUWpdFjwqWuoMugEJlqBnKO180/n+4SR/J8MRDt1AN48X1ovgoD9KrdVXcaa3Rg==", - "dev": true, - "dependencies": { - "js-levenshtein": "^1.1.6" - } - }, - "node_modules/@bundled-es-modules/statuses": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@bundled-es-modules/statuses/-/statuses-1.0.1.tgz", - "integrity": "sha512-yn7BklA5acgcBr+7w064fGV+SGIFySjCKpqjcWgBAIfrAkY+4GQTJJHQMeT3V/sgz23VTEVV8TtOmkvJAhFVfg==", - "dev": true, - "dependencies": { - "statuses": "^2.0.1" - } - }, - "node_modules/@colors/colors": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", - "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/@cypress/request": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.1.tgz", - "integrity": "sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ==", - "dev": true, - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "http-signature": "~1.3.6", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "performance-now": "^2.1.0", - "qs": "6.10.4", - "safe-buffer": "^5.1.2", - "tough-cookie": "^4.1.3", - "tunnel-agent": "^0.6.0", - "uuid": "^8.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@cypress/request/node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/@cypress/xvfb": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz", - "integrity": "sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==", - "dev": true, - "dependencies": { - "debug": "^3.1.0", - "lodash.once": "^4.1.1" - } - }, - "node_modules/@cypress/xvfb/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/@emotion/babel-plugin": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz", - "integrity": "sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==", - "dependencies": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/runtime": "^7.18.3", - "@emotion/hash": "^0.9.1", - "@emotion/memoize": "^0.8.1", - "@emotion/serialize": "^1.1.2", - "babel-plugin-macros": "^3.1.0", - "convert-source-map": "^1.5.0", - "escape-string-regexp": "^4.0.0", - "find-root": "^1.1.0", - "source-map": "^0.5.7", - "stylis": "4.2.0" - } - }, - "node_modules/@emotion/cache": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", - "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", - "dependencies": { - "@emotion/memoize": "^0.8.1", - "@emotion/sheet": "^1.2.2", - "@emotion/utils": "^1.2.1", - "@emotion/weak-memoize": "^0.3.1", - "stylis": "4.2.0" - } - }, - "node_modules/@emotion/hash": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz", - "integrity": "sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==" - }, - "node_modules/@emotion/is-prop-valid": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.1.tgz", - "integrity": "sha512-61Mf7Ufx4aDxx1xlDeOm8aFFigGHE4z+0sKCa+IHCeZKiyP9RLD0Mmx7m8b9/Cf37f7NAvQOOJAbQQGVr5uERw==", - "dependencies": { - "@emotion/memoize": "^0.8.1" - } - }, - "node_modules/@emotion/memoize": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", - "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==" - }, - "node_modules/@emotion/react": { - "version": "11.11.1", - "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.1.tgz", - "integrity": "sha512-5mlW1DquU5HaxjLkfkGN1GA/fvVGdyHURRiX/0FHl2cfIfRxSOfmxEH5YS43edp0OldZrZ+dkBKbngxcNCdZvA==", - "dependencies": { - "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.11.0", - "@emotion/cache": "^11.11.0", - "@emotion/serialize": "^1.1.2", - "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", - "@emotion/utils": "^1.2.1", - "@emotion/weak-memoize": "^0.3.1", - "hoist-non-react-statics": "^3.3.1" - }, - "peerDependencies": { - "react": ">=16.8.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@emotion/serialize": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.1.2.tgz", - "integrity": "sha512-zR6a/fkFP4EAcCMQtLOhIgpprZOwNmCldtpaISpvz348+DP4Mz8ZoKaGGCQpbzepNIUWbq4w6hNZkwDyKoS+HA==", - "dependencies": { - "@emotion/hash": "^0.9.1", - "@emotion/memoize": "^0.8.1", - "@emotion/unitless": "^0.8.1", - "@emotion/utils": "^1.2.1", - "csstype": "^3.0.2" - } - }, - "node_modules/@emotion/sheet": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.2.2.tgz", - "integrity": "sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==" - }, - "node_modules/@emotion/styled": { - "version": "11.11.0", - "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.11.0.tgz", - "integrity": "sha512-hM5Nnvu9P3midq5aaXj4I+lnSfNi7Pmd4EWk1fOZ3pxookaQTNew6bp4JaCBYM4HVFZF9g7UjJmsUmC2JlxOng==", - "dependencies": { - "@babel/runtime": "^7.18.3", - "@emotion/babel-plugin": "^11.11.0", - "@emotion/is-prop-valid": "^1.2.1", - "@emotion/serialize": "^1.1.2", - "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", - "@emotion/utils": "^1.2.1" - }, - "peerDependencies": { - "@emotion/react": "^11.0.0-rc.0", - "react": ">=16.8.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@emotion/unitless": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", - "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==" - }, - "node_modules/@emotion/use-insertion-effect-with-fallbacks": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz", - "integrity": "sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==", - "peerDependencies": { - "react": ">=16.8.0" - } - }, - "node_modules/@emotion/utils": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.2.1.tgz", - "integrity": "sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==" - }, - "node_modules/@emotion/weak-memoize": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", - "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==" - }, - "node_modules/@esbuild/android-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", - "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", - "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", - "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", - "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", - "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", - "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", - "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", - "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", - "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", - "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", - "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", - "cpu": [ - "loong64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", - "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", - "cpu": [ - "mips64el" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", - "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", - "cpu": [ - "ppc64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", - "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", - "cpu": [ - "riscv64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", - "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", - "cpu": [ - "s390x" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", - "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", - "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", - "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", - "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", - "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", - "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", - "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.3.tgz", - "integrity": "sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.23.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", - "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/eslintrc/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/js": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.54.0.tgz", - "integrity": "sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@faker-js/faker": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-8.3.1.tgz", - "integrity": "sha512-FdgpFxY6V6rLZE9mmIBb9hM0xpfvQOSNOLnzolzKwsE1DH+gC7lEKV1p1IbR0lAYyvYd5a4u3qWJzowUkw1bIw==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/fakerjs" - } - ], - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0", - "npm": ">=6.14.13" - } - }, - "node_modules/@floating-ui/core": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.5.0.tgz", - "integrity": "sha512-kK1h4m36DQ0UHGj5Ah4db7R0rHemTqqO0QLvUqi1/mUUp3LuAWbWxdxSIf/XsnH9VS6rRVPLJCncjRzUvyCLXg==", - "dependencies": { - "@floating-ui/utils": "^0.1.3" - } - }, - "node_modules/@floating-ui/dom": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.3.tgz", - "integrity": "sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA==", - "dependencies": { - "@floating-ui/core": "^1.4.2", - "@floating-ui/utils": "^0.1.3" - } - }, - "node_modules/@floating-ui/react-dom": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.4.tgz", - "integrity": "sha512-CF8k2rgKeh/49UrnIBs4BdxPUV6vize/Db1d/YbCLyp9GiVZ0BEwf5AiDSxJRCr6yOkGqTFHtmrULxkEfYZ7dQ==", - "dependencies": { - "@floating-ui/dom": "^1.5.1" - }, - "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" - } - }, - "node_modules/@floating-ui/utils": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.6.tgz", - "integrity": "sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==" - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", - "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", - "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", - "dev": true - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@microsoft/tsdoc": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz", - "integrity": "sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug==", - "dev": true - }, - "node_modules/@microsoft/tsdoc-config": { - "version": "0.16.2", - "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.16.2.tgz", - "integrity": "sha512-OGiIzzoBLgWWR0UdRJX98oYO+XKGf7tiK4Zk6tQ/E4IJqGCe7dvkTvgDZV5cFJUzLGDOjeAXrnZoA6QkVySuxw==", - "dev": true, - "dependencies": { - "@microsoft/tsdoc": "0.14.2", - "ajv": "~6.12.6", - "jju": "~1.4.0", - "resolve": "~1.19.0" - } - }, - "node_modules/@microsoft/tsdoc-config/node_modules/resolve": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", - "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", - "dev": true, - "dependencies": { - "is-core-module": "^2.1.0", - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/@mswjs/cookies": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@mswjs/cookies/-/cookies-1.1.0.tgz", - "integrity": "sha512-0ZcCVQxifZmhwNBoQIrystCb+2sWBY2Zw8lpfJBPCHGCA/HWqehITeCRVIv4VMy8MPlaHo2w2pTHFV2pFfqKPw==", - "dev": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@mswjs/interceptors": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@mswjs/interceptors/-/interceptors-0.25.12.tgz", - "integrity": "sha512-a+zyoR01cPQeukSmaDEkE6aMwSjjfcT5ILzsyxmctEeCePnc2DMOd0X8Fn9bytq1IsAfMxJf/lu2aTfdivDbRg==", - "dev": true, - "dependencies": { - "@open-draft/deferred-promise": "^2.2.0", - "@open-draft/logger": "^0.3.0", - "@open-draft/until": "^2.0.0", - "is-node-process": "^1.2.0", - "outvariant": "^1.2.1", - "strict-event-emitter": "^0.5.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@mui/base": { - "version": "5.0.0-beta.24", - "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-beta.24.tgz", - "integrity": "sha512-bKt2pUADHGQtqWDZ8nvL2Lvg2GNJyd/ZUgZAJoYzRgmnxBL9j36MSlS3+exEdYkikcnvVafcBtD904RypFKb0w==", - "dependencies": { - "@babel/runtime": "^7.23.2", - "@floating-ui/react-dom": "^2.0.4", - "@mui/types": "^7.2.9", - "@mui/utils": "^5.14.18", - "@popperjs/core": "^2.11.8", - "clsx": "^2.0.0", - "prop-types": "^15.8.1" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui" - }, - "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0", - "react-dom": "^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@mui/core-downloads-tracker": { - "version": "5.14.18", - "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.18.tgz", - "integrity": "sha512-yFpF35fEVDV81nVktu0BE9qn2dD/chs7PsQhlyaV3EnTeZi9RZBuvoEfRym1/jmhJ2tcfeWXiRuHG942mQXJJQ==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui" - } - }, - "node_modules/@mui/icons-material": { - "version": "5.14.18", - "resolved": "https://registry.npmjs.org/@mui/icons-material/-/icons-material-5.14.18.tgz", - "integrity": "sha512-o2z49R1G4SdBaxZjbMmkn+2OdT1bKymLvAYaB6pH59obM1CYv/0vAVm6zO31IqhwtYwXv6A7sLIwCGYTaVkcdg==", - "dependencies": { - "@babel/runtime": "^7.23.2" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui" - }, - "peerDependencies": { - "@mui/material": "^5.0.0", - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@mui/material": { - "version": "5.14.18", - "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.14.18.tgz", - "integrity": "sha512-y3UiR/JqrkF5xZR0sIKj6y7xwuEiweh9peiN3Zfjy1gXWXhz5wjlaLdoxFfKIEBUFfeQALxr/Y8avlHH+B9lpQ==", - "dependencies": { - "@babel/runtime": "^7.23.2", - "@mui/base": "5.0.0-beta.24", - "@mui/core-downloads-tracker": "^5.14.18", - "@mui/system": "^5.14.18", - "@mui/types": "^7.2.9", - "@mui/utils": "^5.14.18", - "@types/react-transition-group": "^4.4.8", - "clsx": "^2.0.0", - "csstype": "^3.1.2", - "prop-types": "^15.8.1", - "react-is": "^18.2.0", - "react-transition-group": "^4.4.5" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui" - }, - "peerDependencies": { - "@emotion/react": "^11.5.0", - "@emotion/styled": "^11.3.0", - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0", - "react-dom": "^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@emotion/react": { - "optional": true - }, - "@emotion/styled": { - "optional": true - }, - "@types/react": { - "optional": true - } - } - }, - "node_modules/@mui/private-theming": { - "version": "5.14.18", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.14.18.tgz", - "integrity": "sha512-WSgjqRlzfHU+2Rou3HlR2Gqfr4rZRsvFgataYO3qQ0/m6gShJN+lhVEvwEiJ9QYyVzMDvNpXZAcqp8Y2Vl+PAw==", - "dependencies": { - "@babel/runtime": "^7.23.2", - "@mui/utils": "^5.14.18", - "prop-types": "^15.8.1" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui" - }, - "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@mui/styled-engine": { - "version": "5.14.18", - "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.14.18.tgz", - "integrity": "sha512-pW8bpmF9uCB5FV2IPk6mfbQCjPI5vGI09NOLhtGXPeph/4xIfC3JdIX0TILU0WcTs3aFQqo6s2+1SFgIB9rCXA==", - "dependencies": { - "@babel/runtime": "^7.23.2", - "@emotion/cache": "^11.11.0", - "csstype": "^3.1.2", - "prop-types": "^15.8.1" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui" - }, - "peerDependencies": { - "@emotion/react": "^11.4.1", - "@emotion/styled": "^11.3.0", - "react": "^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@emotion/react": { - "optional": true - }, - "@emotion/styled": { - "optional": true - } - } - }, - "node_modules/@mui/system": { - "version": "5.14.18", - "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.14.18.tgz", - "integrity": "sha512-hSQQdb3KF72X4EN2hMEiv8EYJZSflfdd1TRaGPoR7CIAG347OxCslpBUwWngYobaxgKvq6xTrlIl+diaactVww==", - "dependencies": { - "@babel/runtime": "^7.23.2", - "@mui/private-theming": "^5.14.18", - "@mui/styled-engine": "^5.14.18", - "@mui/types": "^7.2.9", - "@mui/utils": "^5.14.18", - "clsx": "^2.0.0", - "csstype": "^3.1.2", - "prop-types": "^15.8.1" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui" - }, - "peerDependencies": { - "@emotion/react": "^11.5.0", - "@emotion/styled": "^11.3.0", - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@emotion/react": { - "optional": true - }, - "@emotion/styled": { - "optional": true - }, - "@types/react": { - "optional": true - } - } - }, - "node_modules/@mui/types": { - "version": "7.2.9", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.9.tgz", - "integrity": "sha512-k1lN/PolaRZfNsRdAqXtcR71sTnv3z/VCCGPxU8HfdftDkzi335MdJ6scZxvofMAd/K/9EbzCZTFBmlNpQVdCg==", - "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@mui/utils": { - "version": "5.14.18", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.14.18.tgz", - "integrity": "sha512-HZDRsJtEZ7WMSnrHV9uwScGze4wM/Y+u6pDVo+grUjt5yXzn+wI8QX/JwTHh9YSw/WpnUL80mJJjgCnWj2VrzQ==", - "dependencies": { - "@babel/runtime": "^7.23.2", - "@types/prop-types": "^15.7.10", - "prop-types": "^15.8.1", - "react-is": "^18.2.0" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mui" - }, - "peerDependencies": { - "@types/react": "^17.0.0 || ^18.0.0", - "react": "^17.0.0 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@open-draft/deferred-promise": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@open-draft/deferred-promise/-/deferred-promise-2.2.0.tgz", - "integrity": "sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==", - "dev": true - }, - "node_modules/@open-draft/logger": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@open-draft/logger/-/logger-0.3.0.tgz", - "integrity": "sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==", - "dev": true, - "dependencies": { - "is-node-process": "^1.2.0", - "outvariant": "^1.4.0" - } - }, - "node_modules/@open-draft/until": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@open-draft/until/-/until-2.1.0.tgz", - "integrity": "sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==", - "dev": true - }, - "node_modules/@pkgr/utils": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@pkgr/utils/-/utils-2.4.2.tgz", - "integrity": "sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "fast-glob": "^3.3.0", - "is-glob": "^4.0.3", - "open": "^9.1.0", - "picocolors": "^1.0.0", - "tslib": "^2.6.0" - }, - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/@polka/url": { - "version": "1.0.0-next.23", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.23.tgz", - "integrity": "sha512-C16M+IYz0rgRhWZdCmK+h58JMv8vijAA61gmz2rspCSwKwzBebpdcsiUmwrtJRdphuY30i6BSLEOP8ppbNLyLg==", - "dev": true - }, - "node_modules/@popperjs/core": { - "version": "2.11.8", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", - "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/popperjs" - } - }, - "node_modules/@react-dnd/asap": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-4.0.1.tgz", - "integrity": "sha512-kLy0PJDDwvwwTXxqTFNAAllPHD73AycE9ypWeln/IguoGBEbvFcPDbCV03G52bEcC5E+YgupBE0VzHGdC8SIXg==" - }, - "node_modules/@react-dnd/invariant": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-2.0.0.tgz", - "integrity": "sha512-xL4RCQBCBDJ+GRwKTFhGUW8GXa4yoDfJrPbLblc3U09ciS+9ZJXJ3Qrcs/x2IODOdIE5kQxvMmE2UKyqUictUw==" - }, - "node_modules/@react-dnd/shallowequal": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-2.0.0.tgz", - "integrity": "sha512-Pc/AFTdwZwEKJxFJvlxrSmGe/di+aAOBn60sremrpLo6VI/6cmiUYNNwlI5KNYttg7uypzA3ILPMPgxB2GYZEg==" - }, - "node_modules/@remix-run/router": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.12.0.tgz", - "integrity": "sha512-2hXv036Bux90e1GXTWSMfNzfDDK8LA8JYEWfyHxzvwdp6GyoWEovKc9cotb3KCKmkdwsIBuFGX7ScTWyiHv7Eg==", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true - }, - "node_modules/@testing-library/cypress": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@testing-library/cypress/-/cypress-10.0.1.tgz", - "integrity": "sha512-e8uswjTZIBhaIXjzEcrQQ8nHRWHgZH7XBxKuIWxZ/T7FxfWhCR48nFhUX5nfPizjVOKSThEfOSv67jquc1ASkw==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.14.6", - "@testing-library/dom": "^9.0.0" - }, - "engines": { - "node": ">=12", - "npm": ">=6" - }, - "peerDependencies": { - "cypress": "^12.0.0 || ^13.0.0" - } - }, - "node_modules/@testing-library/dom": { - "version": "9.3.3", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-9.3.3.tgz", - "integrity": "sha512-fB0R+fa3AUqbLHWyxXa2kGVtf1Fe1ZZFr0Zp6AIbIAzXb2mKbEXl+PCQNUOaq5lbTab5tfctfXRNsWXxa2f7Aw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "5.1.3", - "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "pretty-format": "^27.0.2" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/@testing-library/jest-dom": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.1.4.tgz", - "integrity": "sha512-wpoYrCYwSZ5/AxcrjLxJmCU6I5QAJXslEeSiMQqaWmP2Kzpd1LvF/qxmAIW2qposULGWq2gw30GgVNFLSc2Jnw==", - "dev": true, - "dependencies": { - "@adobe/css-tools": "^4.3.1", - "@babel/runtime": "^7.9.2", - "aria-query": "^5.0.0", - "chalk": "^3.0.0", - "css.escape": "^1.5.1", - "dom-accessibility-api": "^0.5.6", - "lodash": "^4.17.15", - "redent": "^3.0.0" - }, - "engines": { - "node": ">=14", - "npm": ">=6", - "yarn": ">=1" - }, - "peerDependencies": { - "@jest/globals": ">= 28", - "@types/jest": ">= 28", - "jest": ">= 28", - "vitest": ">= 0.32" - }, - "peerDependenciesMeta": { - "@jest/globals": { - "optional": true - }, - "@types/jest": { - "optional": true - }, - "jest": { - "optional": true - }, - "vitest": { - "optional": true - } - } - }, - "node_modules/@testing-library/jest-dom/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@testing-library/react": { - "version": "14.1.2", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-14.1.2.tgz", - "integrity": "sha512-z4p7DVBTPjKM5qDZ0t5ZjzkpSNb+fZy1u6bzO7kk8oeGagpPCAtgh4cx1syrfp7a+QWkM021jGqjJaxJJnXAZg==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.12.5", - "@testing-library/dom": "^9.0.0", - "@types/react-dom": "^18.0.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "react": "^18.0.0", - "react-dom": "^18.0.0" - } - }, - "node_modules/@testing-library/user-event": { - "version": "14.5.1", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.5.1.tgz", - "integrity": "sha512-UCcUKrUYGj7ClomOo2SpNVvx4/fkd/2BbIHDCle8A0ax+P3bU7yJwDBDrS6ZwdTMARWTGODX1hEsCcO+7beJjg==", - "dev": true, - "engines": { - "node": ">=12", - "npm": ">=6" - }, - "peerDependencies": { - "@testing-library/dom": ">=7.21.4" - } - }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/@types/aria-query": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", - "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", - "dev": true - }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", - "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.7", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.7.tgz", - "integrity": "sha512-6Sfsq+EaaLrw4RmdFWE9Onp63TOUue71AWb4Gpa6JxzgTYtimbM086WnYTy2U67AofR++QKCo08ZP6pwx8YFHQ==", - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.20.4", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.4.tgz", - "integrity": "sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA==", - "dependencies": { - "@babel/types": "^7.20.7" - } - }, - "node_modules/@types/chai": { - "version": "4.3.11", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.11.tgz", - "integrity": "sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ==", - "dev": true - }, - "node_modules/@types/chai-subset": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/chai-subset/-/chai-subset-1.3.5.tgz", - "integrity": "sha512-c2mPnw+xHtXDoHmdtcCXGwyLMiauiAyxWMzhGpqHC4nqI/Y5G2XhTampslK2rb59kpcuHon03UH8W6iYUzw88A==", - "dev": true, - "dependencies": { - "@types/chai": "*" - } - }, - "node_modules/@types/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", - "dev": true - }, - "node_modules/@types/hoist-non-react-statics": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz", - "integrity": "sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==", - "dependencies": { - "@types/react": "*", - "hoist-non-react-statics": "^3.3.0" - } - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true - }, - "node_modules/@types/js-levenshtein": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@types/js-levenshtein/-/js-levenshtein-1.1.3.tgz", - "integrity": "sha512-jd+Q+sD20Qfu9e2aEXogiO3vpOC1PYJOUdyN9gvs4Qrvkg4wF43L5OhqrPeokdv8TL0/mXoYfpkcoGZMNN2pkQ==", - "dev": true - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "peer": true - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true - }, - "node_modules/@types/mui-datatables": { - "version": "4.3.10", - "resolved": "https://registry.npmjs.org/@types/mui-datatables/-/mui-datatables-4.3.10.tgz", - "integrity": "sha512-MlL9F1kasoGW6tOPpS4P6YGRLQtKYUu0sraj8kcak8HpQJ4+FkOvPLUlETZcct/+D2weYa6uw4uRdXSjqjcnJw==", - "dev": true, - "dependencies": { - "@emotion/react": "^11.10.5", - "@emotion/styled": "^11.10.5", - "@mui/material": "^5.11.4", - "@types/react": "*", - "csstype": "^3.1.1" - } - }, - "node_modules/@types/node": { - "version": "18.18.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.12.tgz", - "integrity": "sha512-G7slVfkwOm7g8VqcEF1/5SXiMjP3Tbt+pXDU3r/qhlM2KkGm786DUD4xyMA2QzEElFrv/KZV9gjygv4LnkpbMQ==", - "devOptional": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@types/parse-json": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", - "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==" - }, - "node_modules/@types/prop-types": { - "version": "15.7.11", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", - "integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==" - }, - "node_modules/@types/react": { - "version": "18.2.38", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.38.tgz", - "integrity": "sha512-cBBXHzuPtQK6wNthuVMV6IjHAFkdl/FOPFIlkd81/Cd1+IqkHu/A+w4g43kaQQoYHik/ruaQBDL72HyCy1vuMw==", - "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, - "node_modules/@types/react-dom": { - "version": "18.2.17", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.17.tgz", - "integrity": "sha512-rvrT/M7Df5eykWFxn6MYt5Pem/Dbyc1N8Y0S9Mrkw2WFCRiqUgw9P7ul2NpwsXCSM1DVdENzdG9J5SreqfAIWg==", - "dev": true, - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/react-transition-group": { - "version": "4.4.9", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.9.tgz", - "integrity": "sha512-ZVNmWumUIh5NhH8aMD9CR2hdW0fNuYInlocZHaZ+dgk/1K49j1w/HoAuK1ki+pgscQrOFRTlXeoURtuzEkV3dg==", - "dependencies": { - "@types/react": "*" - } - }, - "node_modules/@types/scheduler": { - "version": "0.16.8", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz", - "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==" - }, - "node_modules/@types/semver": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", - "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", - "dev": true, - "peer": true - }, - "node_modules/@types/sinonjs__fake-timers": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz", - "integrity": "sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==", - "dev": true - }, - "node_modules/@types/sizzle": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.8.tgz", - "integrity": "sha512-0vWLNK2D5MT9dg0iOo8GlKguPAU02QjmZitPEsXRuJXU/OGIOt9vT9Fc26wtYuavLxtO45v9PGleoL9Z0k1LHg==", - "dev": true - }, - "node_modules/@types/statuses": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/statuses/-/statuses-2.0.4.tgz", - "integrity": "sha512-eqNDvZsCNY49OAXB0Firg/Sc2BgoWsntsLUdybGFOhAfCD6QJ2n9HXUIHGqt5qjrxmMv4wS8WLAw43ZkKcJ8Pw==", - "dev": true - }, - "node_modules/@types/yauzl": { - "version": "2.10.3", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", - "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", - "dev": true, - "optional": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.12.0.tgz", - "integrity": "sha512-XOpZ3IyJUIV1b15M7HVOpgQxPPF7lGXgsfcEIu3yDxFPaf/xZKt7s9QO/pbk7vpWQyVulpJbu4E5LwpZiQo4kA==", - "dev": true, - "peer": true, - "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.12.0", - "@typescript-eslint/type-utils": "6.12.0", - "@typescript-eslint/utils": "6.12.0", - "@typescript-eslint/visitor-keys": "6.12.0", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.2.4", - "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.12.0.tgz", - "integrity": "sha512-s8/jNFPKPNRmXEnNXfuo1gemBdVmpQsK1pcu+QIvuNJuhFzGrpD7WjOcvDc/+uEdfzSYpNu7U/+MmbScjoQ6vg==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "6.12.0", - "@typescript-eslint/types": "6.12.0", - "@typescript-eslint/typescript-estree": "6.12.0", - "@typescript-eslint/visitor-keys": "6.12.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.12.0.tgz", - "integrity": "sha512-5gUvjg+XdSj8pcetdL9eXJzQNTl3RD7LgUiYTl8Aabdi8hFkaGSYnaS6BLc0BGNaDH+tVzVwmKtWvu0jLgWVbw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.12.0", - "@typescript-eslint/visitor-keys": "6.12.0" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.12.0.tgz", - "integrity": "sha512-WWmRXxhm1X8Wlquj+MhsAG4dU/Blvf1xDgGaYCzfvStP2NwPQh6KBvCDbiOEvaE0filhranjIlK/2fSTVwtBng==", - "dev": true, - "peer": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "6.12.0", - "@typescript-eslint/utils": "6.12.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.12.0.tgz", - "integrity": "sha512-MA16p/+WxM5JG/F3RTpRIcuOghWO30//VEOvzubM8zuOOBYXsP+IfjoCXXiIfy2Ta8FRh9+IO9QLlaFQUU+10Q==", - "dev": true, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.12.0.tgz", - "integrity": "sha512-vw9E2P9+3UUWzhgjyyVczLWxZ3GuQNT7QpnIY3o5OMeLO/c8oHljGc8ZpryBMIyympiAAaKgw9e5Hl9dCWFOYw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.12.0", - "@typescript-eslint/visitor-keys": "6.12.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.12.0.tgz", - "integrity": "sha512-LywPm8h3tGEbgfyjYnu3dauZ0U7R60m+miXgKcZS8c7QALO9uWJdvNoP+duKTk2XMWc7/Q3d/QiCuLN9X6SWyQ==", - "dev": true, - "peer": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.12.0", - "@typescript-eslint/types": "6.12.0", - "@typescript-eslint/typescript-estree": "6.12.0", - "semver": "^7.5.4" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.12.0.tgz", - "integrity": "sha512-rg3BizTZHF1k3ipn8gfrzDXXSFKyOEB5zxYXInQ6z0hUvmQlhaZQzK+YmHmNViMA9HzW5Q9+bPPt90bU6GQwyw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "6.12.0", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, - "node_modules/@vitejs/plugin-react": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.2.0.tgz", - "integrity": "sha512-+MHTH/e6H12kRp5HUkzOGqPMksezRMmW+TNzlh/QXfI8rRf6l2Z2yH/v12no1UvTwhZgEDMuQ7g7rrfMseU6FQ==", - "dependencies": { - "@babel/core": "^7.23.3", - "@babel/plugin-transform-react-jsx-self": "^7.23.3", - "@babel/plugin-transform-react-jsx-source": "^7.23.3", - "@types/babel__core": "^7.20.4", - "react-refresh": "^0.14.0" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0" - } - }, - "node_modules/@vitest/coverage-v8": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-0.34.6.tgz", - "integrity": "sha512-fivy/OK2d/EsJFoEoxHFEnNGTg+MmdZBAVK9Ka4qhXR2K3J0DS08vcGVwzDtXSuUMabLv4KtPcpSKkcMXFDViw==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.2.1", - "@bcoe/v8-coverage": "^0.2.3", - "istanbul-lib-coverage": "^3.2.0", - "istanbul-lib-report": "^3.0.1", - "istanbul-lib-source-maps": "^4.0.1", - "istanbul-reports": "^3.1.5", - "magic-string": "^0.30.1", - "picocolors": "^1.0.0", - "std-env": "^3.3.3", - "test-exclude": "^6.0.0", - "v8-to-istanbul": "^9.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "vitest": ">=0.32.0 <1" - } - }, - "node_modules/@vitest/expect": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.34.6.tgz", - "integrity": "sha512-QUzKpUQRc1qC7qdGo7rMK3AkETI7w18gTCUrsNnyjjJKYiuUB9+TQK3QnR1unhCnWRC0AbKv2omLGQDF/mIjOw==", - "dev": true, - "dependencies": { - "@vitest/spy": "0.34.6", - "@vitest/utils": "0.34.6", - "chai": "^4.3.10" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.34.6.tgz", - "integrity": "sha512-1CUQgtJSLF47NnhN+F9X2ycxUP0kLHQ/JWvNHbeBfwW8CzEGgeskzNnHDyv1ieKTltuR6sdIHV+nmR6kPxQqzQ==", - "dev": true, - "dependencies": { - "@vitest/utils": "0.34.6", - "p-limit": "^4.0.0", - "pathe": "^1.1.1" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner/node_modules/p-limit": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", - "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^1.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@vitest/runner/node_modules/yocto-queue": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", - "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", - "dev": true, - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@vitest/snapshot": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.34.6.tgz", - "integrity": "sha512-B3OZqYn6k4VaN011D+ve+AA4whM4QkcwcrwaKwAbyyvS/NB1hCWjFIBQxAQQSQir9/RtyAAGuq+4RJmbn2dH4w==", - "dev": true, - "dependencies": { - "magic-string": "^0.30.1", - "pathe": "^1.1.1", - "pretty-format": "^29.5.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/snapshot/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@vitest/snapshot/node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@vitest/spy": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.34.6.tgz", - "integrity": "sha512-xaCvneSaeBw/cz8ySmF7ZwGvL0lBjfvqc1LpQ/vcdHEvpLn3Ff1vAvjw+CoGn0802l++5L/pxb7whwcWAw+DUQ==", - "dev": true, - "dependencies": { - "tinyspy": "^2.1.1" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/ui": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-0.34.6.tgz", - "integrity": "sha512-/fxnCwGC0Txmr3tF3BwAbo3v6U2SkBTGR9UB8zo0Ztlx0BTOXHucE0gDHY7SjwEktCOHatiGmli9kZD6gYSoWQ==", - "dev": true, - "dependencies": { - "@vitest/utils": "0.34.6", - "fast-glob": "^3.3.0", - "fflate": "^0.8.0", - "flatted": "^3.2.7", - "pathe": "^1.1.1", - "picocolors": "^1.0.0", - "sirv": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "vitest": ">=0.30.1 <1" - } - }, - "node_modules/@vitest/utils": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.34.6.tgz", - "integrity": "sha512-IG5aDD8S6zlvloDsnzHw0Ut5xczlF+kv2BOTo+iXfPr54Yhi5qbVOgGB1hZaVq4iJ4C/MZ2J0y15IlsV/ZcI0A==", - "dev": true, - "dependencies": { - "diff-sequences": "^29.4.3", - "loupe": "^2.3.6", - "pretty-format": "^29.5.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/utils/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@vitest/utils/node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@vue/compiler-core": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.8.tgz", - "integrity": "sha512-hN/NNBUECw8SusQvDSqqcVv6gWq8L6iAktUR0UF3vGu2OhzRqcOiAno0FmBJWwxhYEXRlQJT5XnoKsVq1WZx4g==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.23.0", - "@vue/shared": "3.3.8", - "estree-walker": "^2.0.2", - "source-map-js": "^1.0.2" - } - }, - "node_modules/@vue/compiler-dom": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.8.tgz", - "integrity": "sha512-+PPtv+p/nWDd0AvJu3w8HS0RIm/C6VGBIRe24b9hSyNWOAPEUosFZ5diwawwP8ip5sJ8n0Pe87TNNNHnvjs0FQ==", - "dev": true, - "dependencies": { - "@vue/compiler-core": "3.3.8", - "@vue/shared": "3.3.8" - } - }, - "node_modules/@vue/compiler-sfc": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.3.8.tgz", - "integrity": "sha512-WMzbUrlTjfYF8joyT84HfwwXo+8WPALuPxhy+BZ6R4Aafls+jDBnSz8PDz60uFhuqFbl3HxRfxvDzrUf3THwpA==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.23.0", - "@vue/compiler-core": "3.3.8", - "@vue/compiler-dom": "3.3.8", - "@vue/compiler-ssr": "3.3.8", - "@vue/reactivity-transform": "3.3.8", - "@vue/shared": "3.3.8", - "estree-walker": "^2.0.2", - "magic-string": "^0.30.5", - "postcss": "^8.4.31", - "source-map-js": "^1.0.2" - } - }, - "node_modules/@vue/compiler-ssr": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.8.tgz", - "integrity": "sha512-hXCqQL/15kMVDBuoBYpUnSYT8doDNwsjvm3jTefnXr+ytn294ySnT8NlsFHmTgKNjwpuFy7XVV8yTeLtNl/P6w==", - "dev": true, - "dependencies": { - "@vue/compiler-dom": "3.3.8", - "@vue/shared": "3.3.8" - } - }, - "node_modules/@vue/reactivity": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.8.tgz", - "integrity": "sha512-ctLWitmFBu6mtddPyOKpHg8+5ahouoTCRtmAHZAXmolDtuZXfjL2T3OJ6DL6ezBPQB1SmMnpzjiWjCiMYmpIuw==", - "dev": true, - "dependencies": { - "@vue/shared": "3.3.8" - } - }, - "node_modules/@vue/reactivity-transform": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.3.8.tgz", - "integrity": "sha512-49CvBzmZNtcHua0XJ7GdGifM8GOXoUMOX4dD40Y5DxI3R8OUhMlvf2nvgUAcPxaXiV5MQQ1Nwy09ADpnLQUqRw==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.23.0", - "@vue/compiler-core": "3.3.8", - "@vue/shared": "3.3.8", - "estree-walker": "^2.0.2", - "magic-string": "^0.30.5" - } - }, - "node_modules/@vue/runtime-core": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.3.8.tgz", - "integrity": "sha512-qurzOlb6q26KWQ/8IShHkMDOuJkQnQcTIp1sdP4I9MbCf9FJeGVRXJFr2mF+6bXh/3Zjr9TDgURXrsCr9bfjUw==", - "dev": true, - "dependencies": { - "@vue/reactivity": "3.3.8", - "@vue/shared": "3.3.8" - } - }, - "node_modules/@vue/runtime-dom": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.3.8.tgz", - "integrity": "sha512-Noy5yM5UIf9UeFoowBVgghyGGPIDPy1Qlqt0yVsUdAVbqI8eeMSsTqBtauaEoT2UFXUk5S64aWVNJN4MJ2vRdA==", - "dev": true, - "dependencies": { - "@vue/runtime-core": "3.3.8", - "@vue/shared": "3.3.8", - "csstype": "^3.1.2" - } - }, - "node_modules/@vue/server-renderer": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.3.8.tgz", - "integrity": "sha512-zVCUw7RFskvPuNlPn/8xISbrf0zTWsTSdYTsUTN1ERGGZGVnRxM2QZ3x1OR32+vwkkCm0IW6HmJ49IsPm7ilLg==", - "dev": true, - "dependencies": { - "@vue/compiler-ssr": "3.3.8", - "@vue/shared": "3.3.8" - }, - "peerDependencies": { - "vue": "3.3.8" - } - }, - "node_modules/@vue/shared": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.8.tgz", - "integrity": "sha512-8PGwybFwM4x8pcfgqEQFy70NaQxASvOC5DJwLQfpArw1UDfUXrJkdxD3BhVTMS+0Lef/TU7YO0Jvr0jJY8T+mw==", - "dev": true - }, - "node_modules/abab": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.0.tgz", - "integrity": "sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arch": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", - "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/aria-query": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", - "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", - "dev": true, - "dependencies": { - "deep-equal": "^2.0.5" - } - }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz", - "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "is-array-buffer": "^3.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-includes": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", - "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/array.prototype.findlastindex": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.3.tgz", - "integrity": "sha512-LzLoiOMAxvy+Gd3BAq3B7VeIgPdo+Q8hthvKtXybMvRV0jrXfJM/t8mw7nNlpEcVlVUnCnM2KSX4XU5HmpodOA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0", - "get-intrinsic": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", - "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", - "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.tosorted": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.2.tgz", - "integrity": "sha512-HuQCHOlk1Weat5jzStICBCd83NxiIMwqDg/dHEsoefabn/hJRj5pVdWcPUSpRrwhwxZOsQassMpgN/xRYFBMIg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0", - "get-intrinsic": "^1.2.1" - } - }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz", - "integrity": "sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "is-array-buffer": "^3.0.2", - "is-shared-array-buffer": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dev": true, - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/async": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", - "dev": true - }, - "node_modules/asynciterator.prototype": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/asynciterator.prototype/-/asynciterator.prototype-1.0.0.tgz", - "integrity": "sha512-wwHYEIS0Q80f5mosx3L/dfG5t5rjEa9Ft51GTaNt862EnpyGHpgz2RkZvLPp1oF5TnAiTohkEKVEu8pQPJI7Vg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.3" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "node_modules/at-least-node": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", - "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/aws4": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", - "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", - "dev": true - }, - "node_modules/axios": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", - "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", - "dependencies": { - "follow-redirects": "^1.15.0", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - } - }, - "node_modules/babel-plugin-macros": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", - "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", - "dependencies": { - "@babel/runtime": "^7.12.5", - "cosmiconfig": "^7.0.0", - "resolve": "^1.19.0" - }, - "engines": { - "node": ">=10", - "npm": ">=6" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "dev": true, - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, - "node_modules/big-integer": { - "version": "1.6.52", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.52.tgz", - "integrity": "sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/blob-util": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz", - "integrity": "sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==", - "dev": true - }, - "node_modules/bluebird": { - "version": "3.7.2", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", - "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", - "dev": true - }, - "node_modules/bplist-parser": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", - "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", - "dev": true, - "dependencies": { - "big-integer": "^1.6.44" - }, - "engines": { - "node": ">= 5.10.0" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browserslist": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", - "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001541", - "electron-to-chromium": "^1.4.535", - "node-releases": "^2.0.13", - "update-browserslist-db": "^1.0.13" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/builtin-modules": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", - "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", - "dev": true, - "peer": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/builtins": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", - "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", - "dev": true, - "peer": true, - "dependencies": { - "semver": "^7.0.0" - } - }, - "node_modules/bundle-name": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz", - "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==", - "dev": true, - "dependencies": { - "run-applescript": "^5.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cac": { - "version": "6.7.14", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", - "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/cachedir": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.4.0.tgz", - "integrity": "sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/call-bind": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", - "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.1", - "set-function-length": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001563", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001563.tgz", - "integrity": "sha512-na2WUmOxnwIZtwnFI2CZ/3er0wdNzU7hN+cPYz/z2ajHThnkWjNBOpEPP4n+4r2WPM847JaMotaJE3bnfzjyKw==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true - }, - "node_modules/chai": { - "version": "4.3.10", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz", - "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==", - "dev": true, - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.0.8" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, - "node_modules/check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "dev": true, - "dependencies": { - "get-func-name": "^2.0.2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/check-more-types": { - "version": "2.24.0", - "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", - "integrity": "sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/cli": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", - "integrity": "sha512-41U72MB56TfUMGndAKK8vJ78eooOD4Z5NOL4xEfjc0c23s+6EYKXlXsmACBVclLP1yOfWCgEganVzddVrSNoTg==", - "dev": true, - "dependencies": { - "exit": "0.1.2", - "glob": "^7.1.1" - }, - "engines": { - "node": ">=0.2.5" - } - }, - "node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "dependencies": { - "restore-cursor": "^3.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-spinners": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.1.tgz", - "integrity": "sha512-jHgecW0pxkonBJdrKsqxgRX9AcG+u/5k0Q7WPDfi8AogLAdwxEkyYYNWwZ5GvVFoFx2uiY1eNcSK00fh+1+FyQ==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-table3": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", - "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0" - }, - "engines": { - "node": "10.* || >= 12.*" - }, - "optionalDependencies": { - "@colors/colors": "1.5.0" - } - }, - "node_modules/cli-truncate": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", - "dev": true, - "dependencies": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/clsx": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz", - "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==", - "engines": { - "node": ">=6" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/common-tags": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", - "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/console-browserify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", - "integrity": "sha512-duS7VP5pvfsNLDvL1O4VOEbw37AI3A4ZUQYemvDlnpGrNu9tprR7BYWpDYwC0Xia0Zxz5ZupdiIrUp0GH1aXfg==", - "dev": true, - "dependencies": { - "date-now": "^0.1.4" - } - }, - "node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" - }, - "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/core-js-pure": { - "version": "3.33.3", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.33.3.tgz", - "integrity": "sha512-taJ00IDOP+XYQEA2dAe4ESkmHt1fL8wzYDo3mRWQey8uO9UojlBFMneA65kMyxfYP7106c6LzWaq7/haDT6BCQ==", - "hasInstallScript": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true - }, - "node_modules/cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/css.escape": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", - "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", - "dev": true - }, - "node_modules/cssstyle": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz", - "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==", - "dev": true, - "dependencies": { - "rrweb-cssom": "^0.6.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/csstype": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", - "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" - }, - "node_modules/cypress": { - "version": "13.6.0", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.6.0.tgz", - "integrity": "sha512-quIsnFmtj4dBUEJYU4OH0H12bABJpSujvWexC24Ju1gTlKMJbeT6tTO0vh7WNfiBPPjoIXLN+OUqVtiKFs6SGw==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "@cypress/request": "^3.0.0", - "@cypress/xvfb": "^1.2.4", - "@types/node": "^18.17.5", - "@types/sinonjs__fake-timers": "8.1.1", - "@types/sizzle": "^2.3.2", - "arch": "^2.2.0", - "blob-util": "^2.0.2", - "bluebird": "^3.7.2", - "buffer": "^5.6.0", - "cachedir": "^2.3.0", - "chalk": "^4.1.0", - "check-more-types": "^2.24.0", - "cli-cursor": "^3.1.0", - "cli-table3": "~0.6.1", - "commander": "^6.2.1", - "common-tags": "^1.8.0", - "dayjs": "^1.10.4", - "debug": "^4.3.4", - "enquirer": "^2.3.6", - "eventemitter2": "6.4.7", - "execa": "4.1.0", - "executable": "^4.1.1", - "extract-zip": "2.0.1", - "figures": "^3.2.0", - "fs-extra": "^9.1.0", - "getos": "^3.2.1", - "is-ci": "^3.0.0", - "is-installed-globally": "~0.4.0", - "lazy-ass": "^1.6.0", - "listr2": "^3.8.3", - "lodash": "^4.17.21", - "log-symbols": "^4.0.0", - "minimist": "^1.2.8", - "ospath": "^1.2.2", - "pretty-bytes": "^5.6.0", - "process": "^0.11.10", - "proxy-from-env": "1.0.0", - "request-progress": "^3.0.0", - "semver": "^7.5.3", - "supports-color": "^8.1.1", - "tmp": "~0.2.1", - "untildify": "^4.0.0", - "yauzl": "^2.10.0" - }, - "bin": { - "cypress": "bin/cypress" - }, - "engines": { - "node": "^16.0.0 || ^18.0.0 || >=20.0.0" - } - }, - "node_modules/cypress-file-upload": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/cypress-file-upload/-/cypress-file-upload-5.0.8.tgz", - "integrity": "sha512-+8VzNabRk3zG6x8f8BWArF/xA/W0VK4IZNx3MV0jFWrJS/qKn8eHfa5nU73P9fOQAgwHFJx7zjg4lwOnljMO8g==", - "dev": true, - "engines": { - "node": ">=8.2.1" - }, - "peerDependencies": { - "cypress": ">3.0.0" - } - }, - "node_modules/cypress-plugin-api": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/cypress-plugin-api/-/cypress-plugin-api-2.11.1.tgz", - "integrity": "sha512-62Fc5H59Web01UrcbEsgfhp0pDN7xmHtkXYqTGmwD4NiHz1DN+9ZSxjxVFAUCBY1Q+Ns2E3nTOvDZIl8wdeNDQ==", - "dev": true, - "dependencies": { - "highlight.js": "11.4.0", - "prismjs": "^1.29.0", - "set-cookie-parser": "^2.5.1", - "vue": "^3.2.41" - }, - "peerDependencies": { - "cypress": ">=3" - } - }, - "node_modules/cypress/node_modules/proxy-from-env": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", - "integrity": "sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==", - "dev": true - }, - "node_modules/cypress/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/data-urls": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz", - "integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==", - "dev": true, - "dependencies": { - "abab": "^2.0.6", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^12.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/date-now": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", - "integrity": "sha512-AsElvov3LoNB7tf5k37H2jYSB+ZZPMT5sG2QjJCcdlV5chIv6htBUBUui2IKRjgtKAKtCBN7Zbwa+MtwLjSeNw==", - "dev": true - }, - "node_modules/dayjs": { - "version": "1.11.10", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", - "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==", - "dev": true - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decimal.js": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", - "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", - "dev": true - }, - "node_modules/deep-eql": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", - "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", - "dev": true, - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/deep-equal": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", - "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "call-bind": "^1.0.5", - "es-get-iterator": "^1.1.3", - "get-intrinsic": "^1.2.2", - "is-arguments": "^1.1.1", - "is-array-buffer": "^3.0.2", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "isarray": "^2.0.5", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "side-channel": "^1.0.4", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/default-browser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz", - "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==", - "dev": true, - "dependencies": { - "bundle-name": "^3.0.0", - "default-browser-id": "^3.0.0", - "execa": "^7.1.1", - "titleize": "^3.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser-id": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", - "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==", - "dev": true, - "dependencies": { - "bplist-parser": "^0.2.0", - "untildify": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser/node_modules/execa": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", - "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.1", - "human-signals": "^4.3.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^3.0.7", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": "^14.18.0 || ^16.14.0 || >=18.0.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/default-browser/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser/node_modules/human-signals": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", - "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", - "dev": true, - "engines": { - "node": ">=14.18.0" - } - }, - "node_modules/default-browser/node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser/node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser/node_modules/npm-run-path": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", - "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", - "dev": true, - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser/node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", - "dev": true, - "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser/node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/defaults": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", - "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", - "dev": true, - "dependencies": { - "clone": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/define-data-property": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", - "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/define-lazy-prop": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", - "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/dnd-core": { - "version": "11.1.3", - "resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-11.1.3.tgz", - "integrity": "sha512-QugF55dNW+h+vzxVJ/LSJeTeUw9MCJ2cllhmVThVPEtF16ooBkxj0WBE5RB+AceFxMFo1rO6bJKXtqKl+JNnyA==", - "dependencies": { - "@react-dnd/asap": "^4.0.0", - "@react-dnd/invariant": "^2.0.0", - "redux": "^4.0.4" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dom-accessibility-api": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", - "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", - "dev": true - }, - "node_modules/dom-helpers": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", - "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", - "dependencies": { - "@babel/runtime": "^7.8.7", - "csstype": "^3.0.2" - } - }, - "node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dev": true, - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/domexception": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", - "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", - "dev": true, - "dependencies": { - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dev": true, - "dependencies": { - "domelementtype": "^2.3.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", - "dev": true, - "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "dev": true, - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.590", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.590.tgz", - "integrity": "sha512-hohItzsQcG7/FBsviCYMtQwUSWvVF7NVqPOnJCErWsAshsP/CR2LAXdmq276RbESNdhxiAq5/vRo1g2pxGXVww==" - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/enhanced-resolve": { - "version": "5.15.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", - "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/enquirer": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", - "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.1", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.22.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", - "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.0", - "arraybuffer.prototype.slice": "^1.0.2", - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.5", - "es-set-tostringtag": "^2.0.1", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.2", - "get-symbol-description": "^1.0.0", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0", - "internal-slot": "^1.0.5", - "is-array-buffer": "^3.0.2", - "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.2", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.12", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", - "object-keys": "^1.1.1", - "object.assign": "^4.1.4", - "regexp.prototype.flags": "^1.5.1", - "safe-array-concat": "^1.0.1", - "safe-regex-test": "^1.0.0", - "string.prototype.trim": "^1.2.8", - "string.prototype.trimend": "^1.0.7", - "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.0", - "typed-array-byte-length": "^1.0.0", - "typed-array-byte-offset": "^1.0.0", - "typed-array-length": "^1.0.4", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-get-iterator": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", - "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "has-symbols": "^1.0.3", - "is-arguments": "^1.1.1", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.7", - "isarray": "^2.0.5", - "stop-iteration-iterator": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-iterator-helpers": { - "version": "1.0.15", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.15.tgz", - "integrity": "sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g==", - "dev": true, - "dependencies": { - "asynciterator.prototype": "^1.0.0", - "call-bind": "^1.0.2", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.1", - "es-set-tostringtag": "^2.0.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.2.1", - "globalthis": "^1.0.3", - "has-property-descriptors": "^1.0.0", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "iterator.prototype": "^1.1.2", - "safe-array-concat": "^1.0.1" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", - "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.2", - "has-tostringtag": "^1.0.0", - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-shim-unscopables": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", - "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.0" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/esbuild": { - "version": "0.18.20", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", - "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/android-arm": "0.18.20", - "@esbuild/android-arm64": "0.18.20", - "@esbuild/android-x64": "0.18.20", - "@esbuild/darwin-arm64": "0.18.20", - "@esbuild/darwin-x64": "0.18.20", - "@esbuild/freebsd-arm64": "0.18.20", - "@esbuild/freebsd-x64": "0.18.20", - "@esbuild/linux-arm": "0.18.20", - "@esbuild/linux-arm64": "0.18.20", - "@esbuild/linux-ia32": "0.18.20", - "@esbuild/linux-loong64": "0.18.20", - "@esbuild/linux-mips64el": "0.18.20", - "@esbuild/linux-ppc64": "0.18.20", - "@esbuild/linux-riscv64": "0.18.20", - "@esbuild/linux-s390x": "0.18.20", - "@esbuild/linux-x64": "0.18.20", - "@esbuild/netbsd-x64": "0.18.20", - "@esbuild/openbsd-x64": "0.18.20", - "@esbuild/sunos-x64": "0.18.20", - "@esbuild/win32-arm64": "0.18.20", - "@esbuild/win32-ia32": "0.18.20", - "@esbuild/win32-x64": "0.18.20" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.54.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.54.0.tgz", - "integrity": "sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.3", - "@eslint/js": "8.54.0", - "@humanwhocodes/config-array": "^0.11.13", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-compat-utils": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.1.2.tgz", - "integrity": "sha512-Jia4JDldWnFNIru1Ehx1H5s9/yxiRHY/TimCuUc0jNexew3cF1gI6CYZil1ociakfWO3rRqFjl1mskBblB3RYg==", - "dev": true, - "peer": true, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "eslint": ">=6.0.0" - } - }, - "node_modules/eslint-config-prettier": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz", - "integrity": "sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==", - "dev": true, - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-config-standard": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz", - "integrity": "sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "eslint": "^8.0.1", - "eslint-plugin-import": "^2.25.2", - "eslint-plugin-n": "^15.0.0 || ^16.0.0 ", - "eslint-plugin-promise": "^6.0.0" - } - }, - "node_modules/eslint-config-standard-with-typescript": { - "version": "40.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard-with-typescript/-/eslint-config-standard-with-typescript-40.0.0.tgz", - "integrity": "sha512-GXUJcwIXiTQaS3H4etv8a1lejVVdZYaxZNz3g7vt6GoJosQqMTurbmSC4FVGyHiGT/d1TjFr3+47A3xsHhsG+Q==", - "dev": true, - "dependencies": { - "@typescript-eslint/parser": "^6.4.0", - "eslint-config-standard": "17.1.0" - }, - "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^6.4.0", - "eslint": "^8.0.1", - "eslint-plugin-import": "^2.25.2", - "eslint-plugin-n": "^15.0.0 || ^16.0.0 ", - "eslint-plugin-promise": "^6.0.0", - "typescript": "*" - } - }, - "node_modules/eslint-import-resolver-alias": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-alias/-/eslint-import-resolver-alias-1.1.2.tgz", - "integrity": "sha512-WdviM1Eu834zsfjHtcGHtGfcu+F30Od3V7I9Fi57uhBEwPkjDcii7/yW8jAT+gOhn4P/vOxxNAXbFAKsrrc15w==", - "dev": true, - "engines": { - "node": ">= 4" - }, - "peerDependencies": { - "eslint-plugin-import": ">=1.4.0" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", - "dev": true, - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-import-resolver-typescript": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz", - "integrity": "sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==", - "dev": true, - "dependencies": { - "debug": "^4.3.4", - "enhanced-resolve": "^5.12.0", - "eslint-module-utils": "^2.7.4", - "fast-glob": "^3.3.1", - "get-tsconfig": "^4.5.0", - "is-core-module": "^2.11.0", - "is-glob": "^4.0.3" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts" - }, - "peerDependencies": { - "eslint": "*", - "eslint-plugin-import": "*" - } - }, - "node_modules/eslint-module-utils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", - "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", - "dev": true, - "dependencies": { - "debug": "^3.2.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-cypress": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-2.15.1.tgz", - "integrity": "sha512-eLHLWP5Q+I4j2AWepYq0PgFEei9/s5LvjuSqWrxurkg1YZ8ltxdvMNmdSf0drnsNo57CTgYY/NIHHLRSWejR7w==", - "dev": true, - "dependencies": { - "globals": "^13.20.0" - }, - "peerDependencies": { - "eslint": ">= 3.2.1" - } - }, - "node_modules/eslint-plugin-cypress/node_modules/globals": { - "version": "13.23.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", - "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint-plugin-cypress/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint-plugin-es-x": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.4.0.tgz", - "integrity": "sha512-WJa3RhYzBtl8I37ebY9p76s61UhZyi4KaFOnX2A5r32RPazkXj5yoT6PGnD02dhwzEUj0KwsUdqfKDd/OuvGsw==", - "dev": true, - "peer": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.1.2", - "@eslint-community/regexpp": "^4.6.0", - "eslint-compat-utils": "^0.1.2" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ota-meshi" - }, - "peerDependencies": { - "eslint": ">=8" - } - }, - "node_modules/eslint-plugin-html": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-html/-/eslint-plugin-html-7.1.0.tgz", - "integrity": "sha512-fNLRraV/e6j8e3XYOC9xgND4j+U7b1Rq+OygMlLcMg+wI/IpVbF+ubQa3R78EjKB9njT6TQOlcK5rFKBVVtdfg==", - "dev": true, - "dependencies": { - "htmlparser2": "^8.0.1" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.29.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.0.tgz", - "integrity": "sha512-QPOO5NO6Odv5lpoTkddtutccQjysJuFxoPS7fAHO+9m9udNHvTCPSAMW9zGAYj8lAIdr40I8yPCdUYrncXtrwg==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.7", - "array.prototype.findlastindex": "^1.2.3", - "array.prototype.flat": "^1.3.2", - "array.prototype.flatmap": "^1.3.2", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.8.0", - "hasown": "^2.0.0", - "is-core-module": "^2.13.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.7", - "object.groupby": "^1.0.1", - "object.values": "^1.1.7", - "semver": "^6.3.1", - "tsconfig-paths": "^3.14.2" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-plugin-n": { - "version": "16.3.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.3.1.tgz", - "integrity": "sha512-w46eDIkxQ2FaTHcey7G40eD+FhTXOdKudDXPUO2n9WNcslze/i/HT2qJ3GXjHngYSGDISIgPNhwGtgoix4zeOw==", - "dev": true, - "peer": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "builtins": "^5.0.1", - "eslint-plugin-es-x": "^7.1.0", - "get-tsconfig": "^4.7.0", - "ignore": "^5.2.4", - "is-builtin-module": "^3.2.1", - "is-core-module": "^2.12.1", - "minimatch": "^3.1.2", - "resolve": "^1.22.2", - "semver": "^7.5.3" - }, - "engines": { - "node": ">=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-plugin-prettier": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.1.tgz", - "integrity": "sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg==", - "dev": true, - "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.8.5" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/prettier" - }, - "peerDependencies": { - "@types/eslint": ">=8.0.0", - "eslint": ">=8.0.0", - "prettier": ">=3.0.0" - }, - "peerDependenciesMeta": { - "@types/eslint": { - "optional": true - }, - "eslint-config-prettier": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-promise": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz", - "integrity": "sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - } - }, - "node_modules/eslint-plugin-react": { - "version": "7.33.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.33.2.tgz", - "integrity": "sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flatmap": "^1.3.1", - "array.prototype.tosorted": "^1.1.1", - "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.0.12", - "estraverse": "^5.3.0", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.6", - "object.fromentries": "^2.0.6", - "object.hasown": "^1.1.2", - "object.values": "^1.1.6", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.4", - "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.8" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" - } - }, - "node_modules/eslint-plugin-react-hooks": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", - "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", - "dev": true, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" - } - }, - "node_modules/eslint-plugin-react/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.5", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", - "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", - "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/eslint-plugin-react/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-plugin-tsdoc": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/eslint-plugin-tsdoc/-/eslint-plugin-tsdoc-0.2.17.tgz", - "integrity": "sha512-xRmVi7Zx44lOBuYqG8vzTXuL6IdGOeF9nHX17bjJ8+VE6fsxpdGem0/SBTmAwgYMKYB1WBkqRJVQ+n8GK041pA==", - "dev": true, - "dependencies": { - "@microsoft/tsdoc": "0.14.2", - "@microsoft/tsdoc-config": "0.16.2" - } - }, - "node_modules/eslint-plugin-yaml": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-yaml/-/eslint-plugin-yaml-0.5.0.tgz", - "integrity": "sha512-Z6km4HEiRptSuvzc96nXBND1Vlg57b7pzRmIJOgb9+3PAE+XpaBaiMx+Dg+3Y15tSrEMKCIZ9WoZMwkwUbPI8A==", - "dev": true, - "dependencies": { - "js-yaml": "^4.1.0", - "jshint": "^2.13.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/globals": { - "version": "13.23.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", - "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eventemitter2": { - "version": "6.4.7", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.7.tgz", - "integrity": "sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==", - "dev": true - }, - "node_modules/execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/executable": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", - "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", - "dev": true, - "dependencies": { - "pify": "^2.2.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/external-editor/node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - }, - "bin": { - "extract-zip": "cli.js" - }, - "engines": { - "node": ">= 10.17.0" - }, - "optionalDependencies": { - "@types/yauzl": "^2.9.1" - } - }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", - "dev": true, - "engines": [ - "node >=0.6.0" - ] - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "dev": true, - "dependencies": { - "pend": "~1.2.0" - } - }, - "node_modules/fflate": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.1.tgz", - "integrity": "sha512-/exOvEuc+/iaUm105QIiOt4LpBdMTWsXxqR0HDF35vx3fmaKzw7354gTilCh5rkzEt8WYyG//ku3h3nRmd7CHQ==", - "dev": true - }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/figures/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-root": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", - "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", - "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", - "dev": true - }, - "node_modules/follow-redirects": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", - "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fs-extra": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", - "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", - "dev": true, - "dependencies": { - "at-least-node": "^1.0.0", - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", - "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-tsconfig": { - "version": "4.7.2", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.2.tgz", - "integrity": "sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==", - "dev": true, - "dependencies": { - "resolve-pkg-maps": "^1.0.0" - }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" - } - }, - "node_modules/getos": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz", - "integrity": "sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==", - "dev": true, - "dependencies": { - "async": "^3.2.0" - } - }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/global-dirs": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", - "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", - "dev": true, - "dependencies": { - "ini": "2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "engines": { - "node": ">=4" - } - }, - "node_modules/globalthis": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", - "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globrex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", - "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==" - }, - "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/graphql": { - "version": "16.8.1", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz", - "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", - "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/headers-polyfill": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/headers-polyfill/-/headers-polyfill-4.0.2.tgz", - "integrity": "sha512-EWGTfnTqAO2L/j5HZgoM/3z82L7necsJ0pO9Tp0X1wil3PDLrkypTBRgVO2ExehEEvUycejZD3FuRaXpZZc3kw==", - "dev": true - }, - "node_modules/highlight.js": { - "version": "11.4.0", - "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.4.0.tgz", - "integrity": "sha512-nawlpCBCSASs7EdvZOYOYVkJpGmAOKMYZgZtUqSRqodZE0GRVcFKwo1RcpeOemqh9hyttTdd5wDBwHkuSyUfnA==", - "dev": true, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/history": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz", - "integrity": "sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.7.6" - } - }, - "node_modules/hoist-non-react-statics": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", - "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", - "dependencies": { - "react-is": "^16.7.0" - } - }, - "node_modules/hoist-non-react-statics/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "node_modules/html-encoding-sniffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", - "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", - "dev": true, - "dependencies": { - "whatwg-encoding": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/htmlparser2": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", - "dev": true, - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "entities": "^4.4.0" - } - }, - "node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, - "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/http-signature": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", - "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^2.0.2", - "sshpk": "^1.14.1" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", - "dev": true, - "engines": { - "node": ">=8.12.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ignore": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", - "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/inquirer": { - "version": "8.2.6", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", - "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.1", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.21", - "mute-stream": "0.0.8", - "ora": "^5.4.1", - "run-async": "^2.4.0", - "rxjs": "^7.5.5", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6", - "wrap-ansi": "^6.0.1" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/inquirer/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/internal-slot": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.6.tgz", - "integrity": "sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.2", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz", - "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" - }, - "node_modules/is-async-function": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", - "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-builtin-module": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", - "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", - "dev": true, - "peer": true, - "dependencies": { - "builtin-modules": "^3.3.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-ci": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", - "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", - "dev": true, - "dependencies": { - "ci-info": "^3.2.0" - }, - "bin": { - "is-ci": "bin.js" - } - }, - "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "dependencies": { - "hasown": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-docker": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", - "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", - "dev": true, - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-finalizationregistry": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", - "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-function": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", - "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-inside-container": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", - "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", - "dev": true, - "dependencies": { - "is-docker": "^3.0.0" - }, - "bin": { - "is-inside-container": "cli.js" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", - "dev": true, - "dependencies": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-node-process": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-node-process/-/is-node-process-1.2.0.tgz", - "integrity": "sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==", - "dev": true - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", - "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", - "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", - "dev": true, - "dependencies": { - "which-typed-array": "^1.1.11" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-weakmap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", - "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-wsl/node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "dev": true - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", - "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/iterator.prototype": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", - "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", - "dev": true, - "dependencies": { - "define-properties": "^1.2.1", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "reflect.getprototypeof": "^1.0.4", - "set-function-name": "^2.0.1" - } - }, - "node_modules/jju": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", - "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", - "dev": true - }, - "node_modules/js-levenshtein": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", - "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "dev": true - }, - "node_modules/jsdom": { - "version": "22.1.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz", - "integrity": "sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==", - "dev": true, - "dependencies": { - "abab": "^2.0.6", - "cssstyle": "^3.0.0", - "data-urls": "^4.0.0", - "decimal.js": "^10.4.3", - "domexception": "^4.0.0", - "form-data": "^4.0.0", - "html-encoding-sniffer": "^3.0.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.1", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.4", - "parse5": "^7.1.2", - "rrweb-cssom": "^0.6.0", - "saxes": "^6.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.1.2", - "w3c-xmlserializer": "^4.0.0", - "webidl-conversions": "^7.0.0", - "whatwg-encoding": "^2.0.0", - "whatwg-mimetype": "^3.0.0", - "whatwg-url": "^12.0.1", - "ws": "^8.13.0", - "xml-name-validator": "^4.0.0" - }, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "canvas": "^2.5.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/jshint": { - "version": "2.13.6", - "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.13.6.tgz", - "integrity": "sha512-IVdB4G0NTTeQZrBoM8C5JFVLjV2KtZ9APgybDA1MK73xb09qFs0jCXyQLnCOp1cSZZZbvhq/6mfXHUTaDkffuQ==", - "dev": true, - "dependencies": { - "cli": "~1.0.0", - "console-browserify": "1.1.x", - "exit": "0.1.x", - "htmlparser2": "3.8.x", - "lodash": "~4.17.21", - "minimatch": "~3.0.2", - "strip-json-comments": "1.0.x" - }, - "bin": { - "jshint": "bin/jshint" - } - }, - "node_modules/jshint/node_modules/dom-serializer": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", - "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", - "dev": true, - "dependencies": { - "domelementtype": "^2.0.1", - "entities": "^2.0.0" - } - }, - "node_modules/jshint/node_modules/dom-serializer/node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/jshint/node_modules/dom-serializer/node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "dev": true, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/jshint/node_modules/domelementtype": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", - "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", - "dev": true - }, - "node_modules/jshint/node_modules/domhandler": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", - "integrity": "sha512-q9bUwjfp7Eif8jWxxxPSykdRZAb6GkguBGSgvvCrhI9wB71W2K/Kvv4E61CF/mcCfnVJDeDWx/Vb/uAqbDj6UQ==", - "dev": true, - "dependencies": { - "domelementtype": "1" - } - }, - "node_modules/jshint/node_modules/domutils": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", - "integrity": "sha512-gSu5Oi/I+3wDENBsOWBiRK1eoGxcywYSqg3rR960/+EfY0CF4EX1VPkgHOZ3WiS/Jg2DtliF6BhWcHlfpYUcGw==", - "dev": true, - "dependencies": { - "dom-serializer": "0", - "domelementtype": "1" - } - }, - "node_modules/jshint/node_modules/entities": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", - "integrity": "sha512-LbLqfXgJMmy81t+7c14mnulFHJ170cM6E+0vMXR9k/ZiZwgX8i5pNgjTCX3SO4VeUsFLV+8InixoretwU+MjBQ==", - "dev": true - }, - "node_modules/jshint/node_modules/htmlparser2": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", - "integrity": "sha512-hBxEg3CYXe+rPIua8ETe7tmG3XDn9B0edOE/e9wH2nLczxzgdu0m0aNHY+5wFZiviLWLdANPJTssa92dMcXQ5Q==", - "dev": true, - "dependencies": { - "domelementtype": "1", - "domhandler": "2.3", - "domutils": "1.5", - "entities": "1.0", - "readable-stream": "1.1" - } - }, - "node_modules/jshint/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", - "dev": true - }, - "node_modules/jshint/node_modules/minimatch": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", - "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/jshint/node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/jshint/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - }, - "node_modules/jshint/node_modules/strip-json-comments": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", - "integrity": "sha512-AOPG8EBc5wAikaG1/7uFCNFJwnKOuQwFTpYBdTW6OvWHeZBQBrAA/amefHGrEiOnCPcLFZK6FUPtWVKpQVIRgg==", - "dev": true, - "bin": { - "strip-json-comments": "cli.js" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" - }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/jsprim": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", - "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - } - }, - "node_modules/jsx-ast-utils": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", - "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "object.assign": "^4.1.4", - "object.values": "^1.1.6" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/lazy-ass": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", - "integrity": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==", - "dev": true, - "engines": { - "node": "> 0.8" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" - }, - "node_modules/listr2": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", - "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==", - "dev": true, - "dependencies": { - "cli-truncate": "^2.1.0", - "colorette": "^2.0.16", - "log-update": "^4.0.0", - "p-map": "^4.0.0", - "rfdc": "^1.3.0", - "rxjs": "^7.5.1", - "through": "^2.3.8", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "enquirer": ">= 2.3.0 < 3" - }, - "peerDependenciesMeta": { - "enquirer": { - "optional": true - } - } - }, - "node_modules/local-pkg": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz", - "integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/lodash.assignwith": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.assignwith/-/lodash.assignwith-4.2.0.tgz", - "integrity": "sha512-ZznplvbvtjK2gMvnQ1BR/zqPFZmS6jbK4p+6Up4xcRYA7yMIwxHCfbTcrYxXKzzqLsQ05eJPVznEW3tuwV7k1g==" - }, - "node_modules/lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" - }, - "node_modules/lodash.find": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.find/-/lodash.find-4.6.0.tgz", - "integrity": "sha512-yaRZoAV3Xq28F1iafWN1+a0rflOej93l1DQUejs3SZ41h2O9UJBoS9aueGjPDgAl4B6tPC0NuuchLKaDQQ3Isg==" - }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" - }, - "node_modules/lodash.isequal": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz", - "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==" - }, - "node_modules/lodash.isundefined": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz", - "integrity": "sha512-MXB1is3s899/cD8jheYYE2V9qTHwKvt+npCwpD+1Sxm3Q3cECXCiYHjeHWXNwr6Q0SOBPrYUDxendrO6goVTEA==" - }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==" - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" - }, - "node_modules/lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", - "dev": true - }, - "node_modules/lodash.throttle": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", - "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==" - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", - "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.3.0", - "cli-cursor": "^3.1.0", - "slice-ansi": "^4.0.0", - "wrap-ansi": "^6.2.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update/node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/log-update/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dev": true, - "dependencies": { - "get-func-name": "^2.0.1" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/lz-string": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", - "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", - "dev": true, - "bin": { - "lz-string": "bin/bin.js" - } - }, - "node_modules/magic-string": { - "version": "0.30.5", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", - "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", - "dev": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mlly": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.4.2.tgz", - "integrity": "sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==", - "dev": true, - "dependencies": { - "acorn": "^8.10.0", - "pathe": "^1.1.1", - "pkg-types": "^1.0.3", - "ufo": "^1.3.0" - } - }, - "node_modules/mrmime": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", - "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/msw": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/msw/-/msw-2.0.8.tgz", - "integrity": "sha512-/5nQCotVka62lvubQ3tMfUS3TukyeBwvWyvAthcXvDlXGhkA/85HlEwZyFlJ3ZsPW45Ty+ao0S4oFvuM12R/kA==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "@bundled-es-modules/cookie": "^2.0.0", - "@bundled-es-modules/js-levenshtein": "^2.0.1", - "@bundled-es-modules/statuses": "^1.0.1", - "@mswjs/cookies": "^1.1.0", - "@mswjs/interceptors": "^0.25.11", - "@open-draft/until": "^2.1.0", - "@types/cookie": "^0.4.1", - "@types/js-levenshtein": "^1.1.1", - "@types/statuses": "^2.0.1", - "chalk": "^4.1.2", - "chokidar": "^3.4.2", - "graphql": "^16.8.1", - "headers-polyfill": "^4.0.1", - "inquirer": "^8.2.0", - "is-node-process": "^1.2.0", - "js-levenshtein": "^1.1.6", - "outvariant": "^1.4.0", - "path-to-regexp": "^6.2.0", - "strict-event-emitter": "^0.5.0", - "type-fest": "^2.19.0", - "yargs": "^17.3.1" - }, - "bin": { - "msw": "cli/index.js" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mswjs" - }, - "peerDependencies": { - "typescript": ">= 4.7.x <= 5.2.x" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/msw/node_modules/type-fest": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", - "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", - "dev": true, - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mui-datatables": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/mui-datatables/-/mui-datatables-4.3.0.tgz", - "integrity": "sha512-LFliQwNnnxW03IO+V3q/ORxZsOHkzl53iGogLbjUJzme47hNEN106dM0ie8oMSc0heYJY0J07oZmKm7Xn3X7IQ==", - "dependencies": { - "@babel/runtime-corejs3": "^7.12.1", - "@emotion/cache": "^11.7.1", - "clsx": "^1.1.1", - "lodash.assignwith": "^4.2.0", - "lodash.clonedeep": "^4.5.0", - "lodash.debounce": "^4.0.8", - "lodash.find": "^4.6.0", - "lodash.get": "^4.4.2", - "lodash.isequal": "^4.5.0", - "lodash.isundefined": "^3.0.1", - "lodash.memoize": "^4.1.2", - "lodash.merge": "^4.6.2", - "prop-types": "^15.7.2", - "react-dnd": "^11.1.3", - "react-dnd-html5-backend": "^11.1.3", - "react-sortable-tree-patch-react-17": "^2.9.0", - "react-to-print": "^2.8.0", - "tss-react": "^3.6.0" - }, - "peerDependencies": { - "@emotion/react": "^11.10.5", - "@mui/icons-material": "^5.11.0", - "@mui/material": "^5.11.0", - "react": "^16.8.0 || ^17.0.2 || ^18.2.0", - "react-dom": "^16.8.0 || ^17.0.2 || ^18.2.0" - } - }, - "node_modules/mui-datatables/node_modules/clsx": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", - "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "node_modules/nanoid": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", - "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==" - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/nwsapi": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", - "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==", - "dev": true - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", - "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.entries": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.7.tgz", - "integrity": "sha512-jCBs/0plmPsOnrKAfFQXRG2NFjlhZgjjcBLSmTnEhU8U6vVTsVe8ANeQJCHTl3gSsI4J+0emOoCgoKlmQPMgmA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.fromentries": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", - "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.groupby": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.1.tgz", - "integrity": "sha512-HqaQtqLnp/8Bn4GL16cj+CUYbnpe1bh0TtEaWvybszDG4tgxCJuRpV8VGuvNaI1fAnI4lUJzDG55MXcOH4JZcQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1" - } - }, - "node_modules/object.hasown": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.3.tgz", - "integrity": "sha512-fFI4VcYpRHvSLXxP7yiZOMAd331cPfd2p7PFDVbgUsYOfCT3tICVqXWngbjr4m49OvsBwUBQ6O2uQoJvy3RexA==", - "dev": true, - "dependencies": { - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.values": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", - "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/open": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz", - "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==", - "dev": true, - "dependencies": { - "default-browser": "^4.0.0", - "define-lazy-prop": "^3.0.0", - "is-inside-container": "^1.0.0", - "is-wsl": "^2.2.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", - "dev": true, - "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/ora": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", - "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", - "dev": true, - "dependencies": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ospath": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz", - "integrity": "sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==", - "dev": true - }, - "node_modules/outvariant": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/outvariant/-/outvariant-1.4.0.tgz", - "integrity": "sha512-AlWY719RF02ujitly7Kk/0QlV+pXGFDHrHf9O2OKqyqgBieaPOIeuSkL8sRK6j2WK+/ZAURq2kZsY0d8JapUiw==", - "dev": true - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "dev": true, - "dependencies": { - "entities": "^4.4.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" - }, - "node_modules/path-to-regexp": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz", - "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==", - "dev": true - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/pathe": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.1.tgz", - "integrity": "sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==", - "dev": true - }, - "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true - }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pkg-types": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz", - "integrity": "sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==", - "dev": true, - "dependencies": { - "jsonc-parser": "^3.2.0", - "mlly": "^1.2.0", - "pathe": "^1.1.0" - } - }, - "node_modules/postcss": { - "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.0.tgz", - "integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==", - "dev": true, - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/pretty-bytes": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", - "dev": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/pretty-format/node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "dev": true - }, - "node_modules/prismjs": { - "version": "1.29.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", - "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", - "dev": true, - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/prop-types/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" - }, - "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.10.4", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.4.tgz", - "integrity": "sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==", - "dev": true, - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/raf": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", - "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", - "dependencies": { - "performance-now": "^2.1.0" - } - }, - "node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-display-name": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/react-display-name/-/react-display-name-0.2.5.tgz", - "integrity": "sha512-I+vcaK9t4+kypiSgaiVWAipqHRXYmZIuAiS8vzFvXHHXVigg/sMKwlRgLy6LH2i3rmP+0Vzfl5lFsFRwF1r3pg==" - }, - "node_modules/react-dnd": { - "version": "11.1.3", - "resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-11.1.3.tgz", - "integrity": "sha512-8rtzzT8iwHgdSC89VktwhqdKKtfXaAyC4wiqp0SywpHG12TTLvfOoL6xNEIUWXwIEWu+CFfDn4GZJyynCEuHIQ==", - "dependencies": { - "@react-dnd/shallowequal": "^2.0.0", - "@types/hoist-non-react-statics": "^3.3.1", - "dnd-core": "^11.1.3", - "hoist-non-react-statics": "^3.3.0" - }, - "peerDependencies": { - "react": ">= 16.9.0", - "react-dom": ">= 16.9.0" - } - }, - "node_modules/react-dnd-html5-backend": { - "version": "11.1.3", - "resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-11.1.3.tgz", - "integrity": "sha512-/1FjNlJbW/ivkUxlxQd7o3trA5DE33QiRZgxent3zKme8DwF4Nbw3OFVhTRFGaYhHFNL1rZt6Rdj1D78BjnNLw==", - "dependencies": { - "dnd-core": "^11.1.3" - } - }, - "node_modules/react-dom": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", - "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.0" - }, - "peerDependencies": { - "react": "^18.2.0" - } - }, - "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" - }, - "node_modules/react-lifecycles-compat": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", - "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" - }, - "node_modules/react-refresh": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz", - "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-router": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.19.0.tgz", - "integrity": "sha512-0W63PKCZ7+OuQd7Tm+RbkI8kCLmn4GPjDbX61tWljPxWgqTKlEpeQUwPkT1DRjYhF8KSihK0hQpmhU4uxVMcdw==", - "dependencies": { - "@remix-run/router": "1.12.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "react": ">=16.8" - } - }, - "node_modules/react-router-dom": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.19.0.tgz", - "integrity": "sha512-N6dWlcgL2w0U5HZUUqU2wlmOrSb3ighJmtQ438SWbhB1yuLTXQ8yyTBMK3BSvVjp7gBtKurT554nCtMOgxCZmQ==", - "dependencies": { - "@remix-run/router": "1.12.0", - "react-router": "6.19.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "react": ">=16.8", - "react-dom": ">=16.8" - } - }, - "node_modules/react-sortable-tree-patch-react-17": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/react-sortable-tree-patch-react-17/-/react-sortable-tree-patch-react-17-2.9.0.tgz", - "integrity": "sha512-Ngtdbf78OfjqCxLj7+N+K4zM9d1mQ/tfnUsOfICFDzNa5JHg6AjixAj69ijvz0ykEiA9lYop+0Fm4KCOqCdlKA==", - "dependencies": { - "lodash.isequal": "^4.5.0", - "prop-types": "^15.6.1", - "react": "^17.0.0", - "react-dnd": "^11.1.3", - "react-dnd-html5-backend": "^11.1.3", - "react-dnd-scrollzone-patch-react-17": "^1.0.2", - "react-dom": "^17.0.0", - "react-lifecycles-compat": "^3.0.4", - "react-virtualized": "^9.21.2" - }, - "peerDependencies": { - "react": "^17.0.0", - "react-dnd": "^11.1.3", - "react-dom": "^17.0.0" - } - }, - "node_modules/react-sortable-tree-patch-react-17/node_modules/react": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", - "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-sortable-tree-patch-react-17/node_modules/react-dnd-scrollzone-patch-react-17": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/react-dnd-scrollzone-patch-react-17/-/react-dnd-scrollzone-patch-react-17-1.0.2.tgz", - "integrity": "sha512-Wfhyc/Y/Veim29REBYm8nMmtDB5IwSmPPhXIuabBgsEa1MrVsuOwK9+7LmuP+mGbDOEP/S6G8+5XvDqPlRFK2g==", - "dependencies": { - "hoist-non-react-statics": "^3.1.0", - "lodash.throttle": "^4.0.1", - "prop-types": "^15.5.9", - "raf": "^3.2.0", - "react-display-name": "^0.2.0" - }, - "peerDependencies": { - "react": "^17.0.1", - "react-dnd": "^11.1.3", - "react-dom": "^17.0.1" - } - }, - "node_modules/react-sortable-tree-patch-react-17/node_modules/react-dom": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", - "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1", - "scheduler": "^0.20.2" - }, - "peerDependencies": { - "react": "17.0.2" - } - }, - "node_modules/react-sortable-tree-patch-react-17/node_modules/scheduler": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz", - "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==", - "dependencies": { - "loose-envify": "^1.1.0", - "object-assign": "^4.1.1" - } - }, - "node_modules/react-to-print": { - "version": "2.14.15", - "resolved": "https://registry.npmjs.org/react-to-print/-/react-to-print-2.14.15.tgz", - "integrity": "sha512-SKnwOzU2cJ8eaAkoJO7+gNhvfEDmm+Y34IdcHsjtHioUevUPhprqbVtvNJlZ2JkGJ8ExK2QNWM9pXECTDR5D8w==", - "peerDependencies": { - "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", - "react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/react-transition-group": { - "version": "4.4.5", - "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", - "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", - "dependencies": { - "@babel/runtime": "^7.5.5", - "dom-helpers": "^5.0.1", - "loose-envify": "^1.4.0", - "prop-types": "^15.6.2" - }, - "peerDependencies": { - "react": ">=16.6.0", - "react-dom": ">=16.6.0" - } - }, - "node_modules/react-virtualized": { - "version": "9.22.5", - "resolved": "https://registry.npmjs.org/react-virtualized/-/react-virtualized-9.22.5.tgz", - "integrity": "sha512-YqQMRzlVANBv1L/7r63OHa2b0ZsAaDp1UhVNEdUaXI8A5u6hTpA5NYtUueLH2rFuY/27mTGIBl7ZhqFKzw18YQ==", - "dependencies": { - "@babel/runtime": "^7.7.2", - "clsx": "^1.0.4", - "dom-helpers": "^5.1.3", - "loose-envify": "^1.4.0", - "prop-types": "^15.7.2", - "react-lifecycles-compat": "^3.0.4" - }, - "peerDependencies": { - "react": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0", - "react-dom": "^15.3.0 || ^16.0.0-alpha || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/react-virtualized/node_modules/clsx": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz", - "integrity": "sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==", - "engines": { - "node": ">=6" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", - "dev": true, - "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/redux": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", - "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", - "dependencies": { - "@babel/runtime": "^7.9.2" - } - }, - "node_modules/reflect.getprototypeof": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz", - "integrity": "sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "globalthis": "^1.0.3", - "which-builtin-type": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", - "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==" - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", - "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "set-function-name": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/request-progress": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", - "integrity": "sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==", - "dev": true, - "dependencies": { - "throttleit": "^1.0.0" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true - }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve-pkg-maps": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "dev": true, - "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" - } - }, - "node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rfdc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", - "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", - "dev": true - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rollup": { - "version": "3.29.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", - "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=14.18.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/rrweb-cssom": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", - "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==", - "dev": true - }, - "node_modules/run-applescript": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", - "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==", - "dev": true, - "dependencies": { - "execa": "^5.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/run-applescript/node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/run-applescript/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/run-applescript/node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "dev": true, - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/safe-array-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.1.tgz", - "integrity": "sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safe-regex-test": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", - "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "node_modules/saxes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", - "dev": true, - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=v12.22.7" - } - }, - "node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/set-cookie-parser": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", - "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==", - "dev": true - }, - "node_modules/set-function-length": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", - "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", - "dev": true, - "dependencies": { - "define-data-property": "^1.1.1", - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-function-name": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", - "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", - "dev": true, - "dependencies": { - "define-data-property": "^1.0.1", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/sirv": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.3.tgz", - "integrity": "sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==", - "dev": true, - "dependencies": { - "@polka/url": "^1.0.0-next.20", - "mrmime": "^1.0.0", - "totalist": "^3.0.0" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/slice-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sshpk": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", - "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", - "dev": true, - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stackback": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "dev": true - }, - "node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/std-env": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.5.0.tgz", - "integrity": "sha512-JGUEaALvL0Mf6JCfYnJOTcobY+Nc7sG/TemDRBqCA0wEr4DER7zDchaaixTlmOxAjG1uRJmX82EQcxwTQTkqVA==", - "dev": true - }, - "node_modules/stop-iteration-iterator": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", - "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", - "dev": true, - "dependencies": { - "internal-slot": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/strict-event-emitter": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz", - "integrity": "sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==", - "dev": true - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string.prototype.matchall": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz", - "integrity": "sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "get-intrinsic": "^1.2.1", - "has-symbols": "^1.0.3", - "internal-slot": "^1.0.5", - "regexp.prototype.flags": "^1.5.0", - "set-function-name": "^2.0.0", - "side-channel": "^1.0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", - "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", - "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", - "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "dev": true, - "dependencies": { - "min-indent": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strip-literal": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.3.0.tgz", - "integrity": "sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg==", - "dev": true, - "dependencies": { - "acorn": "^8.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/stylis": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", - "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==" - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, - "node_modules/synckit": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", - "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==", - "dev": true, - "dependencies": { - "@pkgr/utils": "^2.3.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/throttleit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.1.tgz", - "integrity": "sha512-vDZpf9Chs9mAdfY046mcPt8fg5QSZr37hEH4TXYBnDF+izxgrbRGUAAaBvIk/fJm9aOFCGFd1EsNg5AZCbnQCQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true - }, - "node_modules/tinybench": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.5.1.tgz", - "integrity": "sha512-65NKvSuAVDP/n4CqH+a9w2kTlLReS9vhsAP06MWx+/89nMinJyB2icyl58RIcqCmIggpojIGeuJGhjU1aGMBSg==", - "dev": true - }, - "node_modules/tinypool": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.7.0.tgz", - "integrity": "sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww==", - "dev": true, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tinyspy": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.0.tgz", - "integrity": "sha512-d2eda04AN/cPOR89F7Xv5bK/jrQEhmcLFe6HFldoeO9AJtps+fqEnh486vnT/8y4bw38pSyxDcTCAq+Ks2aJTg==", - "dev": true, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/titleize": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", - "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/tmp": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", - "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", - "dev": true, - "dependencies": { - "rimraf": "^3.0.0" - }, - "engines": { - "node": ">=8.17.0" - } - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "engines": { - "node": ">=4" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/totalist": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", - "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/tough-cookie": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", - "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", - "dev": true, - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tough-cookie/node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/tr46": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", - "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", - "dev": true, - "dependencies": { - "punycode": "^2.3.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/ts-api-utils": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", - "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", - "dev": true, - "engines": { - "node": ">=16.13.0" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, - "node_modules/tsconfck": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-2.1.2.tgz", - "integrity": "sha512-ghqN1b0puy3MhhviwO2kGF8SeMDNhEbnKxjK7h6+fvY9JAxqvXi8y5NAHSQv687OVboS2uZIByzGd45/YxrRHg==", - "bin": { - "tsconfck": "bin/tsconfck.js" - }, - "engines": { - "node": "^14.13.1 || ^16 || >=18" - }, - "peerDependencies": { - "typescript": "^4.3.5 || ^5.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/tsconfig-paths": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz", - "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==", - "dev": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true - }, - "node_modules/tss-react": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/tss-react/-/tss-react-3.7.1.tgz", - "integrity": "sha512-dfWUoxBlKZfIG9UC1A2h02OmcE/Ni0itCmmZu94E9g+KyBhKMHKcsKvUm0bNlRqTmYjXiCgPJDmj5fyc8CSrLg==", - "dependencies": { - "@emotion/cache": "*", - "@emotion/serialize": "*", - "@emotion/utils": "*" - }, - "peerDependencies": { - "@emotion/react": "^11.4.1", - "@emotion/server": "^11.4.0", - "react": "^16.8.0 || ^17.0.2 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@emotion/server": { - "optional": true - } - } - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typed-array-buffer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz", - "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typed-array-byte-length": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", - "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", - "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "has-proto": "^1.0.1", - "is-typed-array": "^1.1.10" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", - "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", - "devOptional": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/ufo": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.3.2.tgz", - "integrity": "sha512-o+ORpgGwaYQXgqGDwd+hkS4PuZ3QnmqMMxRuajK/a38L6fTpcE5GPIfrf+L/KemFzfUpeUQc1rRS1iDBozvnFA==", - "dev": true - }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "devOptional": true - }, - "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "dev": true, - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dev": true, - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/v8-to-istanbul": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.3.tgz", - "integrity": "sha512-9lDD+EVI2fjFsMWXc6dy5JJzBsVTcQ2fVkfBvncZ6xJWG9wtBhOldG+mHkSL0+V1K/xgZz0JDO5UT5hFwHUghg==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^2.0.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/v8-to-istanbul/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "node_modules/vite": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.1.tgz", - "integrity": "sha512-AXXFaAJ8yebyqzoNB9fu2pHoo/nWX+xZlaRwoeYUxEqBO+Zj4msE5G+BhGBll9lYEKv9Hfks52PAF2X7qDYXQA==", - "dependencies": { - "esbuild": "^0.18.10", - "postcss": "^8.4.27", - "rollup": "^3.27.1" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - }, - "peerDependencies": { - "@types/node": ">= 14", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - }, - "node_modules/vite-node": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.34.6.tgz", - "integrity": "sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==", - "dev": true, - "dependencies": { - "cac": "^6.7.14", - "debug": "^4.3.4", - "mlly": "^1.4.0", - "pathe": "^1.1.1", - "picocolors": "^1.0.0", - "vite": "^3.0.0 || ^4.0.0 || ^5.0.0-0" - }, - "bin": { - "vite-node": "vite-node.mjs" - }, - "engines": { - "node": ">=v14.18.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/vite-tsconfig-paths": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-4.2.1.tgz", - "integrity": "sha512-GNUI6ZgPqT3oervkvzU+qtys83+75N/OuDaQl7HmOqFTb0pjZsuARrRipsyJhJ3enqV8beI1xhGbToR4o78nSQ==", - "dependencies": { - "debug": "^4.1.1", - "globrex": "^0.1.2", - "tsconfck": "^2.1.0" - }, - "peerDependencies": { - "vite": "*" - }, - "peerDependenciesMeta": { - "vite": { - "optional": true - } - } - }, - "node_modules/vitest": { - "version": "0.34.6", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.34.6.tgz", - "integrity": "sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q==", - "dev": true, - "dependencies": { - "@types/chai": "^4.3.5", - "@types/chai-subset": "^1.3.3", - "@types/node": "*", - "@vitest/expect": "0.34.6", - "@vitest/runner": "0.34.6", - "@vitest/snapshot": "0.34.6", - "@vitest/spy": "0.34.6", - "@vitest/utils": "0.34.6", - "acorn": "^8.9.0", - "acorn-walk": "^8.2.0", - "cac": "^6.7.14", - "chai": "^4.3.10", - "debug": "^4.3.4", - "local-pkg": "^0.4.3", - "magic-string": "^0.30.1", - "pathe": "^1.1.1", - "picocolors": "^1.0.0", - "std-env": "^3.3.3", - "strip-literal": "^1.0.1", - "tinybench": "^2.5.0", - "tinypool": "^0.7.0", - "vite": "^3.1.0 || ^4.0.0 || ^5.0.0-0", - "vite-node": "0.34.6", - "why-is-node-running": "^2.2.2" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": ">=v14.18.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@vitest/browser": "*", - "@vitest/ui": "*", - "happy-dom": "*", - "jsdom": "*", - "playwright": "*", - "safaridriver": "*", - "webdriverio": "*" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@vitest/browser": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - }, - "playwright": { - "optional": true - }, - "safaridriver": { - "optional": true - }, - "webdriverio": { - "optional": true - } - } - }, - "node_modules/vue": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.3.8.tgz", - "integrity": "sha512-5VSX/3DabBikOXMsxzlW8JyfeLKlG9mzqnWgLQLty88vdZL7ZJgrdgBOmrArwxiLtmS+lNNpPcBYqrhE6TQW5w==", - "dev": true, - "dependencies": { - "@vue/compiler-dom": "3.3.8", - "@vue/compiler-sfc": "3.3.8", - "@vue/runtime-dom": "3.3.8", - "@vue/server-renderer": "3.3.8", - "@vue/shared": "3.3.8" - }, - "peerDependencies": { - "typescript": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/w3c-xmlserializer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", - "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", - "dev": true, - "dependencies": { - "xml-name-validator": "^4.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/wcwidth": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", - "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", - "dev": true, - "dependencies": { - "defaults": "^1.0.3" - } - }, - "node_modules/webidl-conversions": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", - "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-encoding": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", - "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", - "dev": true, - "dependencies": { - "iconv-lite": "0.6.3" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-encoding/node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/whatwg-mimetype": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", - "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/whatwg-url": { - "version": "12.0.1", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz", - "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==", - "dev": true, - "dependencies": { - "tr46": "^4.1.1", - "webidl-conversions": "^7.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-builtin-type": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", - "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", - "dev": true, - "dependencies": { - "function.prototype.name": "^1.1.5", - "has-tostringtag": "^1.0.0", - "is-async-function": "^2.0.0", - "is-date-object": "^1.0.5", - "is-finalizationregistry": "^1.0.2", - "is-generator-function": "^1.0.10", - "is-regex": "^1.1.4", - "is-weakref": "^1.0.2", - "isarray": "^2.0.5", - "which-boxed-primitive": "^1.0.2", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.9" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", - "dev": true, - "dependencies": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", - "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.4", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/why-is-node-running": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz", - "integrity": "sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==", - "dev": true, - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, - "node_modules/ws": { - "version": "8.14.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", - "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xml-name-validator": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", - "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" - }, - "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "dev": true, - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/frontend/package.json b/frontend/package.json deleted file mode 100644 index 898c1a2..0000000 --- a/frontend/package.json +++ /dev/null @@ -1,71 +0,0 @@ -{ - "name": "quickstart-openshift-react-frontend", - "private": true, - "version": "1.0.0", - "type": "module", - "scripts": { - "dev": "vite --host", - "clean": "rimraf ./node_modules/.vite", - "build:analyze": "vite build --mode analyze", - "build:clean": "rimraf dist", - "preview": "vite preview", - "test:unit": "vitest --mode test", - "test:cov": "vitest run --mode test --coverage", - "build": "vite build" - }, - "dependencies": { - "@emotion/react": "^11.11.0", - "@emotion/styled": "^11.11.0", - "@mui/icons-material": "^5.11.16", - "@mui/material": "^5.13.1", - "@vitejs/plugin-react": "^4.0.0", - "axios": "^1.4.0", - "mui-datatables": "^4.3.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-router": "^6.12.1", - "react-router-dom": "^6.12.1", - "vite": "^4.4.11", - "vite-tsconfig-paths": "^4.2.0" - }, - "devDependencies": { - "@faker-js/faker": "^8.0.2", - "@testing-library/cypress": "^10.0.0", - "@testing-library/jest-dom": "^6.0.0", - "@testing-library/react": "^14.0.0", - "@testing-library/user-event": "^14.4.3", - "@types/mui-datatables": "^4.3.5", - "@types/react": "^18.2.6", - "@types/react-dom": "^18.2.4", - "@vitest/coverage-v8": "^0.34.0", - "@vitest/ui": "^0.34.6", - "cypress": "^13.0.0", - "cypress-file-upload": "^5.0.8", - "cypress-plugin-api": "^2.11.1", - "eslint": "^8.41.0", - "eslint-config-prettier": "^9.0.0", - "eslint-config-standard-with-typescript": "^40.0.0", - "eslint-import-resolver-alias": "^1.1.2", - "eslint-import-resolver-typescript": "^3.5.5", - "eslint-plugin-cypress": "^2.13.3", - "eslint-plugin-html": "^7.1.0", - "eslint-plugin-import": "^2.27.5", - "eslint-plugin-prettier": "^5.0.0", - "eslint-plugin-promise": "^6.1.1", - "eslint-plugin-react": "^7.32.2", - "eslint-plugin-react-hooks": "^4.6.0", - "eslint-plugin-tsdoc": "^0.2.17", - "eslint-plugin-yaml": "^0.5.0", - "history": "^5.3.0", - "jsdom": "^22.1.0", - "msw": "^2.0.1", - "prettier": "^3.0.0", - "typescript": "^5.1.3", - "vitest": "^0.34.6" - }, - "overrides": { - "@testing-library/jest-dom": { - "@adobe/css-tools@<4.3.2": "^4.3.2" - } - } -} diff --git a/frontend/public/favicon.ico b/frontend/public/favicon.ico deleted file mode 100644 index 20742f9..0000000 Binary files a/frontend/public/favicon.ico and /dev/null differ diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx deleted file mode 100644 index ba32ec2..0000000 --- a/frontend/src/App.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import Box from '@mui/material/Box' -import Header from '@/components/Header' -import Footer from '@/components/Footer' -import AppRoutes from '@/routes' -import { BrowserRouter } from 'react-router-dom' - -const styles = { - container: { - display: 'flex', - flexDirection: 'column', - minHeight: '100vh', - }, - content: { - flexGrow: 1, - marginTop: '5em', - marginRight: '1em', - marginLeft: '1em', - marginBottom: '5em', - height: '100%', - }, -} -export default function App() { - return ( - -
- - - - - -