progress
ci / build (push) Failing after 1m54s Details

This commit is contained in:
CJ_Clippy 2024-07-13 21:20:35 -08:00
parent a61c88e536
commit 4962ae34f8
229 changed files with 972 additions and 11470 deletions

104
Tiltfile
View File

@ -13,11 +13,11 @@ secret_settings(
## cert-manager loaded using this extension is PAINFULLY SLOW, and it must re-install and re-test every time the Tiltfile changes. ## cert-manager loaded using this extension is PAINFULLY SLOW, and it must re-install and re-test every time the Tiltfile changes.
## additionally, it is SYNCRHONOUS, which means nothing else can update until cert-manager is updated. @see https://github.com/tilt-dev/tilt-extensions/pull/90#issuecomment-704381205 ## additionally, it is SYNCRHONOUS, which means nothing else can update until cert-manager is updated. @see https://github.com/tilt-dev/tilt-extensions/pull/90#issuecomment-704381205
## TL;DR: It's much preferred & much faster to use a helm chart for working with cert-manager in every environment. ## TL;DR: It's much preferred & much faster to use a helm chart for working with cert-manager in every environment.
# load('ext://cert_manager', 'deploy_cert_manager') load('ext://cert_manager', 'deploy_cert_manager')
# deploy_cert_manager( deploy_cert_manager(
# load_to_kind=False, load_to_kind=True,
# version='v1.15.1', version='v1.15.1',
# ) )
load('ext://helm_remote', 'helm_remote') load('ext://helm_remote', 'helm_remote')
@ -120,15 +120,18 @@ docker_build(
'fp/strapi', 'fp/strapi',
'.', '.',
dockerfile='./d.strapi.dockerfile', dockerfile='./d.strapi.dockerfile',
target='dev', target='strapi',
only=[ only=[
'./.npmrc',
'./package.json', './package.json',
'./pnpm-lock.yaml', './pnpm-lock.yaml',
'./pnpm-workspace.yaml',
'./packages/strapi', './packages/strapi',
'./packages/types', './packages/types',
], ],
live_update=[ live_update=[
sync('./packages/strapi', '/app') sync('./packages/strapi', '/app'),
run('cd /app && pnpm i', trigger=['./packages/strapi/package.json', './packages/strapi/pnpm-lock.yaml'])
] ]
) )
@ -217,10 +220,10 @@ docker_build(
docker_build( docker_build(
'fp/scout-manager', 'fp/scout',
'.', '.',
dockerfile='d.scout.dockerfile', dockerfile='d.scout.dockerfile',
target='scout-manager', target='scout',
live_update=[ live_update=[
sync('./packages/scout', '/app'), sync('./packages/scout', '/app'),
run('cd /app && pnpm i', trigger=['./packages/scout/package.json', './packages/scout/pnpm-lock.yaml']), run('cd /app && pnpm i', trigger=['./packages/scout/package.json', './packages/scout/pnpm-lock.yaml']),
@ -230,6 +233,34 @@ docker_build(
) )
docker_build(
'fp/worker',
'.',
dockerfile='d.worker.dockerfile',
target='worker',
only=[
'./.npmrc',
'./package.json',
'./pnpm-lock.yaml',
'./pnpm-workspace.yaml',
'./packages/image',
'./packages/scout',
'./packages/temporal-workflows',
'./packages/temporal-worker',
'./packages/types',
'./packages/utils',
'./packages/video',
'./packages/storage',
],
live_update=[
sync('./packages/temporal-worker', '/app'),
run('cd /app && pnpm i', trigger=['./packages/temporal-worker/package.json', './packages/temporal-worker/pnpm-lock.yaml']),
],
# entrypoint='pnpm nodemon --ext js,ts,json,yaml --exec node --no-warnings=ExperimentalWarning --loader ts-node/esm ./src/index.ts'
)
docker_build( docker_build(
'fp/boop', 'fp/boop',
'.', '.',
@ -252,26 +283,26 @@ docker_build(
docker_build( # docker_build(
'fp/scout-worker', # 'fp/scout-worker',
'.', # '.',
# ignore=['./packages/next'], # I wish I could use this ignore to ignore file changes in this dir, but that's not how it works # # ignore=['./packages/next'], # I wish I could use this ignore to ignore file changes in this dir, but that's not how it works
dockerfile='d.scout.dockerfile', # dockerfile='d.scout.dockerfile',
target='scout-worker', # target='scout-worker',
live_update=[ # live_update=[
# idk if this run() is effective # # idk if this run() is effective
# run('cd /app && pnpm i', trigger=['./packages/scout/package.json', './packages/scout/pnpm-lock.yaml']), # # run('cd /app && pnpm i', trigger=['./packages/scout/package.json', './packages/scout/pnpm-lock.yaml']),
sync('./packages/scout', '/app'), # sync('./packages/scout', '/app'),
## this is a hack to avoid complete scout image rebuilds when src in ./packages/next is updated # ## this is a hack to avoid complete scout image rebuilds when src in ./packages/next is updated
## ./packages/next needs to be in the build context because scout depends on types exported from next module (a feature of pnpm workspaces) # ## ./packages/next needs to be in the build context because scout depends on types exported from next module (a feature of pnpm workspaces)
## instead of a full rebuild, we put ./packages/next in the live_update spec so the changed files get shoved into /ignore-me # ## instead of a full rebuild, we put ./packages/next in the live_update spec so the changed files get shoved into /ignore-me
## ideally, I would like to include ./packages/next in the build context, but ignore file changes there for rebuilds. # ## ideally, I would like to include ./packages/next in the build context, but ignore file changes there for rebuilds.
## however, I don't think tilt has this capability. # ## however, I don't think tilt has this capability.
sync('./packages/next', '/ignore-me'), # sync('./packages/next', '/ignore-me'),
], # ],
# this entrypoint is a godsend. It lets me restart the node app (fast) without having to rebuild the docker container (slow) # # this entrypoint is a godsend. It lets me restart the node app (fast) without having to rebuild the docker container (slow)
entrypoint='pnpm nodemon --ext js,ts,json,yaml --exec node --no-warnings=ExperimentalWarning --loader ts-node/esm ./src/temporal/worker.ts' # entrypoint='pnpm nodemon --ext js,ts,json,yaml --exec node --no-warnings=ExperimentalWarning --loader ts-node/esm ./src/temporal/worker.ts'
) # )
@ -341,15 +372,10 @@ k8s_resource(
) )
k8s_resource(
workload='scout-worker',
resource_deps=['postgres', 'strapi', 'temporal-frontend'],
labels=['backend'],
)
k8s_resource( k8s_resource(
workload='scout-manager', workload='scout',
resource_deps=['postgres', 'strapi', 'temporal-frontend', 'scout-worker'], resource_deps=['postgres', 'strapi', 'temporal-frontend', 'worker'],
labels=['backend'], labels=['backend'],
) )
@ -513,6 +539,12 @@ k8s_resource(
# resource_deps=['strapi', 'temporal-web'], # resource_deps=['strapi', 'temporal-web'],
) )
k8s_resource(
workload='worker',
labels=['backend'],
resource_deps=['strapi', 'temporal-web', 'postgres' ],
)
# k8s_resource( # k8s_resource(
# workload='trigger', # workload='trigger',
# labels=['backend'], # labels=['backend'],

View File

@ -6,7 +6,7 @@ metadata:
labels: labels:
app: bot app: bot
spec: spec:
replicas: {{ .Values.scout.worker.replicas }} replicas: {{ .Values.bot.replicas }}
selector: selector:
matchLabels: matchLabels:
app: bot app: bot

View File

@ -1,99 +1,73 @@
apiVersion: apps/v1 # apiVersion: apps/v1
kind: ReplicaSet # kind: ReplicaSet
metadata: # metadata:
name: scout-worker # name: scout-worker
namespace: futureporn # namespace: futureporn
labels: # labels:
app: scout-worker # app: scout-worker
spec: # spec:
replicas: {{ .Values.scout.worker.replicas }} # replicas: {{ .Values.scout.replicas }}
selector: # selector:
matchLabels: # matchLabels:
app: scout-worker # app: scout-worker
template: # template:
metadata: # metadata:
labels: # labels:
app: scout-worker # app: scout-worker
spec: # spec:
containers: # containers:
- name: scout-worker # - name: scout-worker
image: "{{ .Values.scout.worker.imageName }}" # image: "{{ .Values.scout.imageName }}"
imagePullPolicy: Always # imagePullPolicy: Always
ports: # ports:
- containerPort: 8080 # - containerPort: 8080
env: # env:
- name: TEMPORAL_SERVICE_ADDRESS # - name: TEMPORAL_SERVICE_ADDRESS
value: "temporal-frontend.futureporn.svc.cluster.local:7233" # value: "temporal-frontend.futureporn.svc.cluster.local:7233"
- name: TEMPORAL_NAMESPACE # - name: TEMPORAL_NAMESPACE
value: "futureporn" # value: "futureporn"
- name: TEMPORAL_TASK_QUEUE # - name: TEMPORAL_TASK_QUEUE
value: "scout" # value: "scout"
- name: S3_BUCKET_NAME # - name: S3_BUCKET_NAME
value: "{{ .Values.scout.s3BucketName }}" # value: "{{ .Values.scout.s3BucketName }}"
- name: CDN_BUCKET_URL # - name: CDN_BUCKET_URL
value: "{{ .Values.scout.cdnBucketUrl }}" # value: "{{ .Values.scout.cdnBucketUrl }}"
- name: STRAPI_URL # - name: STRAPI_URL
value: https://strapi.fp.sbtp.xyz # value: https://strapi.fp.sbtp.xyz
- name: S3_BUCKET_APPLICATION_KEY # - name: S3_BUCKET_APPLICATION_KEY
valueFrom:
secretKeyRef:
name: scout
key: s3BucketApplicationKey
- name: S3_BUCKET_KEY_ID
valueFrom:
secretKeyRef:
name: scout
key: s3BucketKeyId
- name: SCOUT_NITTER_ACCESS_KEY
valueFrom:
secretKeyRef:
name: scout
key: nitterAccessKey
- name: SCOUT_NITTER_URL
value: https://nitter.sbtp.xyz
- name: SCOUT_RECENTS_TOKEN
valueFrom:
secretKeyRef:
name: scout
key: recentsToken
- name: SCOUT_STRAPI_API_KEY
valueFrom:
secretKeyRef:
name: scout
key: strapiApiKey
# - name: SCOUT_IMAP_SERVER
# valueFrom: # valueFrom:
# secretKeyRef: # secretKeyRef:
# name: scout # name: scout
# key: imapServer # key: s3BucketApplicationKey
# - name: SCOUT_IMAP_PORT # - name: S3_BUCKET_KEY_ID
# valueFrom: # valueFrom:
# secretKeyRef: # secretKeyRef:
# name: scout # name: scout
# key: imapPort # key: s3BucketKeyId
# - name: SCOUT_IMAP_USERNAME # - name: SCOUT_NITTER_ACCESS_KEY
# valueFrom: # valueFrom:
# secretKeyRef: # secretKeyRef:
# name: scout # name: scout
# key: imapUsername # key: nitterAccessKey
# - name: SCOUT_IMAP_PASSWORD # - name: SCOUT_NITTER_URL
# value: https://nitter.sbtp.xyz
# - name: SCOUT_RECENTS_TOKEN
# valueFrom: # valueFrom:
# secretKeyRef: # secretKeyRef:
# name: scout # name: scout
# key: imapPassword # key: recentsToken
# - name: SCOUT_IMAP_ACCESS_TOKEN # - name: SCOUT_STRAPI_API_KEY
# valueFrom: # valueFrom:
# secretKeyRef: # secretKeyRef:
# name: scout # name: scout
# key: imapAccessToken # key: strapiApiKey
# Add any other necessary environment variables # resources:
resources: # limits:
limits: # cpu: "500m"
cpu: "500m" # memory: "512Mi"
memory: "512Mi" # requests:
requests: # cpu: "250m"
cpu: "250m" # memory: "256Mi"
memory: "256Mi"
@ -101,23 +75,23 @@ spec:
apiVersion: apps/v1 apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
name: scout-manager name: scout
namespace: futureporn namespace: futureporn
labels: labels:
app: scout-manager app: scout
spec: spec:
replicas: 1 replicas: {{ .Values.scout.replicas }}
selector: selector:
matchLabels: matchLabels:
app: scout-manager app: scout
template: template:
metadata: metadata:
labels: labels:
app: scout-manager app: scout
spec: spec:
containers: containers:
- name: scout-manager - name: scout
image: "{{ .Values.scout.manager.imageName }}" image: "{{ .Values.scout.imageName }}"
ports: ports:
- name: http - name: http
containerPort: 3000 containerPort: 3000
@ -147,56 +121,3 @@ spec:
secretKeyRef: secretKeyRef:
name: scout name: scout
key: imapAccessToken key: imapAccessToken
# env:
# - name: POSTGRES_REALTIME_CONNECTION_STRING
# valueFrom:
# secretKeyRef:
# name: realtime
# key: postgresRealtimeConnectionString
# - name: CDN_BUCKET_URL
# value: "{{ .Values.scout.cdnBucketUrl }}"
# - name: STRAPI_URL
# value: https://strapi.fp.sbtp.xyz
# - name: SCOUT_NITTER_ACCESS_KEY
# valueFrom:
# secretKeyRef:
# name: scout
# key: nitterAccessKey
# - name: SCOUT_NITTER_URL
# value: https://nitter.sbtp.xyz
# - name: SCOUT_RECENTS_TOKEN
# valueFrom:
# secretKeyRef:
# name: scout
# key: recentsToken
# - name: SCOUT_IMAP_SERVER
# valueFrom:
# secretKeyRef:
# name: scout
# key: imapServer
# - name: SCOUT_IMAP_PORT
# valueFrom:
# secretKeyRef:
# name: scout
# key: imapPort
# - name: SCOUT_IMAP_USERNAME
# valueFrom:
# secretKeyRef:
# name: scout
# key: imapUsername
# - name: SCOUT_IMAP_PASSWORD
# valueFrom:
# secretKeyRef:
# name: scout
# key: imapPassword
# - name: SCOUT_IMAP_ACCESS_TOKEN
# valueFrom:
# secretKeyRef:
# name: scout
# key: imapAccessToken
# - name: SCOUT_STRAPI_API_KEY
# valueFrom:
# secretKeyRef:
# name: scout
# key: strapiApiKey

View File

@ -0,0 +1,67 @@
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: worker
namespace: futureporn
labels:
app: worker
spec:
replicas: {{ .Values.worker.replicas }}
selector:
matchLabels:
app: worker
template:
metadata:
labels:
app: worker
spec:
containers:
- name: worker
image: "{{ .Values.worker.imageName }}"
imagePullPolicy: Always
ports:
- containerPort: 8080
env:
- name: TEMPORAL_SERVICE_ADDRESS
value: "temporal-frontend.futureporn.svc.cluster.local:7233"
- name: TEMPORAL_NAMESPACE
value: "futureporn"
- name: TEMPORAL_TASK_QUEUE
value: "futureporn"
# - name: STRAPI_URL
# value: https://strapi.fp.sbtp.xyz
# - name: S3_BUCKET_APPLICATION_KEY
# valueFrom:
# secretKeyRef:
# name: scout
# key: s3BucketApplicationKey
# - name: S3_BUCKET_KEY_ID
# valueFrom:
# secretKeyRef:
# name: scout
# key: s3BucketKeyId
# - name: SCOUT_NITTER_ACCESS_KEY
# valueFrom:
# secretKeyRef:
# name: scout
# key: nitterAccessKey
# - name: SCOUT_NITTER_URL
# value: https://nitter.sbtp.xyz
# - name: SCOUT_RECENTS_TOKEN
# valueFrom:
# secretKeyRef:
# name: scout
# key: recentsToken
# - name: SCOUT_STRAPI_API_KEY
# valueFrom:
# secretKeyRef:
# name: scout
# key: strapiApiKey
resources:
limits:
cpu: "500m"
memory: "512Mi"
requests:
cpu: "250m"
memory: "256Mi"

View File

@ -10,12 +10,17 @@ next:
nodeExtraCaCerts: /app/letsencrypt-stg-root-x1.pem nodeExtraCaCerts: /app/letsencrypt-stg-root-x1.pem
capture: capture:
imageName: fp/capture imageName: fp/capture
scout:
manager:
imageName: fp/scout-manager
worker: worker:
imageName: fp/scout-worker imageName: fp/worker
replicas: 3
cdnBucketUrl: https://fp-dev.b-cdn.net
s3BucketName: fp-dev
scout:
replicas: 1 replicas: 1
imageName: fp/scout
# worker:
# imageName: fp/scout-
# replicas: 1
pubsubServerUrl: https://realtime.futureporn.svc.cluster.local/faye pubsubServerUrl: https://realtime.futureporn.svc.cluster.local/faye
hostname: next.futureporn.svc.cluster.local hostname: next.futureporn.svc.cluster.local
cdnBucketUrl: https://fp-dev.b-cdn.net cdnBucketUrl: https://fp-dev.b-cdn.net
@ -25,6 +30,7 @@ strapi:
port: 1339 port: 1339
url: https://strapi.fp.sbtp.xyz url: https://strapi.fp.sbtp.xyz
hostname: strapi.fp.sbtp.xyz hostname: strapi.fp.sbtp.xyz
# hostname: strapi.futureporn.svc.cluster.local ## https://gitea.futureporn.net/futureporn/pm/issues/126
ingressClassName: traefik ingressClassName: traefik
ngrok: ngrok:
hostname: grateful-engaging-cicada.ngrok-free.app hostname: grateful-engaging-cicada.ngrok-free.app
@ -53,6 +59,7 @@ bot:
discordChannelId: "1185024773231759481" discordChannelId: "1185024773231759481"
discordGuildId: "1084674137391374338" discordGuildId: "1084674137391374338"
imageName: fp/bot imageName: fp/bot
replicas: 1
trigger: trigger:
imageName: ghcr.io/triggerdotdev/trigger.dev:self-host-rc.3 imageName: ghcr.io/triggerdotdev/trigger.dev:self-host-rc.3
worker: worker:

View File

@ -21,23 +21,32 @@ ENV NEXT_TELEMETRY_DISABLED 1
ENV NODE_EXTRA_CA_CERTS ${NODE_EXTRA_CA_CERTS} ENV NODE_EXTRA_CA_CERTS ${NODE_EXTRA_CA_CERTS}
COPY pnpm-lock.yaml ./ COPY pnpm-lock.yaml ./
RUN pnpm fetch RUN pnpm fetch
COPY ./packages/next /app # COPY pnpm-lock.yaml .npmrc package.json .
RUN --mount=type=cache,id=pnpm-store,target=/pnpm/store pnpm install COPY ./packages/next ./packages/next
COPY ./packages/types ./packages/types
# COPY ./packages/strapi ./packages/strapi
# COPY ./packages/scout ./packages/scout
# COPY ./packages/image ./packages/image
# COPY ./packages/utils ./packages/utils
# COPY ./packages/temporal-workflows ./packages/temporal-workflows
RUN --mount=type=cache,id=pnpm-store,target=/pnpm/store pnpm install --recursive --frozen-lockfile --prefer-offline
FROM install AS dev FROM install AS dev
CMD ["pnpm", "run", "dev"] CMD ["pnpm", "run", "dev"]
FROM install AS build FROM install AS build
RUN pnpm run build RUN pnpm run -r build
RUN pnpm --filter=next deploy --prod /prod/next
FROM deps AS next FROM deps AS next
RUN apt-get update && apt-get install -y -qq --no-install-recommends dumb-init RUN apt-get update && apt-get install -y -qq --no-install-recommends dumb-init
COPY --chown=node:node --from=build /app/package.json /app/pnpm-lock.yaml ./ COPY --chown=node:node --from=build /prod/next/package.json /prod/next/pnpm-lock.yaml ./
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --prod --frozen-lockfile RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --prod --frozen-lockfile
COPY --chown=node:node --from=build /app/public ./public COPY --chown=node:node --from=build /prod/next/public ./public
COPY --chown=node:node --from=build /app/.next/standalone ./ COPY --chown=node:node --from=build /prod/next/.next/standalone ./
COPY --chown=node:node --from=build /app/.next/static ./.next/static COPY --chown=node:node --from=build /prod/next/.next/static ./.next/static
ENV TZ=UTC ENV TZ=UTC
ENV NODE_ENV=production ENV NODE_ENV=production
ENV HOSTNAME="0.0.0.0" ENV HOSTNAME="0.0.0.0"

View File

@ -11,11 +11,15 @@ COPY package.json pnpm-lock.yaml .
COPY ./packages/scout/pnpm-lock.yaml ./packages/scout/ COPY ./packages/scout/pnpm-lock.yaml ./packages/scout/
COPY ./packages/taco/pnpm-lock.yaml ./packages/taco/ COPY ./packages/taco/pnpm-lock.yaml ./packages/taco/
COPY ./packages/types/pnpm-lock.yaml ./packages/types/ COPY ./packages/types/pnpm-lock.yaml ./packages/types/
COPY ./packages/temporal-workflows/pnpm-lock.yaml ./packages/temporal-workflows/
COPY ./packages/temporal-worker/pnpm-lock.yaml ./packages/temporal-worker/
RUN pnpm fetch RUN pnpm fetch
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --recursive --frozen-lockfile RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --recursive --frozen-lockfile
COPY ./packages/scout/ ./packages/scout/ COPY ./packages/scout/ ./packages/scout/
COPY ./packages/taco/ ./packages/taco/ COPY ./packages/taco/ ./packages/taco/
COPY ./packages/types/ ./packages/types/ COPY ./packages/types/ ./packages/types/
COPY ./packages/temporal-workflows/ ./packages/temporal-workflows/
COPY ./packages/temporal-worker/ ./packages/temporal-worker/
RUN pnpm -r build RUN pnpm -r build
RUN pnpm deploy --filter=scout --prod /prod/scout RUN pnpm deploy --filter=scout --prod /prod/scout

View File

@ -1,7 +1,8 @@
FROM node:20 AS base FROM node:20 AS base
# Installing libvips-dev for sharp Compatibility ## Installing libvips-dev for sharp Compatibility
## (only needed on alpine)
# RUN apk update && apk add --no-cache build-base gcc autoconf automake zlib-dev libpng-dev nasm bash vips-dev git # RUN apk update && apk add --no-cache build-base gcc autoconf automake zlib-dev libpng-dev nasm bash vips-dev git
RUN corepack enable RUN corepack enable && corepack prepare pnpm@9.5.0 --activate
ENV PNPM_HOME="/pnpm" ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH" ENV PATH="$PNPM_HOME:$PATH"
ARG NODE_ENV=development ARG NODE_ENV=development
@ -10,21 +11,39 @@ EXPOSE 1339
ENTRYPOINT ["pnpm"] ENTRYPOINT ["pnpm"]
FROM base AS build FROM base AS build
WORKDIR /app
RUN mkdir -p /prod/strapi RUN mkdir -p /prod/strapi
WORKDIR /opt/ COPY pnpm-workspace.yaml pnpm-lock.yaml .npmrc package.json .
COPY ./packages/strapi/package.json ./packages/strapi/pnpm-lock.yaml ./ COPY ./packages/types ./packages/types
COPY ./packages/strapi ./packages/strapi
RUN pnpm fetch RUN pnpm fetch
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install -g node-gyp RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install -g node-gyp --prefer-offline
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --recursive --prefer-offline
ENV PATH /opt/node_modules/.bin:$PATH
WORKDIR /opt/app
COPY ./packages/strapi/. .
RUN pnpm -r build RUN pnpm -r build
RUN pnpm deploy --filter=strapi /prod/strapi RUN pnpm deploy --filter=strapi /prod/strapi
RUN ls -lah ./
RUN ls -lah ./packages
RUN ls -lah ./packages/strapi
RUN ls -lah /prod/strapi
# FROM base AS build
# RUN mkdir -p /prod/strapi
# WORKDIR /opt/
# COPY ./packages/strapi/package.json ./packages/strapi/pnpm-lock.yaml ./
# RUN pnpm fetch
# RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install -g node-gyp
# RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
# ENV PATH /opt/node_modules/.bin:$PATH
# WORKDIR /opt/app
# COPY ./packages/strapi/. .
# RUN pnpm -r build
# RUN pnpm deploy --filter=strapi /prod/strapi
FROM build AS dev FROM base AS dev
COPY --from=build /prod/strapi .
CMD ["run", "develop"] CMD ["run", "develop"]

41
d.worker.dockerfile Normal file
View File

@ -0,0 +1,41 @@
FROM node:20 as base
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
WORKDIR /app
RUN corepack enable && corepack prepare pnpm@9.5.0 --activate
FROM base AS install
COPY pnpm-lock.yaml .npmrc package.json .
COPY ./packages/types/ ./packages/types/
COPY ./packages/storage/ ./packages/storage/
COPY ./packages/scout/ ./packages/scout/
COPY ./packages/image/ ./packages/image/
COPY ./packages/utils/ ./packages/utils/
COPY ./packages/temporal-worker/ ./packages/temporal-worker/
COPY ./packages/temporal-workflows/ ./packages/temporal-workflows/
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --recursive --frozen-lockfile --prefer-offline
FROM install AS build
RUN pnpm -r build
RUN pnpm deploy --filter=temporal-worker --prod /prod/temporal-worker
# FROM base as build
# RUN mkdir -p /prod/worker
# COPY pnpm-workspace.yaml package.json pnpm-lock.yaml .npmrc .
# COPY ./packages/temporal-workflows/pnpm-lock.yaml ./packages/temporal-workflows/
# COPY ./packages/temporal-worker/pnpm-lock.yaml ./packages/temporal-worker/
# # RUN pnpm fetch
# RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --recursive --frozen-lockfile --prefer-offline
# COPY ./packages/temporal-workflows/ ./packages/temporal-workflows/
# COPY ./packages/temporal-worker/ ./packages/temporal-worker/
# RUN ls -la .
# RUN ls -la ./packages
# RUN ls -la ./packages/temporal-workflows
# RUN pnpm -r build
# RUN pnpm deploy --filter=temporal-worker --prod /prod/worker
FROM base as worker
COPY --from=build /prod/temporal-worker .
ENTRYPOINT ["pnpm", "start"]

View File

@ -25,40 +25,6 @@ importers:
specifier: ^5.5.3 specifier: ^5.5.3
version: 5.5.3 version: 5.5.3
../..: {}
../archive: {}
../boop: {}
../capture: {}
../image: {}
../infra: {}
../next: {}
../scout: {}
../storage: {}
../strapi: {}
../taco: {}
../temporal-worker: {}
../temporal-workflows: {}
../types: {}
../uppy: {}
../utils: {}
../video: {}
packages: packages:
'@cspotcode/source-map-support@0.8.1': '@cspotcode/source-map-support@0.8.1':

View File

@ -59,11 +59,12 @@
"react-hook-form": "^7.52.1", "react-hook-form": "^7.52.1",
"react-loading-skeleton": "^3.4.0", "react-loading-skeleton": "^3.4.0",
"react-toastify": "^9.1.3", "react-toastify": "^9.1.3",
"sass": "^1.77.8",
"sharp": "^0.33.4", "sharp": "^0.33.4",
"slugify": "^1.6.6", "slugify": "^1.6.6",
"styled-components": "5.3.3", "styled-components": "5.3.3",
"yup": "^1.4.0", "types": "workspace:*",
"types": "workspace:*" "yup": "^1.4.0"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^20.14.9", "@types/node": "^20.14.9",

View File

@ -121,13 +121,13 @@ importers:
version: 13.1.3 version: 13.1.3
next: next:
specifier: 14.0.4 specifier: 14.0.4
version: 14.0.4(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) version: 14.0.4(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8)
next-goatcounter: next-goatcounter:
specifier: ^1.0.5 specifier: ^1.0.5
version: 1.0.5(next@14.0.4(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) version: 1.0.5(next@14.0.4(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
nextjs-toploader: nextjs-toploader:
specifier: ^1.6.12 specifier: ^1.6.12
version: 1.6.12(next@14.0.4(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1) version: 1.6.12(next@14.0.4(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
plyr: plyr:
specifier: ^3.7.8 specifier: ^3.7.8
version: 3.7.8 version: 3.7.8
@ -155,6 +155,9 @@ importers:
react-toastify: react-toastify:
specifier: ^9.1.3 specifier: ^9.1.3
version: 9.1.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1) version: 9.1.3(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
sass:
specifier: ^1.77.8
version: 1.77.8
sharp: sharp:
specifier: ^0.33.4 specifier: ^0.33.4
version: 0.33.4 version: 0.33.4
@ -891,6 +894,10 @@ packages:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'} engines: {node: '>=8'}
anymatch@3.1.3:
resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
engines: {node: '>= 8'}
argparse@1.0.10: argparse@1.0.10:
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
@ -964,6 +971,10 @@ packages:
base64-js@1.5.1: base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
binary-extensions@2.3.0:
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
engines: {node: '>=8'}
bl@4.1.0: bl@4.1.0:
resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
@ -1020,6 +1031,10 @@ packages:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'} engines: {node: '>=10'}
chokidar@3.6.0:
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
engines: {node: '>= 8.10.0'}
chownr@1.1.4: chownr@1.1.4:
resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
@ -1400,6 +1415,11 @@ packages:
fs.realpath@1.0.0: fs.realpath@1.0.0:
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
function-bind@1.1.2: function-bind@1.1.2:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
@ -1519,6 +1539,9 @@ packages:
resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==} resolution: {integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==}
engines: {node: '>= 4'} engines: {node: '>= 4'}
immutable@4.3.6:
resolution: {integrity: sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ==}
import-fresh@3.3.0: import-fresh@3.3.0:
resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==}
engines: {node: '>=6'} engines: {node: '>=6'}
@ -1559,6 +1582,10 @@ packages:
is-bigint@1.0.4: is-bigint@1.0.4:
resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==}
is-binary-path@2.1.0:
resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
engines: {node: '>=8'}
is-boolean-object@1.1.2: is-boolean-object@1.1.2:
resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
@ -1855,6 +1882,10 @@ packages:
node-releases@2.0.14: node-releases@2.0.14:
resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==}
normalize-path@3.0.0:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'}
nprogress@0.2.0: nprogress@0.2.0:
resolution: {integrity: sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==} resolution: {integrity: sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==}
@ -2052,6 +2083,10 @@ packages:
resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
engines: {node: '>= 6'} engines: {node: '>= 6'}
readdirp@3.6.0:
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
engines: {node: '>=8.10.0'}
reflect.getprototypeof@1.0.6: reflect.getprototypeof@1.0.6:
resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==} resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
@ -2105,6 +2140,11 @@ packages:
resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
sass@1.77.8:
resolution: {integrity: sha512-4UHg6prsrycW20fqLGPShtEvo/WyHRVRHwOP4DzkUrObWoWI05QBSfzU71TVB7PFaL104TwNaHpjlWXAZbQiNQ==}
engines: {node: '>=14.0.0'}
hasBin: true
sax@1.4.1: sax@1.4.1:
resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==}
@ -3162,6 +3202,11 @@ snapshots:
dependencies: dependencies:
color-convert: 2.0.1 color-convert: 2.0.1
anymatch@3.1.3:
dependencies:
normalize-path: 3.0.0
picomatch: 2.3.1
argparse@1.0.10: argparse@1.0.10:
dependencies: dependencies:
sprintf-js: 1.0.3 sprintf-js: 1.0.3
@ -3274,6 +3319,8 @@ snapshots:
base64-js@1.5.1: {} base64-js@1.5.1: {}
binary-extensions@2.3.0: {}
bl@4.1.0: bl@4.1.0:
dependencies: dependencies:
buffer: 5.7.1 buffer: 5.7.1
@ -3342,6 +3389,18 @@ snapshots:
ansi-styles: 4.3.0 ansi-styles: 4.3.0
supports-color: 7.2.0 supports-color: 7.2.0
chokidar@3.6.0:
dependencies:
anymatch: 3.1.3
braces: 3.0.3
glob-parent: 5.1.2
is-binary-path: 2.1.0
is-glob: 4.0.3
normalize-path: 3.0.0
readdirp: 3.6.0
optionalDependencies:
fsevents: 2.3.3
chownr@1.1.4: {} chownr@1.1.4: {}
classnames@2.5.1: {} classnames@2.5.1: {}
@ -3628,7 +3687,7 @@ snapshots:
eslint: 8.57.0 eslint: 8.57.0
eslint-import-resolver-node: 0.3.9 eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0) eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0)
eslint-plugin-jsx-a11y: 6.9.0(eslint@8.57.0) eslint-plugin-jsx-a11y: 6.9.0(eslint@8.57.0)
eslint-plugin-react: 7.34.3(eslint@8.57.0) eslint-plugin-react: 7.34.3(eslint@8.57.0)
eslint-plugin-react-hooks: 4.6.2(eslint@8.57.0) eslint-plugin-react-hooks: 4.6.2(eslint@8.57.0)
@ -3652,7 +3711,7 @@ snapshots:
enhanced-resolve: 5.17.0 enhanced-resolve: 5.17.0
eslint: 8.57.0 eslint: 8.57.0
eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0) eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0) eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0)
fast-glob: 3.3.2 fast-glob: 3.3.2
get-tsconfig: 4.7.5 get-tsconfig: 4.7.5
is-core-module: 2.14.0 is-core-module: 2.14.0
@ -3674,7 +3733,7 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0): eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.3.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0):
dependencies: dependencies:
array-includes: 3.1.8 array-includes: 3.1.8
array.prototype.findlastindex: 1.2.5 array.prototype.findlastindex: 1.2.5
@ -3878,6 +3937,9 @@ snapshots:
fs.realpath@1.0.0: {} fs.realpath@1.0.0: {}
fsevents@2.3.3:
optional: true
function-bind@1.1.2: {} function-bind@1.1.2: {}
function.prototype.name@1.1.6: function.prototype.name@1.1.6:
@ -4006,6 +4068,8 @@ snapshots:
ignore@5.3.1: {} ignore@5.3.1: {}
immutable@4.3.6: {}
import-fresh@3.3.0: import-fresh@3.3.0:
dependencies: dependencies:
parent-module: 1.0.1 parent-module: 1.0.1
@ -4048,6 +4112,10 @@ snapshots:
dependencies: dependencies:
has-bigints: 1.0.2 has-bigints: 1.0.2
is-binary-path@2.1.0:
dependencies:
binary-extensions: 2.3.0
is-boolean-object@1.1.2: is-boolean-object@1.1.2:
dependencies: dependencies:
call-bind: 1.0.7 call-bind: 1.0.7
@ -4263,13 +4331,13 @@ snapshots:
natural-compare@1.4.0: {} natural-compare@1.4.0: {}
next-goatcounter@1.0.5(next@14.0.4(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): next-goatcounter@1.0.5(next@14.0.4(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies: dependencies:
next: 14.0.4(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next: 14.0.4(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8)
react: 18.3.1 react: 18.3.1
react-dom: 18.3.1(react@18.3.1) react-dom: 18.3.1(react@18.3.1)
next@14.0.4(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): next@14.0.4(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8):
dependencies: dependencies:
'@next/env': 14.0.4 '@next/env': 14.0.4
'@swc/helpers': 0.5.2 '@swc/helpers': 0.5.2
@ -4291,13 +4359,14 @@ snapshots:
'@next/swc-win32-arm64-msvc': 14.0.4 '@next/swc-win32-arm64-msvc': 14.0.4
'@next/swc-win32-ia32-msvc': 14.0.4 '@next/swc-win32-ia32-msvc': 14.0.4
'@next/swc-win32-x64-msvc': 14.0.4 '@next/swc-win32-x64-msvc': 14.0.4
sass: 1.77.8
transitivePeerDependencies: transitivePeerDependencies:
- '@babel/core' - '@babel/core'
- babel-plugin-macros - babel-plugin-macros
nextjs-toploader@1.6.12(next@14.0.4(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react-dom@18.3.1(react@18.3.1))(react@18.3.1): nextjs-toploader@1.6.12(next@14.0.4(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8))(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
dependencies: dependencies:
next: 14.0.4(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) next: 14.0.4(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(sass@1.77.8)
nprogress: 0.2.0 nprogress: 0.2.0
prop-types: 15.8.1 prop-types: 15.8.1
react: 18.3.1 react: 18.3.1
@ -4311,6 +4380,8 @@ snapshots:
node-releases@2.0.14: {} node-releases@2.0.14: {}
normalize-path@3.0.0: {}
nprogress@0.2.0: {} nprogress@0.2.0: {}
object-assign@4.1.1: {} object-assign@4.1.1: {}
@ -4525,6 +4596,10 @@ snapshots:
string_decoder: 1.3.0 string_decoder: 1.3.0
util-deprecate: 1.0.2 util-deprecate: 1.0.2
readdirp@3.6.0:
dependencies:
picomatch: 2.3.1
reflect.getprototypeof@1.0.6: reflect.getprototypeof@1.0.6:
dependencies: dependencies:
call-bind: 1.0.7 call-bind: 1.0.7
@ -4587,6 +4662,12 @@ snapshots:
es-errors: 1.3.0 es-errors: 1.3.0
is-regex: 1.1.4 is-regex: 1.1.4
sass@1.77.8:
dependencies:
chokidar: 3.6.0
immutable: 4.3.6
source-map-js: 1.2.0
sax@1.4.1: {} sax@1.4.1: {}
scheduler@0.23.2: scheduler@0.23.2:

View File

@ -37,7 +37,6 @@
"imapflow": "^1.0.160", "imapflow": "^1.0.160",
"limiter": "2.0.1", "limiter": "2.0.1",
"mailparser": "^3.7.1", "mailparser": "^3.7.1",
"next": "workspace:*",
"node-fetch": "^3.3.0", "node-fetch": "^3.3.0",
"nodemon": "^3.1.3", "nodemon": "^3.1.3",
"p-retry": "^5.1.2", "p-retry": "^5.1.2",
@ -48,12 +47,12 @@
"ts-node": "^10.9.2", "ts-node": "^10.9.2",
"tsx": "^4.7.2", "tsx": "^4.7.2",
"types": "workspace:^", "types": "workspace:^",
"typescript": "^5.4.5",
"xpath": "^0.0.34" "xpath": "^0.0.34"
}, },
"packageManager": "pnpm@9.2.0", "packageManager": "pnpm@9.2.0",
"devDependencies": { "devDependencies": {
"chai": "^5.1.0", "chai": "^5.1.0",
"mocha": "^10.4.0" "mocha": "^10.4.0",
"typescript": "^5.4.5"
} }
} }

View File

@ -65,9 +65,6 @@ importers:
mailparser: mailparser:
specifier: ^3.7.1 specifier: ^3.7.1
version: 3.7.1 version: 3.7.1
next:
specifier: workspace:*
version: link:../next
node-fetch: node-fetch:
specifier: ^3.3.0 specifier: ^3.3.0
version: 3.3.2 version: 3.3.2
@ -98,9 +95,6 @@ importers:
types: types:
specifier: workspace:^ specifier: workspace:^
version: link:../types version: link:../types
typescript:
specifier: ^5.4.5
version: 5.5.3
xpath: xpath:
specifier: ^0.0.34 specifier: ^0.0.34
version: 0.0.34 version: 0.0.34
@ -111,6 +105,9 @@ importers:
mocha: mocha:
specifier: ^10.4.0 specifier: ^10.4.0
version: 10.6.0 version: 10.6.0
typescript:
specifier: ^5.4.5
version: 5.5.3
packages: packages:

View File

@ -8,7 +8,7 @@ import { checkEmail } from './parsers.js'
// import { createStreamInDb } from './signals.js' // import { createStreamInDb } from './signals.js'
import { Email } from './imap.js' import { Email } from './imap.js'
import { Client, Connection } from '@temporalio/client' import { Client, Connection } from '@temporalio/client'
import { NotificationData, processEmail } from './temporal/workflows.js' import { NotificationData, processEmailNotification } from 'temporal-workflows'
import { FetchMessageObject } from 'imapflow' import { FetchMessageObject } from 'imapflow'
import { createId } from '@paralleldrive/cuid2' import { createId } from '@paralleldrive/cuid2'

View File

@ -1,5 +1,6 @@
{ {
"name": "storage", "name": "storage",
"type": "module",
"version": "1.0.0", "version": "1.0.0",
"description": "", "description": "",
"main": "index.js", "main": "index.js",

View File

@ -3,7 +3,7 @@ dotenv.config({
path: '../../.env', path: '../../.env',
}); });
import { S3Client, S3ClientConfig } from "@aws-sdk/client-s3"; import { S3Client, type S3ClientConfig } from "@aws-sdk/client-s3";
import { Upload } from "@aws-sdk/lib-storage"; import { Upload } from "@aws-sdk/lib-storage";
import { createId } from '@paralleldrive/cuid2'; import { createId } from '@paralleldrive/cuid2';
import { basename } from 'node:path'; import { basename } from 'node:path';

View File

@ -19,7 +19,12 @@
"@strapi/plugin-i18n": "4.25.3", "@strapi/plugin-i18n": "4.25.3",
"@strapi/plugin-users-permissions": "4.25.3", "@strapi/plugin-users-permissions": "4.25.3",
"@strapi/strapi": "4.25.3", "@strapi/strapi": "4.25.3",
"@strapi/utils": "^4.25.3",
"canvas": "^2.11.2", "canvas": "^2.11.2",
"date-fns": "^3.6.0",
"dotenv": "^16.4.5",
"lodash": "^4.17.21",
"node-fetch": "^2.7.0",
"pg": "8.8.0", "pg": "8.8.0",
"react": "^18.0.0", "react": "^18.0.0",
"react-dom": "^18.0.0", "react-dom": "^18.0.0",
@ -37,5 +42,6 @@
"node": "20.x.x", "node": "20.x.x",
"npm": ">=6.0.0" "npm": ">=6.0.0"
}, },
"packageManager": "pnpm@9.5.0",
"license": "MIT" "license": "MIT"
} }

View File

@ -32,9 +32,24 @@ importers:
'@strapi/strapi': '@strapi/strapi':
specifier: 4.25.3 specifier: 4.25.3
version: 4.25.3(@babel/runtime@7.24.7)(@codemirror/autocomplete@6.17.0(@codemirror/language@6.10.2)(@codemirror/state@6.4.1)(@codemirror/view@6.28.4)(@lezer/common@1.2.1))(@codemirror/language@6.10.2)(@codemirror/lint@6.8.1)(@codemirror/search@6.5.6)(@codemirror/state@6.4.1)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.28.4)(@swc/helpers@0.5.11)(@types/hoist-non-react-statics@3.3.5)(@types/node@20.14.10)(@types/react@18.3.3)(codemirror@5.65.16)(pg@8.8.0)(react-dom@18.3.1(react@18.3.1))(react-router-dom@5.3.4(react@18.3.1))(react@18.3.1)(redux@4.2.1)(styled-components@5.3.3(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react-is@18.3.1)(react@18.3.1))(terser@5.31.2)(type-fest@2.19.0) version: 4.25.3(@babel/runtime@7.24.7)(@codemirror/autocomplete@6.17.0(@codemirror/language@6.10.2)(@codemirror/state@6.4.1)(@codemirror/view@6.28.4)(@lezer/common@1.2.1))(@codemirror/language@6.10.2)(@codemirror/lint@6.8.1)(@codemirror/search@6.5.6)(@codemirror/state@6.4.1)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.28.4)(@swc/helpers@0.5.11)(@types/hoist-non-react-statics@3.3.5)(@types/node@20.14.10)(@types/react@18.3.3)(codemirror@5.65.16)(pg@8.8.0)(react-dom@18.3.1(react@18.3.1))(react-router-dom@5.3.4(react@18.3.1))(react@18.3.1)(redux@4.2.1)(styled-components@5.3.3(@babel/core@7.24.7)(react-dom@18.3.1(react@18.3.1))(react-is@18.3.1)(react@18.3.1))(terser@5.31.2)(type-fest@2.19.0)
'@strapi/utils':
specifier: ^4.25.3
version: 4.25.3
canvas: canvas:
specifier: ^2.11.2 specifier: ^2.11.2
version: 2.11.2 version: 2.11.2
date-fns:
specifier: ^3.6.0
version: 3.6.0
dotenv:
specifier: ^16.4.5
version: 16.4.5
lodash:
specifier: ^4.17.21
version: 4.17.21
node-fetch:
specifier: ^2.7.0
version: 2.7.0
pg: pg:
specifier: 8.8.0 specifier: 8.8.0
version: 8.8.0 version: 8.8.0
@ -2901,6 +2916,9 @@ packages:
resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==}
engines: {node: '>=0.11'} engines: {node: '>=0.11'}
date-fns@3.6.0:
resolution: {integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==}
debounce@1.2.1: debounce@1.2.1:
resolution: {integrity: sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==} resolution: {integrity: sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==}
@ -3118,6 +3136,10 @@ packages:
resolution: {integrity: sha512-05POuPJyPpO6jqzTNweQFfAyMSD4qa4lvsMOWyTRTdpHKy6nnnN+IYWaXF+lHivhBH/ufDKlR4IWCAN3oPnHuw==} resolution: {integrity: sha512-05POuPJyPpO6jqzTNweQFfAyMSD4qa4lvsMOWyTRTdpHKy6nnnN+IYWaXF+lHivhBH/ufDKlR4IWCAN3oPnHuw==}
engines: {node: '>=12'} engines: {node: '>=12'}
dotenv@16.4.5:
resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==}
engines: {node: '>=12'}
duplexer@0.1.2: duplexer@0.1.2:
resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==}
@ -10544,6 +10566,8 @@ snapshots:
dependencies: dependencies:
'@babel/runtime': 7.24.7 '@babel/runtime': 7.24.7
date-fns@3.6.0: {}
debounce@1.2.1: {} debounce@1.2.1: {}
debug@2.6.9: debug@2.6.9:
@ -10744,6 +10768,8 @@ snapshots:
dotenv@14.2.0: {} dotenv@14.2.0: {}
dotenv@16.4.5: {}
duplexer@0.1.2: {} duplexer@0.1.2: {}
eastasianwidth@0.2.0: {} eastasianwidth@0.2.0: {}

View File

@ -0,0 +1,13 @@
# strapi extensions
note by CJ
Reminder: Plugins don't go here. Plugins are added using pnpm. example: `pnpm add strapi-chatgpt`
This extensions directory is the place for plugin override code.
@see https://docs.strapi.io/dev-docs/plugins-extension
We are using overrides patch in patreon support. In ./users-permissions/services/providers-registry.js we make some changes. When user logs in via Patreon, we determine if the Patreon account is a Futureporn supporter. Based on that information, we update the user role to one of 'Authenticated' or 'Patron'.

View File

@ -1,2 +0,0 @@
node_modules/
.eslintrc.js

View File

@ -1,14 +0,0 @@
module.exports = {
root: true,
overrides: [
{
files: ['admin/**/*'],
extends: ['custom/front'],
},
{
files: ['**/*'],
excludedFiles: ['admin/**/*'],
extends: ['custom/back'],
},
],
};

View File

@ -1,22 +0,0 @@
Copyright (c) 2015-present Strapi Solutions SAS
Portions of the Strapi software are licensed as follows:
* All software that resides under an "ee/" directory (the “EE Software”), if that directory exists, is licensed under the license defined in "ee/LICENSE".
* All software outside of the above-mentioned directories or restrictions above is available under the "MIT Expat" license as set forth below.
MIT Expat License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1 +0,0 @@
# Strapi plugin

View File

@ -1,41 +0,0 @@
const getMethodColor = (verb) => {
switch (verb) {
case 'POST': {
return {
text: 'success600',
border: 'success200',
background: 'success100',
};
}
case 'GET': {
return {
text: 'secondary600',
border: 'secondary200',
background: 'secondary100',
};
}
case 'PUT': {
return {
text: 'warning600',
border: 'warning200',
background: 'warning100',
};
}
case 'DELETE': {
return {
text: 'danger600',
border: 'danger200',
background: 'danger100',
};
}
default: {
return {
text: 'neutral600',
border: 'neutral200',
background: 'neutral100',
};
}
}
};
export default getMethodColor;

View File

@ -1,72 +0,0 @@
import React from 'react';
import { Box, Flex, Typography } from '@strapi/design-system';
import map from 'lodash/map';
import tail from 'lodash/tail';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import styled from 'styled-components';
import getMethodColor from './getMethodColor';
const MethodBox = styled(Box)`
margin: -1px;
border-radius: ${({ theme }) => theme.spaces[1]} 0 0 ${({ theme }) => theme.spaces[1]};
`;
function BoundRoute({ route }) {
const { formatMessage } = useIntl();
const { method, handler: title, path } = route;
const formattedRoute = path ? tail(path.split('/')) : [];
const [controller = '', action = ''] = title ? title.split('.') : [];
const colors = getMethodColor(route.method);
return (
<Flex direction="column" alignItems="stretch" gap={2}>
<Typography variant="delta" as="h3">
{formatMessage({
id: 'users-permissions.BoundRoute.title',
defaultMessage: 'Bound route to',
})}
&nbsp;
<span>{controller}</span>
<Typography variant="delta" textColor="primary600">
.{action}
</Typography>
</Typography>
<Flex hasRadius background="neutral0" borderColor="neutral200" gap={0}>
<MethodBox background={colors.background} borderColor={colors.border} padding={2}>
<Typography fontWeight="bold" textColor={colors.text}>
{method}
</Typography>
</MethodBox>
<Box paddingLeft={2} paddingRight={2}>
{map(formattedRoute, (value) => (
<Typography key={value} textColor={value.includes(':') ? 'neutral600' : 'neutral900'}>
/{value}
</Typography>
))}
</Box>
</Flex>
</Flex>
);
}
BoundRoute.defaultProps = {
route: {
handler: 'Nocontroller.error',
method: 'GET',
path: '/there-is-no-path',
},
};
BoundRoute.propTypes = {
route: PropTypes.shape({
handler: PropTypes.string,
method: PropTypes.string,
path: PropTypes.string,
}),
};
export default BoundRoute;

View File

@ -1,123 +0,0 @@
/**
*
* Input
*
*/
import React from 'react';
import { TextInput, ToggleInput } from '@strapi/design-system';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
const Input = ({
description,
disabled,
intlLabel,
error,
name,
onChange,
placeholder,
providerToEditName,
type,
value,
}) => {
const { formatMessage } = useIntl();
const inputValue =
name === 'noName'
? `${window.strapi.backendURL}/api/connect/${providerToEditName}/callback`
: value;
const label = formatMessage(
{ id: intlLabel.id, defaultMessage: intlLabel.defaultMessage },
{ provider: providerToEditName, ...intlLabel.values }
);
const hint = description
? formatMessage(
{ id: description.id, defaultMessage: description.defaultMessage },
{ provider: providerToEditName, ...description.values }
)
: '';
if (type === 'bool') {
return (
<ToggleInput
aria-label={name}
checked={value}
disabled={disabled}
hint={hint}
label={label}
name={name}
offLabel={formatMessage({
id: 'app.components.ToggleCheckbox.off-label',
defaultMessage: 'Off',
})}
onLabel={formatMessage({
id: 'app.components.ToggleCheckbox.on-label',
defaultMessage: 'On',
})}
onChange={(e) => {
onChange({ target: { name, value: e.target.checked } });
}}
/>
);
}
const formattedPlaceholder = placeholder
? formatMessage(
{ id: placeholder.id, defaultMessage: placeholder.defaultMessage },
{ ...placeholder.values }
)
: '';
const errorMessage = error ? formatMessage({ id: error, defaultMessage: error }) : '';
return (
<TextInput
aria-label={name}
disabled={disabled}
error={errorMessage}
label={label}
name={name}
onChange={onChange}
placeholder={formattedPlaceholder}
type={type}
value={inputValue}
/>
);
};
Input.defaultProps = {
description: null,
disabled: false,
error: '',
placeholder: null,
value: '',
};
Input.propTypes = {
description: PropTypes.shape({
id: PropTypes.string.isRequired,
defaultMessage: PropTypes.string.isRequired,
values: PropTypes.object,
}),
disabled: PropTypes.bool,
error: PropTypes.string,
intlLabel: PropTypes.shape({
id: PropTypes.string.isRequired,
defaultMessage: PropTypes.string.isRequired,
values: PropTypes.object,
}).isRequired,
name: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
placeholder: PropTypes.shape({
id: PropTypes.string.isRequired,
defaultMessage: PropTypes.string.isRequired,
values: PropTypes.object,
}),
providerToEditName: PropTypes.string.isRequired,
type: PropTypes.string.isRequired,
value: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
};
export default Input;

View File

@ -1,126 +0,0 @@
/**
*
* FormModal
*
*/
import React from 'react';
import {
Button,
Flex,
Grid,
GridItem,
ModalBody,
ModalFooter,
ModalHeader,
ModalLayout,
} from '@strapi/design-system';
import { Breadcrumbs, Crumb } from '@strapi/design-system/v2';
import { Form } from '@strapi/helper-plugin';
import { Formik } from 'formik';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import Input from './Input';
const FormModal = ({
headerBreadcrumbs,
initialData,
isSubmiting,
layout,
isOpen,
onSubmit,
onToggle,
providerToEditName,
}) => {
const { formatMessage } = useIntl();
if (!isOpen) {
return null;
}
return (
<ModalLayout onClose={onToggle} labelledBy="title">
<ModalHeader>
<Breadcrumbs label={headerBreadcrumbs.join(', ')}>
{headerBreadcrumbs.map((crumb, index, arr) => (
<Crumb isCurrent={index === arr.length - 1} key={crumb}>
{crumb}
</Crumb>
))}
</Breadcrumbs>
</ModalHeader>
<Formik
onSubmit={(values) => onSubmit(values)}
initialValues={initialData}
validationSchema={layout.schema}
validateOnChange={false}
>
{({ errors, handleChange, values }) => {
return (
<Form>
<ModalBody>
<Flex direction="column" alignItems="stretch" gap={1}>
<Grid gap={5}>
{layout.form.map((row) => {
return row.map((input) => {
return (
<GridItem key={input.name} col={input.size} xs={12}>
<Input
{...input}
error={errors[input.name]}
onChange={handleChange}
value={values[input.name]}
providerToEditName={providerToEditName}
/>
</GridItem>
);
});
})}
</Grid>
</Flex>
</ModalBody>
<ModalFooter
startActions={
<Button variant="tertiary" onClick={onToggle} type="button">
{formatMessage({
id: 'app.components.Button.cancel',
defaultMessage: 'Cancel',
})}
</Button>
}
endActions={
<Button type="submit" loading={isSubmiting}>
{formatMessage({ id: 'global.save', defaultMessage: 'Save' })}
</Button>
}
/>
</Form>
);
}}
</Formik>
</ModalLayout>
);
};
FormModal.defaultProps = {
initialData: null,
providerToEditName: null,
};
FormModal.propTypes = {
headerBreadcrumbs: PropTypes.arrayOf(PropTypes.string).isRequired,
initialData: PropTypes.object,
layout: PropTypes.shape({
form: PropTypes.arrayOf(PropTypes.array),
schema: PropTypes.object,
}).isRequired,
isOpen: PropTypes.bool.isRequired,
isSubmiting: PropTypes.bool.isRequired,
onSubmit: PropTypes.func.isRequired,
onToggle: PropTypes.func.isRequired,
providerToEditName: PropTypes.string,
};
export default FormModal;

View File

@ -1,30 +0,0 @@
import { Box } from '@strapi/design-system';
import styled, { css } from 'styled-components';
const activeCheckboxWrapperStyles = css`
background: ${(props) => props.theme.colors.primary100};
svg {
opacity: 1;
}
`;
const CheckboxWrapper = styled(Box)`
display: flex;
justify-content: space-between;
align-items: center;
svg {
opacity: 0;
path {
fill: ${(props) => props.theme.colors.primary600};
}
}
/* Show active style both on hover and when the action is selected */
${(props) => props.isActive && activeCheckboxWrapperStyles}
&:hover {
${activeCheckboxWrapperStyles}
}
`;
export default CheckboxWrapper;

View File

@ -1,131 +0,0 @@
import React, { useCallback, useMemo } from 'react';
import {
Box,
Checkbox,
Flex,
Typography,
Grid,
GridItem,
VisuallyHidden,
} from '@strapi/design-system';
import { Cog as CogIcon } from '@strapi/icons';
import get from 'lodash/get';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import styled from 'styled-components';
import { useUsersPermissions } from '../../../contexts/UsersPermissionsContext';
import CheckboxWrapper from './CheckboxWrapper';
const Border = styled.div`
flex: 1;
align-self: center;
border-top: 1px solid ${({ theme }) => theme.colors.neutral150};
`;
const SubCategory = ({ subCategory }) => {
const { formatMessage } = useIntl();
const { onChange, onChangeSelectAll, onSelectedAction, selectedAction, modifiedData } =
useUsersPermissions();
const currentScopedModifiedData = useMemo(() => {
return get(modifiedData, subCategory.name, {});
}, [modifiedData, subCategory]);
const hasAllActionsSelected = useMemo(() => {
return Object.values(currentScopedModifiedData).every((action) => action.enabled === true);
}, [currentScopedModifiedData]);
const hasSomeActionsSelected = useMemo(() => {
return (
Object.values(currentScopedModifiedData).some((action) => action.enabled === true) &&
!hasAllActionsSelected
);
}, [currentScopedModifiedData, hasAllActionsSelected]);
const handleChangeSelectAll = useCallback(
({ target: { name } }) => {
onChangeSelectAll({ target: { name, value: !hasAllActionsSelected } });
},
[hasAllActionsSelected, onChangeSelectAll]
);
const isActionSelected = useCallback(
(actionName) => {
return selectedAction === actionName;
},
[selectedAction]
);
return (
<Box>
<Flex justifyContent="space-between" alignItems="center">
<Box paddingRight={4}>
<Typography variant="sigma" textColor="neutral600">
{subCategory.label}
</Typography>
</Box>
<Border />
<Box paddingLeft={4}>
<Checkbox
name={subCategory.name}
value={hasAllActionsSelected}
onValueChange={(value) =>
handleChangeSelectAll({ target: { name: subCategory.name, value } })
}
indeterminate={hasSomeActionsSelected}
>
{formatMessage({ id: 'app.utils.select-all', defaultMessage: 'Select all' })}
</Checkbox>
</Box>
</Flex>
<Flex paddingTop={6} paddingBottom={6}>
<Grid gap={2} style={{ flex: 1 }}>
{subCategory.actions.map((action) => {
const name = `${action.name}.enabled`;
return (
<GridItem col={6} key={action.name}>
<CheckboxWrapper isActive={isActionSelected(action.name)} padding={2} hasRadius>
<Checkbox
value={get(modifiedData, name, false)}
name={name}
onValueChange={(value) => onChange({ target: { name, value } })}
>
{action.label}
</Checkbox>
<button
type="button"
onClick={() => onSelectedAction(action.name)}
style={{ display: 'inline-flex', alignItems: 'center' }}
>
<VisuallyHidden as="span">
{formatMessage(
{
id: 'app.utils.show-bound-route',
defaultMessage: 'Show bound route for {route}',
},
{
route: action.name,
}
)}
</VisuallyHidden>
<CogIcon />
</button>
</CheckboxWrapper>
</GridItem>
);
})}
</Grid>
</Flex>
</Box>
);
};
SubCategory.propTypes = {
subCategory: PropTypes.object.isRequired,
};
export default SubCategory;

View File

@ -1,55 +0,0 @@
import React, { useMemo } from 'react';
import { Box } from '@strapi/design-system';
import sortBy from 'lodash/sortBy';
import PropTypes from 'prop-types';
import SubCategory from './SubCategory';
const PermissionRow = ({ name, permissions }) => {
const subCategories = useMemo(() => {
return sortBy(
Object.values(permissions.controllers).reduce((acc, curr, index) => {
const currentName = `${name}.controllers.${Object.keys(permissions.controllers)[index]}`;
const actions = sortBy(
Object.keys(curr).reduce((acc, current) => {
return [
...acc,
{
...curr[current],
label: current,
name: `${currentName}.${current}`,
},
];
}, []),
'label'
);
return [
...acc,
{
actions,
label: Object.keys(permissions.controllers)[index],
name: currentName,
},
];
}, []),
'label'
);
}, [name, permissions]);
return (
<Box padding={6}>
{subCategories.map((subCategory) => (
<SubCategory key={subCategory.name} subCategory={subCategory} />
))}
</Box>
);
};
PermissionRow.propTypes = {
name: PropTypes.string.isRequired,
permissions: PropTypes.object.isRequired,
};
export default PermissionRow;

View File

@ -1,57 +0,0 @@
import React, { useReducer } from 'react';
import { Accordion, AccordionContent, AccordionToggle, Box, Flex } from '@strapi/design-system';
import { useIntl } from 'react-intl';
import { useUsersPermissions } from '../../contexts/UsersPermissionsContext';
import formatPluginName from '../../utils/formatPluginName';
import init from './init';
import PermissionRow from './PermissionRow';
import { initialState, reducer } from './reducer';
const Permissions = () => {
const { modifiedData } = useUsersPermissions();
const { formatMessage } = useIntl();
const [{ collapses }, dispatch] = useReducer(reducer, initialState, (state) =>
init(state, modifiedData)
);
const handleToggle = (index) =>
dispatch({
type: 'TOGGLE_COLLAPSE',
index,
});
return (
<Flex direction="column" alignItems="stretch" gap={1}>
{collapses.map((collapse, index) => (
<Accordion
expanded={collapse.isOpen}
onToggle={() => handleToggle(index)}
key={collapse.name}
variant={index % 2 === 0 ? 'secondary' : undefined}
>
<AccordionToggle
title={formatPluginName(collapse.name)}
description={formatMessage(
{
id: 'users-permissions.Plugin.permissions.plugins.description',
defaultMessage: 'Define all allowed actions for the {name} plugin.',
},
{ name: collapse.name }
)}
variant={index % 2 ? 'primary' : 'secondary'}
/>
<AccordionContent>
<Box>
<PermissionRow permissions={modifiedData[collapse.name]} name={collapse.name} />
</Box>
</AccordionContent>
</Accordion>
))}
</Flex>
);
};
export default Permissions;

View File

@ -1,9 +0,0 @@
const init = (initialState, permissions) => {
const collapses = Object.keys(permissions)
.sort()
.map((name) => ({ name, isOpen: false }));
return { ...initialState, collapses };
};
export default init;

View File

@ -1,27 +0,0 @@
import produce from 'immer';
const initialState = {
collapses: [],
};
const reducer = (state, action) =>
// eslint-disable-next-line consistent-return
produce(state, (draftState) => {
switch (action.type) {
case 'TOGGLE_COLLAPSE': {
draftState.collapses = state.collapses.map((collapse, index) => {
if (index === action.index) {
return { ...collapse, isOpen: !collapse.isOpen };
}
return { ...collapse, isOpen: false };
});
break;
}
default:
return draftState;
}
});
export { initialState, reducer };

View File

@ -1,62 +0,0 @@
import React from 'react';
import { Flex, GridItem, Typography } from '@strapi/design-system';
import get from 'lodash/get';
import isEmpty from 'lodash/isEmpty';
import without from 'lodash/without';
import { useIntl } from 'react-intl';
import { useUsersPermissions } from '../../contexts/UsersPermissionsContext';
import BoundRoute from '../BoundRoute';
const Policies = () => {
const { formatMessage } = useIntl();
const { selectedAction, routes } = useUsersPermissions();
const path = without(selectedAction.split('.'), 'controllers');
const controllerRoutes = get(routes, path[0]);
const pathResolved = path.slice(1).join('.');
const displayedRoutes = isEmpty(controllerRoutes)
? []
: controllerRoutes.filter((o) => o.handler.endsWith(pathResolved));
return (
<GridItem
col={5}
background="neutral150"
paddingTop={6}
paddingBottom={6}
paddingLeft={7}
paddingRight={7}
style={{ minHeight: '100%' }}
>
{selectedAction ? (
<Flex direction="column" alignItems="stretch" gap={2}>
{displayedRoutes.map((route, key) => (
// eslint-disable-next-line react/no-array-index-key
<BoundRoute key={key} route={route} />
))}
</Flex>
) : (
<Flex direction="column" alignItems="stretch" gap={2}>
<Typography variant="delta" as="h3">
{formatMessage({
id: 'users-permissions.Policies.header.title',
defaultMessage: 'Advanced settings',
})}
</Typography>
<Typography as="p" textColor="neutral600">
{formatMessage({
id: 'users-permissions.Policies.header.hint',
defaultMessage:
"Select the application's actions or the plugin's actions and click on the cog icon to display the bound route",
})}
</Typography>
</Flex>
)}
</GridItem>
);
};
export default Policies;

View File

@ -1,95 +0,0 @@
import React, { forwardRef, memo, useImperativeHandle, useReducer } from 'react';
import { Flex, Grid, GridItem, Typography } from '@strapi/design-system';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import { UsersPermissionsProvider } from '../../contexts/UsersPermissionsContext';
import getTrad from '../../utils/getTrad';
import Permissions from '../Permissions';
import Policies from '../Policies';
import init from './init';
import reducer, { initialState } from './reducer';
const UsersPermissions = forwardRef(({ permissions, routes }, ref) => {
const { formatMessage } = useIntl();
const [state, dispatch] = useReducer(reducer, initialState, (state) =>
init(state, permissions, routes)
);
useImperativeHandle(ref, () => ({
getPermissions() {
return {
permissions: state.modifiedData,
};
},
resetForm() {
dispatch({ type: 'ON_RESET' });
},
setFormAfterSubmit() {
dispatch({ type: 'ON_SUBMIT_SUCCEEDED' });
},
}));
const handleChange = ({ target: { name, value } }) =>
dispatch({
type: 'ON_CHANGE',
keys: name.split('.'),
value: value === 'empty__string_value' ? '' : value,
});
const handleChangeSelectAll = ({ target: { name, value } }) =>
dispatch({
type: 'ON_CHANGE_SELECT_ALL',
keys: name.split('.'),
value,
});
const handleSelectedAction = (actionToSelect) =>
dispatch({
type: 'SELECT_ACTION',
actionToSelect,
});
const providerValue = {
...state,
onChange: handleChange,
onChangeSelectAll: handleChangeSelectAll,
onSelectedAction: handleSelectedAction,
};
return (
<UsersPermissionsProvider value={providerValue}>
<Grid gap={0} shadow="filterShadow" hasRadius background="neutral0">
<GridItem col={7} paddingTop={6} paddingBottom={6} paddingLeft={7} paddingRight={7}>
<Flex direction="column" alignItems="stretch" gap={6}>
<Flex direction="column" alignItems="stretch" gap={2}>
<Typography variant="delta" as="h2">
{formatMessage({
id: getTrad('Plugins.header.title'),
defaultMessage: 'Permissions',
})}
</Typography>
<Typography as="p" textColor="neutral600">
{formatMessage({
id: getTrad('Plugins.header.description'),
defaultMessage: 'Only actions bound by a route are listed below.',
})}
</Typography>
</Flex>
<Permissions />
</Flex>
</GridItem>
<Policies />
</Grid>
</UsersPermissionsProvider>
);
});
UsersPermissions.propTypes = {
permissions: PropTypes.object.isRequired,
routes: PropTypes.object.isRequired,
};
export default memo(UsersPermissions);

View File

@ -1,10 +0,0 @@
const init = (state, permissions, routes) => {
return {
...state,
initialData: permissions,
modifiedData: permissions,
routes,
};
};
export default init;

View File

@ -1,62 +0,0 @@
/* eslint-disable consistent-return */
import produce from 'immer';
import get from 'lodash/get';
import set from 'lodash/set';
import take from 'lodash/take';
export const initialState = {
initialData: {},
modifiedData: {},
routes: {},
selectedAction: '',
policies: [],
};
const reducer = (state, action) =>
produce(state, (draftState) => {
switch (action.type) {
case 'ON_CHANGE': {
const keysLength = action.keys.length;
const isChangingCheckbox = action.keys[keysLength - 1] === 'enabled';
if (action.value && isChangingCheckbox) {
const selectedAction = take(action.keys, keysLength - 1).join('.');
draftState.selectedAction = selectedAction;
}
set(draftState, ['modifiedData', ...action.keys], action.value);
break;
}
case 'ON_CHANGE_SELECT_ALL': {
const pathToValue = ['modifiedData', ...action.keys];
const oldValues = get(state, pathToValue, {});
const updatedValues = Object.keys(oldValues).reduce((acc, current) => {
acc[current] = { ...oldValues[current], enabled: action.value };
return acc;
}, {});
set(draftState, pathToValue, updatedValues);
break;
}
case 'ON_RESET': {
draftState.modifiedData = state.initialData;
break;
}
case 'ON_SUBMIT_SUCCEEDED': {
draftState.initialData = state.modifiedData;
break;
}
case 'SELECT_ACTION': {
const { actionToSelect } = action;
draftState.selectedAction = actionToSelect === state.selectedAction ? '' : actionToSelect;
break;
}
default:
return draftState;
}
});
export default reducer;

View File

@ -1,18 +0,0 @@
import React, { createContext, useContext } from 'react';
import PropTypes from 'prop-types';
const UsersPermissions = createContext({});
const UsersPermissionsProvider = ({ children, value }) => {
return <UsersPermissions.Provider value={value}>{children}</UsersPermissions.Provider>;
};
const useUsersPermissions = () => useContext(UsersPermissions);
UsersPermissionsProvider.propTypes = {
children: PropTypes.node.isRequired,
value: PropTypes.object.isRequired,
};
export { UsersPermissions, UsersPermissionsProvider, useUsersPermissions };

View File

@ -1,5 +0,0 @@
// eslint-disable-next-line import/prefer-default-export
export { default as useForm } from './useForm';
export { default as useRolesList } from './useRolesList';
export * from './usePlugins';
export { default as useFetchRole } from './useFetchRole';

View File

@ -1,67 +0,0 @@
import { useCallback, useEffect, useReducer, useRef } from 'react';
import { useFetchClient, useNotification } from '@strapi/helper-plugin';
import pluginId from '../../pluginId';
import reducer, { initialState } from './reducer';
const useFetchRole = (id) => {
const [state, dispatch] = useReducer(reducer, initialState);
const toggleNotification = useNotification();
const isMounted = useRef(null);
const { get } = useFetchClient();
useEffect(() => {
isMounted.current = true;
if (id) {
fetchRole(id);
} else {
dispatch({
type: 'GET_DATA_SUCCEEDED',
role: {},
});
}
return () => (isMounted.current = false);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [id]);
const fetchRole = async (roleId) => {
try {
const {
data: { role },
} = await get(`/${pluginId}/roles/${roleId}`);
// Prevent updating state on an unmounted component
if (isMounted.current) {
dispatch({
type: 'GET_DATA_SUCCEEDED',
role,
});
}
} catch (err) {
console.error(err);
dispatch({
type: 'GET_DATA_ERROR',
});
toggleNotification({
type: 'warning',
message: { id: 'notification.error' },
});
}
};
const handleSubmitSucceeded = useCallback((data) => {
dispatch({
type: 'ON_SUBMIT_SUCCEEDED',
...data,
});
}, []);
return { ...state, onSubmitSucceeded: handleSubmitSucceeded };
};
export default useFetchRole;

View File

@ -1,31 +0,0 @@
/* eslint-disable consistent-return */
import produce from 'immer';
export const initialState = {
role: {},
isLoading: true,
};
const reducer = (state, action) =>
produce(state, (draftState) => {
switch (action.type) {
case 'GET_DATA_SUCCEEDED': {
draftState.role = action.role;
draftState.isLoading = false;
break;
}
case 'GET_DATA_ERROR': {
draftState.isLoading = false;
break;
}
case 'ON_SUBMIT_SUCCEEDED': {
draftState.role.name = action.name;
draftState.role.description = action.description;
break;
}
default:
return draftState;
}
});
export default reducer;

View File

@ -1,70 +0,0 @@
import { useCallback, useEffect, useReducer, useRef } from 'react';
import { useFetchClient, useNotification, useRBAC } from '@strapi/helper-plugin';
import { getRequestURL } from '../../utils';
import reducer, { initialState } from './reducer';
const useUserForm = (endPoint, permissions) => {
const { isLoading: isLoadingForPermissions, allowedActions } = useRBAC(permissions);
const [{ isLoading, modifiedData }, dispatch] = useReducer(reducer, initialState);
const toggleNotification = useNotification();
const isMounted = useRef(true);
const { get } = useFetchClient();
useEffect(() => {
const getData = async () => {
try {
dispatch({
type: 'GET_DATA',
});
const { data } = await get(getRequestURL(endPoint));
dispatch({
type: 'GET_DATA_SUCCEEDED',
data,
});
} catch (err) {
// The user aborted the request
if (isMounted.current) {
dispatch({
type: 'GET_DATA_ERROR',
});
console.error(err);
toggleNotification({
type: 'warning',
message: { id: 'notification.error' },
});
}
}
};
if (!isLoadingForPermissions) {
getData();
}
return () => {
isMounted.current = false;
};
}, [isLoadingForPermissions, endPoint, get, toggleNotification]);
const dispatchSubmitSucceeded = useCallback((data) => {
dispatch({
type: 'ON_SUBMIT_SUCCEEDED',
data,
});
}, []);
return {
allowedActions,
dispatchSubmitSucceeded,
isLoading,
isLoadingForPermissions,
modifiedData,
};
};
export default useUserForm;

View File

@ -1,40 +0,0 @@
import produce from 'immer';
const initialState = {
isLoading: true,
modifiedData: {},
};
const reducer = (state, action) =>
// eslint-disable-next-line consistent-return
produce(state, (draftState) => {
switch (action.type) {
case 'GET_DATA': {
draftState.isLoading = true;
draftState.modifiedData = {};
break;
}
case 'GET_DATA_SUCCEEDED': {
draftState.isLoading = false;
draftState.modifiedData = action.data;
break;
}
case 'GET_DATA_ERROR': {
draftState.isLoading = true;
break;
}
case 'ON_SUBMIT_SUCCEEDED': {
draftState.modifiedData = action.data;
break;
}
default: {
return draftState;
}
}
});
export default reducer;
export { initialState };

View File

@ -1,71 +0,0 @@
import { useEffect } from 'react';
import { useNotification, useFetchClient, useAPIErrorHandler } from '@strapi/helper-plugin';
import { useQueries } from 'react-query';
import pluginId from '../pluginId';
import { cleanPermissions, getTrad } from '../utils';
export const usePlugins = () => {
const toggleNotification = useNotification();
const { get } = useFetchClient();
const { formatAPIError } = useAPIErrorHandler(getTrad);
const [
{
data: permissions,
isLoading: isLoadingPermissions,
error: permissionsError,
refetch: refetchPermissions,
},
{ data: routes, isLoading: isLoadingRoutes, error: routesError, refetch: refetchRoutes },
] = useQueries([
{
queryKey: [pluginId, 'permissions'],
async queryFn() {
const res = await get(`/${pluginId}/permissions`);
return res.data.permissions;
},
},
{
queryKey: [pluginId, 'routes'],
async queryFn() {
const res = await get(`/${pluginId}/routes`);
return res.data.routes;
},
},
]);
const refetchQueries = async () => {
await Promise.all([refetchPermissions(), refetchRoutes()]);
};
useEffect(() => {
if (permissionsError) {
toggleNotification({
type: 'warning',
message: formatAPIError(permissionsError),
});
}
}, [toggleNotification, permissionsError, formatAPIError]);
useEffect(() => {
if (routesError) {
toggleNotification({
type: 'warning',
message: formatAPIError(routesError),
});
}
}, [toggleNotification, routesError, formatAPIError]);
const isLoading = isLoadingPermissions || isLoadingRoutes;
return {
permissions: permissions ? cleanPermissions(permissions) : {},
routes: routes ?? {},
getData: refetchQueries,
isLoading,
};
};

View File

@ -1,65 +0,0 @@
import { useCallback, useEffect, useReducer, useRef } from 'react';
import { useFetchClient, useNotification } from '@strapi/helper-plugin';
import get from 'lodash/get';
import pluginId from '../../pluginId';
import init from './init';
import reducer, { initialState } from './reducer';
const useRolesList = (shouldFetchData = true) => {
const [{ roles, isLoading }, dispatch] = useReducer(reducer, initialState, () =>
init(initialState, shouldFetchData)
);
const toggleNotification = useNotification();
const isMounted = useRef(true);
const fetchClient = useFetchClient();
const fetchRolesList = useCallback(async () => {
try {
dispatch({
type: 'GET_DATA',
});
const {
data: { roles },
} = await fetchClient.get(`/${pluginId}/roles`);
dispatch({
type: 'GET_DATA_SUCCEEDED',
data: roles,
});
} catch (err) {
const message = get(err, ['response', 'payload', 'message'], 'An error occured');
if (isMounted.current) {
dispatch({
type: 'GET_DATA_ERROR',
});
if (message !== 'Forbidden') {
toggleNotification({
type: 'warning',
message,
});
}
}
}
}, [fetchClient, toggleNotification]);
useEffect(() => {
if (shouldFetchData) {
fetchRolesList();
}
return () => {
isMounted.current = false;
};
}, [shouldFetchData, fetchRolesList]);
return { roles, isLoading, getData: fetchRolesList };
};
export default useRolesList;

View File

@ -1,5 +0,0 @@
const init = (initialState, shouldFetchData) => {
return { ...initialState, isLoading: shouldFetchData };
};
export default init;

View File

@ -1,31 +0,0 @@
/* eslint-disable consistent-return */
import produce from 'immer';
export const initialState = {
roles: [],
isLoading: true,
};
const reducer = (state, action) =>
produce(state, (draftState) => {
switch (action.type) {
case 'GET_DATA': {
draftState.isLoading = true;
draftState.roles = [];
break;
}
case 'GET_DATA_SUCCEEDED': {
draftState.roles = action.data;
draftState.isLoading = false;
break;
}
case 'GET_DATA_ERROR': {
draftState.isLoading = false;
break;
}
default:
return draftState;
}
});
export default reducer;

View File

@ -1,125 +0,0 @@
// NOTE TO PLUGINS DEVELOPERS:
// If you modify this file by adding new options to the plugin entry point
// Here's the file: strapi/docs/3.0.0-beta.x/plugin-development/frontend-field-api.md
// Here's the file: strapi/docs/3.0.0-beta.x/guides/registering-a-field-in-admin.md
// Also the strapi-generate-plugins/files/admin/src/index.js needs to be updated
// IF THE DOC IS NOT UPDATED THE PULL REQUEST WILL NOT BE MERGED
import { prefixPluginTranslations } from '@strapi/helper-plugin';
import pluginPkg from '../../package.json';
import pluginPermissions from './permissions';
import pluginId from './pluginId';
import getTrad from './utils/getTrad';
const name = pluginPkg.strapi.name;
export default {
register(app) {
// Create the plugin's settings section
app.createSettingSection(
{
id: pluginId,
intlLabel: {
id: getTrad('Settings.section-label'),
defaultMessage: 'Users & Permissions plugin',
},
},
[
{
intlLabel: {
id: 'global.roles',
defaultMessage: 'Roles',
},
id: 'roles',
to: `/settings/${pluginId}/roles`,
async Component() {
const component = await import(
/* webpackChunkName: "users-roles-settings-page" */ './pages/Roles'
);
return component;
},
permissions: pluginPermissions.accessRoles,
},
{
intlLabel: {
id: getTrad('HeaderNav.link.providers'),
defaultMessage: 'Providers',
},
id: 'providers',
to: `/settings/${pluginId}/providers`,
async Component() {
const component = await import(
/* webpackChunkName: "users-providers-settings-page" */ './pages/Providers'
);
return component;
},
permissions: pluginPermissions.readProviders,
},
{
intlLabel: {
id: getTrad('HeaderNav.link.emailTemplates'),
defaultMessage: 'Email templates',
},
id: 'email-templates',
to: `/settings/${pluginId}/email-templates`,
async Component() {
const component = await import(
/* webpackChunkName: "users-email-settings-page" */ './pages/EmailTemplates'
);
return component;
},
permissions: pluginPermissions.readEmailTemplates,
},
{
intlLabel: {
id: getTrad('HeaderNav.link.advancedSettings'),
defaultMessage: 'Advanced Settings',
},
id: 'advanced-settings',
to: `/settings/${pluginId}/advanced-settings`,
async Component() {
const component = await import(
/* webpackChunkName: "users-advanced-settings-page" */ './pages/AdvancedSettings'
);
return component;
},
permissions: pluginPermissions.readAdvancedSettings,
},
]
);
app.registerPlugin({
id: pluginId,
name,
});
},
bootstrap() {},
async registerTrads({ locales }) {
const importedTrads = await Promise.all(
locales.map((locale) => {
return import(
/* webpackChunkName: "users-permissions-translation-[request]" */ `./translations/${locale}.json`
)
.then(({ default: data }) => {
return {
data: prefixPluginTranslations(data, pluginId),
locale,
};
})
.catch(() => {
return {
data: {},
locale,
};
});
})
);
return Promise.resolve(importedTrads);
},
};

View File

@ -1,246 +0,0 @@
import React, { useMemo } from 'react';
import {
Box,
Button,
ContentLayout,
Flex,
Grid,
GridItem,
HeaderLayout,
Main,
Option,
Select,
Typography,
useNotifyAT,
} from '@strapi/design-system';
import {
CheckPagePermissions,
Form,
GenericInput,
LoadingIndicatorPage,
SettingsPageTitle,
useFocusWhenNavigate,
useNotification,
useOverlayBlocker,
useRBAC,
} from '@strapi/helper-plugin';
import { Check } from '@strapi/icons';
import { Formik } from 'formik';
import { useIntl } from 'react-intl';
import { useMutation, useQuery, useQueryClient } from 'react-query';
import pluginPermissions from '../../permissions';
import { getTrad } from '../../utils';
import { fetchData, putAdvancedSettings } from './utils/api';
import layout from './utils/layout';
import schema from './utils/schema';
const ProtectedAdvancedSettingsPage = () => (
<CheckPagePermissions permissions={pluginPermissions.readAdvancedSettings}>
<AdvancedSettingsPage />
</CheckPagePermissions>
);
const AdvancedSettingsPage = () => {
const { formatMessage } = useIntl();
const toggleNotification = useNotification();
const { lockApp, unlockApp } = useOverlayBlocker();
const { notifyStatus } = useNotifyAT();
const queryClient = useQueryClient();
useFocusWhenNavigate();
const updatePermissions = useMemo(
() => ({ update: pluginPermissions.updateAdvancedSettings }),
[]
);
const {
isLoading: isLoadingForPermissions,
allowedActions: { canUpdate },
} = useRBAC(updatePermissions);
const { status: isLoadingData, data } = useQuery('advanced', () => fetchData(), {
onSuccess() {
notifyStatus(
formatMessage({
id: getTrad('Form.advancedSettings.data.loaded'),
defaultMessage: 'Advanced settings data has been loaded',
})
);
},
onError() {
toggleNotification({
type: 'warning',
message: { id: getTrad('notification.error'), defaultMessage: 'An error occured' },
});
},
});
const isLoading = isLoadingForPermissions || isLoadingData !== 'success';
const submitMutation = useMutation((body) => putAdvancedSettings(body), {
async onSuccess() {
await queryClient.invalidateQueries('advanced');
toggleNotification({
type: 'success',
message: { id: getTrad('notification.success.saved'), defaultMessage: 'Saved' },
});
unlockApp();
},
onError() {
toggleNotification({
type: 'warning',
message: { id: getTrad('notification.error'), defaultMessage: 'An error occured' },
});
unlockApp();
},
refetchActive: true,
});
const { isLoading: isSubmittingForm } = submitMutation;
const handleSubmit = async (body) => {
lockApp();
const urlConfirmation = body.email_confirmation ? body.email_confirmation_redirection : '';
await submitMutation.mutateAsync({ ...body, email_confirmation_redirection: urlConfirmation });
};
if (isLoading) {
return (
<Main aria-busy="true">
<SettingsPageTitle
name={formatMessage({
id: getTrad('HeaderNav.link.advancedSettings'),
defaultMessage: 'Advanced Settings',
})}
/>
<HeaderLayout
title={formatMessage({
id: getTrad('HeaderNav.link.advancedSettings'),
defaultMessage: 'Advanced Settings',
})}
/>
<ContentLayout>
<LoadingIndicatorPage />
</ContentLayout>
</Main>
);
}
return (
<Main aria-busy={isSubmittingForm}>
<SettingsPageTitle
name={formatMessage({
id: getTrad('HeaderNav.link.advancedSettings'),
defaultMessage: 'Advanced Settings',
})}
/>
<Formik
onSubmit={handleSubmit}
initialValues={data.settings}
validateOnChange={false}
validationSchema={schema}
enableReinitialize
>
{({ errors, values, handleChange, isSubmitting }) => {
return (
<Form>
<HeaderLayout
title={formatMessage({
id: getTrad('HeaderNav.link.advancedSettings'),
defaultMessage: 'Advanced Settings',
})}
primaryAction={
<Button
loading={isSubmitting}
type="submit"
disabled={!canUpdate}
startIcon={<Check />}
size="S"
>
{formatMessage({ id: 'global.save', defaultMessage: 'Save' })}
</Button>
}
/>
<ContentLayout>
<Box
background="neutral0"
hasRadius
shadow="filterShadow"
paddingTop={6}
paddingBottom={6}
paddingLeft={7}
paddingRight={7}
>
<Flex direction="column" alignItems="stretch" gap={4}>
<Typography variant="delta" as="h2">
{formatMessage({
id: 'global.settings',
defaultMessage: 'Settings',
})}
</Typography>
<Grid gap={6}>
<GridItem col={6} s={12}>
<Select
label={formatMessage({
id: getTrad('EditForm.inputSelect.label.role'),
defaultMessage: 'Default role for authenticated users',
})}
value={values.default_role}
hint={formatMessage({
id: getTrad('EditForm.inputSelect.description.role'),
defaultMessage:
'It will attach the new authenticated user to the selected role.',
})}
onChange={(e) =>
handleChange({ target: { name: 'default_role', value: e } })
}
>
{data.roles.map((role) => {
return (
<Option key={role.type} value={role.type}>
{role.name}
</Option>
);
})}
</Select>
</GridItem>
{layout.map((input) => {
let value = values[input.name];
if (!value) {
value = input.type === 'bool' ? false : '';
}
return (
<GridItem key={input.name} {...input.size}>
<GenericInput
{...input}
value={value}
error={errors[input.name]}
disabled={
input.name === 'email_confirmation_redirection' &&
values.email_confirmation === false
}
onChange={handleChange}
/>
</GridItem>
);
})}
</Grid>
</Flex>
</Box>
</ContentLayout>
</Form>
);
}}
</Formik>
</Main>
);
};
export default ProtectedAdvancedSettingsPage;

View File

@ -1,18 +0,0 @@
import { getFetchClient } from '@strapi/helper-plugin';
import { getRequestURL } from '../../../utils';
const fetchData = async () => {
const { get } = getFetchClient();
const { data } = await get(getRequestURL('advanced'));
return data;
};
const putAdvancedSettings = (body) => {
const { put } = getFetchClient();
return put(getRequestURL('advanced'), body);
};
export { fetchData, putAdvancedSettings };

View File

@ -1,96 +0,0 @@
import { getTrad } from '../../../utils';
const layout = [
{
intlLabel: {
id: getTrad('EditForm.inputToggle.label.email'),
defaultMessage: 'One account per email address',
},
description: {
id: getTrad('EditForm.inputToggle.description.email'),
defaultMessage:
'Disallow the user to create multiple accounts using the same email address with different authentication providers.',
},
name: 'unique_email',
type: 'bool',
size: {
col: 12,
xs: 12,
},
},
{
intlLabel: {
id: getTrad('EditForm.inputToggle.label.sign-up'),
defaultMessage: 'Enable sign-ups',
},
description: {
id: getTrad('EditForm.inputToggle.description.sign-up'),
defaultMessage:
'When disabled (OFF), the registration process is forbidden. No one can subscribe anymore no matter the used provider.',
},
name: 'allow_register',
type: 'bool',
size: {
col: 12,
xs: 12,
},
},
{
intlLabel: {
id: getTrad('EditForm.inputToggle.label.email-reset-password'),
defaultMessage: 'Reset password page',
},
description: {
id: getTrad('EditForm.inputToggle.description.email-reset-password'),
defaultMessage: "URL of your application's reset password page.",
},
placeholder: {
id: getTrad('EditForm.inputToggle.placeholder.email-reset-password'),
defaultMessage: 'ex: https://youtfrontend.com/reset-password',
},
name: 'email_reset_password',
type: 'text',
size: {
col: 6,
xs: 12,
},
},
{
intlLabel: {
id: getTrad('EditForm.inputToggle.label.email-confirmation'),
defaultMessage: 'Enable email confirmation',
},
description: {
id: getTrad('EditForm.inputToggle.description.email-confirmation'),
defaultMessage: 'When enabled (ON), new registered users receive a confirmation email.',
},
name: 'email_confirmation',
type: 'bool',
size: {
col: 12,
xs: 12,
},
},
{
intlLabel: {
id: getTrad('EditForm.inputToggle.label.email-confirmation-redirection'),
defaultMessage: 'Redirection url',
},
description: {
id: getTrad('EditForm.inputToggle.description.email-confirmation-redirection'),
defaultMessage: 'After you confirmed your email, choose where you will be redirected.',
},
placeholder: {
id: getTrad('EditForm.inputToggle.placeholder.email-confirmation-redirection'),
defaultMessage: 'ex: https://youtfrontend.com/email-confirmation',
},
name: 'email_confirmation_redirection',
type: 'text',
size: {
col: 6,
xs: 12,
},
},
];
export default layout;

View File

@ -1,19 +0,0 @@
import { translatedErrors } from '@strapi/helper-plugin';
import * as yup from 'yup';
// eslint-disable-next-line prefer-regex-literals
const URL_REGEX = new RegExp('(^$)|((.+:\\/\\/.*)(d*)\\/?(.*))');
const schema = yup.object().shape({
email_confirmation_redirection: yup.mixed().when('email_confirmation', {
is: true,
then: yup.string().matches(URL_REGEX).required(),
otherwise: yup.string().nullable(),
}),
email_reset_password: yup
.string(translatedErrors.string)
.matches(URL_REGEX, translatedErrors.regex)
.nullable(),
});
export default schema;

View File

@ -1,176 +0,0 @@
import React from 'react';
import {
Button,
Grid,
GridItem,
ModalBody,
ModalFooter,
ModalHeader,
ModalLayout,
Textarea,
} from '@strapi/design-system';
import { Breadcrumbs, Crumb } from '@strapi/design-system/v2';
import { Form, GenericInput } from '@strapi/helper-plugin';
import { Formik } from 'formik';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import { getTrad } from '../../../utils';
import schema from '../utils/schema';
const EmailForm = ({ template, onToggle, onSubmit }) => {
const { formatMessage } = useIntl();
return (
<ModalLayout
onClose={onToggle}
labelledBy={`${formatMessage({
id: getTrad('PopUpForm.header.edit.email-templates'),
defaultMessage: 'Edit email template',
})}, ${formatMessage({ id: getTrad(template.display), defaultMessage: template.display })}`}
>
<ModalHeader>
<Breadcrumbs
label={`${formatMessage({
id: getTrad('PopUpForm.header.edit.email-templates'),
defaultMessage: 'Edit email template',
})}, ${formatMessage({
id: getTrad(template.display),
defaultMessage: template.display,
})}`}
>
<Crumb>
{formatMessage({
id: getTrad('PopUpForm.header.edit.email-templates'),
defaultMessage: 'Edit email template',
})}
</Crumb>
<Crumb isCurrent>
{formatMessage({ id: getTrad(template.display), defaultMessage: template.display })}
</Crumb>
</Breadcrumbs>
</ModalHeader>
<Formik
onSubmit={onSubmit}
initialValues={template}
validateOnChange={false}
validationSchema={schema}
enableReinitialize
>
{({ errors, values, handleChange, isSubmitting }) => {
return (
<Form>
<ModalBody>
<Grid gap={5}>
<GridItem col={6} s={12}>
<GenericInput
intlLabel={{
id: getTrad('PopUpForm.Email.options.from.name.label'),
defaultMessage: 'Shipper name',
}}
name="options.from.name"
onChange={handleChange}
value={values.options.from.name}
error={errors?.options?.from?.name}
type="text"
/>
</GridItem>
<GridItem col={6} s={12}>
<GenericInput
intlLabel={{
id: getTrad('PopUpForm.Email.options.from.email.label'),
defaultMessage: 'Shipper email',
}}
name="options.from.email"
onChange={handleChange}
value={values.options.from.email}
error={errors?.options?.from?.email}
type="text"
/>
</GridItem>
<GridItem col={6} s={12}>
<GenericInput
intlLabel={{
id: getTrad('PopUpForm.Email.options.response_email.label'),
defaultMessage: 'Response email',
}}
name="options.response_email"
onChange={handleChange}
value={values.options.response_email}
error={errors?.options?.response_email}
type="text"
/>
</GridItem>
<GridItem col={6} s={12}>
<GenericInput
intlLabel={{
id: getTrad('PopUpForm.Email.options.object.label'),
defaultMessage: 'Subject',
}}
name="options.object"
onChange={handleChange}
value={values.options.object}
error={errors?.options?.object}
type="text"
/>
</GridItem>
<GridItem col={12} s={12}>
<Textarea
label={formatMessage({
id: getTrad('PopUpForm.Email.options.message.label'),
defaultMessage: 'Message',
})}
id="options.message"
onChange={handleChange}
value={values.options.message}
error={
errors?.options?.message &&
formatMessage({
id: errors.options.message,
defaultMessage: errors.options.message,
})
}
/>
</GridItem>
</Grid>
</ModalBody>
<ModalFooter
startActions={
<Button onClick={onToggle} variant="tertiary">
Cancel
</Button>
}
endActions={
<Button loading={isSubmitting} type="submit">
Finish
</Button>
}
/>
</Form>
);
}}
</Formik>
</ModalLayout>
);
};
EmailForm.propTypes = {
template: PropTypes.shape({
display: PropTypes.string,
icon: PropTypes.string,
options: PropTypes.shape({
from: PropTypes.shape({
name: PropTypes.string,
email: PropTypes.string,
}),
message: PropTypes.string,
object: PropTypes.string,
response_email: PropTypes.string,
}),
}).isRequired,
onSubmit: PropTypes.func.isRequired,
onToggle: PropTypes.func.isRequired,
};
export default EmailForm;

View File

@ -1,128 +0,0 @@
import React from 'react';
import {
Icon,
IconButton,
Table,
Tbody,
Td,
Th,
Thead,
Tr,
Typography,
VisuallyHidden,
} from '@strapi/design-system';
import { onRowClick, stopPropagation } from '@strapi/helper-plugin';
import { Check, Pencil, Refresh } from '@strapi/icons';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import { getTrad } from '../../../utils';
const EmailTable = ({ canUpdate, onEditClick }) => {
const { formatMessage } = useIntl();
return (
<Table colCount={3} rowCount={3}>
<Thead>
<Tr>
<Th width="1%">
<VisuallyHidden>
{formatMessage({
id: getTrad('Email.template.table.icon.label'),
defaultMessage: 'icon',
})}
</VisuallyHidden>
</Th>
<Th>
<Typography variant="sigma" textColor="neutral600">
{formatMessage({
id: getTrad('Email.template.table.name.label'),
defaultMessage: 'name',
})}
</Typography>
</Th>
<Th width="1%">
<VisuallyHidden>
{formatMessage({
id: getTrad('Email.template.table.action.label'),
defaultMessage: 'action',
})}
</VisuallyHidden>
</Th>
</Tr>
</Thead>
<Tbody>
<Tr {...onRowClick({ fn: () => onEditClick('reset_password') })}>
<Td>
<Icon>
<Refresh
aria-label={formatMessage({
id: 'global.reset-password',
defaultMessage: 'Reset password',
})}
/>
</Icon>
</Td>
<Td>
<Typography>
{formatMessage({
id: 'global.reset-password',
defaultMessage: 'Reset password',
})}
</Typography>
</Td>
<Td {...stopPropagation}>
<IconButton
onClick={() => onEditClick('reset_password')}
label={formatMessage({
id: getTrad('Email.template.form.edit.label'),
defaultMessage: 'Edit a template',
})}
noBorder
icon={canUpdate && <Pencil />}
/>
</Td>
</Tr>
<Tr {...onRowClick({ fn: () => onEditClick('email_confirmation') })}>
<Td>
<Icon>
<Check
aria-label={formatMessage({
id: getTrad('Email.template.email_confirmation'),
defaultMessage: 'Email address confirmation',
})}
/>
</Icon>
</Td>
<Td>
<Typography>
{formatMessage({
id: getTrad('Email.template.email_confirmation'),
defaultMessage: 'Email address confirmation',
})}
</Typography>
</Td>
<Td {...stopPropagation}>
<IconButton
onClick={() => onEditClick('email_confirmation')}
label={formatMessage({
id: getTrad('Email.template.form.edit.label'),
defaultMessage: 'Edit a template',
})}
noBorder
icon={canUpdate && <Pencil />}
/>
</Td>
</Tr>
</Tbody>
</Table>
);
};
EmailTable.propTypes = {
canUpdate: PropTypes.bool.isRequired,
onEditClick: PropTypes.func.isRequired,
};
export default EmailTable;

View File

@ -1,163 +0,0 @@
import React, { useMemo, useRef, useState } from 'react';
import { ContentLayout, HeaderLayout, Main, useNotifyAT } from '@strapi/design-system';
import {
CheckPagePermissions,
LoadingIndicatorPage,
SettingsPageTitle,
useFocusWhenNavigate,
useNotification,
useOverlayBlocker,
useRBAC,
useTracking,
} from '@strapi/helper-plugin';
import { useIntl } from 'react-intl';
import { useMutation, useQuery, useQueryClient } from 'react-query';
import pluginPermissions from '../../permissions';
import { getTrad } from '../../utils';
import EmailForm from './components/EmailForm';
import EmailTable from './components/EmailTable';
import { fetchData, putEmailTemplate } from './utils/api';
const ProtectedEmailTemplatesPage = () => (
<CheckPagePermissions permissions={pluginPermissions.readEmailTemplates}>
<EmailTemplatesPage />
</CheckPagePermissions>
);
const EmailTemplatesPage = () => {
const { formatMessage } = useIntl();
const { trackUsage } = useTracking();
const { notifyStatus } = useNotifyAT();
const toggleNotification = useNotification();
const { lockApp, unlockApp } = useOverlayBlocker();
const trackUsageRef = useRef(trackUsage);
const queryClient = useQueryClient();
useFocusWhenNavigate();
const [isModalOpen, setIsModalOpen] = useState(false);
const [templateToEdit, setTemplateToEdit] = useState(null);
const updatePermissions = useMemo(() => {
return { update: pluginPermissions.updateEmailTemplates };
}, []);
const {
isLoading: isLoadingForPermissions,
allowedActions: { canUpdate },
} = useRBAC(updatePermissions);
const { status: isLoadingData, data } = useQuery('email-templates', () => fetchData(), {
onSuccess() {
notifyStatus(
formatMessage({
id: getTrad('Email.template.data.loaded'),
defaultMessage: 'Email templates has been loaded',
})
);
},
onError() {
toggleNotification({
type: 'warning',
message: { id: 'notification.error', defaultMessage: 'An error occured' },
});
},
});
const isLoading = isLoadingForPermissions || isLoadingData !== 'success';
const handleToggle = () => {
setIsModalOpen((prev) => !prev);
};
const handleEditClick = (template) => {
setTemplateToEdit(template);
handleToggle();
};
const submitMutation = useMutation((body) => putEmailTemplate({ 'email-templates': body }), {
async onSuccess() {
await queryClient.invalidateQueries('email-templates');
toggleNotification({
type: 'success',
message: { id: 'notification.success.saved', defaultMessage: 'Saved' },
});
trackUsageRef.current('didEditEmailTemplates');
unlockApp();
handleToggle();
},
onError() {
toggleNotification({
type: 'warning',
message: { id: 'notification.error', defaultMessage: 'An error occured' },
});
unlockApp();
},
refetchActive: true,
});
const { isLoading: isSubmittingForm } = submitMutation;
const handleSubmit = (body) => {
lockApp();
trackUsageRef.current('willEditEmailTemplates');
const editedTemplates = { ...data, [templateToEdit]: body };
submitMutation.mutate(editedTemplates);
};
if (isLoading) {
return (
<Main aria-busy="true">
<SettingsPageTitle
name={formatMessage({
id: getTrad('HeaderNav.link.emailTemplates'),
defaultMessage: 'Email templates',
})}
/>
<HeaderLayout
title={formatMessage({
id: getTrad('HeaderNav.link.emailTemplates'),
defaultMessage: 'Email templates',
})}
/>
<ContentLayout>
<LoadingIndicatorPage />
</ContentLayout>
</Main>
);
}
return (
<Main aria-busy={isSubmittingForm}>
<SettingsPageTitle
name={formatMessage({
id: getTrad('HeaderNav.link.emailTemplates'),
defaultMessage: 'Email templates',
})}
/>
<HeaderLayout
title={formatMessage({
id: getTrad('HeaderNav.link.emailTemplates'),
defaultMessage: 'Email templates',
})}
/>
<ContentLayout>
<EmailTable onEditClick={handleEditClick} canUpdate={canUpdate} />
{isModalOpen && (
<EmailForm
template={data[templateToEdit]}
onToggle={handleToggle}
onSubmit={handleSubmit}
/>
)}
</ContentLayout>
</Main>
);
};
export default ProtectedEmailTemplatesPage;

View File

@ -1,18 +0,0 @@
import { getFetchClient } from '@strapi/helper-plugin';
import { getRequestURL } from '../../../utils';
const fetchData = async () => {
const { get } = getFetchClient();
const { data } = await get(getRequestURL('email-templates'));
return data;
};
const putEmailTemplate = (body) => {
const { put } = getFetchClient();
return put(getRequestURL('email-templates'), body);
};
export { fetchData, putEmailTemplate };

View File

@ -1,22 +0,0 @@
import { translatedErrors } from '@strapi/helper-plugin';
import * as yup from 'yup';
const schema = yup.object().shape({
options: yup
.object()
.shape({
from: yup
.object()
.shape({
name: yup.string().required(translatedErrors.required),
email: yup.string().email(translatedErrors.email).required(translatedErrors.required),
})
.required(),
response_email: yup.string().email(translatedErrors.email),
object: yup.string().required(translatedErrors.required),
message: yup.string().required(translatedErrors.required),
})
.required(translatedErrors.required),
});
export default schema;

View File

@ -1,275 +0,0 @@
import React, { useMemo, useRef, useState } from 'react';
import {
ContentLayout,
HeaderLayout,
IconButton,
Layout,
Main,
Table,
Tbody,
Td,
Th,
Thead,
Tr,
Typography,
useNotifyAT,
VisuallyHidden,
} from '@strapi/design-system';
import {
CheckPagePermissions,
LoadingIndicatorPage,
onRowClick,
SettingsPageTitle,
stopPropagation,
useFocusWhenNavigate,
useNotification,
useOverlayBlocker,
useRBAC,
useTracking,
} from '@strapi/helper-plugin';
import { Pencil } from '@strapi/icons';
import has from 'lodash/has';
import upperFirst from 'lodash/upperFirst';
import { useIntl } from 'react-intl';
import { useMutation, useQuery, useQueryClient } from 'react-query';
import FormModal from '../../components/FormModal';
import pluginPermissions from '../../permissions';
import { getTrad } from '../../utils';
import { fetchData, putProvider } from './utils/api';
import createProvidersArray from './utils/createProvidersArray';
import forms from './utils/forms';
export const ProvidersPage = () => {
const { formatMessage } = useIntl();
useFocusWhenNavigate();
const { notifyStatus } = useNotifyAT();
const queryClient = useQueryClient();
const { trackUsage } = useTracking();
const trackUsageRef = useRef(trackUsage);
const [isOpen, setIsOpen] = useState(false);
const [isSubmiting, setIsSubmiting] = useState(false);
const [providerToEditName, setProviderToEditName] = useState(null);
const toggleNotification = useNotification();
const { lockApp, unlockApp } = useOverlayBlocker();
const updatePermissions = useMemo(() => {
return { update: pluginPermissions.updateProviders };
}, []);
const {
isLoading: isLoadingForPermissions,
allowedActions: { canUpdate },
} = useRBAC(updatePermissions);
const {
isLoading: isLoadingForData,
data: modifiedData,
isFetching,
} = useQuery('get-providers', () => fetchData(toggleNotification), {
onSuccess() {
notifyStatus(
formatMessage({
id: getTrad('Providers.data.loaded'),
defaultMessage: 'Providers have been loaded',
})
);
},
initialData: {},
});
const isLoading = isLoadingForData || isFetching;
const submitMutation = useMutation(putProvider, {
async onSuccess() {
await queryClient.invalidateQueries('get-providers');
toggleNotification({
type: 'info',
message: { id: getTrad('notification.success.submit') },
});
trackUsageRef.current('didEditAuthenticationProvider');
setIsSubmiting(false);
handleToggleModal();
unlockApp();
},
onError() {
toggleNotification({
type: 'warning',
message: { id: 'notification.error' },
});
unlockApp();
setIsSubmiting(false);
},
refetchActive: false,
});
const providers = useMemo(() => createProvidersArray(modifiedData), [modifiedData]);
const rowCount = providers.length;
const isProviderWithSubdomain = useMemo(() => {
if (!providerToEditName) {
return false;
}
const providerToEdit = providers.find((obj) => obj.name === providerToEditName);
return has(providerToEdit, 'subdomain');
}, [providers, providerToEditName]);
const pageTitle = formatMessage({
id: getTrad('HeaderNav.link.providers'),
defaultMessage: 'Providers',
});
const layoutToRender = useMemo(() => {
if (providerToEditName === 'email') {
return forms.email;
}
if (isProviderWithSubdomain) {
return forms.providersWithSubdomain;
}
return forms.providers;
}, [providerToEditName, isProviderWithSubdomain]);
const handleToggleModal = () => {
setIsOpen((prev) => !prev);
};
const handleClickEdit = (provider) => {
if (canUpdate) {
setProviderToEditName(provider.name);
handleToggleModal();
}
};
const handleSubmit = async (values) => {
setIsSubmiting(true);
lockApp();
trackUsageRef.current('willEditAuthenticationProvider');
const body = { ...modifiedData, [providerToEditName]: values };
submitMutation.mutate({ providers: body });
};
return (
<Layout>
<SettingsPageTitle name={pageTitle} />
<Main>
<HeaderLayout
title={formatMessage({
id: getTrad('HeaderNav.link.providers'),
defaultMessage: 'Providers',
})}
/>
{isLoading || isLoadingForPermissions ? (
<LoadingIndicatorPage />
) : (
<ContentLayout>
<Table colCount={3} rowCount={rowCount + 1}>
<Thead>
<Tr>
<Th>
<Typography variant="sigma" textColor="neutral600">
{formatMessage({ id: 'global.name', defaultMessage: 'Name' })}
</Typography>
</Th>
<Th>
<Typography variant="sigma" textColor="neutral600">
{formatMessage({ id: getTrad('Providers.status'), defaultMessage: 'Status' })}
</Typography>
</Th>
<Th>
<Typography variant="sigma">
<VisuallyHidden>
{formatMessage({
id: 'global.settings',
defaultMessage: 'Settings',
})}
</VisuallyHidden>
</Typography>
</Th>
</Tr>
</Thead>
<Tbody>
{providers.map((provider) => (
<Tr
key={provider.name}
{...onRowClick({
fn: () => handleClickEdit(provider),
condition: canUpdate,
})}
>
<Td width="45%">
<Typography fontWeight="semiBold" textColor="neutral800">
{provider.name}
</Typography>
</Td>
<Td width="65%">
<Typography
textColor={provider.enabled ? 'success600' : 'danger600'}
data-testid={`enable-${provider.name}`}
>
{provider.enabled
? formatMessage({
id: 'global.enabled',
defaultMessage: 'Enabled',
})
: formatMessage({
id: 'global.disabled',
defaultMessage: 'Disabled',
})}
</Typography>
</Td>
<Td {...stopPropagation}>
{canUpdate && (
<IconButton
onClick={() => handleClickEdit(provider)}
noBorder
icon={<Pencil />}
label="Edit"
/>
)}
</Td>
</Tr>
))}
</Tbody>
</Table>
</ContentLayout>
)}
</Main>
<FormModal
initialData={modifiedData[providerToEditName]}
isOpen={isOpen}
isSubmiting={isSubmiting}
layout={layoutToRender}
headerBreadcrumbs={[
formatMessage({
id: getTrad('PopUpForm.header.edit.providers'),
defaultMessage: 'Edit Provider',
}),
upperFirst(providerToEditName),
]}
onToggle={handleToggleModal}
onSubmit={handleSubmit}
providerToEditName={providerToEditName}
/>
</Layout>
);
};
const ProtectedProvidersPage = () => (
<CheckPagePermissions permissions={pluginPermissions.readProviders}>
<ProvidersPage />
</CheckPagePermissions>
);
export default ProtectedProvidersPage;

View File

@ -1,54 +0,0 @@
import produce from 'immer';
import set from 'lodash/set';
const initialState = {
formErrors: {},
isLoading: true,
initialData: {},
modifiedData: {},
};
const reducer = (state, action) =>
// eslint-disable-next-line consistent-return
produce(state, (draftState) => {
switch (action.type) {
case 'GET_DATA': {
draftState.isLoading = true;
draftState.initialData = {};
draftState.modifiedData = {};
break;
}
case 'GET_DATA_SUCCEEDED': {
draftState.isLoading = false;
draftState.initialData = action.data;
draftState.modifiedData = action.data;
break;
}
case 'GET_DATA_ERROR': {
draftState.isLoading = true;
break;
}
case 'ON_CHANGE': {
set(draftState, ['modifiedData', ...action.keys.split('.')], action.value);
break;
}
case 'RESET_FORM': {
draftState.modifiedData = state.initialData;
draftState.formErrors = {};
break;
}
case 'SET_ERRORS': {
draftState.formErrors = action.errors;
break;
}
default: {
return draftState;
}
}
});
export default reducer;
export { initialState };

View File

@ -1,26 +0,0 @@
import { getFetchClient } from '@strapi/helper-plugin';
import { getRequestURL } from '../../../utils';
// eslint-disable-next-line import/prefer-default-export
export const fetchData = async (toggleNotification) => {
try {
const { get } = getFetchClient();
const { data } = await get(getRequestURL('providers'));
return data;
} catch (err) {
toggleNotification({
type: 'warning',
message: { id: 'notification.error' },
});
throw new Error('error');
}
};
export const putProvider = (body) => {
const { put } = getFetchClient();
return put(getRequestURL('providers'), body);
};

View File

@ -1,21 +0,0 @@
import sortBy from 'lodash/sortBy';
const createProvidersArray = (data) => {
return sortBy(
Object.keys(data).reduce((acc, current) => {
const { icon: iconName, enabled, subdomain } = data[current];
const icon = iconName === 'envelope' ? ['fas', 'envelope'] : ['fab', iconName];
if (subdomain !== undefined) {
acc.push({ name: current, icon, enabled, subdomain });
} else {
acc.push({ name: current, icon, enabled });
}
return acc;
}, []),
'name'
);
};
export default createProvidersArray;

View File

@ -1,259 +0,0 @@
import { translatedErrors } from '@strapi/helper-plugin';
import * as yup from 'yup';
import { getTrad } from '../../../utils';
const callbackLabel = {
id: getTrad('PopUpForm.Providers.redirectURL.front-end.label'),
defaultMessage: 'The redirect URL to your front-end app',
};
const callbackPlaceholder = {
id: 'http://www.client-app.com',
defaultMessage: 'http://www.client-app.com',
};
const enabledDescription = {
id: getTrad('PopUpForm.Providers.enabled.description'),
defaultMessage: "If disabled, users won't be able to use this provider.",
};
const enabledLabel = {
id: getTrad('PopUpForm.Providers.enabled.label'),
defaultMessage: 'Enable',
};
const keyLabel = { id: getTrad('PopUpForm.Providers.key.label'), defaultMessage: 'Client ID' };
const hintLabel = {
id: getTrad('PopUpForm.Providers.redirectURL.label'),
defaultMessage: 'The redirect URL to add in your {provider} application configurations',
};
const textPlaceholder = {
id: getTrad('PopUpForm.Providers.key.placeholder'),
defaultMessage: 'TEXT',
};
const secretLabel = {
id: getTrad('PopUpForm.Providers.secret.label'),
defaultMessage: 'Client Secret',
};
const forms = {
email: {
form: [
[
{
intlLabel: enabledLabel,
name: 'enabled',
type: 'bool',
description: enabledDescription,
size: 6,
// TODO check if still needed
// validations: {
// required: true,
// },
},
],
],
schema: yup.object().shape({
enabled: yup.bool().required(translatedErrors.required),
}),
},
providers: {
form: [
[
{
intlLabel: enabledLabel,
name: 'enabled',
type: 'bool',
description: enabledDescription,
size: 6,
validations: {
required: true,
},
},
],
[
{
intlLabel: keyLabel,
name: 'key',
type: 'text',
placeholder: textPlaceholder,
size: 12,
validations: {
required: true,
},
},
],
[
{
intlLabel: secretLabel,
name: 'secret',
type: 'text',
placeholder: textPlaceholder,
size: 12,
validations: {
required: true,
},
},
],
[
{
intlLabel: callbackLabel,
placeholder: callbackPlaceholder,
name: 'callback',
type: 'text',
size: 12,
validations: {
required: true,
},
},
],
[
{
intlLabel: hintLabel,
name: 'noName',
type: 'text',
validations: {},
size: 12,
disabled: true,
},
],
],
schema: yup.object().shape({
enabled: yup.bool().required(translatedErrors.required),
key: yup.string().when('enabled', {
is: true,
then: yup.string().required(translatedErrors.required),
otherwise: yup.string(),
}),
secret: yup.string().when('enabled', {
is: true,
then: yup.string().required(translatedErrors.required),
otherwise: yup.string(),
}),
callback: yup.string().when('enabled', {
is: true,
then: yup.string().required(translatedErrors.required),
otherwise: yup.string(),
}),
}),
},
providersWithSubdomain: {
form: [
[
{
intlLabel: enabledLabel,
name: 'enabled',
type: 'bool',
description: enabledDescription,
size: 6,
validations: {
required: true,
},
},
],
[
{
intlLabel: keyLabel,
name: 'key',
type: 'text',
placeholder: textPlaceholder,
size: 12,
validations: {
required: true,
},
},
],
[
{
intlLabel: secretLabel,
name: 'secret',
type: 'text',
placeholder: textPlaceholder,
size: 12,
validations: {
required: true,
},
},
],
[
{
intlLabel: {
id: getTrad({ id: 'PopUpForm.Providers.jwksurl.label' }),
defaultMessage: 'JWKS URL',
},
name: 'jwksurl',
type: 'text',
placeholder: textPlaceholder,
size: 12,
validations: {
required: false,
},
},
],
[
{
intlLabel: {
id: getTrad('PopUpForm.Providers.subdomain.label'),
defaultMessage: 'Host URI (Subdomain)',
},
name: 'subdomain',
type: 'text',
placeholder: {
id: getTrad('PopUpForm.Providers.subdomain.placeholder'),
defaultMessage: 'my.subdomain.com',
},
size: 12,
validations: {
required: true,
},
},
],
[
{
intlLabel: callbackLabel,
placeholder: callbackPlaceholder,
name: 'callback',
type: 'text',
size: 12,
validations: {
required: true,
},
},
],
[
{
intlLabel: hintLabel,
name: 'noName',
type: 'text',
validations: {},
size: 12,
disabled: true,
},
],
],
schema: yup.object().shape({
enabled: yup.bool().required(translatedErrors.required),
key: yup.string().when('enabled', {
is: true,
then: yup.string().required(translatedErrors.required),
otherwise: yup.string(),
}),
secret: yup.string().when('enabled', {
is: true,
then: yup.string().required(translatedErrors.required),
otherwise: yup.string(),
}),
subdomain: yup.string().when('enabled', {
is: true,
then: yup.string().required(translatedErrors.required),
otherwise: yup.string(),
}),
callback: yup.string().when('enabled', {
is: true,
then: yup.string().required(translatedErrors.required),
otherwise: yup.string(),
}),
}),
},
};
export default forms;

View File

@ -1,185 +0,0 @@
import React, { useRef, useState } from 'react';
import {
Box,
Button,
ContentLayout,
Flex,
Grid,
GridItem,
HeaderLayout,
Main,
Textarea,
TextInput,
Typography,
} from '@strapi/design-system';
import {
Form,
SettingsPageTitle,
useFetchClient,
useNotification,
useOverlayBlocker,
useTracking,
} from '@strapi/helper-plugin';
import { Check } from '@strapi/icons';
import { Formik } from 'formik';
import { useIntl } from 'react-intl';
import { useHistory } from 'react-router-dom';
import UsersPermissions from '../../components/UsersPermissions';
import { usePlugins } from '../../hooks';
import pluginId from '../../pluginId';
import getTrad from '../../utils/getTrad';
import { createRoleSchema } from './constants';
const CreatePage = () => {
const { formatMessage } = useIntl();
const [isSubmitting, setIsSubmitting] = useState(false);
const toggleNotification = useNotification();
const { goBack } = useHistory();
const { lockApp, unlockApp } = useOverlayBlocker();
const { isLoading: isLoadingPlugins, permissions, routes } = usePlugins();
const { trackUsage } = useTracking();
const permissionsRef = useRef();
const { post } = useFetchClient();
const handleCreateRoleSubmit = async (data) => {
// Set loading state
lockApp();
setIsSubmitting(true);
try {
const permissions = permissionsRef.current.getPermissions();
// Update role in Strapi
await post(`/${pluginId}/roles`, { ...data, ...permissions, users: [] });
// Notify success
trackUsage('didCreateRole');
toggleNotification({
type: 'success',
message: {
id: getTrad('Settings.roles.created'),
defaultMessage: 'Role created',
},
});
// Forcing redirecting since we don't have the id in the response
goBack();
} catch (err) {
console.error(err);
toggleNotification({
type: 'warning',
message: {
id: 'notification.error',
defaultMessage: 'An error occurred',
},
});
}
// Unset loading state
setIsSubmitting(false);
unlockApp();
};
return (
<Main>
<SettingsPageTitle name="Roles" />
<Formik
enableReinitialize
initialValues={{ name: '', description: '' }}
onSubmit={handleCreateRoleSubmit}
validationSchema={createRoleSchema}
>
{({ handleSubmit, values, handleChange, errors }) => (
<Form noValidate onSubmit={handleSubmit}>
<HeaderLayout
primaryAction={
!isLoadingPlugins && (
<Button type="submit" loading={isSubmitting} startIcon={<Check />}>
{formatMessage({
id: 'global.save',
defaultMessage: 'Save',
})}
</Button>
)
}
title={formatMessage({
id: 'Settings.roles.create.title',
defaultMessage: 'Create a role',
})}
subtitle={formatMessage({
id: 'Settings.roles.create.description',
defaultMessage: 'Define the rights given to the role',
})}
/>
<ContentLayout>
<Flex direction="column" alignItems="stretch" gap={7}>
<Box
background="neutral0"
hasRadius
shadow="filterShadow"
paddingTop={6}
paddingBottom={6}
paddingLeft={7}
paddingRight={7}
>
<Flex direction="column" alignItems="stretch" gap={4}>
<Typography variant="delta" as="h2">
{formatMessage({
id: getTrad('EditPage.form.roles'),
defaultMessage: 'Role details',
})}
</Typography>
<Grid gap={4}>
<GridItem col={6}>
<TextInput
name="name"
value={values.name || ''}
onChange={handleChange}
label={formatMessage({
id: 'global.name',
defaultMessage: 'Name',
})}
error={
errors.name
? formatMessage({ id: errors.name, defaultMessage: 'Invalid value' })
: null
}
/>
</GridItem>
<GridItem col={6}>
<Textarea
id="description"
value={values.description || ''}
onChange={handleChange}
label={formatMessage({
id: 'global.description',
defaultMessage: 'Description',
})}
error={
errors.description
? formatMessage({
id: errors.description,
defaultMessage: 'Invalid value',
})
: null
}
/>
</GridItem>
</Grid>
</Flex>
</Box>
{!isLoadingPlugins && (
<UsersPermissions
ref={permissionsRef}
permissions={permissions}
routes={routes}
/>
)}
</Flex>
</ContentLayout>
</Form>
)}
</Formik>
</Main>
);
};
export default CreatePage;

View File

@ -1,197 +0,0 @@
import React, { useRef, useState } from 'react';
import {
ContentLayout,
HeaderLayout,
Main,
Button,
Flex,
Box,
TextInput,
Textarea,
Typography,
GridItem,
Grid,
} from '@strapi/design-system';
import {
useFetchClient,
useOverlayBlocker,
SettingsPageTitle,
LoadingIndicatorPage,
Form,
useNotification,
Link,
} from '@strapi/helper-plugin';
import { ArrowLeft, Check } from '@strapi/icons';
import { Formik } from 'formik';
import { useIntl } from 'react-intl';
import { useRouteMatch } from 'react-router-dom';
import UsersPermissions from '../../components/UsersPermissions';
import { usePlugins, useFetchRole } from '../../hooks';
import pluginId from '../../pluginId';
import getTrad from '../../utils/getTrad';
import { createRoleSchema } from './constants';
const EditPage = () => {
const { formatMessage } = useIntl();
const [isSubmitting, setIsSubmitting] = useState(false);
const toggleNotification = useNotification();
const { lockApp, unlockApp } = useOverlayBlocker();
const {
params: { id },
} = useRouteMatch(`/settings/${pluginId}/roles/:id`);
const { isLoading: isLoadingPlugins, routes } = usePlugins();
const { role, onSubmitSucceeded, isLoading: isLoadingRole } = useFetchRole(id);
const permissionsRef = useRef();
const { put } = useFetchClient();
const handleEditRoleSubmit = async (data) => {
// Set loading state
lockApp();
setIsSubmitting(true);
try {
const permissions = permissionsRef.current.getPermissions();
// Update role in Strapi
await put(`/${pluginId}/roles/${id}`, { ...data, ...permissions, users: [] });
// Notify success
onSubmitSucceeded({ name: data.name, description: data.description });
toggleNotification({
type: 'success',
message: {
id: getTrad('Settings.roles.edited'),
defaultMessage: 'Role edited',
},
});
} catch (err) {
console.error(err);
toggleNotification({
type: 'warning',
message: {
id: 'notification.error',
defaultMessage: 'An error occurred',
},
});
}
// Unset loading state
setIsSubmitting(false);
unlockApp();
};
if (isLoadingRole) {
return <LoadingIndicatorPage />;
}
return (
<Main>
<SettingsPageTitle name="Roles" />
<Formik
enableReinitialize
initialValues={{ name: role.name, description: role.description }}
onSubmit={handleEditRoleSubmit}
validationSchema={createRoleSchema}
>
{({ handleSubmit, values, handleChange, errors }) => (
<Form noValidate onSubmit={handleSubmit}>
<HeaderLayout
primaryAction={
!isLoadingPlugins && (
<Button
disabled={role.code === 'strapi-super-admin'}
type="submit"
loading={isSubmitting}
startIcon={<Check />}
>
{formatMessage({
id: 'global.save',
defaultMessage: 'Save',
})}
</Button>
)
}
title={role.name}
subtitle={role.description}
navigationAction={
<Link startIcon={<ArrowLeft />} to="/settings/users-permissions/roles">
{formatMessage({
id: 'global.back',
defaultMessage: 'Back',
})}
</Link>
}
/>
<ContentLayout>
<Flex direction="column" alignItems="stretch" gap={7}>
<Box
background="neutral0"
hasRadius
shadow="filterShadow"
paddingTop={6}
paddingBottom={6}
paddingLeft={7}
paddingRight={7}
>
<Flex direction="column" alignItems="stretch" gap={4}>
<Typography variant="delta" as="h2">
{formatMessage({
id: getTrad('EditPage.form.roles'),
defaultMessage: 'Role details',
})}
</Typography>
<Grid gap={4}>
<GridItem col={6}>
<TextInput
name="name"
value={values.name || ''}
onChange={handleChange}
label={formatMessage({
id: 'global.name',
defaultMessage: 'Name',
})}
error={
errors.name
? formatMessage({ id: errors.name, defaultMessage: 'Invalid value' })
: null
}
/>
</GridItem>
<GridItem col={6}>
<Textarea
id="description"
value={values.description || ''}
onChange={handleChange}
label={formatMessage({
id: 'global.description',
defaultMessage: 'Description',
})}
error={
errors.description
? formatMessage({
id: errors.description,
defaultMessage: 'Invalid value',
})
: null
}
/>
</GridItem>
</Grid>
</Flex>
</Box>
{!isLoadingPlugins && (
<UsersPermissions
ref={permissionsRef}
permissions={role.permissions}
routes={routes}
/>
)}
</Flex>
</ContentLayout>
</Form>
)}
</Formik>
</Main>
);
};
export default EditPage;

View File

@ -1,93 +0,0 @@
import React from 'react';
import { Flex, IconButton, Tbody, Td, Tr, Typography } from '@strapi/design-system';
import { CheckPermissions, onRowClick, stopPropagation } from '@strapi/helper-plugin';
import { Pencil, Trash } from '@strapi/icons';
import PropTypes from 'prop-types';
import { useIntl } from 'react-intl';
import { useHistory } from 'react-router-dom';
import pluginId from '../../../../pluginId';
const TableBody = ({ sortedRoles, canDelete, permissions, setRoleToDelete, onDelete }) => {
const { formatMessage } = useIntl();
const { push } = useHistory();
const [showConfirmDelete, setShowConfirmDelete] = onDelete;
const checkCanDeleteRole = (role) =>
canDelete && !['public', 'authenticated'].includes(role.type);
const handleClickDelete = (id) => {
setRoleToDelete(id);
setShowConfirmDelete(!showConfirmDelete);
};
const handleClickEdit = (id) => {
push(`/settings/${pluginId}/roles/${id}`);
};
return (
<Tbody>
{sortedRoles?.map((role) => (
<Tr key={role.name} {...onRowClick({ fn: () => handleClickEdit(role.id) })}>
<Td width="20%">
<Typography>{role.name}</Typography>
</Td>
<Td width="50%">
<Typography>{role.description}</Typography>
</Td>
<Td width="30%">
<Typography>
{`${role.nb_users} ${formatMessage({
id: 'global.users',
defaultMessage: 'users',
}).toLowerCase()}`}
</Typography>
</Td>
<Td>
<Flex justifyContent="end" {...stopPropagation}>
<CheckPermissions permissions={permissions.updateRole}>
<IconButton
onClick={() => handleClickEdit(role.id)}
noBorder
icon={<Pencil />}
label={formatMessage(
{ id: 'app.component.table.edit', defaultMessage: 'Edit {target}' },
{ target: `${role.name}` }
)}
/>
</CheckPermissions>
{checkCanDeleteRole(role) && (
<CheckPermissions permissions={permissions.deleteRole}>
<IconButton
onClick={() => handleClickDelete(role.id)}
noBorder
icon={<Trash />}
label={formatMessage(
{ id: 'global.delete-target', defaultMessage: 'Delete {target}' },
{ target: `${role.name}` }
)}
/>
</CheckPermissions>
)}
</Flex>
</Td>
</Tr>
))}
</Tbody>
);
};
export default TableBody;
TableBody.defaultProps = {
canDelete: false,
};
TableBody.propTypes = {
onDelete: PropTypes.array.isRequired,
permissions: PropTypes.object.isRequired,
setRoleToDelete: PropTypes.func.isRequired,
sortedRoles: PropTypes.array.isRequired,
canDelete: PropTypes.bool,
};

View File

@ -1,243 +0,0 @@
import React, { useMemo, useState } from 'react';
import {
ActionLayout,
Button,
ContentLayout,
HeaderLayout,
Layout,
Main,
Table,
Th,
Thead,
Tr,
Typography,
useNotifyAT,
VisuallyHidden,
} from '@strapi/design-system';
import {
CheckPermissions,
ConfirmDialog,
EmptyStateLayout,
LoadingIndicatorPage,
NoPermissions,
SearchURLQuery,
SettingsPageTitle,
useCollator,
useFilter,
useFocusWhenNavigate,
useNotification,
useQueryParams,
useRBAC,
useTracking,
} from '@strapi/helper-plugin';
import { Plus } from '@strapi/icons';
import { useIntl } from 'react-intl';
import { useMutation, useQuery, useQueryClient } from 'react-query';
import { useHistory } from 'react-router-dom';
import permissions from '../../../permissions';
import pluginId from '../../../pluginId';
import { getTrad } from '../../../utils';
import TableBody from './components/TableBody';
import { deleteData, fetchData } from './utils/api';
const RoleListPage = () => {
const { trackUsage } = useTracking();
const { formatMessage, locale } = useIntl();
const { push } = useHistory();
const toggleNotification = useNotification();
const { notifyStatus } = useNotifyAT();
const [{ query }] = useQueryParams();
const _q = query?._q || '';
const [showConfirmDelete, setShowConfirmDelete] = useState(false);
const [isConfirmButtonLoading, setIsConfirmButtonLoading] = useState(false);
const [roleToDelete, setRoleToDelete] = useState();
useFocusWhenNavigate();
const queryClient = useQueryClient();
const updatePermissions = useMemo(() => {
return {
create: permissions.createRole,
read: permissions.readRoles,
update: permissions.updateRole,
delete: permissions.deleteRole,
};
}, []);
const {
isLoading: isLoadingForPermissions,
allowedActions: { canRead, canDelete },
} = useRBAC(updatePermissions);
const {
isLoading: isLoadingForData,
data: { roles },
isFetching,
} = useQuery('get-roles', () => fetchData(toggleNotification, notifyStatus), {
initialData: {},
enabled: canRead,
});
const { includes } = useFilter(locale, {
sensitivity: 'base',
});
/**
* @type {Intl.Collator}
*/
const formatter = useCollator(locale, {
sensitivity: 'base',
});
const isLoading = isLoadingForData || isFetching;
const handleNewRoleClick = () => {
trackUsage('willCreateRole');
push(`/settings/${pluginId}/roles/new`);
};
const handleShowConfirmDelete = () => {
setShowConfirmDelete(!showConfirmDelete);
};
const emptyLayout = {
roles: {
id: getTrad('Roles.empty'),
defaultMessage: "You don't have any roles yet.",
},
search: {
id: getTrad('Roles.empty.search'),
defaultMessage: 'No roles match the search.',
},
};
const pageTitle = formatMessage({
id: 'global.roles',
defaultMessage: 'Roles',
});
const deleteMutation = useMutation((id) => deleteData(id, toggleNotification), {
async onSuccess() {
await queryClient.invalidateQueries('get-roles');
},
});
const handleConfirmDelete = async () => {
setIsConfirmButtonLoading(true);
await deleteMutation.mutateAsync(roleToDelete);
setShowConfirmDelete(!showConfirmDelete);
setIsConfirmButtonLoading(false);
};
const sortedRoles = (roles || [])
.filter((role) => includes(role.name, _q) || includes(role.description, _q))
.sort(
(a, b) => formatter.compare(a.name, b.name) || formatter.compare(a.description, b.description)
);
const emptyContent = _q && !sortedRoles.length ? 'search' : 'roles';
const colCount = 4;
const rowCount = (roles?.length || 0) + 1;
return (
<Layout>
<SettingsPageTitle name={pageTitle} />
<Main aria-busy={isLoading}>
<HeaderLayout
title={formatMessage({
id: 'global.roles',
defaultMessage: 'Roles',
})}
subtitle={formatMessage({
id: 'Settings.roles.list.description',
defaultMessage: 'List of roles',
})}
primaryAction={
<CheckPermissions permissions={permissions.createRole}>
<Button onClick={handleNewRoleClick} startIcon={<Plus />} size="S">
{formatMessage({
id: getTrad('List.button.roles'),
defaultMessage: 'Add new role',
})}
</Button>
</CheckPermissions>
}
/>
<ActionLayout
startActions={
<SearchURLQuery
label={formatMessage({
id: 'app.component.search.label',
defaultMessage: 'Search',
})}
/>
}
/>
<ContentLayout>
{!canRead && <NoPermissions />}
{(isLoading || isLoadingForPermissions) && <LoadingIndicatorPage />}
{canRead && sortedRoles && sortedRoles?.length ? (
<Table colCount={colCount} rowCount={rowCount}>
<Thead>
<Tr>
<Th>
<Typography variant="sigma" textColor="neutral600">
{formatMessage({ id: 'global.name', defaultMessage: 'Name' })}
</Typography>
</Th>
<Th>
<Typography variant="sigma" textColor="neutral600">
{formatMessage({
id: 'global.description',
defaultMessage: 'Description',
})}
</Typography>
</Th>
<Th>
<Typography variant="sigma" textColor="neutral600">
{formatMessage({
id: 'global.users',
defaultMessage: 'Users',
})}
</Typography>
</Th>
<Th>
<VisuallyHidden>
{formatMessage({
id: 'global.actions',
defaultMessage: 'Actions',
})}
</VisuallyHidden>
</Th>
</Tr>
</Thead>
<TableBody
sortedRoles={sortedRoles}
canDelete={canDelete}
permissions={permissions}
setRoleToDelete={setRoleToDelete}
onDelete={[showConfirmDelete, setShowConfirmDelete]}
/>
</Table>
) : (
<EmptyStateLayout content={emptyLayout[emptyContent]} />
)}
</ContentLayout>
<ConfirmDialog
isConfirmButtonLoading={isConfirmButtonLoading}
onConfirm={handleConfirmDelete}
onToggleDialog={handleShowConfirmDelete}
isOpen={showConfirmDelete}
/>
</Main>
</Layout>
);
};
export default RoleListPage;

View File

@ -1,32 +0,0 @@
import { getFetchClient } from '@strapi/helper-plugin';
import { getRequestURL } from '../../../../utils';
export const fetchData = async (toggleNotification, notifyStatus) => {
try {
const { get } = getFetchClient();
const { data } = await get(getRequestURL('roles'));
notifyStatus('The roles have loaded successfully');
return data;
} catch (err) {
toggleNotification({
type: 'warning',
message: { id: 'notification.error' },
});
throw new Error(err);
}
};
export const deleteData = async (id, toggleNotification) => {
try {
const { del } = getFetchClient();
await del(`${getRequestURL('roles')}/${id}`);
} catch (error) {
toggleNotification({
type: 'warning',
message: { id: 'notification.error', defaultMessage: 'An error occured' },
});
}
};

View File

@ -1,15 +0,0 @@
import React from 'react';
import { CheckPagePermissions } from '@strapi/helper-plugin';
import pluginPermissions from '../../permissions';
import RolesCreatePage from './CreatePage';
const ProtectedRolesCreatePage = () => (
<CheckPagePermissions permissions={pluginPermissions.createRole}>
<RolesCreatePage />
</CheckPagePermissions>
);
export default ProtectedRolesCreatePage;

View File

@ -1,15 +0,0 @@
import React from 'react';
import { CheckPagePermissions } from '@strapi/helper-plugin';
import pluginPermissions from '../../permissions';
import RolesEditPage from './EditPage';
const ProtectedRolesEditPage = () => (
<CheckPagePermissions permissions={pluginPermissions.updateRole}>
<RolesEditPage />
</CheckPagePermissions>
);
export default ProtectedRolesEditPage;

View File

@ -1,17 +0,0 @@
import React from 'react';
import { CheckPagePermissions } from '@strapi/helper-plugin';
import pluginPermissions from '../../permissions';
import RolesListPage from './ListPage';
const ProtectedRolesListPage = () => {
return (
<CheckPagePermissions permissions={pluginPermissions.accessRoles}>
<RolesListPage />
</CheckPagePermissions>
);
};
export default ProtectedRolesListPage;

View File

@ -1,7 +0,0 @@
import { translatedErrors } from '@strapi/helper-plugin';
import * as yup from 'yup';
export const createRoleSchema = yup.object().shape({
name: yup.string().required(translatedErrors.required),
description: yup.string().required(translatedErrors.required),
});

View File

@ -1,30 +0,0 @@
import React from 'react';
import { AnErrorOccurred, CheckPagePermissions } from '@strapi/helper-plugin';
import { Route, Switch } from 'react-router-dom';
import pluginPermissions from '../../permissions';
import pluginId from '../../pluginId';
import ProtectedRolesCreatePage from './ProtectedCreatePage';
import ProtectedRolesEditPage from './ProtectedEditPage';
import ProtectedRolesListPage from './ProtectedListPage';
const Roles = () => {
return (
<CheckPagePermissions permissions={pluginPermissions.accessRoles}>
<Switch>
<Route
path={`/settings/${pluginId}/roles/new`}
component={ProtectedRolesCreatePage}
exact
/>
<Route path={`/settings/${pluginId}/roles/:id`} component={ProtectedRolesEditPage} exact />
<Route path={`/settings/${pluginId}/roles`} component={ProtectedRolesListPage} exact />
<Route path="" component={AnErrorOccurred} />
</Switch>
</CheckPagePermissions>
);
};
export default Roles;

View File

@ -1,31 +0,0 @@
const pluginPermissions = {
// Roles
accessRoles: [
{ action: 'plugin::users-permissions.roles.create', subject: null },
{ action: 'plugin::users-permissions.roles.read', subject: null },
],
createRole: [{ action: 'plugin::users-permissions.roles.create', subject: null }],
deleteRole: [{ action: 'plugin::users-permissions.roles.delete', subject: null }],
readRoles: [{ action: 'plugin::users-permissions.roles.read', subject: null }],
updateRole: [{ action: 'plugin::users-permissions.roles.update', subject: null }],
// AdvancedSettings
readAdvancedSettings: [
{ action: 'plugin::users-permissions.advanced-settings.read', subject: null },
],
updateAdvancedSettings: [
{ action: 'plugin::users-permissions.advanced-settings.update', subject: null },
],
// Emails
readEmailTemplates: [{ action: 'plugin::users-permissions.email-templates.read', subject: null }],
updateEmailTemplates: [
{ action: 'plugin::users-permissions.email-templates.update', subject: null },
],
// Providers
readProviders: [{ action: 'plugin::users-permissions.providers.read', subject: null }],
updateProviders: [{ action: 'plugin::users-permissions.providers.update', subject: null }],
};
export default pluginPermissions;

View File

@ -1,5 +0,0 @@
import pluginPkg from '../../package.json';
const pluginId = pluginPkg.name.replace(/^@strapi\/plugin-/i, '');
export default pluginId;

View File

@ -1,40 +0,0 @@
{
"BoundRoute.title": "Bound route to",
"EditForm.inputSelect.description.role": "سيتم إرفاق المستخدم المصادق الجديد بالدور المحدد.",
"EditForm.inputSelect.label.role": "الدور الافتراضي للمستخدمين المصادقين",
"EditForm.inputToggle.description.email": "عدم السماح للمستخدم بإنشاء حسابات متعددة باستخدام نفس عنوان البريد الإلكتروني مع موفري مصادقة مختلفين.",
"EditForm.inputToggle.description.sign-up": "عند تعطيل (OFF) ، يتم حظر عملية التسجيل. لا أحد يستطيع الاشتراك بعد الآن بغض النظر عن المزود المستخدم.",
"EditForm.inputToggle.label.email": "حساب واحد لكل بريد الاكتروني",
"EditForm.inputToggle.label.sign-up": "تفعيل التسجيل",
"HeaderNav.link.advancedSettings": "إعدادات متقدمة",
"HeaderNav.link.emailTemplates": "قوالب الإيميل",
"HeaderNav.link.providers": "مزودين",
"Plugin.permissions.plugins.description": "حدد جميع الإجراءات المسموح بها للإضافة {name}.",
"Plugins.header.description": "يتم سرد الإجراءات المحددة المرتبطة بالمسار أدناه.",
"Plugins.header.title": "الصلاحيات",
"Policies.header.hint": "حدد إجراءات التطبيق أو إجراءات الإضافة وانقر على رمز الترس لعرض المسار المرتبط",
"Policies.header.title": "إعدادات متقدمة",
"PopUpForm.Email.email_templates.inputDescription": "إذا كنت غير متأكد من كيفية استخدام المتغيرات ، {link}",
"PopUpForm.Email.options.from.email.label": "البريد الإلكتروني للشاحن",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "أسم المورد",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "الرسالة",
"PopUpForm.Email.options.object.label": "موضوع",
"PopUpForm.Email.options.response_email.label": "البريد الإلكتروني للاستجابة",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "في حالة التعطيل ، لن يتمكن المستخدمون من استخدام هذا الموفر.",
"PopUpForm.Providers.enabled.label": "مفعل",
"PopUpForm.Providers.key.label": "معرف العميل",
"PopUpForm.Providers.key.placeholder": "نص",
"PopUpForm.Providers.redirectURL.front-end.label": "عنوان URL لإعادة التوجيه إلى تطبيق الواجهة الأمامية (front-end)",
"PopUpForm.Providers.secret.label": "سر العميل (Client Secret)",
"PopUpForm.Providers.secret.placeholder": "نص",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "تحرير قوالب البريد الإلكتروني",
"notification.success.submit": "تم تحديث الإعدادات",
"plugin.description.long": "حماية الـAPI الخاص بك مع عملية مصادقة كاملة استناداً إلى JWT. يأتي هذا الملحق أيضًا مع إستراتيجية ACL التي تسمح لك بإدارة الأذونات بين مجموعات المستخدمين.",
"plugin.description.short": "حماية الـAPI الخاص بك مع عملية مصادقة كاملة استناداً إلى JWT",
"plugin.name": "الأدوار والصلاحية"
}

View File

@ -1,46 +0,0 @@
{
"BoundRoute.title": "Spojit adresu s",
"EditForm.inputSelect.description.role": "Připojí nově autentifikovaného uživatele ke svolené roli.",
"EditForm.inputSelect.label.role": "Výchozí role pro autentifikovaného uživatele",
"EditForm.inputToggle.description.email": "Zabránit uživateli vytvářet různé účty se stejným e-mailem a jinými poskytovateli autentifikace.",
"EditForm.inputToggle.description.email-confirmation": "Pokud je tato funkce povolena (ON), nově registrovaní uživatelé dostanou potvrzující e-mail.",
"EditForm.inputToggle.description.email-confirmation-redirection": "Po potvrzení e-mailu, zvolte kam budete přesměrováni.",
"EditForm.inputToggle.description.email-reset-password": "Adresa stránky obnovení hesla vaší aplikace",
"EditForm.inputToggle.description.sign-up": "Pokud je tato možnost zakázána (OFF), není možno projít registrací. Nikdo se již nemůže připojit, bez ohledu jakého použije poskytovatele.",
"EditForm.inputToggle.label.email": "Jeden účet na e-mail",
"EditForm.inputToggle.label.email-confirmation": "Povolit potvrzení z e-mailu",
"EditForm.inputToggle.label.email-confirmation-redirection": "Adresa pro přesměrování",
"EditForm.inputToggle.label.email-reset-password": "Stránka pro obnovení hesla",
"EditForm.inputToggle.label.sign-up": "Povolit registrace",
"HeaderNav.link.advancedSettings": "Pokročilá nastavení",
"HeaderNav.link.emailTemplates": "E-mailové šablony",
"HeaderNav.link.providers": "Poskytovatelé",
"Plugin.permissions.plugins.description": "Nastavit všechny akce pro zásuvný modul {name}.",
"Plugins.header.description": "Pouze akce spojené s adresou jsou vypsány níže.",
"Plugins.header.title": "Povolení",
"Policies.header.hint": "Vyberte akce aplikace, nebo akce zásuvného modulu a klikněte na ikonku ozubeného kolečka pro zobrazení adresy s nimi spojenou.",
"Policies.header.title": "Pokročilá nastavení",
"PopUpForm.Email.email_templates.inputDescription": "Pokud si nejste jisti jak používat proměnné, {link}",
"PopUpForm.Email.options.from.email.label": "Odesilatelův e-mail",
"PopUpForm.Email.options.from.email.placeholder": "jannovak@gmail.com",
"PopUpForm.Email.options.from.name.label": "Jméno odesilatele",
"PopUpForm.Email.options.from.name.placeholder": "Jan Novák",
"PopUpForm.Email.options.message.label": "Zpráva",
"PopUpForm.Email.options.object.label": "Předmět",
"PopUpForm.Email.options.response_email.label": "Response e-mail",
"PopUpForm.Email.options.response_email.placeholder": "jannovak@gmail.com",
"PopUpForm.Providers.enabled.description": "If disabled, users won't be able to use this provider.",
"PopUpForm.Providers.enabled.label": "Povolit",
"PopUpForm.Providers.key.label": "Client ID",
"PopUpForm.Providers.key.placeholder": "TEXT",
"PopUpForm.Providers.redirectURL.front-end.label": "Adresa pro přesměrování na vaši front-end aplikaci",
"PopUpForm.Providers.secret.label": "Client Secret",
"PopUpForm.Providers.secret.placeholder": "TEXT",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "Upravit e-mailové šablony",
"notification.success.submit": "Nastavení bylo aktualizování",
"plugin.description.long": "Chraňte své API pomocí kompletního autentifikačního procesu, založeného na JWT. Tento zásuvný modul obsahuje ACL strategii, která vám umožní spravovat oprávnění mezi skupinami uživatelů.",
"plugin.description.short": "Chraňte své API pomocí kompletního autentifikačního procesu, založeného na JWT",
"plugin.name": "Role a oprávnění"
}

View File

@ -1,58 +0,0 @@
{
"BoundRoute.title": "Pfad gebunden an",
"EditForm.inputSelect.description.role": "Die Rolle, die neu authentifizierten Benutzern automatisch zugewiesen wird.",
"EditForm.inputSelect.label.role": "Standardrolle für authentifizierte Benutzer",
"EditForm.inputToggle.description.email": "Verbiete das Anlegen verschiedener Accounts mit der gleichen E-Mail-Adresse bei unterschiedlichen Anmeldemethoden.",
"EditForm.inputToggle.description.email-confirmation": "Wenn aktiviert (ON) erhalten neu registrierte Benutzer eine Bestätigungs-E-Mail.",
"EditForm.inputToggle.description.email-confirmation-redirection": "Nachdem Sie die E-Mail bestätigt haben, wähle wohin sie weitergeleitet wird.",
"EditForm.inputToggle.description.email-reset-password": "URL deiner Passwort-Zurücksetzen-Seite deiner Anwendung",
"EditForm.inputToggle.description.sign-up": "Wenn deaktiviert (OFF), wird der Registrationsprozess unterbunden. Niemand kann sich mehr registrieren.",
"EditForm.inputToggle.label.email": "Ein Account pro E-Mail-Adresse",
"EditForm.inputToggle.label.email-confirmation": "Aktiviere E-Mail Benachrichtigungen",
"EditForm.inputToggle.label.email-confirmation-redirection": "Weiterleitungs-URL",
"EditForm.inputToggle.label.email-reset-password": "Passwort-Zurücksetzen-Seite",
"EditForm.inputToggle.label.sign-up": "Registration ermöglichen",
"Email.template.email_confirmation": "Bestätigung der E-Mail-Addresse",
"HeaderNav.link.advancedSettings": "Erweiterte Einstellungen",
"HeaderNav.link.emailTemplates": "E-Mail-Templates",
"HeaderNav.link.providers": "Methoden",
"Plugin.permissions.plugins.description": "Definiere die möglichen Aktionen des {name} Plugins.",
"Plugins.header.description": "Nur Aktionen, die an einen Pfad gebunden sind, werden hier gelistet.",
"Plugins.header.title": "Berechtigungen",
"Policies.header.hint": "Wähle eine Aktion aus und klicke auf das Zahnrad, um den an diese Aktion gebundenen Pfad anzuzeigen",
"Policies.header.title": "Fortgeschrittene Einstellungen",
"PopUpForm.Email.email_templates.inputDescription": "{link} für mehr Informationen",
"PopUpForm.Email.link.documentation": "Lies die Dokumentation",
"PopUpForm.Email.options.from.email.label": "E-Mail-Adresse des Absenders",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "Name des Absenders",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "Nachricht",
"PopUpForm.Email.options.object.label": "Betreff",
"PopUpForm.Email.options.object.placeholder": "Bitte bestätige deine E-Mail-Adresse für %APP_NAME%",
"PopUpForm.Email.options.response_email.label": "Antwort E-Mail-Adresse",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "Wenn deaktiviert, kann diese Methode nicht verwendet werden.",
"PopUpForm.Providers.enabled.label": "Aktivieren",
"PopUpForm.Providers.key.label": "Client ID",
"PopUpForm.Providers.key.placeholder": "TEXT",
"PopUpForm.Providers.redirectURL.front-end.label": "Die URL zur Weiterleitung zu deiner Frontend-App",
"PopUpForm.Providers.redirectURL.label": "Die Weiterleitungs-URL für die App-Einstellungen von {provider}",
"PopUpForm.Providers.secret.label": "Client Secret",
"PopUpForm.Providers.secret.placeholder": "TEXT",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "E-Mail-Templates bearbeiten",
"PopUpForm.header.edit.providers": "Anbieter bearbeiten",
"Settings.roles.deleted": "Rolle gelöscht",
"Settings.roles.edited": "Rolle bearbeitet",
"Settings.section-label": "Nutzer- & Berechtigungen-Plugin",
"notification.success.submit": "Einstellungen aktualisiert",
"plugin.description.long": "Beschütze deine API mit einem vollständigen Authentifikationsprozess basierend auf JWT. Zudem bietet dieses Plugin eine ACL-Strategie, die erlaubt, die Berechtigungen für Benutzergruppen festzulegen.",
"plugin.description.short": "Beschütze deine API mit einem vollständigen Authentifikationsprozess basierend auf JWT.",
"plugin.name": "Nutzer- & Berechtigungen-Plugin",
"popUpWarning.button.cancel": "Abbrechen",
"popUpWarning.button.confirm": "Bestätigen",
"popUpWarning.title": "Bitte bestätigen",
"popUpWarning.warning.cancel": "Willst du wirklich alle deine Änderungen verwerfen?"
}

View File

@ -1,82 +0,0 @@
{
"BoundRoute.title": "Bundet rute til",
"EditForm.inputSelect.description.role": "Den vil tilknytte den nye godkendte bruger til den valgte rolle.",
"EditForm.inputSelect.label.role": "Standard rolle for godkendte brugere",
"EditForm.inputToggle.description.email": "Tillad IKKE brugere at oprette flere brugere med den samme e-mail-adresse med forskellige godkendelsesudbydere.",
"EditForm.inputToggle.description.email-confirmation": "Når aktiv (TIL), modtager nye registrerede brugere en bekræftelses e-mail.",
"EditForm.inputToggle.description.email-confirmation-redirection": "Efter bekræftet email, vælg hvor du vil omdirigeres til.",
"EditForm.inputToggle.description.email-reset-password": "URL til din apps nulstil kodeord side",
"EditForm.inputToggle.description.sign-up": "Når deaktiveret (FRA), er registrering forbudt. Ingen kan subscribe uanset udbyder.",
"EditForm.inputToggle.label.email": "En bruger pr. e-mail",
"EditForm.inputToggle.label.email-confirmation": "Aktivér e-mail bekræftelse",
"EditForm.inputToggle.label.email-confirmation-redirection": "Omdirigerings URL",
"EditForm.inputToggle.label.email-reset-password": "Nulstil kodeord side",
"EditForm.inputToggle.label.sign-up": "Aktivér oprettelser",
"EditForm.inputToggle.placeholder.email-confirmation-redirection": "f.eks. https://hjemmeside.dk/nulstil-kodeord",
"EditForm.inputToggle.placeholder.email-reset-password": "f.eks. https://hjemmeside.dk/nulstil-kodeord",
"EditPage.form.roles": "Rolle detaljer",
"Email.template.data.loaded": "E-mail skabeloner er hentet",
"Email.template.email_confirmation": "E-mail adresse bekræftelse",
"Email.template.form.edit.label": "Redigér en skabelon",
"Email.template.table.action.label": "handling",
"Email.template.table.icon.label": "ikon",
"Email.template.table.name.label": "navn",
"Form.advancedSettings.data.loaded": "Avancerede indstillinger hentet",
"HeaderNav.link.advancedSettings": "Advancerede indstillinger",
"HeaderNav.link.emailTemplates": "E-mail skabeloner",
"HeaderNav.link.providers": "Udbydere",
"Plugin.permissions.plugins.description": "Definér alle tilladte handlinger for {name} plugin.",
"Plugins.header.description": "Kunne handlinger tilknyttet en rute er vist nedenfor.",
"Plugins.header.title": "Rettigheder",
"Policies.header.hint": "Vælg applikationens handlinger eller plugin handlinger og klik på tandhjulet for at vise den bunde rute",
"Policies.header.title": "Advancerede indstillinger",
"PopUpForm.Email.email_templates.inputDescription": "Hvis du er usikker på brugen af variabler, {link}",
"PopUpForm.Email.link.documentation": "tjek vores dokumentation.",
"PopUpForm.Email.options.from.email.label": "Afsender e-mail",
"PopUpForm.Email.options.from.email.placeholder": "johndoe@gmail.com",
"PopUpForm.Email.options.from.name.label": "Afsender name",
"PopUpForm.Email.options.from.name.placeholder": "John Doe",
"PopUpForm.Email.options.message.label": "Besked",
"PopUpForm.Email.options.object.label": "Emne",
"PopUpForm.Email.options.object.placeholder": "Bekræft venligst din e-mail adresse for %APP_NAME%",
"PopUpForm.Email.options.response_email.label": "Svar e-mail",
"PopUpForm.Email.options.response_email.placeholder": "johndoe@gmail.com",
"PopUpForm.Providers.enabled.description": "Hvis deaktiveret, kan brugere ikke bruge denne udbyder.",
"PopUpForm.Providers.enabled.label": "Aktivér",
"PopUpForm.Providers.key.label": "Klient ID",
"PopUpForm.Providers.key.placeholder": "TEKST",
"PopUpForm.Providers.redirectURL.front-end.label": "Omstillings URL til din font-end app",
"PopUpForm.Providers.redirectURL.label": "Omstillings URL som tilføjes til din {provider} applikation konfigurationer",
"PopUpForm.Providers.secret.label": "Klient hemmelighed",
"PopUpForm.Providers.secret.placeholder": "TEKST",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "mit.subdomain.dk",
"PopUpForm.header.edit.email-templates": "Redigér e-mail skabeloner",
"PopUpForm.header.edit.providers": "Redigér udbydere",
"Providers.data.loaded": "Providers hentet",
"Providers.status": "Status",
"Roles.empty": "Du har endnu ingen roller.",
"Roles.empty.search": "Ingen roller matcher søgningen.",
"Settings.roles.deleted": "Rolle slettet",
"Settings.roles.edited": "Rolle redigeret",
"Settings.section-label": "Brugere & Tilladelser plugin",
"components.Input.error.validation.email": "Dette er en ugyldig e.mail",
"components.Input.error.validation.json": "Dette stemmer ikke med JSON formatet",
"components.Input.error.validation.max": "Værdien er for høj.",
"components.Input.error.validation.maxLength": "Værdien er for lang.",
"components.Input.error.validation.min": "Værdien er for lav.",
"components.Input.error.validation.minLength": "Værdien er for kort.",
"components.Input.error.validation.minSupMax": "Kan ikke være overlegen",
"components.Input.error.validation.regex": "Værdien stemmer ikke overens med regex.",
"components.Input.error.validation.required": "Værdien er påkrævet.",
"components.Input.error.validation.unique": "Værdien er allerede brugt.",
"notification.success.submit": "Indstillingerne er blevet opdateret",
"page.title": "Indstillinger - Roller",
"plugin.description.long": "Beskyt din API med fuld godkendelse med JWT. Dette plugin kommer også med en ACL strategi som tillader dig at håndtere rettigeheder mellem grupper af brugere.",
"plugin.description.short": "Beskyt din API med fuld godkendelse med JWT",
"plugin.name": "Roller & rettigheder",
"popUpWarning.button.cancel": "Annuller",
"popUpWarning.button.confirm": "Bekræft",
"popUpWarning.title": "Bekræft venligst",
"popUpWarning.warning.cancel": "Er du sikker på at du vil annullere dine ændringer?"
}

View File

@ -1,82 +0,0 @@
{
"BoundRoute.title": "Bound route to",
"EditForm.inputSelect.description.role": "It will attach the new authenticated user to the selected role.",
"EditForm.inputSelect.label.role": "Default role for authenticated users",
"EditForm.inputToggle.description.email": "Disallow the user to create multiple accounts using the same email address with different authentication providers.",
"EditForm.inputToggle.description.email-confirmation": "When enabled (ON), new registered users receive a confirmation email.",
"EditForm.inputToggle.description.email-confirmation-redirection": "After you confirmed your email, choose where you will be redirected.",
"EditForm.inputToggle.description.email-reset-password": "URL of your application's reset password page",
"EditForm.inputToggle.description.sign-up": "When disabled (OFF), the registration process is forbidden. No one can subscribe anymore no matter the used provider.",
"EditForm.inputToggle.label.email": "One account per email address",
"EditForm.inputToggle.label.email-confirmation": "Enable email confirmation",
"EditForm.inputToggle.label.email-confirmation-redirection": "Redirection url",
"EditForm.inputToggle.label.email-reset-password": "Reset password page",
"EditForm.inputToggle.label.sign-up": "Enable sign-ups",
"EditForm.inputToggle.placeholder.email-confirmation-redirection": "ex: https://yourfrontend.com/email-confirmation-redirection",
"EditForm.inputToggle.placeholder.email-reset-password": "ex: https://yourfrontend.com/reset-password",
"EditPage.form.roles": "Role details",
"Email.template.data.loaded": "Email templates has been loaded",
"Email.template.email_confirmation": "Email address confirmation",
"Email.template.form.edit.label": "Edit a template",
"Email.template.table.action.label": "action",
"Email.template.table.icon.label": "icon",
"Email.template.table.name.label": "name",
"Form.advancedSettings.data.loaded": "Advanced settings data has been loaded",
"HeaderNav.link.advancedSettings": "Advanced settings",
"HeaderNav.link.emailTemplates": "Email templates",
"HeaderNav.link.providers": "Providers",
"Plugin.permissions.plugins.description": "Define all allowed actions for the {name} plugin.",
"Plugins.header.description": "Only actions bound by a route are listed below.",
"Plugins.header.title": "Permissions",
"Policies.header.hint": "Select the application's actions or the plugin's actions and click on the cog icon to display the bound route",
"Policies.header.title": "Advanced settings",
"PopUpForm.Email.email_templates.inputDescription": "If you're unsure how to use variables, {link}",
"PopUpForm.Email.link.documentation": "check out our documentation.",
"PopUpForm.Email.options.from.email.label": "Shipper email",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "Shipper name",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "Message",
"PopUpForm.Email.options.object.label": "Subject",
"PopUpForm.Email.options.object.placeholder": "Please confirm your email address for %APP_NAME%",
"PopUpForm.Email.options.response_email.label": "Response email",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "If disabled, users won't be able to use this provider.",
"PopUpForm.Providers.enabled.label": "Enable",
"PopUpForm.Providers.key.label": "Client ID",
"PopUpForm.Providers.key.placeholder": "TEXT",
"PopUpForm.Providers.redirectURL.front-end.label": "The redirect URL to your front-end app",
"PopUpForm.Providers.redirectURL.label": "The redirect URL to add in your {provider} application configurations",
"PopUpForm.Providers.secret.label": "Client Secret",
"PopUpForm.Providers.secret.placeholder": "TEXT",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "Edit email template",
"PopUpForm.header.edit.providers": "Edit Provider",
"Providers.data.loaded": "Providers have been loaded",
"Providers.status": "Status",
"Roles.empty": "You don't have any roles yet.",
"Roles.empty.search": "No roles match the search.",
"Settings.roles.deleted": "Role deleted",
"Settings.roles.edited": "Role edited",
"Settings.section-label": "Users & Permissions plugin",
"components.Input.error.validation.email": "This is an invalid email",
"components.Input.error.validation.json": "This doesn't match the JSON format",
"components.Input.error.validation.max": "The value is too high.",
"components.Input.error.validation.maxLength": "The value is too long.",
"components.Input.error.validation.min": "The value is too low.",
"components.Input.error.validation.minLength": "The value is too short.",
"components.Input.error.validation.minSupMax": "Can't be superior",
"components.Input.error.validation.regex": "The value does not match the regex.",
"components.Input.error.validation.required": "This value is required.",
"components.Input.error.validation.unique": "This value is already used.",
"notification.success.submit": "Settings have been updated",
"page.title": "Settings - Roles",
"plugin.description.long": "Protect your API with a full authentication process based on JWT. This plugin comes also with an ACL strategy that allows you to manage the permissions between the groups of users.",
"plugin.description.short": "Protect your API with a full authentication process based on JWT.",
"plugin.name": "Users & Permissions Plugin",
"popUpWarning.button.cancel": "Cancel",
"popUpWarning.button.confirm": "Confirm",
"popUpWarning.title": "Please confirm",
"popUpWarning.warning.cancel": "Are you sure you want to cancel your modifications?"
}

View File

@ -1,82 +0,0 @@
{
"BoundRoute.title": "Ruta enlazada a",
"EditForm.inputSelect.description.role": "Adjuntará el nuevo usuario autenticado al rol seleccionado.",
"EditForm.inputSelect.label.role": "Rol predeterminado para usuarios autenticados",
"EditForm.inputToggle.description.email": "No permita que el usuario cree varias cuentas utilizando la misma dirección de correo electrónico con distintos proveedores de autenticación.",
"EditForm.inputToggle.description.email-confirmation": "Estando habilitado (ON), nuevos usuarios registrados reciben un correo de confirmación.",
"EditForm.inputToggle.description.email-confirmation-redirection": "After confirmed your email, chose where you will be redirected.",
"EditForm.inputToggle.description.email-reset-password": "URL de la página de restablecimiento de contraseña de su aplicación",
"EditForm.inputToggle.description.sign-up": "Cuando está desactivado (OFF), el proceso de registro está prohibido. Nadie puede suscribirse sin importar el proveedor utilizado.",
"EditForm.inputToggle.label.email": "Una cuenta por dirección de correo electrónico",
"EditForm.inputToggle.label.email-confirmation": "Habilitar confirmación de correo",
"EditForm.inputToggle.label.email-confirmation-redirection": "URL de redirección",
"EditForm.inputToggle.label.email-reset-password": "Página de reestablecer la contraseña",
"EditForm.inputToggle.label.sign-up": "Habilitar inscripciones",
"EditForm.inputToggle.placeholder.email-confirmation-redirection": "ej: https://tufrontend.com/restablecer-contrasena",
"EditForm.inputToggle.placeholder.email-reset-password": "ej: https://tufrontend.com/restablecer-contrasena",
"EditPage.form.roles": "Detalles del rol",
"Email.template.data.loaded": "Se han cargado las plantillas de correo electrónico",
"Email.template.email_confirmation": "Confirmación de dirección de correo electrónico",
"Email.template.form.edit.label": "Editar una plantilla",
"Email.template.table.action.label": "acción",
"Email.template.table.icon.label": "icono",
"Email.template.table.name.label": "nombre",
"Form.advancedSettings.data.loaded": "Se han cargado los datos de configuración avanzada",
"HeaderNav.link.advancedSettings": "Ajustes avanzados",
"HeaderNav.link.emailTemplates": "Plantillas de email",
"HeaderNav.link.providers": "Proveedores",
"Plugin.permissions.plugins.description": "Defina todas las acciones permitidas para el plugin {name}.",
"Plugins.header.description": "Sólo las acciones vinculadas a una ruta se enumeran a continuación.",
"Plugins.header.title": "Permisos",
"Policies.header.hint": "Seleccione las acciones de la aplicación o las acciones del plugin y haga clic en el icono del engranaje para ver la ruta vinculada",
"Policies.header.title": "Ajustes avanzados",
"PopUpForm.Email.email_templates.inputDescription": "Si no estás seguro de cómo usar las variables, {link}",
"PopUpForm.Email.link.documentation": "consulte nuestra documentación.",
"PopUpForm.Email.options.from.email.label": "Email del remitente",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "Nombre del remitente",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "Mensaje",
"PopUpForm.Email.options.object.label": "Tema",
"PopUpForm.Email.options.object.placeholder": "Confirma tu dirección de correo electrónico para %APP_NAME%",
"PopUpForm.Email.options.response_email.label": "Email de respuesta",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "Si está desactivado, los usuarios no podrán utilizar este proveedor.",
"PopUpForm.Providers.enabled.label": "Habilitar",
"PopUpForm.Providers.key.label": "ID de cliente",
"PopUpForm.Providers.key.placeholder": "TEXTO",
"PopUpForm.Providers.redirectURL.front-end.label": "La URL de redireccionamiento a su aplicación front-end",
"PopUpForm.Providers.redirectURL.label": "La URL de redireccionamiento para agregar en las configuraciones de su aplicación de {proveedor}",
"PopUpForm.Providers.secret.label": "Secreto Cliente",
"PopUpForm.Providers.secret.placeholder": "TEXTO",
"PopUpForm.Providers.subdomain.label": "URI de host (subdominio)",
"PopUpForm.Providers.subdomain.placeholder": "mi.subdominio.com",
"PopUpForm.header.edit.email-templates": "Editar Plantillas de Email",
"PopUpForm.header.edit.providers": "Editar proveedor",
"Providers.data.loaded": "Los proveedores se han cargado",
"Providers.status": "Estado",
"Roles.empty": "Aún no tienes ningún rol.",
"Roles.empty.search": "Ningún rol coincide con la búsqueda.",
"Settings.roles.deleted": "Rol eliminado",
"Settings.roles.edited": "Rol editado",
"Settings.section-label": "Plugin de Usuarios y Permisos",
"components.Input.error.validation.email": "El correo electrónico inválido",
"components.Input.error.validation.json": "No coincide con el formato JSON",
"components.Input.error.validation.max": "El valor es demasiado alto.",
"components.Input.error.validation.maxLength": "El valor es demasiado largo.",
"components.Input.error.validation.min": "El valor es demasiado bajo.",
"components.Input.error.validation.minLength": "El valor es demasiado corto.",
"components.Input.error.validation.minSupMax": "No puede ser superior",
"components.Input.error.validation.regex": "El valor no coincide con la expresión regular.",
"components.Input.error.validation.required": "Este valor es obligatorio.",
"components.Input.error.validation.unique": "Este valor ya se utiliza.",
"notification.success.submit": "Los ajustes se han actualizado",
"page.title": "Configuración - Roles",
"plugin.description.long": "Proteja su API con un proceso de autenticación completo basado en JWT. Este plugin viene también con una estrategia ACL que le permite administrar los permisos entre los grupos de usuarios.",
"plugin.description.short": "Proteja su API con un proceso de autenticación completo basado en JWT",
"plugin.name": "Roles y Permisos",
"popUpWarning.button.cancel": "Cancelar",
"popUpWarning.button.confirm": "Confirmar",
"popUpWarning.title": "Por favor confirme",
"popUpWarning.warning.cancel": "¿Está seguro de que desea cancelar sus modificaciones?"
}

View File

@ -1,46 +0,0 @@
{
"BoundRoute.title": "Route associée à",
"EditForm.inputSelect.description.role": "Choisissez le rôle qui sera lié aux utilisateurs lors de leur enregistrement.",
"EditForm.inputSelect.label.role": "Rôle par defaut pour les nouveaux utilisateurs",
"EditForm.inputToggle.description.email": "Interdire l'utilisateur de créer de multiple comptes avec la même adresse e-mail avec des providers différents",
"EditForm.inputToggle.description.email-confirmation": "Quand cette option est activée (ON), les nouveaux utilisateurs enregistrés reçoivent un e-mail de confirmation.",
"EditForm.inputToggle.description.email-confirmation-redirection": "Après confirmation de votre e-mail, choisissez où vous allez être redirigé.",
"EditForm.inputToggle.description.email-reset-password": "URL de la page de réinitialisation de mot de passe.",
"EditForm.inputToggle.description.sign-up": "Quand l'inscription est désactivée (OFF), aucun utilisateur ne peut s'inscrire qu'importe le provider",
"EditForm.inputToggle.label.email": "Un compte par adresse e-mail",
"EditForm.inputToggle.label.email-confirmation": "Activer l'e-mail de confirmation",
"EditForm.inputToggle.label.email-confirmation-redirection": "Redirection de l'URL",
"EditForm.inputToggle.label.email-reset-password": "Page de réinitialisation de mot de passe",
"EditForm.inputToggle.label.sign-up": "Activer l'inscription",
"HeaderNav.link.advancedSettings": "Paramètres avancés",
"HeaderNav.link.emailTemplates": "Templates d'e-mail",
"HeaderNav.link.providers": "Fournisseurs",
"Plugin.permissions.plugins.description": "Définissez les actions autorisées dans le {name} plugin.",
"Plugins.header.description": "Sont listés uniquement les actions associées à une route.",
"Plugins.header.title": "Permissions",
"Policies.header.hint": "Sélectionnez les actions de l'application ou d'un plugin et cliquer sur l'icon de paramètres pour voir les routes associées à cette action",
"Policies.header.title": "Paramètres avancés",
"PopUpForm.Email.email_templates.inputDescription": "Regardez la documentation des variables, {link}",
"PopUpForm.Email.options.from.email.label": "E-mail de l'envoyeur",
"PopUpForm.Email.options.from.email.placeholder": "arthurdupont@gmail.com",
"PopUpForm.Email.options.from.name.label": "Nom de l'envoyeur",
"PopUpForm.Email.options.from.name.placeholder": "Arthur Dupont",
"PopUpForm.Email.options.message.label": "Message",
"PopUpForm.Email.options.object.label": "Objet",
"PopUpForm.Email.options.response_email.label": "E-mail de réponse",
"PopUpForm.Email.options.response_email.placeholder": "arthurdupont@gmail.com",
"PopUpForm.Providers.enabled.description": "S'il est désactivé les utilisateurs ne pourront pas utiliser ce provider.",
"PopUpForm.Providers.enabled.label": "Activer",
"PopUpForm.Providers.key.label": "Client ID",
"PopUpForm.Providers.key.placeholder": "TEXT",
"PopUpForm.Providers.redirectURL.front-end.label": "L'URL de redirection de votre app front-end",
"PopUpForm.Providers.secret.label": "Client Secret",
"PopUpForm.Providers.secret.placeholder": "TEXT",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "Editer E-mail Templates",
"notification.success.submit": "Les configurations ont bien été sauvegardés",
"plugin.description.long": "Protégez votre API avec un système d'authentification complet basé sur JWT (JSON Web Token). Ce plugin ajoute aussi une stratégie ACL (Access Control Layer) qui vous permet de gérer les permissions entre les groupes d'utilisateurs.",
"plugin.description.short": "Protégez votre API avec un système d'authentification complet basé sur JWT.",
"plugin.name": "Rôles et autorisations"
}

View File

@ -1,58 +0,0 @@
{
"BoundRoute.title": "Rute terikat ke",
"EditForm.inputSelect.description.role": "Ini akan melampirkan pengguna baru yang diautentikasi ke peran yang dipilih.",
"EditForm.inputSelect.label.role": "Peran default untuk pengguna yang diautentikasi",
"EditForm.inputToggle.description.email": "Larang pengguna membuat beberapa akun menggunakan alamat email yang sama dengan penyedia otentikasi yang berbeda.",
"EditForm.inputToggle.description.email-confirmation": "Saat diaktifkan (ON), pengguna baru yang terdaftar menerima email konfirmasi.",
"EditForm.inputToggle.description.email-confirmation-redirection": "Setelah Anda mengkonfirmasi email Anda, pilih ke mana Anda akan diarahkan.",
"EditForm.inputToggle.description.email-reset-password": "URL halaman setel ulang sandi aplikasi Anda",
"EditForm.inputToggle.description.sign-up": "Saat dinonaktifkan (OFF), proses pendaftaran dilarang. Tidak ada yang bisa berlangganan lagi tidak peduli penyedia yang digunakan.",
"EditForm.inputToggle.label.email": "Satu akun per alamat email",
"EditForm.inputToggle.label.email-confirmation": "Aktifkan konfirmasi email",
"EditForm.inputToggle.label.email-confirmation-redirection": "URL pengalihan",
"EditForm.inputToggle.label.email-reset-password": "Atur ulang halaman kata sandi",
"EditForm.inputToggle.label.sign-up": "Aktifkan pendaftaran",
"Email.template.email_confirmation": "Konfirmasi alamat email",
"HeaderNav.link.advancedSettings": "Pengaturan lanjutan",
"HeaderNav.link.emailTemplates": "Template email",
"HeaderNav.link.providers": "Penyedia",
"Plugin.permissions.plugins.description": "Tentukan semua tindakan yang diizinkan untuk plugin {name}.",
"Plugins.header.description": "Hanya tindakan yang terikat oleh rute yang dicantumkan di bawah.",
"Plugins.header.title": "Izin",
"Policies.header.hint": "Pilih tindakan aplikasi atau tindakan plugin dan klik ikon roda gigi untuk menampilkan rute terikat",
"Policies.header.title": "Pengaturan lanjutan",
"PopUpForm.Email.email_templates.inputDescription": "Jika Anda tidak yakin bagaimana menggunakan variabel, {link}",
"PopUpForm.Email.link.documentation": "lihat dokumentasi kami.",
"PopUpForm.Email.options.from.email.label": "Email pengirim",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "Nama pengirim",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "Pesan",
"PopUpForm.Email.options.object.label": "Subyek",
"PopUpForm.Email.options.object.placeholder": "Harap konfirmasi alamat email Anda untuk% APP_NAME%",
"PopUpForm.Email.options.response_email.label": "Email tanggapan",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "Jika dinonaktifkan, pengguna tidak akan dapat menggunakan penyedia ini.",
"PopUpForm.Providers.enabled.label": "Memungkinkan",
"PopUpForm.Providers.key.label": "ID Klien",
"PopUpForm.Providers.key.placeholder": "TEKS",
"PopUpForm.Providers.redirectURL.front-end.label": "URL pengalihan ke aplikasi front-end Anda",
"PopUpForm.Providers.redirectURL.label": "URL pengalihan yang akan ditambahkan dalam konfigurasi aplikasi {provider} Anda",
"PopUpForm.Providers.secret.label": "Client Secret",
"PopUpForm.Providers.secret.placeholder": "TEKS",
"PopUpForm.Providers.subdomain.label": "URI Host (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "saya.subdomain.com",
"PopUpForm.header.edit.email-templates": "Edit Template Email",
"PopUpForm.header.edit.providers": "Edit Penyedia",
"Settings.roles.deleted": "Peran dihapus",
"Settings.roles.edited": "Peran diedit",
"Settings.section-label": "Plugin Pengguna & Izin",
"notification.success.submit": "Pengaturan telah diperbarui",
"plugin.description.long": "Lindungi API Anda dengan proses otentikasi penuh berdasarkan JWT. Plugin ini juga dilengkapi dengan strategi ACL yang memungkinkan Anda untuk mengelola izin di antara grup pengguna.",
"plugin.description.short": "Lindungi API Anda dengan proses otentikasi penuh berdasarkan JWT",
"plugin.name": "Plugin Pengguna & Izin",
"popUpWarning.button.cancel": "Batalkan",
"popUpWarning.button.confirm": "Konfirmasi",
"popUpWarning.title": "Harap konfirmasi",
"popUpWarning.warning.cancel": "Anda yakin ingin membatalkan modifikasi Anda?"
}

View File

@ -1,58 +0,0 @@
{
"BoundRoute.title": "Vincola route a",
"EditForm.inputSelect.description.role": "Questa operazione assocerà i nuovi utenti autenticati al ruolo selezionato.",
"EditForm.inputSelect.label.role": "Ruolo di default per gli utenti registrati",
"EditForm.inputToggle.description.email": "Non consentire all'utente di creare account multipli usando lo stesso indirizzo email con provider di autenticazione diversi.",
"EditForm.inputToggle.description.email-confirmation": "Quando abilitato (ON), i nuovi utenti registrati riceveranno una richiesta di conferma via email.",
"EditForm.inputToggle.description.email-confirmation-redirection": "Scegli dove redirigere gli utenti che completano la conferma dell'indirizzo email.",
"EditForm.inputToggle.description.email-reset-password": "URL della pagina per il reset della password della tua applicazione",
"EditForm.inputToggle.description.sign-up": "Quando disabilitata (OFF), il processo di registrazione è proibito. Nessuno può iscriversi indipendentemente dal provider utilizzato.",
"EditForm.inputToggle.label.email": "Un solo account per indirizzo email",
"EditForm.inputToggle.label.email-confirmation": "Abilita conferma email",
"EditForm.inputToggle.label.email-confirmation-redirection": "URL di reindirizzamento",
"EditForm.inputToggle.label.email-reset-password": "Pagina reset password",
"EditForm.inputToggle.label.sign-up": "Abilita registrazione",
"Email.template.email_confirmation": "Conferma dell'indirizzo Email",
"HeaderNav.link.advancedSettings": "Impostazioni avanzate",
"HeaderNav.link.emailTemplates": "Template delle Email",
"HeaderNav.link.providers": "Provider",
"Plugin.permissions.plugins.description": "Definisce tutte le azioni consentite per il plugin {name}.",
"Plugins.header.description": "Di seguito sono elencate solo le azioni vincolate da una route.",
"Plugins.header.title": "Permessi",
"Policies.header.hint": "Seleziona le azioni dell'applicazione o del plugin e clicca sull'ingranaggio per mostrare il percorso corrispondente",
"Policies.header.title": "Impostazioni avanzate",
"PopUpForm.Email.email_templates.inputDescription": "Se non sai bene come usare le variabili, {link}",
"PopUpForm.Email.link.documentation": "controlla la nostra documentazione.",
"PopUpForm.Email.options.from.email.label": "Email del mittente",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "Nome del mittente",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "Messaggio",
"PopUpForm.Email.options.object.label": "Oggetto",
"PopUpForm.Email.options.object.placeholder": "Conferma il tuo indirizzo email per %APP_NAME%",
"PopUpForm.Email.options.response_email.label": "Email di risposta",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "Se disabilitato, gli utenti non potranno usare questo provider.",
"PopUpForm.Providers.enabled.label": "Abilita",
"PopUpForm.Providers.key.label": "Client ID",
"PopUpForm.Providers.key.placeholder": "TEXT",
"PopUpForm.Providers.redirectURL.front-end.label": "L'URL di reindirizzamento per la tua app di front-end",
"PopUpForm.Providers.redirectURL.label": "L'URL di reindirizzamento da aggiungere nelle impostazioni dell'applicazione di {provider}",
"PopUpForm.Providers.secret.label": "Client Secret",
"PopUpForm.Providers.secret.placeholder": "TEXT",
"PopUpForm.Providers.subdomain.label": "Host URI (Sottodominio)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "Modifica i Template Email",
"PopUpForm.header.edit.providers": "Modifica Provider",
"Settings.roles.deleted": "Ruolo eliminato",
"Settings.roles.edited": "Ruolo modificato",
"Settings.section-label": "Plugin Utenti & Permessi",
"notification.success.submit": "Impostazioni aggiornate",
"plugin.description.long": "Proteggi le tue API con un processo di autenticazione completo basato su JWT. Questo plugin è implementato con una strategia ACL che ti consente di gestire i permessi tra i gruppi di utenti.",
"plugin.description.short": "Proteggi le tue API con un processo di autenticazione completo basato su JWT",
"plugin.name": "Plugin Utenti & Permessi",
"popUpWarning.button.cancel": "Annulla",
"popUpWarning.button.confirm": "Conferma",
"popUpWarning.title": "Si prega di confermare",
"popUpWarning.warning.cancel": "Sei sicuro di voler annullare le tue modifiche?"
}

View File

@ -1,44 +0,0 @@
{
"BoundRoute.title": "Bound route to",
"EditForm.inputSelect.description.role": "新しい認証されたユーザーが選択された役割にアタッチされます。",
"EditForm.inputSelect.label.role": "認証されたユーザーのデフォルトの役割",
"EditForm.inputToggle.description.email": "ユーザーが異なる認証プロバイダで同じ電子メールアドレスを使用して複数のアカウントを作成できないようにします。",
"EditForm.inputToggle.description.email-confirmation": "有効ONにすると、新しい登録ユーザーに確認メールが送信されます。",
"EditForm.inputToggle.description.email-confirmation-redirection": "あなたのEメールを確認したら、リダイレクト先を選択してください。",
"EditForm.inputToggle.description.sign-up": "あなたの電子メールを確認した後、リダイレクト先を選択しました。",
"EditForm.inputToggle.label.email": "メールアドレスごとに1つのアカウント",
"EditForm.inputToggle.label.email-confirmation": "Eメールの確認を有効にする",
"EditForm.inputToggle.label.email-confirmation-redirection": "リダイレクトURL",
"EditForm.inputToggle.label.sign-up": "申し込みを有効にする",
"HeaderNav.link.advancedSettings": "高度な設定",
"HeaderNav.link.emailTemplates": "メールテンプレート",
"HeaderNav.link.providers": "プロバイダー",
"Plugin.permissions.plugins.description": "{name} 個のプラグインに対して許可されたすべてのアクションを定義する",
"Plugins.header.description": "ルートにバインドされたアクションのみが以下にリストされています",
"Plugins.header.title": "権限",
"Policies.header.hint": "アプリケーションのアクションまたはプラグインのアクションを選択し、コグアイコンをクリックしてバインドされたルートを表示します",
"Policies.header.title": "高度な設定",
"PopUpForm.Email.email_templates.inputDescription": "変数の使用方法がわからない場合は、{link}",
"PopUpForm.Email.options.from.email.label": "送信者Eメール",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "送信者名",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "メッセージ",
"PopUpForm.Email.options.object.label": "件名",
"PopUpForm.Email.options.response_email.label": "応答メール",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "無効にすると、ユーザーはこのプロバイダを使用できなくなります。",
"PopUpForm.Providers.enabled.label": "有効にする",
"PopUpForm.Providers.key.label": "クライアントID",
"PopUpForm.Providers.key.placeholder": "TEXT",
"PopUpForm.Providers.redirectURL.front-end.label": "フロントエンドアプリへのリダイレクトURL",
"PopUpForm.Providers.secret.label": "クライアントの秘密",
"PopUpForm.Providers.secret.placeholder": "TEXT",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "メールテンプレートの編集",
"notification.success.submit": "設定が更新されました",
"plugin.description.long": "JWTに基づいた完全な認証プロセスでAPIを保護します。このプラグインには、ユーザーのグループ間で権限を管理できるACL戦略もあります。",
"plugin.description.short": "JWTに基づく完全な認証プロセスでAPIを保護する",
"plugin.name": "ロールと権限"
}

View File

@ -1,82 +0,0 @@
{
"BoundRoute.title": "라우트(bound route)",
"EditForm.inputSelect.description.role": "인증된 사용자에 선택한 역할(role)을 부여합니다.",
"EditForm.inputSelect.label.role": "인증된 사용자의 기본 역할(role)",
"EditForm.inputToggle.description.email": "사용자가 동일한 이메일 주소를 사용해 여러 계정을 만들지 못하게 합니다.",
"EditForm.inputToggle.description.email-confirmation": "(ON)이 활성화되면, 새로 가입하는 사용자는 인증 메일을 받게됩니다.",
"EditForm.inputToggle.description.email-confirmation-redirection": "이메일 인증완료 후 리다이렉트 될 주소",
"EditForm.inputToggle.description.email-reset-password": "애플리케이션의 비밀번호 재설정 URL 페이지",
"EditForm.inputToggle.description.sign-up": "비활성(OFF)일 경우, 등록 프로세스를 금지합니다. 사용하는 프로바이더(provider)에 관계 없이 누구도 가입할 수 없습니다.",
"EditForm.inputToggle.label.email": "이메일 주소 당 하나의 계정",
"EditForm.inputToggle.label.email-confirmation": "이메일 인증 활성화",
"EditForm.inputToggle.label.email-confirmation-redirection": "리다이렉션 url",
"EditForm.inputToggle.label.email-reset-password": "패스워드 재설정 페이지",
"EditForm.inputToggle.label.sign-up": "사용자 등록",
"EditForm.inputToggle.placeholder.email-confirmation-redirection": "예: https://yourfrontend.com/reset-password",
"EditForm.inputToggle.placeholder.email-reset-password": "예: https://yourfrontend.com/reset-password",
"EditPage.form.roles": "역할 상세정보",
"Email.template.data.loaded": "이메일 템플릿을 불러왔습니다.",
"Email.template.email_confirmation": "이메일 주소 확인",
"Email.template.form.edit.label": "템플릿 수정",
"Email.template.table.action.label": "action",
"Email.template.table.icon.label": "icon",
"Email.template.table.name.label": "name",
"Form.advancedSettings.data.loaded": "고급 설정 정보를 불러왔습니다.",
"HeaderNav.link.advancedSettings": "고급 설정",
"HeaderNav.link.emailTemplates": "이메일 템플릿",
"HeaderNav.link.providers": "프로바이더(Providers)",
"Plugin.permissions.plugins.description": "{name} 플러그인에서 허용할 액션을 설정합니다.",
"Plugins.header.description": "라우트(route)에 연결된 액션만 표시됩니다.",
"Plugins.header.title": "권한(Permissions)",
"Policies.header.hint": "애플리케이션 또는 플러그인을 선택하고 항목을 클릭하면 바인딩 된 경로를 표시할 수 있습니다.",
"Policies.header.title": "고급 설정",
"PopUpForm.Email.email_templates.inputDescription": "이메일 템플릿 문법은 이 {link}를 확인하세요.",
"PopUpForm.Email.link.documentation": "check out our documentation.",
"PopUpForm.Email.options.from.email.label": "보내는 이메일",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "보내는 사람",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "내용",
"PopUpForm.Email.options.object.label": "제목",
"PopUpForm.Email.options.object.placeholder": "Please confirm your email address for %APP_NAME%",
"PopUpForm.Email.options.response_email.label": "응답받을 이메일",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "사용하지 않을 경우 이 프로바이더(provider) 기능을 이용할 수 없습니다.",
"PopUpForm.Providers.enabled.label": "사용",
"PopUpForm.Providers.key.label": "클라이언트 ID(Client ID)",
"PopUpForm.Providers.key.placeholder": "텍스트",
"PopUpForm.Providers.redirectURL.front-end.label": "프론트엔드 애플리케이션 리다이렉트 URL",
"PopUpForm.Providers.redirectURL.label": "{provider} 애플리케이션 구성에 추가할 리디렉션 URL",
"PopUpForm.Providers.secret.label": "클라이언트 시크릿(Client Secret)",
"PopUpForm.Providers.secret.placeholder": "텍스트",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "이메일 템플릿 수정",
"PopUpForm.header.edit.providers": "프로바이더 수정",
"Providers.data.loaded": "프로바이더를 불러왔습니다.",
"Providers.status": "상태",
"Roles.empty": "아직 역할이 없습니다.",
"Roles.empty.search": "검색과 일치하는 역할이 없습니다.",
"Settings.roles.deleted": "Role deleted",
"Settings.roles.edited": "Role edited",
"Settings.section-label": "사용자 & 권한 플러그인",
"components.Input.error.validation.email": "유효하지 않은 이메일입니다.",
"components.Input.error.validation.json": "JSON 형식과 일치하지 않습니다.",
"components.Input.error.validation.max": "값이 너무 큽니다.",
"components.Input.error.validation.maxLength": "값이 너무 깁니다.",
"components.Input.error.validation.min": "값이 너무 작습니다.",
"components.Input.error.validation.minLength": "값이 너무 짧습니다.",
"components.Input.error.validation.minSupMax": "이보다 클 수 없습니다.",
"components.Input.error.validation.regex": "값이 정규식과 일치하지 않습니다.",
"components.Input.error.validation.required": "필수 항목입니다.",
"components.Input.error.validation.unique": "이 값은 이미 사용되고 있습니다.",
"notification.success.submit": "설정을 업데이트했습니다.",
"page.title": "설정 - 역할",
"plugin.description.long": "JWT 기반의 인증 프로세스로 API를 보호하세요. 이 플러그인에서 사용자 그룹간 권한을 관리할 수 있는 ACL 전략도 설정할 수 있습니다.",
"plugin.description.short": "JWT 기반의 인증 프로세스로 API를 보호하세요.",
"plugin.name": "역할(roles) & 권한(permissions)",
"popUpWarning.button.cancel": "취소",
"popUpWarning.button.confirm": "확인",
"popUpWarning.title": "Please confirm",
"popUpWarning.warning.cancel": "수정 사항을 취소하시겠습니까?"
}

View File

@ -1,45 +0,0 @@
{
"BoundRoute.title": "Ikat laluan ke",
"EditForm.inputSelect.description.role": "Ini akan meletakkan peranan yang dipilih pada pengguna baru.",
"EditForm.inputSelect.label.role": "Peranan asal untuk pengguna yang disahkan",
"EditForm.inputToggle.description.email": "Tidak membenarkan pengguna membuat beberapa akaun menggunakan alamat e-mel yang sama dengan pembekal pengesahan yang berbeza.",
"EditForm.inputToggle.description.email-confirmation": "Apabila diaktifkan (ON), pengguna berdaftar baru akan menerima e-mel pengesahan.",
"EditForm.inputToggle.description.email-confirmation-redirection": "Setelah mengesahkan e-mel anda, pilih di mana anda akan di redirect kan.",
"EditForm.inputToggle.description.email-reset-password": "URL halaman kata laluan tetapan semula untuk aplikasi anda",
"EditForm.inputToggle.description.sign-up": "Apabila dinyahaktifkan (MATI), proses pendaftaran tidak dibenarkan. Tidak ada yang boleh melanggan lagi tidak kira pembekal telah dipakai.",
"EditForm.inputToggle.label.email": "Satu akaun setiap alamat e-mel",
"EditForm.inputToggle.label.email-confirmation": "Aktifkan pengesahan e-mel",
"EditForm.inputToggle.label.email-confirmation-redirection": "Redirection url",
"EditForm.inputToggle.label.email-reset-password": "Halaman tetapan semula kata laluan",
"EditForm.inputToggle.label.sign-up": "Aktifkan pendaftaran",
"HeaderNav.link.advancedSettings": "Tetapan lanjut",
"HeaderNav.link.emailTemplates": "Templat e-mel",
"HeaderNav.link.providers": "Pembekal",
"Plugin.permissions.plugins.description": "Pilih arahan yang dibenarkan untuk plugin {name}.",
"Plugins.header.description": "Hanya arahan yang terpasang dengan laluan sahaja yang tersenarai di bawah.",
"Plugins.header.title": "Keizinan",
"Policies.header.hint": "Pilih tindakan aplikasi atau plugin dan klik pada ikon gear untuk melihat laluan yang terpasang",
"Policies.header.title": "Tetapan lanjut",
"PopUpForm.Email.email_templates.inputDescription": "Sekiranya anda tidak pasti cara menggunakan pemboleh ubah, {link} ",
"PopUpForm.Email.options.from.email.label": "E-mel penghantar",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "Nama pengirim",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "Mesej",
"PopUpForm.Email.options.object.label": "Subjek",
"PopUpForm.Email.options.response_email.label": "E-mel jawapan",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "Sekiranya dinyahaktifkan, pengguna tidak akan dapat menggunakan pembekal ini.",
"PopUpForm.Providers.enabled.label": "Aktifkan",
"PopUpForm.Providers.key.label": "ID Pelanggan",
"PopUpForm.Providers.key.placeholder": "TEKS",
"PopUpForm.Providers.redirectURL.front-end.label": "URL pengubah hala ke aplikasi 'front-end' anda",
"PopUpForm.Providers.secret.label": "Client Secret",
"PopUpForm.Providers.secret.placeholder": "TEKS",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "Edit Templat E-mel",
"notification.success.submit": "Tetapan telah dikemas kini",
"plugin.description.long": "Lindungi API anda dengan proses pengesahan penuh berdasarkan JWT. Plugin ini juga dilengkapi dengan strategi ACL yang membolehkan anda mengurus pengizinan antara kumpulan pengguna.",
"plugin.description.short": "Lindungi API anda dengan proses pengesahan penuh berdasarkan JWT"
}

View File

@ -1,44 +0,0 @@
{
"BoundRoute.title": "Gebonden route naar",
"EditForm.inputSelect.description.role": "Het zal de nieuwe geautoriseerde gebruiker aan de geselecteerde rol verbinden.",
"EditForm.inputSelect.label.role": "Standaard rol voor geautoriseerde gebruikers",
"EditForm.inputToggle.description.email": "Zorg ervoor dat de gebruiker niet meerdere accounts kan maken met hetzelfde e-mailadres maar met verschillende leveranciers.",
"EditForm.inputToggle.description.email-confirmation": "Wanneer ingeschakeld (ON), ontvangen nieuw geregistreerde gebruikers een bevestigingsmail.",
"EditForm.inputToggle.description.email-confirmation-redirection": "Na het bevestigen van je e-mail, kies naar waar je doorgestuurd zal worden.",
"EditForm.inputToggle.description.sign-up": "Wanneer uitgeschakeld (OFF), is registratie verboden. Niemand kan abonneren ongeacht de leverancier",
"EditForm.inputToggle.label.email": "Één account per e-mailadres.",
"EditForm.inputToggle.label.email-confirmation": "Schakel emailbevestiging in",
"EditForm.inputToggle.label.email-confirmation-redirection": "Doorstuur URL",
"EditForm.inputToggle.label.sign-up": "Registratie inschakelen",
"HeaderNav.link.advancedSettings": "Geavanceerde instellingen",
"HeaderNav.link.emailTemplates": "E-mail sjabloon",
"HeaderNav.link.providers": "Leveranciers",
"Plugin.permissions.plugins.description": "Voer alle toegestane acties in voor extensie {name}.",
"Plugins.header.description": "Alleen acties gekoppeld aan een route worden hieronder weergegeven.",
"Plugins.header.title": "Permissies",
"Policies.header.hint": "Selecteer de actie van de applicatie of de acties van de extensie en klik op het tandwiel icoontje om de gekoppelde route weer te geven",
"Policies.header.title": "Geavanceerde instellingen",
"PopUpForm.Email.email_templates.inputDescription": "Als je niet zeker weet hoe je variabelen moet gebruiken, {link}",
"PopUpForm.Email.options.from.email.label": "Afzender e-mail",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "Afzender naam",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "Bericht",
"PopUpForm.Email.options.object.label": "Onderwerp",
"PopUpForm.Email.options.response_email.label": "Antwoord e-mail",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "Als deze uitgeschakeld is kunnen gebruikers geen gebruik maken van deze leverancier.",
"PopUpForm.Providers.enabled.label": "Inschakelen",
"PopUpForm.Providers.key.label": "Client ID",
"PopUpForm.Providers.key.placeholder": "TEXT",
"PopUpForm.Providers.redirectURL.front-end.label": "De doorstuur URL voor jouw front-end app",
"PopUpForm.Providers.secret.label": "Client Secret",
"PopUpForm.Providers.secret.placeholder": "TEXT",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "E-mail sjablonen aanpassen",
"notification.success.submit": "Instellingen zijn geüpdatet",
"plugin.description.long": "Beveilig je API met een volledig authenticatie proces op JWT. Deze extensie komt ook met een ACL strategie welke ervoor zorgt dat je de permissies tussen groepen van gebruikers kan beheren.",
"plugin.description.short": "Beveilig je API met een volledig authenticatie proces op JWT",
"plugin.name": "Rollen & Permissies"
}

View File

@ -1,82 +0,0 @@
{
"BoundRoute.title": "Wywoływanie",
"EditForm.inputSelect.description.role": "Połączy nowego uwierzytelnionego użytkownika z wybraną rolą.",
"EditForm.inputSelect.label.role": "Domyślna rola dla uwierzytelnionych użytkowników",
"EditForm.inputToggle.description.email": "Nie zezwalaj użytkownikowi na tworzenie wielu kont za pomocą tego samego adresu e-mail u różnych dostawców uwierzytelniania.",
"EditForm.inputToggle.description.email-confirmation": "Gdy włączone (ON), nowo zarejestrowani uzytkownicy otrzymają wiadomość potwierdzającą.",
"EditForm.inputToggle.description.email-confirmation-redirection": "Po potwierdzeniu adresu email, wybierz gdzie zostaniesz przekierowany.",
"EditForm.inputToggle.description.email-reset-password": "Adres URL strony resetowania hasła aplikacji",
"EditForm.inputToggle.description.sign-up": "Po wyłączeniu (OFF) proces rejestracji jest zabroniony. Nikt nie może już dołączyć bez względu na używanego dostawcę.",
"EditForm.inputToggle.label.email": "Jedno konto na adres email",
"EditForm.inputToggle.label.email-confirmation": "Zezwól na potwierdzenie adresu email",
"EditForm.inputToggle.label.email-confirmation-redirection": "Url przekierowania",
"EditForm.inputToggle.label.email-reset-password": "Strona resetowania hasła",
"EditForm.inputToggle.label.sign-up": "Włącz możliwość rejestracji",
"EditForm.inputToggle.placeholder.email-confirmation-redirection": "ex: https://yourfrontend.com/confirmation-redirection",
"EditForm.inputToggle.placeholder.email-reset-password": "ex: https://yourfrontend.com/reset-password",
"EditPage.form.roles": "Szczegóły roli",
"Email.template.data.loaded": "Szablon email został załadowany",
"Email.template.email_confirmation": "Potwierdzenie adresu email",
"Email.template.form.edit.label": "Edytuj szablon",
"Email.template.table.action.label": "akcja",
"Email.template.table.icon.label": "ikonka",
"Email.template.table.name.label": "nazwa",
"Form.advancedSettings.data.loaded": "Ustawienia zaawansowane zostały załadowane",
"HeaderNav.link.advancedSettings": "Zaawansowane",
"HeaderNav.link.emailTemplates": "Szablony e-mail",
"HeaderNav.link.providers": "Dostawcy",
"Plugin.permissions.plugins.description": "Określ dozwolone działania dla pluginu {name}.",
"Plugins.header.description": "Jedynie akcje związane z wywoływaniami są wymienione poniżej.",
"Plugins.header.title": "Uprawnienia",
"Policies.header.hint": "Wybierz działania aplikacji lub działania pluginu i kliknij ikonę koła zębatego, aby wyświetlić wywoływania",
"Policies.header.title": "Zaawansowane",
"PopUpForm.Email.email_templates.inputDescription": "Nie wiesz jak skonfigurować zmienne? {link}",
"PopUpForm.Email.link.documentation": "sprawdź dokumentację.",
"PopUpForm.Email.options.from.email.label": "Email nadawcy",
"PopUpForm.Email.options.from.email.placeholder": "jannowak@gmail.com",
"PopUpForm.Email.options.from.name.label": "Nazwa nadawcy",
"PopUpForm.Email.options.from.name.placeholder": "Jan Nowak",
"PopUpForm.Email.options.message.label": "Wiadomość",
"PopUpForm.Email.options.object.label": "Temat",
"PopUpForm.Email.options.object.placeholder": "Proszę potwierdź adres email dla %APP_NAME%",
"PopUpForm.Email.options.response_email.label": "Email zwrotny",
"PopUpForm.Email.options.response_email.placeholder": "jannowak@gmail.com",
"PopUpForm.Providers.enabled.description": "W przypadku wyłączenia, użytkownicy nie będą mogli skorzystać z tego dostawcy.",
"PopUpForm.Providers.enabled.label": "Włączony",
"PopUpForm.Providers.key.label": "ID klienta",
"PopUpForm.Providers.key.placeholder": "TEKST",
"PopUpForm.Providers.redirectURL.front-end.label": "Adres przekierowania do własnej aplikacji",
"PopUpForm.Providers.redirectURL.label": "Adres przekierowania do dodania w twoich ustawieniach aplikacji: {provider}",
"PopUpForm.Providers.secret.label": "Klucz sekretny klienta",
"PopUpForm.Providers.secret.placeholder": "TEKST",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "Zmień szablony e-mail",
"PopUpForm.header.edit.providers": "Edytuj dostawcę",
"Providers.data.loaded": "Dostawcy zostali załadowani",
"Providers.status": "Status",
"Roles.empty": "Nie masz jeszcze żadnych ról.",
"Roles.empty.search": "Żadne role nie pasują do wyszukiwania.",
"Settings.roles.deleted": "Rola usunięta",
"Settings.roles.edited": "Rola edytowana",
"Settings.section-label": "Użytkownicy i Uprawnienia",
"components.Input.error.validation.email": "Ten email jest niepoprawny",
"components.Input.error.validation.json": "Nie pasuje do formatu JSON",
"components.Input.error.validation.max": "Wartość zbyt duża.",
"components.Input.error.validation.maxLength": "Wartość zbyt długa.",
"components.Input.error.validation.min": "Wartość zbyt mała.",
"components.Input.error.validation.minLength": "Wartość zbyt krótka.",
"components.Input.error.validation.minSupMax": "Nie może być wyższy",
"components.Input.error.validation.regex": "Wartość nie pasuje do regexa.",
"components.Input.error.validation.required": "Wartość wymagana.",
"components.Input.error.validation.unique": "Wartość już używana.",
"notification.success.submit": "Ustawienia zostały zaktualizowane",
"page.title": "Ustawienia - Role",
"plugin.description.long": "Chroń API za pomocą procesu pełnego uwierzytelniania opartego na JWT. Ten plugin zawiera również strategię ACL, która pozwala zarządzać uprawnieniami między grupami użytkowników.",
"plugin.description.short": "Chroń API za pomocą procesu pełnego uwierzytelniania opartego na JWT",
"plugin.name": "Role i Uprawnienia",
"popUpWarning.button.cancel": "Anuluj",
"popUpWarning.button.confirm": "Potwierdź",
"popUpWarning.title": "Proszę potwierdź",
"popUpWarning.warning.cancel": "Czy jesteś pewny, że chcesz anulować zmiany?"
}

View File

@ -1,40 +0,0 @@
{
"BoundRoute.title": "Rota definida para",
"EditForm.inputSelect.description.role": "Ele anexará o novo usuário autenticado ao nível selecionado.",
"EditForm.inputSelect.label.role": "Nível padrão para usuários autenticados",
"EditForm.inputToggle.description.email": "Não permitir que o usuário crie várias contas usando o mesmo endereço de e-mail com diferentes provedores de autenticação.",
"EditForm.inputToggle.description.sign-up": "Quando desativado (OFF), o processo de registro é proibido. Nenhum novo usuário poderá se registrar, não importa o provedor usado.",
"EditForm.inputToggle.label.email": "Limitar 1 conta por endereço de email",
"EditForm.inputToggle.label.sign-up": "Ativar registro de usuários",
"HeaderNav.link.advancedSettings": "Configurações avançadas",
"HeaderNav.link.emailTemplates": "Modelos de email",
"HeaderNav.link.providers": "Provedores",
"Plugin.permissions.plugins.description": "Defina todas as ações permitidas para o plugin {name}.",
"Plugins.header.description": "Somente ações vinculadas por uma rota estão listadas abaixo.",
"Plugins.header.title": "Permissões",
"Policies.header.hint": "Selecione as ações do aplicativo ou as ações do plugin e clique no ícone do cog para exibir a rota",
"Policies.header.title": "Configurações avançadas",
"PopUpForm.Email.email_templates.inputDescription": "Se não tiver certeza de como usar variáveis, {link}",
"PopUpForm.Email.options.from.email.label": "Email do remetente",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "Nome do remetente",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "Mensagem",
"PopUpForm.Email.options.object.label": "Assunto",
"PopUpForm.Email.options.response_email.label": "Email de resposta",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "Se desativado, os usuários não poderão usar este provedor",
"PopUpForm.Providers.enabled.label": "Ativar",
"PopUpForm.Providers.key.label": "ID do cliente",
"PopUpForm.Providers.key.placeholder": "TEXT",
"PopUpForm.Providers.redirectURL.front-end.label": "O URL de redirecionamento para seu aplicativo front-end",
"PopUpForm.Providers.secret.label": "Segredo do Cliente",
"PopUpForm.Providers.secret.placeholder": "TEXT",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "Editar modelos de email",
"notification.success.submit": "As configurações foram atualizadas",
"plugin.description.long": "Proteja sua API com um processo de autenticação completo baseado no JWT. Esse plugin também vem com uma estratégia de ACL que permite gerenciar as permissões entre os grupos de usuários.",
"plugin.description.short": "Proteja sua API com um processo de autenticação completo baseado no JWT",
"plugin.name": "Papéis e permissões"
}

View File

@ -1,44 +0,0 @@
{
"BoundRoute.title": "Ligar rota a",
"EditForm.inputSelect.description.role": "Vai atribuir o grupo selecionado ao novo utilizador autenticado.",
"EditForm.inputSelect.label.role": "Grupo por defeito para utilizadores autenticados",
"EditForm.inputToggle.description.email": "Proibir a criação de múltiplas contas com o mesmo email por serviços de autenticação diferentes.",
"EditForm.inputToggle.description.email-confirmation": "Quando ativado (ON), os novos utilizadores recebem um email de confirmação.",
"EditForm.inputToggle.description.email-confirmation-redirection": "Após confirmar o seu email, escolha para onde vai ser redirecionado.",
"EditForm.inputToggle.description.sign-up": "Quando desativado (OFF), o processo de registo está proibido. Ninguém se consegue registar mais, independentemente do serviço de authenticação.",
"EditForm.inputToggle.label.email": "Uma conta por endereço de email",
"EditForm.inputToggle.label.email-confirmation": "Ativar email de confirmação",
"EditForm.inputToggle.label.email-confirmation-redirection": "Endereço de redirecionamento (URL)",
"EditForm.inputToggle.label.sign-up": "Ativar registos",
"HeaderNav.link.advancedSettings": "Configurações avançadas",
"HeaderNav.link.emailTemplates": "Modelos de email",
"HeaderNav.link.providers": "Serviços de autenticação",
"Plugin.permissions.plugins.description": "Defina todas as ações permitidas para o plugin {name}.",
"Plugins.header.description": "Todas as ações associadas a uma rota estão listadas abaixo.",
"Plugins.header.title": "Permissões",
"Policies.header.hint": "Selecione as ações da aplicação ou dos plugins e clique no ícone para mostrar as rotas associadas",
"Policies.header.title": "Configurações avançadas",
"PopUpForm.Email.email_templates.inputDescription": "Se não tem a certeza de como usar as variáveis, {link}",
"PopUpForm.Email.options.from.email.label": "Shipper email",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "Shipper name",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "Mensagem",
"PopUpForm.Email.options.object.label": "Assunto",
"PopUpForm.Email.options.response_email.label": "Email de resposta",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "Se desativado, os utilizadores não conseguirão utilizar este serviço de autenticação.",
"PopUpForm.Providers.enabled.label": "Ativar",
"PopUpForm.Providers.key.label": "ID de Client",
"PopUpForm.Providers.key.placeholder": "TEXTO",
"PopUpForm.Providers.redirectURL.front-end.label": "Endereço de redirecionamento para a sua aplicação de front-end",
"PopUpForm.Providers.secret.label": "Segredo de cliente",
"PopUpForm.Providers.secret.placeholder": "TEXTO",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "Editar Modelos de Email",
"notification.success.submit": "As configurações foram atualizadas",
"plugin.description.long": "Proteja a sua API com um processo completo de autenticação baseado em JWT. Este plugin também vem com estratégia de ACL que permite gerir permissões entre grupos de utilizadores.",
"plugin.description.short": "Proteja a sua API com um processo completo de autenticação baseado em JWT",
"plugin.name": "Grupos & Permissões"
}

View File

@ -1,82 +0,0 @@
{
"BoundRoute.title": "Связать путь с",
"EditForm.inputSelect.description.role": "При регистрации пользователи будут иметь выбранную роль.",
"EditForm.inputSelect.label.role": "Роль по умолчанию для новых пользователей",
"EditForm.inputToggle.description.email": "Запретить пользователю создавать несколько учётных записей, используя один и тот же адрес электронной почты, у разных поставщиков аутентификации.",
"EditForm.inputToggle.description.email-confirmation": "Если включено (ON), при регистрации пользователи будут получать письмо для подтверждения адреса электронной почты.",
"EditForm.inputToggle.description.email-confirmation-redirection": "Укажите URL-адрес для перенаправления пользователей после подтверждения адреса электронной почты.",
"EditForm.inputToggle.description.email-reset-password": "URL-адрес страницы для сброса пароля учётной записи пользователя",
"EditForm.inputToggle.description.sign-up": "Если выключено (OFF), процесс регистрации пользователей запрещен. Никто не может зарегистрироваться, независимо от провайдера.",
"EditForm.inputToggle.label.email": "Одна учётная запись на один адрес электронной почты",
"EditForm.inputToggle.label.email-confirmation": "Включить подтверждение по электронной почте",
"EditForm.inputToggle.label.email-confirmation-redirection": "URL-адрес для перенаправления",
"EditForm.inputToggle.label.email-reset-password": "Страница сброса пароля",
"EditForm.inputToggle.label.sign-up": "Включить регистрации",
"EditForm.inputToggle.placeholder.email-confirmation-redirection": "например: https://yourfrontend.com/email-confirmation-redirection",
"EditForm.inputToggle.placeholder.email-reset-password": "например: https://yourfrontend.com/reset-password",
"EditPage.form.roles": "Сведения о роли",
"Email.template.data.loaded": "Шаблоны автоматических писем для электронной почты были загружены",
"Email.template.email_confirmation": "Адреса электронной почты с письмом о подтверждении",
"Email.template.form.edit.label": "Редактировать шаблон",
"Email.template.table.action.label": "действие",
"Email.template.table.icon.label": "иконка",
"Email.template.table.name.label": "название",
"Form.advancedSettings.data.loaded": "Данные расширенных настроек были загружены",
"HeaderNav.link.advancedSettings": "Расширенные настройки",
"HeaderNav.link.emailTemplates": "Шаблоны писем",
"HeaderNav.link.providers": "Провайдеры",
"Plugin.permissions.plugins.description": "Определите все разрешенные действия для плагина {name}.",
"Plugins.header.description": "Ниже перечислены только действия, связанные с путём.",
"Plugins.header.title": "Разрешения",
"Policies.header.hint": "Выберите действия приложения или плагина и нажмите на значок шестерёнки, чтобы отобразить связанный путь",
"Policies.header.title": "Расширенные настройки",
"PopUpForm.Email.email_templates.inputDescription": "Если вы не уверены, как использовать переменные — {link}",
"PopUpForm.Email.link.documentation": "ознакомьтесь с нашей документацией.",
"PopUpForm.Email.options.from.email.label": "Электронная почта отправителя",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "Имя отправителя",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "Сообщение",
"PopUpForm.Email.options.object.label": "Тема",
"PopUpForm.Email.options.object.placeholder": "Пожалуйста, подтвердите свой адрес электронной почты для %APP_NAME%",
"PopUpForm.Email.options.response_email.label": "Электронная почта для ответов",
"PopUpForm.Email.options.response_email.placeholder": "paul@example.com",
"PopUpForm.Providers.enabled.description": "Если этот параметр отключен, пользователи не смогут использовать этого поставщика.",
"PopUpForm.Providers.enabled.label": "Включено",
"PopUpForm.Providers.key.label": "ID клиента",
"PopUpForm.Providers.key.placeholder": "TEXT",
"PopUpForm.Providers.redirectURL.front-end.label": "URL-адрес перенаправления на ваше приложение",
"PopUpForm.Providers.redirectURL.label": "URL-адрес перенаправления, который нужно добавить в {provider} конфигурации приложения",
"PopUpForm.Providers.secret.label": "Client Secret",
"PopUpForm.Providers.secret.placeholder": "TEXT",
"PopUpForm.Providers.subdomain.label": "Хост URI (Поддомен)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "Редактировать шаблон письма",
"PopUpForm.header.edit.providers": "Редактировать провайдера",
"Providers.data.loaded": "Провайдеры были загружены",
"Providers.status": "Статус",
"Roles.empty": "У вас пока нет никаких ролей.",
"Roles.empty.search": "Ни одна роль не соответствует поисковому запросу.",
"Settings.roles.deleted": "Роль удалена",
"Settings.roles.edited": "Роль отредактирована",
"Settings.section-label": "Плагин «Пользователи и Разрешения»",
"components.Input.error.validation.email": "Неверный адрес электронной почты",
"components.Input.error.validation.json": "Это не соответствует формату JSON",
"components.Input.error.validation.max": "Значение слишком велико.",
"components.Input.error.validation.maxLength": "Значение слишком длинное.",
"components.Input.error.validation.min": "Значение слишком мало.",
"components.Input.error.validation.minLength": "Значение слишком короткое.",
"components.Input.error.validation.minSupMax": "Не может быть выше",
"components.Input.error.validation.regex": "Значение не соответствует регулярному выражению.",
"components.Input.error.validation.required": "Это значение является обязательным.",
"components.Input.error.validation.unique": "Это значение уже используется.",
"notification.success.submit": "Настройки были обновлены",
"page.title": "Настройки — Роли",
"plugin.description.long": "Защитите свой API с помощью полноценного процесса аутентификации, основанного на JWT. Этот плагин также имеет настройки стратегии ACL, которые позволяют вам управлять разрешениями между группами пользователей.",
"plugin.description.short": "Защитите свой API с помощью полноценного процесса аутентификации, основанного на JWT.",
"plugin.name": "Пользователи и Разрешения",
"popUpWarning.button.cancel": "Отменить",
"popUpWarning.button.confirm": "Подтвердить",
"popUpWarning.title": "Пожалуйста подтвердите",
"popUpWarning.warning.cancel": "Вы уверены, что хотите отменить свои изменения?"
}

View File

@ -1,46 +0,0 @@
{
"BoundRoute.title": "URL endpoint naviazaný k",
"EditForm.inputSelect.description.role": "Pridá rolu k používateľovi.",
"EditForm.inputSelect.label.role": "Predvolená rola pre autorizovaných používateľov",
"EditForm.inputToggle.description.email": "Zakázať používateľovi vytvoriť viac účtov s rovnakou e-mailovou adresou pre rôznych poskytovateľov.",
"EditForm.inputToggle.description.email-confirmation": "Ak je povolené (ON), registrovaní používatelia dostanú potvrdzovací e-mail.",
"EditForm.inputToggle.description.email-confirmation-redirection": "URL na ktorú bude používateľ presmerovaný po potvrdení e-mailu.",
"EditForm.inputToggle.description.email-reset-password": "URL pre nastavenie nového hesla",
"EditForm.inputToggle.description.sign-up": "Ak je zakázané (OFF), registrácie nebudú povolené. Nikto sa nebude môcť registrovať bez ohľadu na zvoleného poskytovateľa.",
"EditForm.inputToggle.label.email": "Iba jedno konto pre jednu e-mailovú adresu",
"EditForm.inputToggle.label.email-confirmation": "Povoliť potvrdzovanie e-mailových adries",
"EditForm.inputToggle.label.email-confirmation-redirection": "URL pre potvrdenie e-mailovej adresy",
"EditForm.inputToggle.label.email-reset-password": "URL pre obnovu hesla",
"EditForm.inputToggle.label.sign-up": "Povoliť registrácie",
"HeaderNav.link.advancedSettings": "Pokročilé nastavenia",
"HeaderNav.link.emailTemplates": "Šablóny emailov",
"HeaderNav.link.providers": "Poskytovatelia",
"Plugin.permissions.plugins.description": "Zvoľte akcie, ktoré majú byť povolené pre plugin {name}.",
"Plugins.header.description": "Zobrazujú sa iba akcie naviazané na URL endpoint.",
"Plugins.header.title": "Oprávnenia",
"Policies.header.hint": "Vyberte akciu a kliknite na ikonku nastavení pre zobrazenie naviazanej URL",
"Policies.header.title": "Pokročilé nastavenia",
"PopUpForm.Email.email_templates.inputDescription": "Ak si nie ste istý ako používať premenné, {link}",
"PopUpForm.Email.options.from.email.label": "E-mail odosielateľa",
"PopUpForm.Email.options.from.email.placeholder": "janko.hrasko@gmail.com",
"PopUpForm.Email.options.from.name.label": "Meno odosielateľa",
"PopUpForm.Email.options.from.name.placeholder": "Janko Hraško",
"PopUpForm.Email.options.message.label": "Obsah e-mailu",
"PopUpForm.Email.options.object.label": "Predmet",
"PopUpForm.Email.options.response_email.label": "Odpovedať na e-mail",
"PopUpForm.Email.options.response_email.placeholder": "janko.hrasko@gmail.com",
"PopUpForm.Providers.enabled.description": "Ak je zakázané, používatelia nebudú môcť použiť tohto poskytovateľa.",
"PopUpForm.Providers.enabled.label": "Povoliť",
"PopUpForm.Providers.key.label": "Client ID",
"PopUpForm.Providers.key.placeholder": "TEXT",
"PopUpForm.Providers.redirectURL.front-end.label": "URL presmerovania do vašej aplikácie",
"PopUpForm.Providers.secret.label": "Client Secret",
"PopUpForm.Providers.secret.placeholder": "TEXT",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "Upraviť šablóny e-mailov",
"notification.success.submit": "Nastavenia boli uložené",
"plugin.description.long": "Zabezpečte vaše API pomocou JWT tokenov. Tento plugin taktiež podporuje ACL záznamy, ktoré umožňujú spravovať oprávnenia v rámci skupín používateľov.",
"plugin.description.short": "Zabezpečte vaše API pomocou JWT tokenov",
"plugin.name": "Roly a oprávnenia"
}

View File

@ -1,82 +0,0 @@
{
"BoundRoute.title": "Bind rutt till",
"EditForm.inputSelect.description.role": "Den bifogar den nya autentiserade användaren till den valda rollen.",
"EditForm.inputSelect.label.role": "Standardroll för autentiserade användare",
"EditForm.inputToggle.description.email": "Tillåt ej användaren att skapa flera konton med samma e-postadress med olika autentiseringstjänster.",
"EditForm.inputToggle.description.email-confirmation": "När aktiverat (PÅ) får nya registrerade användare ett bekräftelsemeddelande.",
"EditForm.inputToggle.description.email-confirmation-redirection": "När du har bekräftat din e-post väljer du var du ska omdirigeras.",
"EditForm.inputToggle.description.email-reset-password": "URL:en till din applikations sida för återställning av lösenord",
"EditForm.inputToggle.description.sign-up": "När inaktiverad (AV) är registreringsprocessen förbjuden. Ingen kan prenumerera längre oavsett vilken autentiseringstjänst som används.",
"EditForm.inputToggle.label.email": "Ett konto per e-postadress",
"EditForm.inputToggle.label.email-confirmation": "Aktivera e-postbekräftelse",
"EditForm.inputToggle.label.email-confirmation-redirection": "Omdirigerings-url",
"EditForm.inputToggle.label.email-reset-password": "Återställ lösenordssidan",
"EditForm.inputToggle.label.sign-up": "Tillåt registreringar",
"EditForm.inputToggle.placeholder.email-confirmation-redirection": "t.ex: https://yourfrontend.com/email-confirmation-redirection",
"EditForm.inputToggle.placeholder.email-reset-password": "t.ex: https://yourfrontend.com/reset-password",
"EditPage.form.roles": "Rolldetaljer",
"Email.template.data.loaded": "E-postmallar har laddats",
"Email.template.email_confirmation": "Bekräftelse av e-postadress",
"Email.template.form.edit.label": "Redigera en mall",
"Email.template.table.action.label": "händelse",
"Email.template.table.icon.label": "ikon",
"Email.template.table.name.label": "namn",
"Form.advancedSettings.data.loaded": "Data för avancerade inställningar har laddats",
"HeaderNav.link.advancedSettings": "Avancerade inställningar",
"HeaderNav.link.emailTemplates": "E-postmall",
"HeaderNav.link.providers": "Autentiseringstjänster",
"Plugin.permissions.plugins.description": "Definiera alla tillåtna åtgärder för {name} plugin.",
"Plugins.header.description": "Endast åtgärder som är bundna av en rutt listas nedan.",
"Plugins.header.title": "Behörigheter",
"Policies.header.hint": "Välj programmets åtgärder eller plugins åtgärder och klicka på kugghjulsikonen för att visa den bundna rutten",
"Policies.header.title": "Avancerade inställningar",
"PopUpForm.Email.email_templates.inputDescription": "Om du är osäker på hur du använder variabler, {link}",
"PopUpForm.Email.link.documentation": "Kolla in vår dokumentation.",
"PopUpForm.Email.options.from.email.label": "Avsändarens e-postadress",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "Avsändarens namn",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "Meddelande",
"PopUpForm.Email.options.object.label": "Ämne",
"PopUpForm.Email.options.object.placeholder": "Bekräfta din e-postadress för %APP_NAME%",
"PopUpForm.Email.options.response_email.label": "Svarsmail",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "Om inaktiverat kan användarna inte använda den här tjänsten.",
"PopUpForm.Providers.enabled.label": "Tillåt",
"PopUpForm.Providers.key.label": "Klient ID",
"PopUpForm.Providers.key.placeholder": "TEXT",
"PopUpForm.Providers.redirectURL.front-end.label": "Omdirigerings-URL: en till din front-end-app",
"PopUpForm.Providers.redirectURL.label": "Webbadressen för omdirigering som ska läggas till i {Provider} applikationskonfigurationer",
"PopUpForm.Providers.secret.label": "Klient hemlighet",
"PopUpForm.Providers.secret.placeholder": "TEXT",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomän)",
"PopUpForm.Providers.subdomain.placeholder": "min.subdoman.com",
"PopUpForm.header.edit.email-templates": "Redigera e-postmallar",
"PopUpForm.header.edit.providers": "Redigera tjänst",
"Providers.data.loaded": "Tjänster har laddats in",
"Providers.status": "Status",
"Roles.empty": "Du har inga roller än.",
"Roles.empty.search": "Inga roller matchar sökningen.",
"Settings.roles.deleted": "Roll borttagen",
"Settings.roles.edited": "Roll redigerad",
"Settings.section-label": "Roller och behörigheter",
"components.Input.error.validation.email": "E-postadressen är ogiltig",
"components.Input.error.validation.json": "Detta är inte giltig JSON",
"components.Input.error.validation.max": "Värdet är för högt.",
"components.Input.error.validation.maxLength": "Värdet är för långt.",
"components.Input.error.validation.min": "Värdet är för lågt.",
"components.Input.error.validation.minLength": "Värdet är för kort.",
"components.Input.error.validation.minSupMax": "Minsta värdet är större än maximalt värde.",
"components.Input.error.validation.regex": "Värdet matchar inte regex-mönstret.",
"components.Input.error.validation.required": "Värdet är obligatoriskt.",
"components.Input.error.validation.unique": "Detta värdet är redan använt.",
"notification.success.submit": "Inställningar har uppdaterats",
"page.title": "Inställningar - Roller",
"plugin.description.long": "Skydda ditt API med en fullständig autentiseringsprocess baserad på JWT. Detta plugin har också en ACL-strategi som låter dig hantera behörigheterna mellan användargrupperna.",
"plugin.description.short": "Skydda ditt API med en fullständig autentiseringsprocess baserad på JWT",
"plugin.name": "Roller och behörigheter",
"popUpWarning.button.cancel": "Avbryt",
"popUpWarning.button.confirm": "Bekräfta",
"popUpWarning.title": "Var god bekräfta",
"popUpWarning.warning.cancel": "Är du säker att du vill avbryta dina ändringar?"
}

View File

@ -1,56 +0,0 @@
{
"BoundRoute.title": "กำหนดเส้นทางไปยัง",
"EditForm.inputSelect.description.role": "แนบผู้ใช้ที่พิสูจน์ตัวตนใหม่ไปยังบทบาทที่เลือก",
"EditForm.inputSelect.label.role": "บทบาทพื้นฐานสำหรับผู้ใช้ที่พิสูจน์ตัวตน",
"EditForm.inputToggle.description.email": "ไม่อนุญาตให้ผู้ใช้สร้างหลายแอคเคาต์ โดยใช้อีเมลเดียวกันกับผู้ให้บริการการพิสูจน์ตัวตนที่ต่างกัน",
"EditForm.inputToggle.description.email-confirmation": "เมื่อเปิดใช้งาน (เปิด) ผู้ใช้สีแดงที่ลงทะเบียนใหม่จะได้รับอีเมลยืนยัน",
"EditForm.inputToggle.description.email-confirmation-redirection": "หลังจากยืนยันอีเมลของคุณแล้ว, ให้เลือกตำแหน่งที่คุณจะเปลี่ยนทิศทาง",
"EditForm.inputToggle.description.email-reset-password": "URL ของเพจรีเซ็ตรหัสผ่านแอปพลิเคชันของคุณ",
"EditForm.inputToggle.description.sign-up": "เมื่อปิดใช้งาน (OFF) กระบวนการลงทะเบียนจะถูกห้าม ไม่มีใครสามารถสมัครสมาชิกได้อีกต่อไปไม่ว่าจะเป็นผู้ให้บริการที่ใช้",
"EditForm.inputToggle.label.email": "หนึ่งแอคเคาต์ต่ออีเมลแอดเดรส",
"EditForm.inputToggle.label.email-confirmation": "เปิดใช้งานการยืนยันอีเมล",
"EditForm.inputToggle.label.email-confirmation-redirection": "Url การเปลี่ยนทิศทาง",
"EditForm.inputToggle.label.email-reset-password": "หน้ารีเซ็ตรหัสผ่าน",
"EditForm.inputToggle.label.sign-up": "เปิดใช้งานการลงทะเบียน",
"Email.template.email_confirmation": "ยืนยันอีเมลแอดเดรส",
"HeaderNav.link.advancedSettings": "การตั้งค่าขั้นสูง",
"HeaderNav.link.emailTemplates": "เท็มเพลตอีเมล",
"HeaderNav.link.providers": "ผู้ให้บริการ",
"Plugin.permissions.plugins.description": "กำหนดการดำเนินการที่อนุญาตทั้งหมดสำหรับปลั๊กอิน {name}",
"Plugins.header.description": "เฉพาะการดำเนินการที่โยงโดยเราต์จะถูกแสดงด้านล่าง",
"Plugins.header.title": "สิทธิการใช้งาน",
"Policies.header.hint": "เลือกแอ็คชันของแอปพลิเคชันหรือแอ็คชันของปลั๊กอินและคลิกบนไอคอนฟันเฟือง เพื่อแสดงเส้นทางที่โยงไว้",
"Policies.header.title": "การตั้งค่าขั้นสูง",
"PopUpForm.Email.email_templates.inputDescription": "ถ้าคุณไม่แน่ใจว่าจะใช้ตัวแปรอย่างไร {link}",
"PopUpForm.Email.link.documentation": "ดูเอกสารของเราสิ",
"PopUpForm.Email.options.from.email.label": "อีเมล Shipper",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "ชื่อ Shipper",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "ข้อความ",
"PopUpForm.Email.options.object.label": "เรื่อง",
"PopUpForm.Email.options.object.placeholder": "โปรดยืนยันอีเมลแอดเดรสของคุณสำหรับ % APP _ NAME %",
"PopUpForm.Email.options.response_email.label": "อีเมลตอบกลับ",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "ถ้าปิดใช้งาน, ผู้ใช้จะไม่สามารถใช้ผู้ให้บริการนี้ได้",
"PopUpForm.Providers.enabled.label": "เปิดใช้งาน",
"PopUpForm.Providers.key.label": "ID ไคลเอ็นต์",
"PopUpForm.Providers.key.placeholder": "ข้อความ",
"PopUpForm.Providers.redirectURL.front-end.label": "เปลี่ยนทิศทาง URL ไปยังแอป front-end ของคุณ",
"PopUpForm.Providers.redirectURL.label": "เปลี่ยนทิศทาง URL เพื่อเพิ่มในตั้งค่าแอปพลิเคชัน {provider} ของคุณ",
"PopUpForm.Providers.secret.label": "Secret ไคลเอ็นต์",
"PopUpForm.Providers.secret.placeholder": "ข้อความ",
"PopUpForm.header.edit.email-templates": "แก้ไขเทมเพลตอีเมล",
"PopUpForm.header.edit.providers": "แก้ไขผู้ให้บริการ",
"Settings.roles.deleted": "ลบบทบาทแล้ว",
"Settings.roles.edited": "บทบาทที่แก้ไข",
"Settings.section-label": "ปลั๊กอินผู้ใช้ & สิทธิ",
"notification.success.submit": "อัปเดตการตั้งค่าแล้ว",
"plugin.description.long": "ป้องกัน API ของคุณด้วยกระบวนการพิสูจน์ตัวตนแบบสมบูรณ์โดยอิงจาก JWT ปลั๊กอินนี้มาพร้อมกับกลยุทธ์ ACL ที่อนุญาตให้คุณจัดการกับสิทธิระหว่างกลุ่มของผู้ใช้ได้ด้วย",
"plugin.description.short": "ปกป้อง API ของคุณที่มีกระบวนการพิสูจน์ตัวตนแบบสมบูรณ์โดยอิงจาก JWT",
"plugin.name": "ปลั๊กอิน ผู้ใช้ & การอนุญาต",
"popUpWarning.button.cancel": "ยกเลิก",
"popUpWarning.button.confirm": "ยืนยัน",
"popUpWarning.title": "โปรดยืนยัน",
"popUpWarning.warning.cancel": "คุณแน่ใจว่าต้องการยกเลิกการแก้ไขของคุณหรือไม่?"
}

View File

@ -1,81 +0,0 @@
{
"BoundRoute.title": "Bağlı rota",
"EditForm.inputSelect.description.role": "Yeni kimliği doğrulanmış kullanıcıyı seçilen rolü ekler.",
"EditForm.inputSelect.label.role": "Kimliği doğrulanmış kullanıcılar için varsayılan rol",
"EditForm.inputToggle.description.email": "Kullanıcıyı, farklı kimlik doğrulama sağlayıcılarıyla aynı e-posta adresini kullanarak birden fazla hesap oluşturmasına izin vermeyin.",
"EditForm.inputToggle.description.email-confirmation": "Etkinleştirildiğinde yeni kayıtlı kullanıcılar bir onay e-postası alır.",
"EditForm.inputToggle.description.email-confirmation-redirection": "E-postanızı onayladıktan sonra, yönlendirileceğiniz yeri seçin.",
"EditForm.inputToggle.description.sign-up": "Devre dışı bırakıldığında (KAPALI), kayıt işlemi yasaktır. Artık kullanılan sağlayıcı ne olursa olsun hiç kimse abone olamaz.",
"EditForm.inputToggle.label.email": "E-posta adresi başına bir hesap",
"EditForm.inputToggle.label.email-confirmation": "E-posta onayını etkinleştir",
"EditForm.inputToggle.label.email-confirmation-redirection": "Yönlendirme URL'si",
"EditForm.inputToggle.label.sign-up": "Kayıtları etkinleştir",
"EditForm.inputToggle.placeholder.email-confirmation-redirection": "ör: https://yourfrontend.com/email-confirmation-redirection",
"EditForm.inputToggle.placeholder.email-reset-password": "ör: https://yourfrontend.com/reset-password",
"EditPage.form.roles": "Rol detayları",
"Email.template.data.loaded": "E-posta şablonları yüklendi",
"Email.template.email_confirmation": "E-posta adresi doğrulaması",
"Email.template.form.edit.label": "Şablonu düzenle",
"Email.template.table.action.label": "eylem",
"Email.template.table.icon.label": "ikon",
"Email.template.table.name.label": "ad",
"Form.advancedSettings.data.loaded": "Gelişmiş ayarlar verisi yüklendi",
"HeaderNav.link.advancedSettings": "Gelişmiş Ayarlar",
"HeaderNav.link.emailTemplates": "E-posta Şablonları",
"HeaderNav.link.providers": "Sağlayıcıları",
"Plugin.permissions.plugins.description": "{name} eklentisi için izin verilen tüm eylemleri tanımlayın.",
"Plugins.header.description": "Yalnızca bir güzergahla sınırlandırılan işlemler aşağıda listelenmiştir.",
"Plugins.header.title": "İzinler",
"Policies.header.hint": "Uygulamanın eylemlerini veya eklentinin eylemlerini seçin ve bağlı rotayı görüntülemek için dişli çark simgesini tıklayın",
"Policies.header.title": "Gelişmiş Ayarlar",
"PopUpForm.Email.email_templates.inputDescription": "Değişkenleri nasıl kullanacağınızdan emin değilseniz, {link}",
"PopUpForm.Email.link.documentation": "dokümantasyonu kontrol et.",
"PopUpForm.Email.options.from.email.label": "Gönderenin E-posta",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "Gönderenin adı",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "Mesaj",
"PopUpForm.Email.options.object.label": "Konu",
"PopUpForm.Email.options.object.placeholder": "%APP_NAME% için e-posta adresini doğrula",
"PopUpForm.Email.options.response_email.label": "Yanıt e-postası",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "Devre dışı bırakıldıysa kullanıcılar bu sağlayıcıyı kullanamaz.",
"PopUpForm.Providers.enabled.label": "Etkinleştirme",
"PopUpForm.Providers.key.label": "Web istemcisi ID",
"PopUpForm.Providers.key.placeholder": "METİN",
"PopUpForm.Providers.redirectURL.front-end.label": "Arayüz uygulamanızın yönlendirme URL'si",
"PopUpForm.Providers.redirectURL.label": "{provider} uygulama ayarlarına ekleyeceğin yönlendirme URLi",
"PopUpForm.Providers.secret.label": "Web istemcisi Secret",
"PopUpForm.Providers.secret.placeholder": "METİN",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "E-posta Şablonlarını Düzenle",
"PopUpForm.header.edit.providers": "Sağlayıcıyı Düzenle",
"Providers.data.loaded": "Sağlayıcılar yüklendi",
"Providers.image": "Görsel",
"Providers.status": "Durum",
"Roles.empty": "Henüz hiç rolün yok.",
"Roles.empty.search": "Aramaya uygun rol bulunmadı.",
"Settings.roles.deleted": "Rol silindi",
"Settings.roles.edited": "Rol düzenlendi",
"Settings.section-label": "Kullanıcılar ve İzinler eklentisi",
"components.Input.error.validation.email": "Bu geçersiz bir e-posta",
"components.Input.error.validation.json": "Bu JSON biçimine uymuyor",
"components.Input.error.validation.max": "Değer çok yüksek.",
"components.Input.error.validation.maxLength": "Değer çok uzun.",
"components.Input.error.validation.min": "Değer çok düşük.",
"components.Input.error.validation.minLength": "Değer çok kısa.",
"components.Input.error.validation.minSupMax": "Üst olamaz",
"components.Input.error.validation.regex": "Değer RegExp'e uymuyor.",
"components.Input.error.validation.required": "Değer gerekli.",
"components.Input.error.validation.unique": "Değer zaten kullanılıyor.",
"notification.success.submit": "Ayarlar güncellendi",
"page.title": "Ayarlar - Roller",
"plugin.description.long": "Servisinizi JWT'ye dayalı tam bir kimlik doğrulama işlemi ile koruyun. Bu eklenti, kullanıcı grupları arasındaki izinleri yönetmenize izin veren bir ACL stratejisiyle de gelir.",
"plugin.description.short": "Servisinizi JWT'ye dayalı tam bir kimlik doğrulama işlemi ile koruyun",
"plugin.name": "Roller ve İzinler",
"popUpWarning.button.cancel": "İptal Et",
"popUpWarning.button.confirm": "Onayla",
"popUpWarning.title": "Lütfen onayla",
"popUpWarning.warning.cancel": "Değişiklikleri iptal etmek istediğinden emin misin?"
}

View File

@ -1,45 +0,0 @@
{
"BoundRoute.title": "Пов'язано з",
"EditForm.inputSelect.description.role": "Підключає нового автентифікованого користувача до вибраної ролі.",
"EditForm.inputSelect.label.role": "Роль за замовчуванням для автентифікованих користувачів",
"EditForm.inputToggle.description.email": "Не дозволяти користувачам створювати кілька аккаунтів з тим самим email, але різним провайдером автентифікації.",
"EditForm.inputToggle.description.email-confirmation": "Якщо увімкнено (ON), щойно зареєстровані користувачі отримують листа для підтверждення.",
"EditForm.inputToggle.description.email-confirmation-redirection": "Куди ви будете перенаправлені після підтвердження свого email.",
"EditForm.inputToggle.description.email-reset-password": "URL-адреса сторінки скидання пароля вашого додатку",
"EditForm.inputToggle.description.sign-up": "Якщо вимкнено (OFF), реєстрація заборонена. Незалежно від використовуваного провайдера більше ніхто не зможе приєднатись.",
"EditForm.inputToggle.label.email": "Один аккаунт на email",
"EditForm.inputToggle.label.email-confirmation": "Увімкнути підтверження email",
"EditForm.inputToggle.label.email-confirmation-redirection": "URL для перенаправлення",
"EditForm.inputToggle.label.email-reset-password": "Сторінка скидання пароля",
"EditForm.inputToggle.label.sign-up": "Увімкнути реєстрацію",
"HeaderNav.link.advancedSettings": "Розширені налаштування",
"HeaderNav.link.emailTemplates": "Шаблони листів",
"HeaderNav.link.providers": "Провайдери",
"Plugin.permissions.plugins.description": "Встановіть всі дозволені дії у плаґіні {name}.",
"Plugins.header.description": "Нижче перераховано лише дії, пов'язані з маршрутом.",
"Plugins.header.title": "Дозволи",
"Policies.header.hint": "Виберіть дії вашого додатку або дії плаґіну та натисніть на значок шестірні, щоб відобразити пов'язаний маршрут",
"Policies.header.title": "Розширені налашрування",
"PopUpForm.Email.email_templates.inputDescription": "Якщо ви не впевнені, як використовувати змінні, {link}",
"PopUpForm.Email.options.from.email.label": "Email відправника",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "Ім'я відправника",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "Повідомлення",
"PopUpForm.Email.options.object.label": "Тема",
"PopUpForm.Email.options.response_email.label": "Email для відповіді",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "Якщо вимкнуто, користувачі не зможуть вікористати цей провайдер.",
"PopUpForm.Providers.enabled.label": "Увімкнути",
"PopUpForm.Providers.key.label": "Client ID",
"PopUpForm.Providers.key.placeholder": "TEXT",
"PopUpForm.Providers.redirectURL.front-end.label": "URL переадресації для вашего front-end додатку",
"PopUpForm.Providers.secret.label": "Client Secret",
"PopUpForm.Providers.secret.placeholder": "TEXT",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "Редагування шаблони листів",
"notification.success.submit": "Налаштування оновлено",
"plugin.description.long": "Захистіть API за допомогою процесу аутентифікації на основі JWT. Цей плагін також включає можливості ACL, які дозволяють керувати дозволами між групами користувачів.",
"plugin.description.short": "Захистіть API за допомогою процесу аутентифікації на основі JWT"
}

View File

@ -1,46 +0,0 @@
{
"BoundRoute.title": "Đến tới",
"EditForm.inputSelect.description.role": "Đính kèm người dùng mới đã được xác thực vào quyền được chọn.",
"EditForm.inputSelect.label.role": "Quyền mặc định cho các người dùng đã được chứng thực",
"EditForm.inputToggle.description.email": "Không cho phép người dùng tạo nhiều tài khoản có cùng địa chỉ email với nhiều nhà cung cấp chứng thực.",
"EditForm.inputToggle.description.email-confirmation": "Khi được kích hoạt (ON), người dùng đăng ký mới nhận được một email xác nhận.",
"EditForm.inputToggle.description.email-confirmation-redirection": "Sau khi xác nhận email của bạn, chọn nơi bạn sẽ được đưa về.",
"EditForm.inputToggle.description.email-reset-password": "URL của trang lấy lại mật khẩu của ứng dụng của bạn",
"EditForm.inputToggle.description.sign-up": "Khi không kích hoạt (OFF), quá trình đăng ký bị cấm. Không ai có thể đăng ký thêm dù dùng bất kỳ nhà cung cấp nào.",
"EditForm.inputToggle.label.email": "Một tài khoản trên một địa chỉ email",
"EditForm.inputToggle.label.email-confirmation": "Kích hoạt email xác nhận",
"EditForm.inputToggle.label.email-confirmation-redirection": "URL đưa về",
"EditForm.inputToggle.label.email-reset-password": "Trang lấy lại mật khẩu",
"EditForm.inputToggle.label.sign-up": "Kích hoạt đăng ký",
"HeaderNav.link.advancedSettings": "Cài đặt nâng cao",
"HeaderNav.link.emailTemplates": "Mẫu email",
"HeaderNav.link.providers": "Các nhà cung cấp",
"Plugin.permissions.plugins.description": "Định nghĩa tất cả hành động được phép cho {name} plugin.",
"Plugins.header.description": "Chỉ các hành động đến bởi một đường dẫn được liệt kê bên dưới.",
"Plugins.header.title": "Các Quyền",
"Policies.header.hint": "Chọn các hành động của ứng dựng hoặc hành động của plugin và nhấn vào biểu tượng bánh răng để hiển thị đường đến",
"Policies.header.title": "Các cài đặt nâng cao",
"PopUpForm.Email.email_templates.inputDescription": "Nếu bạn không chắc sử dụng các biến như thế nào, {link}",
"PopUpForm.Email.options.from.email.label": "Email người gửi",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "Tên người gửi",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "Thông điệp",
"PopUpForm.Email.options.object.label": "Chủ đề",
"PopUpForm.Email.options.response_email.label": "Email phản hồi",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "Nếu không kích hoạt, người dùng sẽ không thể dùng nhà cung cấp này.",
"PopUpForm.Providers.enabled.label": "Kích hoạt",
"PopUpForm.Providers.key.label": "Client ID",
"PopUpForm.Providers.key.placeholder": "VĂN BẢN",
"PopUpForm.Providers.redirectURL.front-end.label": "URL chuyển tiếp đến ứng dụng bên ngoài của bạn",
"PopUpForm.Providers.secret.label": "Client Secret",
"PopUpForm.Providers.secret.placeholder": "VĂN BẢN",
"PopUpForm.Providers.subdomain.label": "Host URI (Subdomain)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "Sửa Các Mẫu Email",
"notification.success.submit": "Các cấu hình đã được cập nhật",
"plugin.description.long": "Bảo vệ API của bạn với quá trình chứng thực đầy đủ dựa trên JWT. Plugin này cũng kèm với chiến lược ACL cho phép bạn quản lý quyền giữa các nhóm người dùng.",
"plugin.description.short": "Bảo vệ API của bạn với quá trình chứng thực đầy đủ dựa trên JWT",
"plugin.name": "Vai trò và Quyền"
}

View File

@ -1,82 +0,0 @@
{
"BoundRoute.title": "绑定路由到",
"EditForm.inputSelect.description.role": "新验证身份的用户将被赋予所选角色。",
"EditForm.inputSelect.label.role": "认证用户的默认角色",
"EditForm.inputToggle.description.email": "不允许用户使用不同的认证提供者(绑定的相同的电子邮件地址)来创建多个帐户。",
"EditForm.inputToggle.description.email-confirmation": "启用ON新注册的用户会收到一封确认电子邮件。",
"EditForm.inputToggle.description.email-confirmation-redirection": "确认您的电子邮件后,选择将您重定向到的位置。",
"EditForm.inputToggle.description.email-reset-password": "应用程序的重置密码页面的 URL",
"EditForm.inputToggle.description.sign-up": "当禁用OFF注册过程将被禁止。任何人无论使用任何的供应商都不可以订阅。",
"EditForm.inputToggle.label.email": "每个电子邮件地址一个帐户",
"EditForm.inputToggle.label.email-confirmation": "启用电子邮件确认",
"EditForm.inputToggle.label.email-confirmation-redirection": "重定向 URL",
"EditForm.inputToggle.label.email-reset-password": "重置密码页面 URL",
"EditForm.inputToggle.label.sign-up": "启用注册",
"EditForm.inputToggle.placeholder.email-confirmation-redirection": "例如: https://yourfrontend.com/reset-password",
"EditForm.inputToggle.placeholder.email-reset-password": "例如: https://yourfrontend.com/reset-password",
"EditPage.form.roles": "角色详情",
"Email.template.data.loaded": "电子邮件模板已加载",
"Email.template.email_confirmation": "邮箱地址确认",
"Email.template.form.edit.label": "编辑模板",
"Email.template.table.action.label": "操作",
"Email.template.table.icon.label": "图标",
"Email.template.table.name.label": "名称",
"Form.advancedSettings.data.loaded": "高级设置数据已加载",
"HeaderNav.link.advancedSettings": "高级设置",
"HeaderNav.link.emailTemplates": "电子邮件模板",
"HeaderNav.link.providers": "提供者",
"Plugin.permissions.plugins.description": "定义 {name} 插件所有允许的操作。",
"Plugins.header.description": "下面只列出路由绑定的操作。",
"Plugins.header.title": "权限",
"Policies.header.hint": "选择应用程序或插件的操作,然后点击 COG 图标显示绑定的路由",
"Policies.header.title": "高级设置",
"PopUpForm.Email.email_templates.inputDescription": "如果你不确定如何使用变量, {link}",
"PopUpForm.Email.link.documentation": "查看我们的文档",
"PopUpForm.Email.options.from.email.label": "发件人地址",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "发件人名称",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "消息",
"PopUpForm.Email.options.object.label": "主题",
"PopUpForm.Email.options.object.placeholder": "请为%APP_NAME%确认邮箱地址",
"PopUpForm.Email.options.response_email.label": "回复邮件",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "如果禁用,用户将无法使用此供应商。",
"PopUpForm.Providers.enabled.label": "启用",
"PopUpForm.Providers.key.label": "客户端 ID",
"PopUpForm.Providers.key.placeholder": "文本",
"PopUpForm.Providers.redirectURL.front-end.label": "重定向 URL",
"PopUpForm.Providers.redirectURL.label": "添加到{provider}应用配置的跳转URL",
"PopUpForm.Providers.secret.label": "客户端秘钥",
"PopUpForm.Providers.secret.placeholder": "文本",
"PopUpForm.Providers.subdomain.label": "主机URI子域名",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "编辑电子邮件模版",
"PopUpForm.header.edit.providers": "编辑提供商",
"Providers.data.loaded": "提供商已加载",
"Providers.status": "状态",
"Roles.empty": "您还没有任何角色。",
"Roles.empty.search": "没有与搜索相匹配的角色。",
"Settings.roles.deleted": "角色已被删除",
"Settings.roles.edited": "角色编辑完成",
"Settings.section-label": "用户及权限插件",
"components.Input.error.validation.email": "这是一个无效的电子邮件",
"components.Input.error.validation.json": "这不符合JSON格式",
"components.Input.error.validation.max": "值过高。",
"components.Input.error.validation.maxLength": "值过长。",
"components.Input.error.validation.min": "值太低。",
"components.Input.error.validation.minLength": "值太短。",
"components.Input.error.validation.minSupMax": "不能超过上限",
"components.Input.error.validation.regex": "该值不符合正则表达式。",
"components.Input.error.validation.required": "该值为必填项。",
"components.Input.error.validation.unique": "该值已被使用。",
"notification.success.submit": "设置已被更新",
"page.title": "设置 - 角色",
"plugin.description.long": "使用基于 JWT 的完整身份验证过程来保护 API。这个插件还有一个 ACL 策略,允许你管理用户组之间的权限。",
"plugin.description.short": "使用基于 JWT 的完整身份验证过程保护 API",
"plugin.name": "角色及权限",
"popUpWarning.button.cancel": "取消",
"popUpWarning.button.confirm": "确认",
"popUpWarning.title": "请确认",
"popUpWarning.warning.cancel": "你确定你要取消你的修改?"
}

View File

@ -1,82 +0,0 @@
{
"BoundRoute.title": "綁定路徑到",
"EditForm.inputSelect.description.role": "將新的驗證使用者加入此身份。",
"EditForm.inputSelect.label.role": "驗證使用者預設身份",
"EditForm.inputToggle.description.email": "禁止使用者使用同一個電子郵件地址 + 不同的驗證方式註冊多個帳號",
"EditForm.inputToggle.description.email-confirmation": "當啟用後,新註冊的使用者將會收到一封認證郵件。",
"EditForm.inputToggle.description.email-confirmation-redirection": "認證完後後,使用者被重新導向的網址。",
"EditForm.inputToggle.description.email-reset-password": "您的應用程式的重設密碼頁面的網址",
"EditForm.inputToggle.description.sign-up": "當停用後,不論使用任何驗證方式使用者將無法註冊。",
"EditForm.inputToggle.label.email": "電子郵件地址單一帳號限制",
"EditForm.inputToggle.label.email-confirmation": "啟用電子郵件地址驗證",
"EditForm.inputToggle.label.email-confirmation-redirection": "重新導向網址",
"EditForm.inputToggle.label.email-reset-password": "密碼重設頁面",
"EditForm.inputToggle.label.sign-up": "啟用註冊",
"EditForm.inputToggle.placeholder.email-confirmation-redirection": "例如https://yourfrontend.com/email-confirmation-redirection",
"EditForm.inputToggle.placeholder.email-reset-password": "例如https://yourfrontend.com/reset-password",
"EditPage.form.roles": "角色詳細資訊",
"Email.template.data.loaded": "已載入電子郵件範本",
"Email.template.email_confirmation": "電子郵件地址確認",
"Email.template.form.edit.label": "編輯範本",
"Email.template.table.action.label": "操作",
"Email.template.table.icon.label": "圖示",
"Email.template.table.name.label": "名稱",
"Form.advancedSettings.data.loaded": "已載入進階設定資料",
"HeaderNav.link.advancedSettings": "進階設定",
"HeaderNav.link.emailTemplates": "郵件範本",
"HeaderNav.link.providers": "驗證方式",
"Plugin.permissions.plugins.description": "為 {name} 擴充功能定義所有可用的操作",
"Plugins.header.description": "只有綁定路徑的操作會顯示在下方",
"Plugins.header.title": "權限",
"Policies.header.hint": "選取應用程式或擴充功能的操作然後點擊齒輪圖示以顯示綁定路徑",
"Policies.header.title": "進階設定",
"PopUpForm.Email.email_templates.inputDescription": "如果您不確定要怎麼使用變數,請 {link}",
"PopUpForm.Email.link.documentation": "查閱我們的說明文件。",
"PopUpForm.Email.options.from.email.label": "寄件人地址",
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
"PopUpForm.Email.options.from.name.label": "寄件人名稱",
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
"PopUpForm.Email.options.message.label": "訊息",
"PopUpForm.Email.options.object.label": "主旨",
"PopUpForm.Email.options.object.placeholder": "請驗證 %APP_NAME% 的電子郵件地址",
"PopUpForm.Email.options.response_email.label": "回覆地址",
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
"PopUpForm.Providers.enabled.description": "如果停用,使用者將無法使用這個驗證方式",
"PopUpForm.Providers.enabled.label": "啟用",
"PopUpForm.Providers.key.label": "客戶端 ID",
"PopUpForm.Providers.key.placeholder": "TEXT",
"PopUpForm.Providers.redirectURL.front-end.label": "您應用程式的前端頁面網址",
"PopUpForm.Providers.redirectURL.label": "The redirect URL to add in your {provider} application configurations",
"PopUpForm.Providers.secret.label": "客戶端密鑰",
"PopUpForm.Providers.secret.placeholder": "TEXT",
"PopUpForm.Providers.subdomain.label": "Host URI (子網域)",
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
"PopUpForm.header.edit.email-templates": "編輯郵件範本",
"PopUpForm.header.edit.providers": "編輯供應者",
"Providers.data.loaded": "已載入供應者",
"Providers.status": "狀態",
"Roles.empty": "您目前沒有任何角色。",
"Roles.empty.search": "沒有符合搜尋的角色。",
"Settings.roles.deleted": "已刪除角色",
"Settings.roles.edited": "已編輯角色",
"Settings.section-label": "使用者與權限外掛程式",
"components.Input.error.validation.email": "此電子郵件地址無效",
"components.Input.error.validation.json": "不符合 JSON 格式",
"components.Input.error.validation.max": "數值過高。",
"components.Input.error.validation.maxLength": "數值過長。",
"components.Input.error.validation.min": "數值過低。",
"components.Input.error.validation.minLength": "數值過短。",
"components.Input.error.validation.minSupMax": "Can't be superior",
"components.Input.error.validation.regex": "數值與 regex 不符。",
"components.Input.error.validation.required": "此數值為必填。",
"components.Input.error.validation.unique": "此值已被使用。",
"notification.success.submit": "設定已更新",
"page.title": "設定 - 角色",
"plugin.description.long": "使用 JWT 認證保護您的 API。這個擴充功能也使用 ACL 來讓你管理不同群組使用者的權限。",
"plugin.description.short": "使用 JWT 認證保護您的 API",
"plugin.name": "身份與權限",
"popUpWarning.button.cancel": "取消",
"popUpWarning.button.confirm": "確認",
"popUpWarning.title": "請確認",
"popUpWarning.warning.cancel": "您確定要取消變更嗎?"
}

Some files were not shown because too many files have changed in this diff Show More