Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e27b5ec62 | ||
|
|
5751cacb4d | ||
|
|
64f9e07d5e | ||
|
|
a6aeb10484 | ||
|
|
2327c5dd30 |
+38
-6
@@ -1,6 +1,38 @@
|
||||
/.github/ @charlesBochet @FelixMalfait @Weiko @prastoin @bosiraphael @etiennejouan @ijreilly @martmull @thomtrp
|
||||
/.github/CODEOWNERS @charlesBochet @FelixMalfait @Weiko @prastoin @bosiraphael @etiennejouan @ijreilly @martmull @thomtrp
|
||||
/.github/workflows/ @charlesBochet @FelixMalfait @Weiko @prastoin @bosiraphael @etiennejouan @ijreilly @martmull @thomtrp
|
||||
/.github/actions/ @charlesBochet @FelixMalfait @Weiko @prastoin @bosiraphael @etiennejouan @ijreilly @martmull @thomtrp
|
||||
/.github/dependabot.yml @charlesBochet @FelixMalfait @Weiko @prastoin @bosiraphael @etiennejouan @ijreilly @martmull @thomtrp
|
||||
/.yarnrc.yml @charlesBochet @FelixMalfait @Weiko @prastoin @bosiraphael @etiennejouan @ijreilly @martmull @thomtrp
|
||||
# ============================================================
|
||||
# CI/CD & GitHub infrastructure
|
||||
# ============================================================
|
||||
/.github/ @Weiko @charlesBochet @prastoin
|
||||
/.github/CODEOWNERS @Weiko @charlesBochet @prastoin
|
||||
/.github/workflows/ @Weiko @charlesBochet @prastoin
|
||||
/.github/actions/ @Weiko @charlesBochet @prastoin
|
||||
/.github/dependabot.yml @Weiko @charlesBochet @prastoin
|
||||
|
||||
# ============================================================
|
||||
# Package management & dependency lockfiles
|
||||
# ============================================================
|
||||
/.yarnrc.yml @Weiko @charlesBochet @prastoin
|
||||
/.npmrc @Weiko @charlesBochet @prastoin
|
||||
**/package.json @Weiko @charlesBochet @prastoin
|
||||
**/yarn.lock @Weiko @charlesBochet @prastoin
|
||||
|
||||
# ============================================================
|
||||
# twenty-apps: exempt from strict ownership (last match wins)
|
||||
# ============================================================
|
||||
/packages/twenty-apps/
|
||||
|
||||
# ============================================================
|
||||
# Build & tooling configs
|
||||
# ============================================================
|
||||
/nx.json @Weiko @charlesBochet @prastoin
|
||||
|
||||
# ============================================================
|
||||
# Docker (container-level compromise)
|
||||
# ============================================================
|
||||
**/Dockerfile* @Weiko @charlesBochet @prastoin
|
||||
**/docker-compose*.yml @Weiko @charlesBochet @prastoin
|
||||
**/docker-compose*.yaml @Weiko @charlesBochet @prastoin
|
||||
|
||||
# ============================================================
|
||||
# Git hooks (execute on checkout/commit/push)
|
||||
# ============================================================
|
||||
/.husky/** @Weiko @charlesBochet @prastoin
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
name: 'Preview Environment Dispatch'
|
||||
|
||||
permissions: {}
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
@@ -10,6 +11,7 @@ on:
|
||||
- packages/twenty-server/**
|
||||
- packages/twenty-front/**
|
||||
- .github/workflows/preview-env-dispatch.yaml
|
||||
- .github/workflows/preview-env-keepalive.yaml
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
@@ -33,15 +35,28 @@ jobs:
|
||||
timeout-minutes: 5
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Dispatch preview-env to ci-privileged
|
||||
- name: Trigger preview environment workflow
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.CI_PRIVILEGED_DISPATCH_TOKEN }}
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
REPOSITORY: ${{ github.repository }}
|
||||
run: |
|
||||
gh api repos/twentyhq/ci-privileged/dispatches \
|
||||
gh api repos/"$REPOSITORY"/dispatches \
|
||||
-f event_type=preview-environment \
|
||||
-f "client_payload[pr_number]=$PR_NUMBER" \
|
||||
-f "client_payload[pr_head_sha]=$PR_HEAD_SHA" \
|
||||
-f "client_payload[repo_full_name]=$REPOSITORY"
|
||||
|
||||
- name: Dispatch to ci-privileged for PR comment
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.CI_PRIVILEGED_DISPATCH_TOKEN }}
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
KEEPALIVE_DISPATCH_TIME: ${{ github.event.pull_request.updated_at }}
|
||||
REPOSITORY: ${{ github.repository }}
|
||||
run: |
|
||||
gh api repos/twentyhq/ci-privileged/dispatches \
|
||||
-f event_type=preview-env-url \
|
||||
-f "client_payload[pr_number]=$PR_NUMBER" \
|
||||
-f "client_payload[keepalive_dispatch_time]=$KEEPALIVE_DISPATCH_TIME" \
|
||||
-f "client_payload[repo]=$REPOSITORY"
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
name: 'Preview Environment Keep Alive'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
on:
|
||||
repository_dispatch:
|
||||
types: [preview-environment]
|
||||
|
||||
jobs:
|
||||
preview-environment:
|
||||
timeout-minutes: 310
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout PR
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
ref: ${{ github.event.client_payload.pr_head_sha }}
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
|
||||
with:
|
||||
username: ${{ vars.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
|
||||
- name: Run compose setup
|
||||
run: |
|
||||
echo "Patching docker-compose.yml..."
|
||||
# change image to localbuild using yq
|
||||
yq eval 'del(.services.server.image)' -i packages/twenty-docker/docker-compose.yml
|
||||
yq eval '.services.server.build.context = "../../"' -i packages/twenty-docker/docker-compose.yml
|
||||
yq eval '.services.server.build.dockerfile = "./packages/twenty-docker/twenty/Dockerfile"' -i packages/twenty-docker/docker-compose.yml
|
||||
yq eval '.services.server.build.target = "twenty"' -i packages/twenty-docker/docker-compose.yml
|
||||
|
||||
yq eval 'del(.services.worker.image)' -i packages/twenty-docker/docker-compose.yml
|
||||
yq eval '.services.worker.build.context = "../../"' -i packages/twenty-docker/docker-compose.yml
|
||||
yq eval '.services.worker.build.dockerfile = "./packages/twenty-docker/twenty/Dockerfile"' -i packages/twenty-docker/docker-compose.yml
|
||||
yq eval '.services.worker.build.target = "twenty"' -i packages/twenty-docker/docker-compose.yml
|
||||
|
||||
echo "Adding SIGN_IN_PREFILLED environment variable to server service..."
|
||||
yq eval '.services.server.environment.SIGN_IN_PREFILLED = "${SIGN_IN_PREFILLED}"' -i packages/twenty-docker/docker-compose.yml
|
||||
|
||||
echo "Setting up .env file..."
|
||||
cp packages/twenty-docker/.env.example packages/twenty-docker/.env
|
||||
|
||||
echo "Generating secrets..."
|
||||
echo "" >> packages/twenty-docker/.env
|
||||
echo "# === Randomly generated secrets ===" >> packages/twenty-docker/.env
|
||||
echo "APP_SECRET=$(openssl rand -base64 32)" >> packages/twenty-docker/.env
|
||||
echo "PG_DATABASE_PASSWORD=$(openssl rand -hex 16)" >> packages/twenty-docker/.env
|
||||
echo "SIGN_IN_PREFILLED=true" >> packages/twenty-docker/.env
|
||||
echo "Docker compose build..."
|
||||
cd packages/twenty-docker/
|
||||
docker compose build
|
||||
working-directory: ./
|
||||
|
||||
- name: Create Tunnel
|
||||
id: expose-tunnel
|
||||
env:
|
||||
CLOUDFLARED_VERSION: '2026.3.0'
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
# Install cloudflared (pinned for reproducibility)
|
||||
sudo curl -fsSL -o /usr/local/bin/cloudflared \
|
||||
"https://github.com/cloudflare/cloudflared/releases/download/${CLOUDFLARED_VERSION}/cloudflared-linux-amd64"
|
||||
sudo chmod +x /usr/local/bin/cloudflared
|
||||
cloudflared --version
|
||||
|
||||
# Start an account-less "quick tunnel" pointing at the server container.
|
||||
# Cloudflare prints the assigned https://*.trycloudflare.com URL into the log.
|
||||
log_file="$RUNNER_TEMP/cloudflared.log"
|
||||
: > "$log_file"
|
||||
|
||||
cloudflared tunnel \
|
||||
--url http://localhost:3000 \
|
||||
--no-autoupdate \
|
||||
--logfile "$log_file" \
|
||||
--loglevel info \
|
||||
> "$RUNNER_TEMP/cloudflared.stdout" 2>&1 &
|
||||
|
||||
pid=$!
|
||||
echo "$pid" > "$RUNNER_TEMP/cloudflared.pid"
|
||||
echo "cloudflared PID: $pid"
|
||||
|
||||
# Wait up to 2 minutes for the URL to appear; fail fast if cloudflared exits.
|
||||
url=''
|
||||
for _ in $(seq 1 60); do
|
||||
url=$(grep -oE 'https://[a-zA-Z0-9-]+\.trycloudflare\.com' "$log_file" 2>/dev/null | head -n1 || true)
|
||||
[ -n "$url" ] && break
|
||||
if ! kill -0 "$pid" 2>/dev/null; then
|
||||
echo "cloudflared exited before producing a URL"
|
||||
cat "$log_file" || true
|
||||
exit 1
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
|
||||
if [ -z "$url" ]; then
|
||||
echo "Timed out waiting for tunnel URL"
|
||||
cat "$log_file" || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Tunnel URL: $url"
|
||||
echo "tunnel-url=$url" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Start services with correct SERVER_URL
|
||||
env:
|
||||
TUNNEL_URL: ${{ steps.expose-tunnel.outputs.tunnel-url }}
|
||||
run: |
|
||||
cd packages/twenty-docker/
|
||||
|
||||
echo "Setting SERVER_URL to $TUNNEL_URL"
|
||||
sed -i '/SERVER_URL=/d' .env
|
||||
echo "" >> .env
|
||||
echo "SERVER_URL=$TUNNEL_URL" >> .env
|
||||
|
||||
# Start the services
|
||||
echo "Docker compose up..."
|
||||
docker compose up -d || {
|
||||
echo "Docker compose failed to start"
|
||||
docker compose logs
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "Waiting for services to be ready..."
|
||||
count=0
|
||||
while [ ! $(docker inspect --format='{{.State.Health.Status}}' twenty-db-1) = "healthy" ] || [ ! $(docker inspect --format='{{.State.Health.Status}}' twenty-server-1) = "healthy" ]; do
|
||||
sleep 5
|
||||
count=$((count+1))
|
||||
if [ $count -gt 60 ]; then
|
||||
echo "Timeout waiting for services to be ready"
|
||||
docker compose logs
|
||||
exit 1
|
||||
fi
|
||||
echo "Still waiting for services... ($count/60)"
|
||||
done
|
||||
|
||||
echo "All services are up and running!"
|
||||
working-directory: ./
|
||||
|
||||
- name: Seed Dev Workspace
|
||||
run: |
|
||||
cd packages/twenty-docker/
|
||||
echo "Seeding light dev workspace (Apple only)..."
|
||||
if ! docker compose exec -T server yarn command:prod workspace:seed:dev --light; then
|
||||
echo "❌ Seeding light dev workspace failed. Dumping server logs..."
|
||||
docker compose logs server
|
||||
exit 1
|
||||
fi
|
||||
working-directory: ./
|
||||
|
||||
- name: Output tunnel URL
|
||||
env:
|
||||
TUNNEL_URL: ${{ steps.expose-tunnel.outputs.tunnel-url }}
|
||||
run: |
|
||||
echo "✅ Preview Environment Ready!"
|
||||
echo "🔗 Preview URL: $TUNNEL_URL"
|
||||
echo "⏱️ This environment will be available for 5 hours"
|
||||
echo "## 🚀 Preview Environment Ready!" >> "$GITHUB_STEP_SUMMARY"
|
||||
echo "" >> "$GITHUB_STEP_SUMMARY"
|
||||
echo "Preview URL: $TUNNEL_URL" >> "$GITHUB_STEP_SUMMARY"
|
||||
echo "" >> "$GITHUB_STEP_SUMMARY"
|
||||
echo "This environment will automatically shut down after 5 hours." >> "$GITHUB_STEP_SUMMARY"
|
||||
echo "$TUNNEL_URL" > tunnel-url.txt
|
||||
|
||||
- name: Upload tunnel URL artifact
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: tunnel-url
|
||||
path: tunnel-url.txt
|
||||
retention-days: 1
|
||||
|
||||
- name: Keep tunnel alive for 5 hours
|
||||
run: timeout 300m sleep 18000 # Stop on whichever we reach first (300m or 5hour sleep)
|
||||
|
||||
- name: Cleanup
|
||||
if: always()
|
||||
run: |
|
||||
if [ -f "$RUNNER_TEMP/cloudflared.pid" ]; then
|
||||
kill "$(cat "$RUNNER_TEMP/cloudflared.pid")" 2>/dev/null || true
|
||||
fi
|
||||
cd packages/twenty-docker/
|
||||
docker compose down -v
|
||||
working-directory: ./
|
||||
@@ -48,9 +48,9 @@ type ApplicationRegistration {
|
||||
isListed: Boolean!
|
||||
isFeatured: Boolean!
|
||||
isPreInstalled: Boolean!
|
||||
logoUrl: String
|
||||
createdAt: DateTime!
|
||||
updatedAt: DateTime!
|
||||
logo: FileOutput
|
||||
isConfigured: Boolean!
|
||||
}
|
||||
|
||||
@@ -283,18 +283,11 @@ type Role {
|
||||
rowLevelPermissionPredicateGroups: [RowLevelPermissionPredicateGroup!]
|
||||
}
|
||||
|
||||
type FileOutput {
|
||||
fileId: UUID
|
||||
label: String
|
||||
extension: String
|
||||
url: String!
|
||||
}
|
||||
|
||||
type ApplicationRegistrationSummary {
|
||||
id: UUID!
|
||||
latestAvailableVersion: String
|
||||
sourceType: ApplicationRegistrationSourceType!
|
||||
logo: FileOutput
|
||||
logoUrl: String
|
||||
}
|
||||
|
||||
type ApplicationVariable {
|
||||
@@ -698,6 +691,7 @@ type Application {
|
||||
id: UUID!
|
||||
name: String!
|
||||
description: String
|
||||
logo: String
|
||||
version: String
|
||||
universalIdentifier: String!
|
||||
packageJsonChecksum: String
|
||||
@@ -717,7 +711,6 @@ type Application {
|
||||
objects: [Object!]!
|
||||
applicationVariables: [ApplicationVariable!]!
|
||||
applicationRegistration: ApplicationRegistrationSummary
|
||||
logo: FileOutput
|
||||
}
|
||||
|
||||
type ViewField {
|
||||
@@ -1978,7 +1971,7 @@ type CreateApplicationRegistration {
|
||||
type PublicApplicationRegistration {
|
||||
id: UUID!
|
||||
name: String!
|
||||
logo: FileOutput
|
||||
logoUrl: String
|
||||
websiteUrl: String
|
||||
oAuthScopes: [String!]!
|
||||
}
|
||||
@@ -2364,7 +2357,6 @@ type MarketplaceAppDetail {
|
||||
sourceType: ApplicationRegistrationSourceType!
|
||||
sourcePackage: String
|
||||
latestAvailableVersion: String
|
||||
logo: FileOutput
|
||||
isListed: Boolean!
|
||||
isFeatured: Boolean!
|
||||
manifest: JSON
|
||||
|
||||
@@ -52,9 +52,9 @@ export interface ApplicationRegistration {
|
||||
isListed: Scalars['Boolean']
|
||||
isFeatured: Scalars['Boolean']
|
||||
isPreInstalled: Scalars['Boolean']
|
||||
logoUrl?: Scalars['String']
|
||||
createdAt: Scalars['DateTime']
|
||||
updatedAt: Scalars['DateTime']
|
||||
logo?: FileOutput
|
||||
isConfigured: Scalars['Boolean']
|
||||
__typename: 'ApplicationRegistration'
|
||||
}
|
||||
@@ -232,19 +232,11 @@ export interface Role {
|
||||
__typename: 'Role'
|
||||
}
|
||||
|
||||
export interface FileOutput {
|
||||
fileId?: Scalars['UUID']
|
||||
label?: Scalars['String']
|
||||
extension?: Scalars['String']
|
||||
url: Scalars['String']
|
||||
__typename: 'FileOutput'
|
||||
}
|
||||
|
||||
export interface ApplicationRegistrationSummary {
|
||||
id: Scalars['UUID']
|
||||
latestAvailableVersion?: Scalars['String']
|
||||
sourceType: ApplicationRegistrationSourceType
|
||||
logo?: FileOutput
|
||||
logoUrl?: Scalars['String']
|
||||
__typename: 'ApplicationRegistrationSummary'
|
||||
}
|
||||
|
||||
@@ -464,6 +456,7 @@ export interface Application {
|
||||
id: Scalars['UUID']
|
||||
name: Scalars['String']
|
||||
description?: Scalars['String']
|
||||
logo?: Scalars['String']
|
||||
version?: Scalars['String']
|
||||
universalIdentifier: Scalars['String']
|
||||
packageJsonChecksum?: Scalars['String']
|
||||
@@ -483,7 +476,6 @@ export interface Application {
|
||||
objects: Object[]
|
||||
applicationVariables: ApplicationVariable[]
|
||||
applicationRegistration?: ApplicationRegistrationSummary
|
||||
logo?: FileOutput
|
||||
__typename: 'Application'
|
||||
}
|
||||
|
||||
@@ -1619,7 +1611,7 @@ export interface CreateApplicationRegistration {
|
||||
export interface PublicApplicationRegistration {
|
||||
id: Scalars['UUID']
|
||||
name: Scalars['String']
|
||||
logo?: FileOutput
|
||||
logoUrl?: Scalars['String']
|
||||
websiteUrl?: Scalars['String']
|
||||
oAuthScopes: Scalars['String'][]
|
||||
__typename: 'PublicApplicationRegistration'
|
||||
@@ -2042,7 +2034,6 @@ export interface MarketplaceAppDetail {
|
||||
sourceType: ApplicationRegistrationSourceType
|
||||
sourcePackage?: Scalars['String']
|
||||
latestAvailableVersion?: Scalars['String']
|
||||
logo?: FileOutput
|
||||
isListed: Scalars['Boolean']
|
||||
isFeatured: Scalars['Boolean']
|
||||
manifest?: Scalars['JSON']
|
||||
@@ -2932,9 +2923,9 @@ export interface ApplicationRegistrationGenqlSelection{
|
||||
isListed?: boolean | number
|
||||
isFeatured?: boolean | number
|
||||
isPreInstalled?: boolean | number
|
||||
logoUrl?: boolean | number
|
||||
createdAt?: boolean | number
|
||||
updatedAt?: boolean | number
|
||||
logo?: FileOutputGenqlSelection
|
||||
isConfigured?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
@@ -3105,20 +3096,11 @@ export interface RoleGenqlSelection{
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface FileOutputGenqlSelection{
|
||||
fileId?: boolean | number
|
||||
label?: boolean | number
|
||||
extension?: boolean | number
|
||||
url?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface ApplicationRegistrationSummaryGenqlSelection{
|
||||
id?: boolean | number
|
||||
latestAvailableVersion?: boolean | number
|
||||
sourceType?: boolean | number
|
||||
logo?: FileOutputGenqlSelection
|
||||
logoUrl?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
@@ -3383,6 +3365,7 @@ export interface ApplicationGenqlSelection{
|
||||
id?: boolean | number
|
||||
name?: boolean | number
|
||||
description?: boolean | number
|
||||
logo?: boolean | number
|
||||
version?: boolean | number
|
||||
universalIdentifier?: boolean | number
|
||||
packageJsonChecksum?: boolean | number
|
||||
@@ -3402,7 +3385,6 @@ export interface ApplicationGenqlSelection{
|
||||
objects?: ObjectGenqlSelection
|
||||
applicationVariables?: ApplicationVariableGenqlSelection
|
||||
applicationRegistration?: ApplicationRegistrationSummaryGenqlSelection
|
||||
logo?: FileOutputGenqlSelection
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
@@ -4573,7 +4555,7 @@ export interface CreateApplicationRegistrationGenqlSelection{
|
||||
export interface PublicApplicationRegistrationGenqlSelection{
|
||||
id?: boolean | number
|
||||
name?: boolean | number
|
||||
logo?: FileOutputGenqlSelection
|
||||
logoUrl?: boolean | number
|
||||
websiteUrl?: boolean | number
|
||||
oAuthScopes?: boolean | number
|
||||
__typename?: boolean | number
|
||||
@@ -5048,7 +5030,6 @@ export interface MarketplaceAppDetailGenqlSelection{
|
||||
sourceType?: boolean | number
|
||||
sourcePackage?: boolean | number
|
||||
latestAvailableVersion?: boolean | number
|
||||
logo?: FileOutputGenqlSelection
|
||||
isListed?: boolean | number
|
||||
isFeatured?: boolean | number
|
||||
manifest?: boolean | number
|
||||
@@ -6428,14 +6409,6 @@ export interface LogicFunctionLogsInput {applicationId?: (Scalars['UUID'] | null
|
||||
|
||||
|
||||
|
||||
const FileOutput_possibleTypes: string[] = ['FileOutput']
|
||||
export const isFileOutput = (obj?: { __typename?: any } | null): obj is FileOutput => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isFileOutput"')
|
||||
return FileOutput_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const ApplicationRegistrationSummary_possibleTypes: string[] = ['ApplicationRegistrationSummary']
|
||||
export const isApplicationRegistrationSummary = (obj?: { __typename?: any } | null): obj is ApplicationRegistrationSummary => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isApplicationRegistrationSummary"')
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,9 +16,10 @@ Jeder Schlüssel enthält einen `publicKey` (unbefristet aufbewahrt, damit er zu
|
||||
|
||||
### Aktuellen Schlüssel rotieren
|
||||
|
||||
Setzen Sie `SIGNING_KEY_ROTATION_DAYS`, um die Funktion zu aktivieren: Ein täglicher Cronjob erstellt dann einen neuen aktuellen Schlüssel, sobald der bestehende Schlüssel älter als dieser Schwellenwert ist. Frühere Schlüssel werden *nicht* widerrufen, daher werden Tokens, die darunter signiert wurden, weiterhin verifiziert. Lassen Sie die Variable ungesetzt, um die automatische Rotation zu deaktivieren.
|
||||
* **Manuell** — **Settings → Admin Panel → Signing keys → Revoke** in der aktuellen Zeile. Das Widerrufen löscht das verschlüsselte private Material und stuft es herab; der nächste Signieraufruf erstellt automatisch ein neues ES256-Schlüsselpaar als neuen aktuellen Schlüssel. Tokens, die unter einem anderen (nicht widerrufenen) `kid` signiert wurden, werden weiterhin verifiziert, bis sie ablaufen.
|
||||
* **Enterprise (automatisch)** — ein täglicher Cron-Job (`'15 3 * * *'` UTC) erstellt einen neuen aktuellen Schlüssel, sobald der vorhandene Schlüssel seit `SIGNING_KEY_ROTATION_DAYS` (Standard `90`) aktuell ist. Der vorherige Schlüssel wird *nicht* widerrufen, daher werden Tokens, die darunter signiert wurden, weiterhin verifiziert. Registriere ihn einmalig mit `yarn command:prod cron:register:all`.
|
||||
|
||||
<Note>Die automatische Rotation ist ab Version v2.6 verfügbar.</Note>
|
||||
<Note>Der Enterprise-Cron-Job und `SIGNING_KEY_ROTATION_DAYS` sind ab v2.6+ enthalten.</Note>
|
||||
|
||||
### Einen Schlüssel widerrufen (nur bei Leak / Notfall)
|
||||
|
||||
|
||||
@@ -16,9 +16,10 @@ Cada chave carrega uma `publicKey` (mantida indefinidamente para que possa verif
|
||||
|
||||
### Rotacionar a chave atual
|
||||
|
||||
Defina `SIGNING_KEY_ROTATION_DAYS` para ativar: um cron diário então gera uma nova chave e a define como atual quando a existente for mais antiga do que esse limite. Chaves anteriores *não* são revogadas, então tokens assinados sob elas continuam sendo verificados. Deixe a variável não definida para desativar a rotação automática.
|
||||
* **Manual** — **Settings → Admin Panel → Signing keys → Revoke** na linha atual. A revogação apaga o material privado criptografado e o rebaixa; a próxima chamada de assinatura gera automaticamente um novo par de chaves ES256 como o novo atual. Tokens assinados sob qualquer outro `kid` (não revogado) continuam sendo verificados até expirarem.
|
||||
* **Enterprise (automático)** — um cron diário (`'15 3 * * *'` UTC) emite uma nova chave atual assim que a existente tiver sido atual por `SIGNING_KEY_ROTATION_DAYS` (padrão `90`). A chave anterior *não* é revogada, então tokens assinados sob ela continuam sendo verificados. Registre-o uma vez com `yarn command:prod cron:register:all`.
|
||||
|
||||
<Note>A rotação automática está disponível a partir da v2.6+.</Note>
|
||||
<Note>O cron do Enterprise e `SIGNING_KEY_ROTATION_DAYS` são disponibilizados a partir da v2.6+.</Note>
|
||||
|
||||
### Revogar uma chave (apenas vazamento / emergência)
|
||||
|
||||
|
||||
@@ -16,9 +16,10 @@ Fiecare cheie are un `publicKey` (păstrat pe termen nelimitat pentru a putea ve
|
||||
|
||||
### Rotește cheia curentă
|
||||
|
||||
Setați `SIGNING_KEY_ROTATION_DAYS` pentru a activa rotația automată: un job cron zilnic va emite o nouă cheie curentă odată ce cea existentă este mai veche decât acest prag. Cheile anterioare *nu* sunt revocate, astfel încât token-urile semnate cu ele continuă să fie verificate. Lăsați variabila nesetată pentru a dezactiva rotația automată.
|
||||
* **Manual** — **Settings → Admin Panel → Signing keys → Revoke** pe rândul curent. Revocarea șterge materialul privat criptat și o retrogradează; următorul apel de semnare generează automat o nouă pereche de chei ES256 ca noua cheie curentă. Token-urile semnate sub orice alt `kid` (nerevocat) continuă să fie verificate până la expirare.
|
||||
* **Enterprise (automat)** — un cron zilnic (`'15 3 * * *'` UTC) emite o nouă cheie curentă după ce cea existentă a fost curentă timp de `SIGNING_KEY_ROTATION_DAYS` (implicit `90`). Cheia anterioară *nu* este revocată, astfel încât token-urile semnate cu ea continuă să fie verificate. Înregistrează-l o singură dată cu `yarn command:prod cron:register:all`.
|
||||
|
||||
<Note>Rotația automată este disponibilă începând cu versiunea v2.6+.</Note>
|
||||
<Note>Cron-ul Enterprise și `SIGNING_KEY_ROTATION_DAYS` sunt disponibile în v2.6+.</Note>
|
||||
|
||||
### Revocă o cheie (numai în caz de scurgere / urgență)
|
||||
|
||||
|
||||
@@ -16,9 +16,10 @@ icon: rotate
|
||||
|
||||
### Выполнить ротацию текущего ключа
|
||||
|
||||
Установите `SIGNING_KEY_ROTATION_DAYS`, чтобы включить эту опцию: ежедневный cron затем будет выпускать новый текущий ключ, как только существующий ключ станет старше этого порогового значения. Предыдущие ключи *не* отзываются, поэтому токены, подписанные ими, продолжают успешно проходить проверку. Оставьте переменную не заданной, чтобы отключить автоматическую ротацию.
|
||||
* **Вручную** — **Settings → Admin Panel → Signing keys → Revoke** в текущей строке. Отзыв стирает его зашифрованный закрытый материал и понижает его; следующий вызов подписи автоматически создает новую пару ключей ES256 как новый текущий ключ. Токены, подписанные любым другим (не отозванным) `kid`, продолжают успешно проходить проверку до истечения срока действия.
|
||||
* **Enterprise (автоматически)** — ежедневный cron (`'15 3 * * *'` UTC) выпускает новый текущий ключ, как только существующий ключ находится в статусе текущего в течение `SIGNING_KEY_ROTATION_DAYS` (по умолчанию `90`). Предыдущий ключ *не* отзывается, поэтому токены, подписанные им, продолжают успешно проходить проверку. Зарегистрируйте его один раз с помощью `yarn command:prod cron:register:all`.
|
||||
|
||||
<Note>Автоматическая ротация доступна, начиная с версии v2.6+.</Note>
|
||||
<Note>Enterprise-cron и `SIGNING_KEY_ROTATION_DAYS` поставляются начиная с v2.6+.</Note>
|
||||
|
||||
### Отозвать ключ (только при утечке / в экстренных случаях)
|
||||
|
||||
|
||||
@@ -16,9 +16,10 @@ Her anahtar bir `publicKey` (önceden verilmiş belirteçleri doğrulayabilmesi
|
||||
|
||||
### Geçerli anahtarı döndür
|
||||
|
||||
Etkinleştirmek için `SIGNING_KEY_ROTATION_DAYS` değerini ayarlayın: günlük bir cron görevi, mevcut anahtar bu eşikten daha eski olduğunda yeni bir güncel anahtar oluşturur. Önceki anahtarlar *iptal edilmez*, bu nedenle onlarla imzalanmış belirteçler doğrulanmaya devam eder. Otomatik döndürmeyi devre dışı bırakmak için değişkeni ayarlamadan bırakın.
|
||||
* **El ile** — geçerli satırda **Settings → Admin Panel → Signing keys → Revoke**. İptal etmek, şifrelenmiş özel materyalini siler ve onu geçerli olmaktan çıkarır; bir sonraki imzalama çağrısı, yeni geçerli olarak otomatik olarak yeni bir ES256 anahtar çifti oluşturur. Herhangi başka bir (iptal edilmemiş) `kid` ile imzalanan belirteçler, süreleri dolana kadar doğrulanmaya devam eder.
|
||||
* **Kurumsal (otomatik)** — günlük bir cron (`'15 3 * * *'` UTC), mevcut anahtar `SIGNING_KEY_ROTATION_DAYS` (varsayılan `90`) kadar süredir geçerli olduğunda yeni bir geçerli anahtar verir. Önceki anahtar *iptal edilmez*, bu nedenle onunla imzalanan belirteçler doğrulanmaya devam eder. `yarn command:prod cron:register:all` ile bir kez kaydedin.
|
||||
|
||||
<Note>Otomatik döndürme v2.6+ ile birlikte gelir.</Note>
|
||||
<Note>Kurumsal cron ve `SIGNING_KEY_ROTATION_DAYS` v2.6+ ile birlikte gelir.</Note>
|
||||
|
||||
### Bir anahtarı iptal et (yalnızca sızıntı / acil durum için)
|
||||
|
||||
|
||||
@@ -16,9 +16,10 @@ Twenty 具有两个相互独立的密钥族:
|
||||
|
||||
### 轮换当前密钥
|
||||
|
||||
将 `SIGNING_KEY_ROTATION_DAYS` 设为启用该功能:然后每日的 cron 任务会在现有密钥超过该阈值后签发新的当前密钥。 先前的密钥*不会*被吊销,因此在其下签名的令牌仍然可以通过验证。 将变量保持未设置以禁用自动轮换。
|
||||
* **手动** — 在当前行上执行 **Settings → Admin Panel → Signing keys → Revoke**。 吊销操作会清除其加密的私有材料并将其降级;下一次签名调用会自动生成一个新的 ES256 密钥对,作为新的当前密钥。 在任何其他(未被吊销的)`kid` 下签名的令牌会一直验证,直到过期。
|
||||
* **Enterprise(自动)** — 每日 cron(`'15 3 * * *'` UTC)会在现有密钥已作为当前密钥使用 `SIGNING_KEY_ROTATION_DAYS`(默认 `90`)后签发一个新的当前密钥。 先前的密钥*不会*被吊销,因此在其下签名的令牌仍然可以通过验证。 使用 `yarn command:prod cron:register:all` 注册一次。
|
||||
|
||||
<Note>自动轮换在 v2.6+ 中提供。</Note>
|
||||
<Note>Enterprise 的 cron 和 `SIGNING_KEY_ROTATION_DAYS` 从 v2.6+ 版本开始提供。</Note>
|
||||
|
||||
### 吊销密钥(仅限泄露 / 紧急情况)
|
||||
|
||||
|
||||
@@ -176,7 +176,7 @@ export type ApplicationRegistration = {
|
||||
isListed: Scalars['Boolean'];
|
||||
isPreInstalled: Scalars['Boolean'];
|
||||
latestAvailableVersion?: Maybe<Scalars['String']>;
|
||||
logo?: Maybe<FileOutput>;
|
||||
logoUrl?: Maybe<Scalars['String']>;
|
||||
name: Scalars['String'];
|
||||
oAuthClientId: Scalars['String'];
|
||||
oAuthRedirectUris: Array<Scalars['String']>;
|
||||
@@ -293,14 +293,6 @@ export enum FeatureFlagKey {
|
||||
IS_UNIQUE_INDEXES_ENABLED = 'IS_UNIQUE_INDEXES_ENABLED'
|
||||
}
|
||||
|
||||
export type FileOutput = {
|
||||
__typename?: 'FileOutput';
|
||||
extension?: Maybe<Scalars['String']>;
|
||||
fileId?: Maybe<Scalars['UUID']>;
|
||||
label?: Maybe<Scalars['String']>;
|
||||
url: Scalars['String'];
|
||||
};
|
||||
|
||||
export enum HealthIndicatorId {
|
||||
app = 'app',
|
||||
connectedAccount = 'connectedAccount',
|
||||
@@ -941,7 +933,7 @@ export type FindAdminApplicationRegistrationVariablesQuery = { __typename?: 'Que
|
||||
export type FindAllApplicationRegistrationsQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type FindAllApplicationRegistrationsQuery = { __typename?: 'Query', findAllApplicationRegistrations: Array<{ __typename?: 'ApplicationRegistration', id: string, universalIdentifier: string, name: string, oAuthClientId: string, oAuthRedirectUris: Array<string>, oAuthScopes: Array<string>, sourceType: ApplicationRegistrationSourceType, sourcePackage?: string | null, latestAvailableVersion?: string | null, isListed: boolean, isFeatured: boolean, isPreInstalled: boolean, isConfigured: boolean, ownerWorkspaceId?: string | null, createdAt: string, updatedAt: string, logo?: { __typename?: 'FileOutput', fileId?: string | null, label?: string | null, extension?: string | null, url: string } | null }> };
|
||||
export type FindAllApplicationRegistrationsQuery = { __typename?: 'Query', findAllApplicationRegistrations: Array<{ __typename?: 'ApplicationRegistration', id: string, universalIdentifier: string, name: string, logoUrl?: string | null, oAuthClientId: string, oAuthRedirectUris: Array<string>, oAuthScopes: Array<string>, sourceType: ApplicationRegistrationSourceType, sourcePackage?: string | null, latestAvailableVersion?: string | null, isListed: boolean, isFeatured: boolean, isPreInstalled: boolean, isConfigured: boolean, ownerWorkspaceId?: string | null, createdAt: string, updatedAt: string }> };
|
||||
|
||||
export type CreateDatabaseConfigVariableMutationVariables = Exact<{
|
||||
key: Scalars['String'];
|
||||
@@ -1008,7 +1000,7 @@ export type FindOneAdminApplicationRegistrationQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type FindOneAdminApplicationRegistrationQuery = { __typename?: 'Query', findOneAdminApplicationRegistration: { __typename?: 'ApplicationRegistration', id: string, universalIdentifier: string, name: string, oAuthClientId: string, oAuthRedirectUris: Array<string>, oAuthScopes: Array<string>, sourceType: ApplicationRegistrationSourceType, sourcePackage?: string | null, latestAvailableVersion?: string | null, isListed: boolean, isFeatured: boolean, isPreInstalled: boolean, isConfigured: boolean, ownerWorkspaceId?: string | null, createdAt: string, updatedAt: string, logo?: { __typename?: 'FileOutput', fileId?: string | null, label?: string | null, extension?: string | null, url: string } | null } };
|
||||
export type FindOneAdminApplicationRegistrationQuery = { __typename?: 'Query', findOneAdminApplicationRegistration: { __typename?: 'ApplicationRegistration', id: string, universalIdentifier: string, name: string, logoUrl?: string | null, oAuthClientId: string, oAuthRedirectUris: Array<string>, oAuthScopes: Array<string>, sourceType: ApplicationRegistrationSourceType, sourcePackage?: string | null, latestAvailableVersion?: string | null, isListed: boolean, isFeatured: boolean, isPreInstalled: boolean, isConfigured: boolean, ownerWorkspaceId?: string | null, createdAt: string, updatedAt: string } };
|
||||
|
||||
export type GetAdminChatThreadMessagesQueryVariables = Exact<{
|
||||
threadId: Scalars['UUID'];
|
||||
@@ -1144,10 +1136,10 @@ export type GetSigningKeysQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
export type GetSigningKeysQuery = { __typename?: 'Query', getSigningKeys: { __typename?: 'SigningKeysAdminPanelDTO', legacyVerifyCountInWindow: number, verifyWindowDays: number, signingKeys: Array<{ __typename?: 'SigningKeyDTO', id: string, publicKey: string, isCurrent: boolean, createdAt: string, revokedAt?: string | null, verifyCountInWindow: number }> } };
|
||||
|
||||
export type ApplicationRegistrationFragmentFragment = { __typename?: 'ApplicationRegistration', id: string, universalIdentifier: string, name: string, oAuthClientId: string, oAuthRedirectUris: Array<string>, oAuthScopes: Array<string>, sourceType: ApplicationRegistrationSourceType, sourcePackage?: string | null, latestAvailableVersion?: string | null, isListed: boolean, isFeatured: boolean, isPreInstalled: boolean, isConfigured: boolean, ownerWorkspaceId?: string | null, createdAt: string, updatedAt: string, logo?: { __typename?: 'FileOutput', fileId?: string | null, label?: string | null, extension?: string | null, url: string } | null };
|
||||
export type ApplicationRegistrationFragmentFragment = { __typename?: 'ApplicationRegistration', id: string, universalIdentifier: string, name: string, logoUrl?: string | null, oAuthClientId: string, oAuthRedirectUris: Array<string>, oAuthScopes: Array<string>, sourceType: ApplicationRegistrationSourceType, sourcePackage?: string | null, latestAvailableVersion?: string | null, isListed: boolean, isFeatured: boolean, isPreInstalled: boolean, isConfigured: boolean, ownerWorkspaceId?: string | null, createdAt: string, updatedAt: string };
|
||||
|
||||
export const UserInfoFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"UserInfoFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"UserInfo"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]} as unknown as DocumentNode<UserInfoFragmentFragment, unknown>;
|
||||
export const ApplicationRegistrationFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ApplicationRegistrationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ApplicationRegistration"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"universalIdentifier"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"logo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"fileId"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"extension"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"oAuthClientId"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthRedirectUris"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthScopes"}},{"kind":"Field","name":{"kind":"Name","value":"sourceType"}},{"kind":"Field","name":{"kind":"Name","value":"sourcePackage"}},{"kind":"Field","name":{"kind":"Name","value":"latestAvailableVersion"}},{"kind":"Field","name":{"kind":"Name","value":"isListed"}},{"kind":"Field","name":{"kind":"Name","value":"isFeatured"}},{"kind":"Field","name":{"kind":"Name","value":"isPreInstalled"}},{"kind":"Field","name":{"kind":"Name","value":"isConfigured"}},{"kind":"Field","name":{"kind":"Name","value":"ownerWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<ApplicationRegistrationFragmentFragment, unknown>;
|
||||
export const ApplicationRegistrationFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ApplicationRegistrationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ApplicationRegistration"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"universalIdentifier"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"logoUrl"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthClientId"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthRedirectUris"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthScopes"}},{"kind":"Field","name":{"kind":"Name","value":"sourceType"}},{"kind":"Field","name":{"kind":"Name","value":"sourcePackage"}},{"kind":"Field","name":{"kind":"Name","value":"latestAvailableVersion"}},{"kind":"Field","name":{"kind":"Name","value":"isListed"}},{"kind":"Field","name":{"kind":"Name","value":"isFeatured"}},{"kind":"Field","name":{"kind":"Name","value":"isPreInstalled"}},{"kind":"Field","name":{"kind":"Name","value":"isConfigured"}},{"kind":"Field","name":{"kind":"Name","value":"ownerWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<ApplicationRegistrationFragmentFragment, unknown>;
|
||||
export const AddAiProviderDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"AddAiProvider"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"providerName"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"providerConfig"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"addAiProvider"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"providerName"},"value":{"kind":"Variable","name":{"kind":"Name","value":"providerName"}}},{"kind":"Argument","name":{"kind":"Name","value":"providerConfig"},"value":{"kind":"Variable","name":{"kind":"Name","value":"providerConfig"}}}]}]}}]} as unknown as DocumentNode<AddAiProviderMutation, AddAiProviderMutationVariables>;
|
||||
export const AddModelToProviderDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"AddModelToProvider"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"providerName"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"modelConfig"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"addModelToProvider"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"providerName"},"value":{"kind":"Variable","name":{"kind":"Name","value":"providerName"}}},{"kind":"Argument","name":{"kind":"Name","value":"modelConfig"},"value":{"kind":"Variable","name":{"kind":"Name","value":"modelConfig"}}}]}]}}]} as unknown as DocumentNode<AddModelToProviderMutation, AddModelToProviderMutationVariables>;
|
||||
export const RemoveAiProviderDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RemoveAiProvider"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"providerName"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"removeAiProvider"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"providerName"},"value":{"kind":"Variable","name":{"kind":"Name","value":"providerName"}}}]}]}}]} as unknown as DocumentNode<RemoveAiProviderMutation, RemoveAiProviderMutationVariables>;
|
||||
@@ -1163,7 +1155,7 @@ export const GetAiProvidersDocument = {"kind":"Document","definitions":[{"kind":
|
||||
export const GetModelsDevProvidersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetModelsDevProviders"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getModelsDevProviders"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"modelCount"}},{"kind":"Field","name":{"kind":"Name","value":"npm"}}]}}]}}]} as unknown as DocumentNode<GetModelsDevProvidersQuery, GetModelsDevProvidersQueryVariables>;
|
||||
export const GetModelsDevSuggestionsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetModelsDevSuggestions"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"providerType"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getModelsDevSuggestions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"providerType"},"value":{"kind":"Variable","name":{"kind":"Name","value":"providerType"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"modelId"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"inputCostPerMillionTokens"}},{"kind":"Field","name":{"kind":"Name","value":"outputCostPerMillionTokens"}},{"kind":"Field","name":{"kind":"Name","value":"cachedInputCostPerMillionTokens"}},{"kind":"Field","name":{"kind":"Name","value":"cacheCreationCostPerMillionTokens"}},{"kind":"Field","name":{"kind":"Name","value":"contextWindowTokens"}},{"kind":"Field","name":{"kind":"Name","value":"maxOutputTokens"}},{"kind":"Field","name":{"kind":"Name","value":"modalities"}},{"kind":"Field","name":{"kind":"Name","value":"supportsReasoning"}}]}}]}}]} as unknown as DocumentNode<GetModelsDevSuggestionsQuery, GetModelsDevSuggestionsQueryVariables>;
|
||||
export const FindAdminApplicationRegistrationVariablesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FindAdminApplicationRegistrationVariables"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"applicationRegistrationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findAdminApplicationRegistrationVariables"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"applicationRegistrationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"applicationRegistrationId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"isSecret"}},{"kind":"Field","name":{"kind":"Name","value":"isRequired"}},{"kind":"Field","name":{"kind":"Name","value":"isFilled"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]} as unknown as DocumentNode<FindAdminApplicationRegistrationVariablesQuery, FindAdminApplicationRegistrationVariablesQueryVariables>;
|
||||
export const FindAllApplicationRegistrationsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FindAllApplicationRegistrations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findAllApplicationRegistrations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ApplicationRegistrationFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ApplicationRegistrationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ApplicationRegistration"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"universalIdentifier"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"logo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"fileId"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"extension"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"oAuthClientId"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthRedirectUris"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthScopes"}},{"kind":"Field","name":{"kind":"Name","value":"sourceType"}},{"kind":"Field","name":{"kind":"Name","value":"sourcePackage"}},{"kind":"Field","name":{"kind":"Name","value":"latestAvailableVersion"}},{"kind":"Field","name":{"kind":"Name","value":"isListed"}},{"kind":"Field","name":{"kind":"Name","value":"isFeatured"}},{"kind":"Field","name":{"kind":"Name","value":"isPreInstalled"}},{"kind":"Field","name":{"kind":"Name","value":"isConfigured"}},{"kind":"Field","name":{"kind":"Name","value":"ownerWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<FindAllApplicationRegistrationsQuery, FindAllApplicationRegistrationsQueryVariables>;
|
||||
export const FindAllApplicationRegistrationsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FindAllApplicationRegistrations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findAllApplicationRegistrations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ApplicationRegistrationFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ApplicationRegistrationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ApplicationRegistration"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"universalIdentifier"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"logoUrl"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthClientId"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthRedirectUris"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthScopes"}},{"kind":"Field","name":{"kind":"Name","value":"sourceType"}},{"kind":"Field","name":{"kind":"Name","value":"sourcePackage"}},{"kind":"Field","name":{"kind":"Name","value":"latestAvailableVersion"}},{"kind":"Field","name":{"kind":"Name","value":"isListed"}},{"kind":"Field","name":{"kind":"Name","value":"isFeatured"}},{"kind":"Field","name":{"kind":"Name","value":"isPreInstalled"}},{"kind":"Field","name":{"kind":"Name","value":"isConfigured"}},{"kind":"Field","name":{"kind":"Name","value":"ownerWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<FindAllApplicationRegistrationsQuery, FindAllApplicationRegistrationsQueryVariables>;
|
||||
export const CreateDatabaseConfigVariableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateDatabaseConfigVariable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"key"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"value"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createDatabaseConfigVariable"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}},{"kind":"Argument","name":{"kind":"Name","value":"value"},"value":{"kind":"Variable","name":{"kind":"Name","value":"value"}}}]}]}}]} as unknown as DocumentNode<CreateDatabaseConfigVariableMutation, CreateDatabaseConfigVariableMutationVariables>;
|
||||
export const DeleteDatabaseConfigVariableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteDatabaseConfigVariable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"key"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteDatabaseConfigVariable"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}]}]}}]} as unknown as DocumentNode<DeleteDatabaseConfigVariableMutation, DeleteDatabaseConfigVariableMutationVariables>;
|
||||
export const UpdateDatabaseConfigVariableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateDatabaseConfigVariable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"key"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"value"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateDatabaseConfigVariable"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}},{"kind":"Argument","name":{"kind":"Name","value":"value"},"value":{"kind":"Variable","name":{"kind":"Name","value":"value"}}}]}]}}]} as unknown as DocumentNode<UpdateDatabaseConfigVariableMutation, UpdateDatabaseConfigVariableMutationVariables>;
|
||||
@@ -1172,7 +1164,7 @@ export const GetDatabaseConfigVariableDocument = {"kind":"Document","definitions
|
||||
export const UpdateWorkspaceFeatureFlagDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateWorkspaceFeatureFlag"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"featureFlag"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"value"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateWorkspaceFeatureFlag"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"workspaceId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}}},{"kind":"Argument","name":{"kind":"Name","value":"featureFlag"},"value":{"kind":"Variable","name":{"kind":"Name","value":"featureFlag"}}},{"kind":"Argument","name":{"kind":"Name","value":"value"},"value":{"kind":"Variable","name":{"kind":"Name","value":"value"}}}]}]}}]} as unknown as DocumentNode<UpdateWorkspaceFeatureFlagMutation, UpdateWorkspaceFeatureFlagMutationVariables>;
|
||||
export const AdminPanelRecentUsersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AdminPanelRecentUsers"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"searchTerm"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"adminPanelRecentUsers"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"searchTerm"},"value":{"kind":"Variable","name":{"kind":"Name","value":"searchTerm"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceName"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceLogo"}}]}}]}}]} as unknown as DocumentNode<AdminPanelRecentUsersQuery, AdminPanelRecentUsersQueryVariables>;
|
||||
export const AdminPanelTopWorkspacesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AdminPanelTopWorkspaces"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"searchTerm"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"adminPanelTopWorkspaces"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"searchTerm"},"value":{"kind":"Variable","name":{"kind":"Name","value":"searchTerm"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"logoUrl"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"totalUsers"}},{"kind":"Field","name":{"kind":"Name","value":"subdomain"}}]}}]}}]} as unknown as DocumentNode<AdminPanelTopWorkspacesQuery, AdminPanelTopWorkspacesQueryVariables>;
|
||||
export const FindOneAdminApplicationRegistrationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FindOneAdminApplicationRegistration"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findOneAdminApplicationRegistration"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ApplicationRegistrationFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ApplicationRegistrationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ApplicationRegistration"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"universalIdentifier"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"logo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"fileId"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"extension"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}},{"kind":"Field","name":{"kind":"Name","value":"oAuthClientId"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthRedirectUris"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthScopes"}},{"kind":"Field","name":{"kind":"Name","value":"sourceType"}},{"kind":"Field","name":{"kind":"Name","value":"sourcePackage"}},{"kind":"Field","name":{"kind":"Name","value":"latestAvailableVersion"}},{"kind":"Field","name":{"kind":"Name","value":"isListed"}},{"kind":"Field","name":{"kind":"Name","value":"isFeatured"}},{"kind":"Field","name":{"kind":"Name","value":"isPreInstalled"}},{"kind":"Field","name":{"kind":"Name","value":"isConfigured"}},{"kind":"Field","name":{"kind":"Name","value":"ownerWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<FindOneAdminApplicationRegistrationQuery, FindOneAdminApplicationRegistrationQueryVariables>;
|
||||
export const FindOneAdminApplicationRegistrationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FindOneAdminApplicationRegistration"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findOneAdminApplicationRegistration"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ApplicationRegistrationFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ApplicationRegistrationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ApplicationRegistration"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"universalIdentifier"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"logoUrl"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthClientId"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthRedirectUris"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthScopes"}},{"kind":"Field","name":{"kind":"Name","value":"sourceType"}},{"kind":"Field","name":{"kind":"Name","value":"sourcePackage"}},{"kind":"Field","name":{"kind":"Name","value":"latestAvailableVersion"}},{"kind":"Field","name":{"kind":"Name","value":"isListed"}},{"kind":"Field","name":{"kind":"Name","value":"isFeatured"}},{"kind":"Field","name":{"kind":"Name","value":"isPreInstalled"}},{"kind":"Field","name":{"kind":"Name","value":"isConfigured"}},{"kind":"Field","name":{"kind":"Name","value":"ownerWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<FindOneAdminApplicationRegistrationQuery, FindOneAdminApplicationRegistrationQueryVariables>;
|
||||
export const GetAdminChatThreadMessagesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetAdminChatThreadMessages"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"threadId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getAdminChatThreadMessages"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"threadId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"threadId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"thread"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"totalInputTokens"}},{"kind":"Field","name":{"kind":"Name","value":"totalOutputTokens"}},{"kind":"Field","name":{"kind":"Name","value":"conversationSize"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}},{"kind":"Field","name":{"kind":"Name","value":"messages"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"parts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"textContent"}},{"kind":"Field","name":{"kind":"Name","value":"toolName"}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]}}]}}]} as unknown as DocumentNode<GetAdminChatThreadMessagesQuery, GetAdminChatThreadMessagesQueryVariables>;
|
||||
export const GetAdminWorkspaceChatThreadsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetAdminWorkspaceChatThreads"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getAdminWorkspaceChatThreads"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"workspaceId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"totalInputTokens"}},{"kind":"Field","name":{"kind":"Name","value":"totalOutputTokens"}},{"kind":"Field","name":{"kind":"Name","value":"conversationSize"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]} as unknown as DocumentNode<GetAdminWorkspaceChatThreadsQuery, GetAdminWorkspaceChatThreadsQueryVariables>;
|
||||
export const GetUpgradeStatusDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetUpgradeStatus"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"workspaceIds"}},"type":{"kind":"NonNullType","type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getUpgradeStatus"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"workspaceIds"},"value":{"kind":"Variable","name":{"kind":"Name","value":"workspaceIds"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"inferredVersion"}},{"kind":"Field","name":{"kind":"Name","value":"health"}},{"kind":"Field","name":{"kind":"Name","value":"latestCommand"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"executedByVersion"}},{"kind":"Field","name":{"kind":"Name","value":"errorMessage"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]}}]}}]} as unknown as DocumentNode<GetUpgradeStatusQuery, GetUpgradeStatusQueryVariables>;
|
||||
|
||||
File diff suppressed because one or more lines are too long
+2
-12
@@ -11,12 +11,7 @@ export const APPLICATION_FRAGMENT = gql`
|
||||
id
|
||||
name
|
||||
description
|
||||
logo {
|
||||
fileId
|
||||
label
|
||||
extension
|
||||
url
|
||||
}
|
||||
logo
|
||||
version
|
||||
universalIdentifier
|
||||
applicationRegistrationId
|
||||
@@ -24,12 +19,7 @@ export const APPLICATION_FRAGMENT = gql`
|
||||
id
|
||||
latestAvailableVersion
|
||||
sourceType
|
||||
logo {
|
||||
fileId
|
||||
label
|
||||
extension
|
||||
url
|
||||
}
|
||||
logoUrl
|
||||
}
|
||||
canBeUninstalled
|
||||
defaultRoleId
|
||||
|
||||
+1
-6
@@ -6,12 +6,7 @@ export const FIND_MANY_APPLICATIONS = gql`
|
||||
id
|
||||
name
|
||||
description
|
||||
logo {
|
||||
fileId
|
||||
label
|
||||
extension
|
||||
url
|
||||
}
|
||||
logo
|
||||
version
|
||||
universalIdentifier
|
||||
applicationRegistrationId
|
||||
|
||||
@@ -8,6 +8,7 @@ import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { buildApplicationLogoUrl } from '@/applications/utils/buildApplicationLogoUrl';
|
||||
import CustomLogo from '~/pages/settings/applications/assets/custom-illustrations/custom-logo.webp';
|
||||
import StandardLogo from '~/pages/settings/applications/assets/standard-illustrations/standard-logo.webp';
|
||||
|
||||
@@ -66,7 +67,11 @@ export const useApplicationChipData = ({
|
||||
? new URL(StandardLogo, window.location.href).toString()
|
||||
: isCustom
|
||||
? new URL(CustomLogo, window.location.href).toString()
|
||||
: (application.logo?.url ?? undefined);
|
||||
: buildApplicationLogoUrl({
|
||||
applicationId: application.id,
|
||||
logo: application.logo,
|
||||
workspaceId: currentWorkspace?.id,
|
||||
});
|
||||
|
||||
return {
|
||||
applicationChipData: {
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { REACT_APP_SERVER_BASE_URL } from '~/config';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
export const buildApplicationLogoUrl = ({
|
||||
workspaceId,
|
||||
applicationId,
|
||||
logo,
|
||||
}: {
|
||||
workspaceId?: string | null;
|
||||
applicationId?: string | null;
|
||||
logo?: string | null;
|
||||
}): string | undefined => {
|
||||
if (
|
||||
!isDefined(logo) ||
|
||||
logo.startsWith('http://') ||
|
||||
logo.startsWith('https://')
|
||||
) {
|
||||
return logo ?? undefined;
|
||||
}
|
||||
|
||||
if (!isDefined(workspaceId) || !isDefined(applicationId)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return `${REACT_APP_SERVER_BASE_URL}/public-assets/${workspaceId}/${applicationId}/${logo}`;
|
||||
};
|
||||
+1
-6
@@ -4,12 +4,7 @@ export const FIND_APPLICATION_REGISTRATION_BY_CLIENT_ID = gql`
|
||||
query FindApplicationRegistrationByClientId($clientId: String!) {
|
||||
findApplicationRegistrationByClientId(clientId: $clientId) {
|
||||
id
|
||||
logo {
|
||||
fileId
|
||||
label
|
||||
extension
|
||||
url
|
||||
}
|
||||
logoUrl
|
||||
name
|
||||
oAuthScopes
|
||||
websiteUrl
|
||||
|
||||
-6
@@ -1,4 +1,3 @@
|
||||
import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { currentUserWorkspaceState } from '@/auth/states/currentUserWorkspaceState';
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { objectPermissionsFamilySelector } from '@/auth/states/objectPermissionsFamilySelector';
|
||||
@@ -28,7 +27,6 @@ export const StandalonePageCommandMenu = () => {
|
||||
const commandMenuItems = useAtomStateValue(commandMenuItemsSelector);
|
||||
const currentWorkspace = useAtomStateValue(currentWorkspaceState);
|
||||
const currentUserWorkspace = useAtomStateValue(currentUserWorkspaceState);
|
||||
const currentUser = useAtomStateValue(currentUserState);
|
||||
const currentPageLayoutId = useAtomStateValue(currentPageLayoutIdState);
|
||||
const isLayoutCustomizationModeEnabled = useAtomStateValue(
|
||||
isLayoutCustomizationModeEnabledState,
|
||||
@@ -87,16 +85,12 @@ export const StandalonePageCommandMenu = () => {
|
||||
permissionFlags,
|
||||
targetObjectReadPermissions,
|
||||
targetObjectWritePermissions,
|
||||
canImpersonate: currentUser?.canImpersonate === true,
|
||||
canAccessFullAdminPanel: currentUser?.canAccessFullAdminPanel === true,
|
||||
objectMetadataItem: {},
|
||||
objectMetadataLabel: '',
|
||||
};
|
||||
}, [
|
||||
currentWorkspace?.featureFlags,
|
||||
currentUserWorkspace?.permissionFlags,
|
||||
currentUser?.canImpersonate,
|
||||
currentUser?.canAccessFullAdminPanel,
|
||||
isLayoutCustomizationModeEnabled,
|
||||
objectMetadataItems,
|
||||
store,
|
||||
|
||||
-2
@@ -27,8 +27,6 @@ export const EMPTY_COMMAND_MENU_CONTEXT_API: CommandMenuContextApi = {
|
||||
permissionFlags: {},
|
||||
targetObjectReadPermissions: {},
|
||||
targetObjectWritePermissions: {},
|
||||
canImpersonate: false,
|
||||
canAccessFullAdminPanel: false,
|
||||
objectMetadataItem: {},
|
||||
objectMetadataLabel: '',
|
||||
};
|
||||
|
||||
-2
@@ -67,8 +67,6 @@ const getWrapper =
|
||||
permissionFlags: {},
|
||||
targetObjectReadPermissions: {},
|
||||
targetObjectWritePermissions: {},
|
||||
canImpersonate: false,
|
||||
canAccessFullAdminPanel: false,
|
||||
objectMetadataItem: {},
|
||||
objectMetadataLabel: '',
|
||||
},
|
||||
|
||||
-7
@@ -1,4 +1,3 @@
|
||||
import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { currentUserWorkspaceState } from '@/auth/states/currentUserWorkspaceState';
|
||||
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { objectPermissionsFamilySelector } from '@/auth/states/objectPermissionsFamilySelector';
|
||||
@@ -152,10 +151,6 @@ export const useCurrentCommandMenuContextApi = (): CommandMenuContextApi => {
|
||||
permissionFlags[flag] = true;
|
||||
}
|
||||
|
||||
const currentUser = useAtomStateValue(currentUserState);
|
||||
const canImpersonate = currentUser?.canImpersonate === true;
|
||||
const canAccessFullAdminPanel = currentUser?.canAccessFullAdminPanel === true;
|
||||
|
||||
const targetObjectReadPermissions: Record<string, boolean> = {};
|
||||
const targetObjectWritePermissions: Record<string, boolean> = {};
|
||||
|
||||
@@ -193,8 +188,6 @@ export const useCurrentCommandMenuContextApi = (): CommandMenuContextApi => {
|
||||
permissionFlags,
|
||||
targetObjectReadPermissions,
|
||||
targetObjectWritePermissions,
|
||||
canImpersonate,
|
||||
canAccessFullAdminPanel,
|
||||
objectMetadataItem: objectMetadataItem ?? {},
|
||||
objectMetadataLabel,
|
||||
};
|
||||
|
||||
-6
@@ -8,12 +8,6 @@ export const MARKETPLACE_APP_DETAIL_FRAGMENT = gql`
|
||||
sourceType
|
||||
sourcePackage
|
||||
latestAvailableVersion
|
||||
logo {
|
||||
fileId
|
||||
label
|
||||
extension
|
||||
url
|
||||
}
|
||||
isListed
|
||||
isFeatured
|
||||
manifest
|
||||
|
||||
+1
-1
@@ -179,7 +179,7 @@ const SettingsAdminAppsTableRow = ({
|
||||
<AppChip
|
||||
size="md"
|
||||
fallbackApplicationData={{
|
||||
logo: registration.logo?.url ?? null,
|
||||
logo: registration.logoUrl,
|
||||
name: registration.name,
|
||||
}}
|
||||
/>
|
||||
|
||||
-21
@@ -1,21 +0,0 @@
|
||||
import { gql } from '@apollo/client';
|
||||
|
||||
export const FIND_ADMIN_APPLICATION_REGISTRATION_VARIABLES = gql`
|
||||
query FindAdminApplicationRegistrationVariables(
|
||||
$applicationRegistrationId: String!
|
||||
) {
|
||||
findAdminApplicationRegistrationVariables(
|
||||
applicationRegistrationId: $applicationRegistrationId
|
||||
) {
|
||||
id
|
||||
key
|
||||
value
|
||||
description
|
||||
isSecret
|
||||
isRequired
|
||||
isFilled
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
}
|
||||
`;
|
||||
+1
-6
@@ -5,12 +5,7 @@ export const APPLICATION_REGISTRATION_FRAGMENT = gql`
|
||||
id
|
||||
universalIdentifier
|
||||
name
|
||||
logo {
|
||||
fileId
|
||||
label
|
||||
extension
|
||||
url
|
||||
}
|
||||
logoUrl
|
||||
oAuthClientId
|
||||
oAuthRedirectUris
|
||||
oAuthScopes
|
||||
|
||||
+1
-8
@@ -28,14 +28,7 @@ export const useObjectAndFieldRows = ({
|
||||
}) => {
|
||||
const objectMetadataItems = useAtomStateValue(objectMetadataItemsSelector);
|
||||
const currentWorkspace = useAtomStateValue(currentWorkspaceState);
|
||||
const installedApplications = currentWorkspace?.installedApplications?.map(
|
||||
(app) => ({
|
||||
id: app.id,
|
||||
name: app.name,
|
||||
universalIdentifier: app.universalIdentifier,
|
||||
logo: app.logo?.url ?? null,
|
||||
}),
|
||||
);
|
||||
const installedApplications = currentWorkspace?.installedApplications;
|
||||
|
||||
return useMemo(() => {
|
||||
if (isDefined(installedApplication)) {
|
||||
|
||||
+1
-1
@@ -44,7 +44,7 @@ export const getInstalledApplicationObjectAndFieldRows = ({
|
||||
}),
|
||||
application: {
|
||||
id: installedApplication.id,
|
||||
logo: installedApplication.logo?.url ?? null,
|
||||
logo: installedApplication.logo,
|
||||
name: installedApplication.name,
|
||||
universalIdentifier: installedApplication.universalIdentifier,
|
||||
},
|
||||
|
||||
@@ -70,12 +70,7 @@ export const USER_QUERY_FRAGMENT = gql`
|
||||
id
|
||||
name
|
||||
universalIdentifier
|
||||
logo {
|
||||
fileId
|
||||
label
|
||||
extension
|
||||
url
|
||||
}
|
||||
logo
|
||||
}
|
||||
isCustomDomainEnabled
|
||||
workspaceUrls {
|
||||
|
||||
@@ -285,7 +285,7 @@ export const Authorize = () => {
|
||||
}
|
||||
|
||||
const appName = applicationRegistration.name;
|
||||
const appLogoUrl = applicationRegistration.logo?.url ?? null;
|
||||
const appLogoUrl = applicationRegistration.logoUrl;
|
||||
const requestedScopes: string[] = applicationRegistration.oAuthScopes ?? [];
|
||||
|
||||
const showLogoImage = isNonEmptyString(appLogoUrl) && !hasLogoError;
|
||||
|
||||
@@ -20,12 +20,7 @@ const buildHandlers = (
|
||||
application: {
|
||||
id: string;
|
||||
name: string;
|
||||
logo: {
|
||||
fileId: string | null;
|
||||
label: string | null;
|
||||
extension: string | null;
|
||||
url: string;
|
||||
} | null;
|
||||
logoUrl: string | null;
|
||||
oAuthScopes: string[];
|
||||
websiteUrl: string | null;
|
||||
} | null,
|
||||
@@ -95,7 +90,7 @@ export const Default: Story = {
|
||||
handlers: buildHandlers({
|
||||
id: 'application-id-default',
|
||||
name: 'ChatGPT',
|
||||
logo: null,
|
||||
logoUrl: null,
|
||||
oAuthScopes: ['api', 'profile'],
|
||||
websiteUrl: null,
|
||||
}),
|
||||
@@ -121,7 +116,7 @@ export const WithApiScopeOnly: Story = {
|
||||
handlers: buildHandlers({
|
||||
id: 'application-id-api-only',
|
||||
name: 'Internal Tool',
|
||||
logo: null,
|
||||
logoUrl: null,
|
||||
oAuthScopes: ['api'],
|
||||
websiteUrl: null,
|
||||
}),
|
||||
@@ -149,7 +144,7 @@ export const WithLongAppName: Story = {
|
||||
handlers: buildHandlers({
|
||||
id: 'application-id-long-name',
|
||||
name: 'Custom Workspace Automation Suite',
|
||||
logo: null,
|
||||
logoUrl: null,
|
||||
oAuthScopes: ['api', 'profile'],
|
||||
websiteUrl: null,
|
||||
}),
|
||||
|
||||
+1
-21
@@ -8,15 +8,12 @@ import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBa
|
||||
import { useApolloAdminClient } from '@/settings/admin-panel/apollo/hooks/useApolloAdminClient';
|
||||
import { APPLICATION_REGISTRATION_ADMIN_PATH } from '@/settings/admin-panel/apps/constants/ApplicationRegistrationAdminPath';
|
||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||
import { styled } from '@linaria/react';
|
||||
import {
|
||||
Avatar,
|
||||
IconInfoCircle,
|
||||
IconKey,
|
||||
IconSettings,
|
||||
IconWorld,
|
||||
} from 'twenty-ui/display';
|
||||
import { themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
import { SettingsApplicationRegistrationConfigTab } from '~/pages/settings/applications/tabs/SettingsApplicationRegistrationConfigTab';
|
||||
import { SettingsApplicationRegistrationOAuthTab } from '~/pages/settings/applications/tabs/SettingsApplicationRegistrationOAuthTab';
|
||||
import { SettingsApplicationRegistrationDistributionTab } from '~/pages/settings/applications/tabs/SettingsApplicationRegistrationDistributionTab';
|
||||
@@ -25,12 +22,6 @@ import { TabList } from '@/ui/layout/tab-list/components/TabList';
|
||||
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
|
||||
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
|
||||
|
||||
const StyledTitleContainer = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: ${themeCssVariables.spacing[2]};
|
||||
`;
|
||||
|
||||
const REGISTRATION_DETAIL_TAB_LIST_ID =
|
||||
'admin-application-registration-detail-tab-list';
|
||||
|
||||
@@ -103,18 +94,7 @@ export const SettingsAdminApplicationRegistrationDetail = () => {
|
||||
|
||||
return (
|
||||
<SubMenuTopBarContainer
|
||||
title={
|
||||
<StyledTitleContainer>
|
||||
<Avatar
|
||||
type="app"
|
||||
size="md"
|
||||
avatarUrl={registration.logo?.url ?? undefined}
|
||||
placeholder={registration.name}
|
||||
placeholderColorSeed={registration.name}
|
||||
/>
|
||||
{registration.name}
|
||||
</StyledTitleContainer>
|
||||
}
|
||||
title={registration.name}
|
||||
links={[
|
||||
{
|
||||
children: t`Other`,
|
||||
|
||||
@@ -54,12 +54,7 @@ const FIND_MANY_APPLICATIONS_FOR_TOOL_TABLE = gql`
|
||||
id
|
||||
name
|
||||
universalIdentifier
|
||||
logo {
|
||||
fileId
|
||||
label
|
||||
extension
|
||||
url
|
||||
}
|
||||
logo
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -97,12 +92,7 @@ export const SettingsToolsTable = () => {
|
||||
id: string;
|
||||
name: string;
|
||||
universalIdentifier: string;
|
||||
logo?: {
|
||||
fileId: string | null;
|
||||
label: string | null;
|
||||
extension: string | null;
|
||||
url: string;
|
||||
} | null;
|
||||
logo?: string | null;
|
||||
}>;
|
||||
}>(FIND_MANY_APPLICATIONS_FOR_TOOL_TABLE);
|
||||
const { data: marketplaceAppsData } = useQuery<{
|
||||
|
||||
+1
-1
@@ -293,7 +293,7 @@ export const SettingsApplicationDetails = () => {
|
||||
applicationInfo={{
|
||||
id: application.id,
|
||||
name: displayName,
|
||||
logo: application.logo?.url ?? null,
|
||||
logo: application.logo,
|
||||
universalIdentifier: application.universalIdentifier,
|
||||
}}
|
||||
/>
|
||||
|
||||
+1
-21
@@ -8,15 +8,12 @@ import { useLingui } from '@lingui/react/macro';
|
||||
import { Tag } from 'twenty-ui/components';
|
||||
import { TabList } from '@/ui/layout/tab-list/components/TabList';
|
||||
import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer';
|
||||
import { styled } from '@linaria/react';
|
||||
import {
|
||||
Avatar,
|
||||
IconInfoCircle,
|
||||
IconKey,
|
||||
IconSettings,
|
||||
IconWorld,
|
||||
} from 'twenty-ui/display';
|
||||
import { themeCssVariables } from 'twenty-ui/theme-constants';
|
||||
import { SettingsApplicationRegistrationConfigTab } from '~/pages/settings/applications/tabs/SettingsApplicationRegistrationConfigTab';
|
||||
import { SettingsApplicationRegistrationOAuthTab } from '~/pages/settings/applications/tabs/SettingsApplicationRegistrationOAuthTab';
|
||||
import { SettingsApplicationRegistrationDistributionTab } from '~/pages/settings/applications/tabs/SettingsApplicationRegistrationDistributionTab';
|
||||
@@ -24,12 +21,6 @@ import { SettingsApplicationRegistrationGeneralTab } from '~/pages/settings/appl
|
||||
import { useAtomComponentStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentStateValue';
|
||||
import { activeTabIdComponentState } from '@/ui/layout/tab-list/states/activeTabIdComponentState';
|
||||
|
||||
const StyledTitleContainer = styled.div`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
gap: ${themeCssVariables.spacing[2]};
|
||||
`;
|
||||
|
||||
const REGISTRATION_DETAIL_TAB_LIST_ID =
|
||||
'application-registration-detail-tab-list';
|
||||
|
||||
@@ -95,18 +86,7 @@ export const SettingsApplicationRegistrationDetails = () => {
|
||||
|
||||
return (
|
||||
<SubMenuTopBarContainer
|
||||
title={
|
||||
<StyledTitleContainer>
|
||||
<Avatar
|
||||
type="app"
|
||||
size="md"
|
||||
avatarUrl={registration.logo?.url ?? undefined}
|
||||
placeholder={registration.name}
|
||||
placeholderColorSeed={registration.name}
|
||||
/>
|
||||
{registration.name}
|
||||
</StyledTitleContainer>
|
||||
}
|
||||
title={registration.name}
|
||||
tag={<Tag text={t`Owner`} color={'gray'} />}
|
||||
links={[
|
||||
{
|
||||
|
||||
+1
-5
@@ -245,7 +245,7 @@ export const SettingsAvailableApplicationDetails = () => {
|
||||
manifestContent={manifest}
|
||||
applicationInfo={{
|
||||
name: displayName,
|
||||
logo: detail?.logo?.url,
|
||||
logo: app?.logoUrl,
|
||||
universalIdentifier: detail.universalIdentifier,
|
||||
}}
|
||||
/>
|
||||
@@ -286,10 +286,6 @@ export const SettingsAvailableApplicationDetails = () => {
|
||||
displayName={displayName}
|
||||
description={description}
|
||||
applicationId={application?.id}
|
||||
fallbackApplicationData={{
|
||||
logo: detail?.logo?.url,
|
||||
name: displayName,
|
||||
}}
|
||||
isUnlisted={isUnlisted}
|
||||
/>
|
||||
}
|
||||
|
||||
+3
-6
@@ -9,11 +9,10 @@ import { useApplicationChipData } from '@/applications/hooks/useApplicationChipD
|
||||
type SettingsApplicationDetailTitleProps = {
|
||||
displayName: string;
|
||||
description?: string;
|
||||
logoUrl?: string;
|
||||
applicationId?: string;
|
||||
fallbackApplicationData?: {
|
||||
logo?: string | null;
|
||||
name?: string | null;
|
||||
};
|
||||
applicationName?: string;
|
||||
universalIdentifier?: string;
|
||||
isUnlisted?: boolean;
|
||||
};
|
||||
|
||||
@@ -74,14 +73,12 @@ export const SettingsApplicationDetailTitle = ({
|
||||
displayName,
|
||||
description,
|
||||
applicationId,
|
||||
fallbackApplicationData,
|
||||
isUnlisted = false,
|
||||
}: SettingsApplicationDetailTitleProps) => {
|
||||
const descriptionSummary = getApplicationDescriptionSummary(description);
|
||||
|
||||
const { applicationChipData } = useApplicationChipData({
|
||||
applicationId,
|
||||
fallbackApplicationData,
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
+3
-7
@@ -177,8 +177,8 @@ export const SettingsApplicationsDeveloperTab = () => {
|
||||
<TableRow
|
||||
gridTemplateColumns={APPLICATION_TABLE_ROW_GRID_TEMPLATE_COLUMNS}
|
||||
>
|
||||
<TableHeader>{t`Name`}</TableHeader>
|
||||
<TableHeader>{t`Type`}</TableHeader>
|
||||
<TableHeader> {t`Name`}</TableHeader>
|
||||
<TableHeader>{''}</TableHeader>
|
||||
<TableHeader>{''}</TableHeader>
|
||||
<TableHeader />
|
||||
</TableRow>
|
||||
@@ -187,11 +187,7 @@ export const SettingsApplicationsDeveloperTab = () => {
|
||||
return (
|
||||
<SettingsApplicationTableRow
|
||||
key={registration.id}
|
||||
application={{
|
||||
...registration,
|
||||
logo: registration.logo?.url ?? null,
|
||||
}}
|
||||
sourceType={registration.sourceType}
|
||||
application={registration}
|
||||
action={
|
||||
<IconChevronRight
|
||||
size={theme.icon.size.md}
|
||||
|
||||
-2
@@ -39,8 +39,6 @@ const buildMockCommandMenuContextApi = (
|
||||
permissionFlags: {},
|
||||
targetObjectReadPermissions: {},
|
||||
targetObjectWritePermissions: {},
|
||||
canImpersonate: false,
|
||||
canAccessFullAdminPanel: false,
|
||||
objectMetadataItem: {},
|
||||
objectMetadataLabel: '',
|
||||
...overrides,
|
||||
|
||||
-4
@@ -25,10 +25,6 @@ export const targetObjectReadPermissions =
|
||||
null as unknown as CommandMenuContextApi['targetObjectReadPermissions'];
|
||||
export const targetObjectWritePermissions =
|
||||
null as unknown as CommandMenuContextApi['targetObjectWritePermissions'];
|
||||
export const canImpersonate =
|
||||
null as unknown as CommandMenuContextApi['canImpersonate'];
|
||||
export const canAccessFullAdminPanel =
|
||||
null as unknown as CommandMenuContextApi['canAccessFullAdminPanel'];
|
||||
|
||||
export const objectMetadataItem =
|
||||
null as unknown as CommandMenuContextApi['objectMetadataItem'];
|
||||
|
||||
@@ -12,8 +12,6 @@ export {
|
||||
featureFlags,
|
||||
targetObjectReadPermissions,
|
||||
targetObjectWritePermissions,
|
||||
canImpersonate,
|
||||
canAccessFullAdminPanel,
|
||||
isDefined,
|
||||
isNonEmptyString,
|
||||
includes,
|
||||
|
||||
@@ -2,7 +2,6 @@ import {
|
||||
DEFAULT_API_URL_NAME,
|
||||
DEFAULT_APP_ACCESS_TOKEN_NAME,
|
||||
} from 'twenty-shared/application';
|
||||
import { buildPublicAssetUrl } from 'twenty-shared/utils';
|
||||
|
||||
const decodeTokenPayload = (
|
||||
token: string,
|
||||
@@ -39,16 +38,5 @@ export const getPublicAssetUrl = (path: string): string => {
|
||||
.map(encodeURIComponent)
|
||||
.join('/');
|
||||
|
||||
const url = buildPublicAssetUrl({
|
||||
path: encodedPath,
|
||||
serverUrl: apiUrl,
|
||||
workspaceId,
|
||||
applicationId,
|
||||
});
|
||||
|
||||
if (!url) {
|
||||
throw new Error('Failed to build public asset URL');
|
||||
}
|
||||
|
||||
return url;
|
||||
return `${apiUrl}/public-assets/${workspaceId}/${applicationId}/${encodedPath}`;
|
||||
};
|
||||
|
||||
@@ -29,7 +29,9 @@ export class AddWorkspaceIdToTotoFastInstanceCommand
|
||||
implements FastInstanceCommand
|
||||
{
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`ALTER TABLE "core"."toto" ADD "workspaceId" uuid`);
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "core"."toto" ADD "workspaceId" uuid`,
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
@@ -79,9 +81,12 @@ Workspace commands run per-workspace logic across all active or suspended worksp
|
||||
@RegisteredWorkspaceCommand('1.22.0', 1780000002000)
|
||||
@Command({
|
||||
name: 'upgrade:1-22:backfill-standard-skills',
|
||||
description: 'Backfill standard skills for existing workspaces',
|
||||
description:
|
||||
'Backfill standard skills for existing workspaces',
|
||||
})
|
||||
export class BackfillStandardSkillsCommand extends ActiveOrSuspendedWorkspaceCommandRunner {
|
||||
export class BackfillStandardSkillsCommand
|
||||
extends ActiveOrSuspendedWorkspaceCommandRunner
|
||||
{
|
||||
constructor(
|
||||
protected readonly workspaceIteratorService: WorkspaceIteratorService,
|
||||
// inject any services you need
|
||||
|
||||
@@ -3,14 +3,12 @@
|
||||
This Bash script helps generate self-signed SSL certificates for local development. It uses OpenSSL to create a root certificate authority, a domain certificate, and configures them for local usage.
|
||||
|
||||
## Features
|
||||
|
||||
- Generates a private key and root certificate.
|
||||
- Creates a signed certificate for a specified domain.
|
||||
- Adds the root certificate to the macOS keychain for trusted usage (macOS only).
|
||||
- Customizable with default values for easier use.
|
||||
|
||||
## Requirements
|
||||
|
||||
- OpenSSL
|
||||
|
||||
## Usage
|
||||
@@ -32,27 +30,24 @@ To generate certificates using the default values:
|
||||
#### Examples:
|
||||
|
||||
1. **Using Default Values**:
|
||||
|
||||
```sh
|
||||
./script.sh
|
||||
```
|
||||
```sh
|
||||
./script.sh
|
||||
```
|
||||
|
||||
2. **Custom Domain Name**:
|
||||
|
||||
```sh
|
||||
./script.sh example.com
|
||||
```
|
||||
```sh
|
||||
./script.sh example.com
|
||||
```
|
||||
|
||||
3. **Custom Domain Name and Root Certificate Name**:
|
||||
|
||||
```sh
|
||||
./script.sh example.com customRootCertificate
|
||||
```
|
||||
```sh
|
||||
./script.sh example.com customRootCertificate
|
||||
```
|
||||
|
||||
4. **Custom Domain Name, Root Certificate Name, and Validity Days**:
|
||||
```sh
|
||||
./script.sh example.com customRootCertificate 398
|
||||
```
|
||||
```sh
|
||||
./script.sh example.com customRootCertificate 398
|
||||
```
|
||||
|
||||
## Script Details
|
||||
|
||||
@@ -76,4 +71,4 @@ The generated files are stored in `~/certs/{domain}`:
|
||||
## Notes
|
||||
|
||||
- If running on non-macOS systems, you'll need to manually add the root certificate to your trusted certificate store.
|
||||
- Ensure that OpenSSL is installed and available in your PATH.
|
||||
- Ensure that OpenSSL is installed and available in your PATH.
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
import { QueryRunner } from 'typeorm';
|
||||
|
||||
import { RegisteredInstanceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-instance-command.decorator';
|
||||
import { FastInstanceCommand } from 'src/engine/core-modules/upgrade/interfaces/fast-instance-command.interface';
|
||||
|
||||
@RegisteredInstanceCommand('2.8.0', 1779387505162)
|
||||
export class AddLogoToApplicationRegistrationFastInstanceCommand
|
||||
implements FastInstanceCommand
|
||||
{
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
'ALTER TABLE "core"."applicationRegistration" ADD "logoFileId" uuid',
|
||||
);
|
||||
await queryRunner.query(
|
||||
'ALTER TABLE "core"."applicationRegistration" ADD CONSTRAINT "UQ_796819fb23559c233e6ebd49f34" UNIQUE ("logoFileId")',
|
||||
);
|
||||
await queryRunner.query(
|
||||
'ALTER TABLE "core"."applicationRegistration" ADD CONSTRAINT "FK_796819fb23559c233e6ebd49f34" FOREIGN KEY ("logoFileId") REFERENCES "core"."file"("id") ON DELETE SET NULL ON UPDATE NO ACTION',
|
||||
);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
'ALTER TABLE "core"."applicationRegistration" DROP CONSTRAINT "FK_796819fb23559c233e6ebd49f34"',
|
||||
);
|
||||
await queryRunner.query(
|
||||
'ALTER TABLE "core"."applicationRegistration" DROP CONSTRAINT "UQ_796819fb23559c233e6ebd49f34"',
|
||||
);
|
||||
await queryRunner.query(
|
||||
'ALTER TABLE "core"."applicationRegistration" DROP COLUMN "logoFileId"',
|
||||
);
|
||||
}
|
||||
}
|
||||
-2
@@ -3,7 +3,6 @@ import { Module } from '@nestjs/common';
|
||||
import { WorkspaceIteratorModule } from 'src/database/commands/command-runners/workspace-iterator.module';
|
||||
import { DropChannelStandardObjectsCommand } from 'src/database/commands/upgrade-version-command/2-8/2-8-workspace-command-1798000050000-drop-channel-standard-objects.command';
|
||||
import { BackfillRelationJoinColumnIndexesCommand } from 'src/database/commands/upgrade-version-command/2-8/2-8-workspace-command-1798100000000-backfill-relation-join-column-indexes.command';
|
||||
import { GateDefaultCommandMenuItemsByPermissionFlagCommand } from 'src/database/commands/upgrade-version-command/2-8/2-8-workspace-command-1798100010000-gate-default-command-menu-items-by-permission-flag.command';
|
||||
import { ApplicationModule } from 'src/engine/core-modules/application/application.module';
|
||||
import { WorkspaceSchemaManagerModule } from 'src/engine/twenty-orm/workspace-schema-manager/workspace-schema-manager.module';
|
||||
import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module';
|
||||
@@ -20,7 +19,6 @@ import { WorkspaceMigrationModule } from 'src/engine/workspace-manager/workspace
|
||||
providers: [
|
||||
DropChannelStandardObjectsCommand,
|
||||
BackfillRelationJoinColumnIndexesCommand,
|
||||
GateDefaultCommandMenuItemsByPermissionFlagCommand,
|
||||
],
|
||||
})
|
||||
export class V2_8_UpgradeVersionCommandModule {}
|
||||
|
||||
-159
@@ -1,159 +0,0 @@
|
||||
import { Command } from 'nest-commander';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { ActiveOrSuspendedWorkspaceCommandRunner } from 'src/database/commands/command-runners/active-or-suspended-workspace.command-runner';
|
||||
import { WorkspaceIteratorService } from 'src/database/commands/command-runners/workspace-iterator.service';
|
||||
import { type RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspace.command-runner';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { RegisteredWorkspaceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-workspace-command.decorator';
|
||||
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
|
||||
import { STANDARD_COMMAND_MENU_ITEMS } from 'src/engine/workspace-manager/twenty-standard-application/constants/standard-command-menu-item.constant';
|
||||
import { computeTwentyStandardApplicationAllFlatEntityMaps } from 'src/engine/workspace-manager/twenty-standard-application/utils/twenty-standard-application-all-flat-entity-maps.constant';
|
||||
import { WorkspaceMigrationValidateBuildAndRunService } from 'src/engine/workspace-manager/workspace-migration/services/workspace-migration-validate-build-and-run-service';
|
||||
|
||||
const UNIVERSAL_IDENTIFIERS_TO_FIX = new Set<string>([
|
||||
STANDARD_COMMAND_MENU_ITEMS.askAi.universalIdentifier,
|
||||
STANDARD_COMMAND_MENU_ITEMS.viewPreviousAiChats.universalIdentifier,
|
||||
STANDARD_COMMAND_MENU_ITEMS.composeEmail.universalIdentifier,
|
||||
STANDARD_COMMAND_MENU_ITEMS.composeEmailToPerson.universalIdentifier,
|
||||
STANDARD_COMMAND_MENU_ITEMS.composeEmailToCompany.universalIdentifier,
|
||||
STANDARD_COMMAND_MENU_ITEMS.composeEmailToOpportunity.universalIdentifier,
|
||||
STANDARD_COMMAND_MENU_ITEMS.goToSettingsAccounts.universalIdentifier,
|
||||
STANDARD_COMMAND_MENU_ITEMS.goToSettingsAccountsEmails.universalIdentifier,
|
||||
STANDARD_COMMAND_MENU_ITEMS.goToSettingsAccountsCalendars.universalIdentifier,
|
||||
STANDARD_COMMAND_MENU_ITEMS.goToSettingsGeneral.universalIdentifier,
|
||||
STANDARD_COMMAND_MENU_ITEMS.goToSettingsObjects.universalIdentifier,
|
||||
STANDARD_COMMAND_MENU_ITEMS.goToSettingsMembers.universalIdentifier,
|
||||
STANDARD_COMMAND_MENU_ITEMS.goToSettingsRoles.universalIdentifier,
|
||||
STANDARD_COMMAND_MENU_ITEMS.goToSettingsDomains.universalIdentifier,
|
||||
STANDARD_COMMAND_MENU_ITEMS.goToSettingsBilling.universalIdentifier,
|
||||
STANDARD_COMMAND_MENU_ITEMS.goToSettingsApiWebhooks.universalIdentifier,
|
||||
STANDARD_COMMAND_MENU_ITEMS.goToSettingsApplications.universalIdentifier,
|
||||
STANDARD_COMMAND_MENU_ITEMS.goToSettingsAI.universalIdentifier,
|
||||
STANDARD_COMMAND_MENU_ITEMS.goToSettingsSecurity.universalIdentifier,
|
||||
STANDARD_COMMAND_MENU_ITEMS.goToSettingsUpdates.universalIdentifier,
|
||||
STANDARD_COMMAND_MENU_ITEMS.goToSettingsAdminPanel.universalIdentifier,
|
||||
]);
|
||||
|
||||
@RegisteredWorkspaceCommand('2.8.0', 1798100010000)
|
||||
@Command({
|
||||
name: 'upgrade:2-8:gate-default-command-menu-items-by-permission-flag',
|
||||
description:
|
||||
'Gate default command menu items (Ask AI, settings navigation, compose email) behind their relevant permission flags so members without permission no longer see them',
|
||||
})
|
||||
export class GateDefaultCommandMenuItemsByPermissionFlagCommand extends ActiveOrSuspendedWorkspaceCommandRunner {
|
||||
constructor(
|
||||
protected readonly workspaceIteratorService: WorkspaceIteratorService,
|
||||
private readonly applicationService: ApplicationService,
|
||||
private readonly workspaceMigrationValidateBuildAndRunService: WorkspaceMigrationValidateBuildAndRunService,
|
||||
private readonly workspaceCacheService: WorkspaceCacheService,
|
||||
) {
|
||||
super(workspaceIteratorService);
|
||||
}
|
||||
|
||||
override async runOnWorkspace({
|
||||
workspaceId,
|
||||
options,
|
||||
}: RunOnWorkspaceArgs): Promise<void> {
|
||||
const isDryRun = options.dryRun ?? false;
|
||||
|
||||
this.logger.log(
|
||||
`${isDryRun ? '[DRY RUN] ' : ''}Gating default command menu items by permission flag for workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
const { twentyStandardFlatApplication } =
|
||||
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
|
||||
{ workspaceId },
|
||||
);
|
||||
|
||||
const { flatCommandMenuItemMaps: existingFlatCommandMenuItemMaps } =
|
||||
await this.workspaceCacheService.getOrRecompute(workspaceId, [
|
||||
'flatCommandMenuItemMaps',
|
||||
]);
|
||||
|
||||
const { allFlatEntityMaps: standardAllFlatEntityMaps } =
|
||||
computeTwentyStandardApplicationAllFlatEntityMaps({
|
||||
now: new Date().toISOString(),
|
||||
workspaceId,
|
||||
twentyStandardApplicationId: twentyStandardFlatApplication.id,
|
||||
});
|
||||
|
||||
const itemsToUpdate = [...UNIVERSAL_IDENTIFIERS_TO_FIX]
|
||||
.map((universalIdentifier) => {
|
||||
const standardItem =
|
||||
standardAllFlatEntityMaps.flatCommandMenuItemMaps
|
||||
.byUniversalIdentifier[universalIdentifier];
|
||||
const existingItem =
|
||||
existingFlatCommandMenuItemMaps.byUniversalIdentifier[
|
||||
universalIdentifier
|
||||
];
|
||||
|
||||
if (
|
||||
!isDefined(standardItem) ||
|
||||
!isDefined(existingItem) ||
|
||||
existingItem.conditionalAvailabilityExpression ===
|
||||
standardItem.conditionalAvailabilityExpression
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return {
|
||||
...existingItem,
|
||||
conditionalAvailabilityExpression:
|
||||
standardItem.conditionalAvailabilityExpression,
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
})
|
||||
.filter(isDefined);
|
||||
|
||||
if (itemsToUpdate.length === 0) {
|
||||
this.logger.log(
|
||||
`Default command menu item expressions already up to date for workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`Found ${itemsToUpdate.length} command menu item(s) to update for workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
if (isDryRun) {
|
||||
this.logger.log(
|
||||
`[DRY RUN] Would update ${itemsToUpdate.length} command menu item availability expression(s) for workspace ${workspaceId}`,
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const validateAndBuildResult =
|
||||
await this.workspaceMigrationValidateBuildAndRunService.validateBuildAndRunWorkspaceMigration(
|
||||
{
|
||||
allFlatEntityOperationByMetadataName: {
|
||||
commandMenuItem: {
|
||||
flatEntityToCreate: [],
|
||||
flatEntityToDelete: [],
|
||||
flatEntityToUpdate: itemsToUpdate,
|
||||
},
|
||||
},
|
||||
workspaceId,
|
||||
applicationUniversalIdentifier:
|
||||
twentyStandardFlatApplication.universalIdentifier,
|
||||
},
|
||||
);
|
||||
|
||||
if (validateAndBuildResult.status === 'fail') {
|
||||
this.logger.error(
|
||||
`Failed to update command menu item availability expressions:\n${JSON.stringify(validateAndBuildResult, null, 2)}`,
|
||||
);
|
||||
|
||||
throw new Error(
|
||||
`Failed to gate default command menu items by permission flag for workspace ${workspaceId}`,
|
||||
);
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`Successfully updated ${itemsToUpdate.length} command menu item availability expression(s) for workspace ${workspaceId}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
-2
@@ -53,7 +53,6 @@ import { DropPostgresCredentialsTableFastInstanceCommand } from 'src/database/co
|
||||
import { AddRelationTargetFieldMetadataIdToViewFilterFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-6/2-6-instance-command-fast-1798000005000-add-relation-target-field-metadata-id-to-view-filter';
|
||||
import { AddChannelSyncStageIndexesFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-6/2-6-instance-command-fast-1798000010000-add-channel-sync-stage-indexes';
|
||||
import { FinalizeRolePermissionFlagCutoverFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-7/2-7-instance-command-fast-1779600000000-finalize-role-permission-flag-cutover';
|
||||
import { AddLogoToApplicationRegistrationFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-8/2-8-instance-command-fast-1779387505162-add-logo-to-application-registration';
|
||||
|
||||
export const INSTANCE_COMMANDS = [
|
||||
AddViewFieldGroupIdIndexOnViewFieldFastInstanceCommand,
|
||||
@@ -109,5 +108,4 @@ export const INSTANCE_COMMANDS = [
|
||||
AddRelationTargetFieldMetadataIdToViewFilterFastInstanceCommand,
|
||||
AddChannelSyncStageIndexesFastInstanceCommand,
|
||||
FinalizeRolePermissionFlagCutoverFastInstanceCommand,
|
||||
AddLogoToApplicationRegistrationFastInstanceCommand,
|
||||
];
|
||||
|
||||
-15
@@ -2,25 +2,10 @@ import { Context, Parent, ResolveField } from '@nestjs/graphql';
|
||||
|
||||
import { AdminResolver } from 'src/engine/api/graphql/graphql-config/decorators/admin-resolver.decorator';
|
||||
import { ApplicationRegistrationEntity } from 'src/engine/core-modules/application/application-registration/application-registration.entity';
|
||||
import { ApplicationRegistrationLogoService } from 'src/engine/core-modules/application/application-registration/application-registration-logo.service';
|
||||
import { type IDataloaders } from 'src/engine/dataloaders/dataloader.interface';
|
||||
import { FileOutputDTO } from 'src/engine/core-modules/file/dtos/file-output.dto';
|
||||
|
||||
@AdminResolver(() => ApplicationRegistrationEntity)
|
||||
export class AdminPanelApplicationRegistrationResolver {
|
||||
constructor(
|
||||
private readonly applicationRegistrationLogoService: ApplicationRegistrationLogoService,
|
||||
) {}
|
||||
|
||||
@ResolveField(() => FileOutputDTO, { nullable: true })
|
||||
async logo(
|
||||
@Parent() registration: ApplicationRegistrationEntity,
|
||||
): Promise<FileOutputDTO | null> {
|
||||
return this.applicationRegistrationLogoService.resolveLogoFile(
|
||||
registration,
|
||||
);
|
||||
}
|
||||
|
||||
@ResolveField(() => Boolean)
|
||||
async isConfigured(
|
||||
@Parent() registration: ApplicationRegistrationEntity,
|
||||
|
||||
+20
-3
@@ -22,6 +22,7 @@ import { UploadApplicationFileInput } from 'src/engine/core-modules/application/
|
||||
import { WorkspaceMigrationDTO } from 'src/engine/core-modules/application/application-development/dtos/workspace-migration.dto';
|
||||
import { ApplicationExceptionFilter } from 'src/engine/core-modules/application/application-exception-filter';
|
||||
import { ApplicationSyncService } from 'src/engine/core-modules/application/application-manifest/application-sync.service';
|
||||
import { resolveManifestAssetUrls } from 'src/engine/core-modules/application/application-marketplace/utils/resolve-manifest-asset-urls.util';
|
||||
import { ApplicationTokenPairDTO } from 'src/engine/core-modules/application/application-oauth/dtos/application-token-pair.dto';
|
||||
import { ApplicationRegistrationVariableService } from 'src/engine/core-modules/application/application-registration-variable/application-registration-variable.service';
|
||||
import { ApplicationRegistrationService } from 'src/engine/core-modules/application/application-registration/application-registration.service';
|
||||
@@ -37,6 +38,7 @@ import { FileDTO } from 'src/engine/core-modules/file/dtos/file.dto';
|
||||
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
|
||||
import { SdkClientGenerationService } from 'src/engine/core-modules/sdk-client/sdk-client-generation.service';
|
||||
import { ThrottlerService } from 'src/engine/core-modules/throttler/throttler.service';
|
||||
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
|
||||
import { type WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
import { AuthUserWorkspaceId } from 'src/engine/decorators/auth/auth-user-workspace-id.decorator';
|
||||
import { AuthUser } from 'src/engine/decorators/auth/auth-user.decorator';
|
||||
@@ -66,6 +68,7 @@ export class ApplicationDevelopmentResolver {
|
||||
private readonly applicationRegistrationVariableService: ApplicationRegistrationVariableService,
|
||||
private readonly fileStorageService: FileStorageService,
|
||||
private readonly sdkClientGenerationService: SdkClientGenerationService,
|
||||
private readonly twentyConfigService: TwentyConfigService,
|
||||
private readonly throttlerService: ThrottlerService,
|
||||
) {}
|
||||
|
||||
@@ -169,7 +172,12 @@ export class ApplicationDevelopmentResolver {
|
||||
});
|
||||
}
|
||||
|
||||
await this.syncRegistrationMetadata(applicationRegistrationId, manifest);
|
||||
await this.syncRegistrationMetadata(
|
||||
applicationRegistrationId,
|
||||
manifest,
|
||||
workspaceId,
|
||||
application.id,
|
||||
);
|
||||
|
||||
return {
|
||||
applicationUniversalIdentifier:
|
||||
@@ -271,11 +279,20 @@ export class ApplicationDevelopmentResolver {
|
||||
private async syncRegistrationMetadata(
|
||||
applicationRegistrationId: string,
|
||||
manifest: ApplicationInput['manifest'],
|
||||
workspaceId: string,
|
||||
applicationId: string,
|
||||
): Promise<void> {
|
||||
const serverUrl = this.twentyConfigService.get('SERVER_URL');
|
||||
|
||||
const manifestWithResolvedUrls = resolveManifestAssetUrls(
|
||||
manifest,
|
||||
(filePath) =>
|
||||
`${serverUrl}/public-assets/${workspaceId}/${applicationId}/${filePath}`,
|
||||
);
|
||||
|
||||
await this.applicationRegistrationService.updateFromManifest(
|
||||
applicationRegistrationId,
|
||||
manifest,
|
||||
ApplicationRegistrationSourceType.LOCAL,
|
||||
manifestWithResolvedUrls,
|
||||
);
|
||||
|
||||
if (manifest.application.serverVariables) {
|
||||
|
||||
+1
-6
@@ -9,7 +9,6 @@ import { ApplicationManifestModule } from 'src/engine/core-modules/application/a
|
||||
import { ApplicationPackageModule } from 'src/engine/core-modules/application/application-package/application-package.module';
|
||||
import { ApplicationInstallResolver } from 'src/engine/core-modules/application/application-install/application-install.resolver';
|
||||
import { ApplicationInstallService } from 'src/engine/core-modules/application/application-install/application-install.service';
|
||||
import { ApplicationLogoResolver } from 'src/engine/core-modules/application/application-install/application-logo.resolver';
|
||||
import { FileStorageModule } from 'src/engine/core-modules/file-storage/file-storage.module';
|
||||
import { LogicFunctionModule } from 'src/engine/core-modules/logic-function/logic-function.module';
|
||||
import { SdkClientModule } from 'src/engine/core-modules/sdk-client/sdk-client.module';
|
||||
@@ -30,11 +29,7 @@ import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache
|
||||
FileStorageModule,
|
||||
WorkspaceCacheModule,
|
||||
],
|
||||
providers: [
|
||||
ApplicationInstallResolver,
|
||||
ApplicationInstallService,
|
||||
ApplicationLogoResolver,
|
||||
],
|
||||
providers: [ApplicationInstallResolver, ApplicationInstallService],
|
||||
exports: [ApplicationInstallService],
|
||||
})
|
||||
export class ApplicationInstallModule {}
|
||||
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
import { Parent, ResolveField } from '@nestjs/graphql';
|
||||
|
||||
import { MetadataResolver } from 'src/engine/api/graphql/graphql-config/decorators/metadata-resolver.decorator';
|
||||
import { ApplicationDTO } from 'src/engine/core-modules/application/dtos/application.dto';
|
||||
import { resolveApplicationLogoUrl } from 'src/engine/core-modules/application/utils/resolve-application-logo-url.util';
|
||||
import { FileOutputDTO } from 'src/engine/core-modules/file/dtos/file-output.dto';
|
||||
import { buildFileOutputFromUrl } from 'src/engine/core-modules/file/utils/build-file-output-from-url.util';
|
||||
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
|
||||
|
||||
@MetadataResolver(() => ApplicationDTO)
|
||||
export class ApplicationLogoResolver {
|
||||
constructor(private readonly twentyConfigService: TwentyConfigService) {}
|
||||
|
||||
@ResolveField(() => FileOutputDTO, { nullable: true })
|
||||
logo(
|
||||
@Parent() application: ApplicationDTO & { workspaceId?: string },
|
||||
): FileOutputDTO | null {
|
||||
if (!application.workspaceId) {
|
||||
return buildFileOutputFromUrl(application.logo ?? null);
|
||||
}
|
||||
|
||||
const serverUrl = this.twentyConfigService.get('SERVER_URL');
|
||||
|
||||
return buildFileOutputFromUrl(
|
||||
resolveApplicationLogoUrl({
|
||||
logo: application.logo,
|
||||
serverUrl,
|
||||
workspaceId: application.workspaceId,
|
||||
applicationId: application.id,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
-5
@@ -5,7 +5,6 @@ import { GraphQLJSON } from 'graphql-type-json';
|
||||
import { type Manifest } from 'twenty-shared/application';
|
||||
|
||||
import { ApplicationRegistrationSourceType } from 'src/engine/core-modules/application/application-registration/enums/application-registration-source-type.enum';
|
||||
import { FileOutputDTO } from 'src/engine/core-modules/file/dtos/file-output.dto';
|
||||
|
||||
@ObjectType('MarketplaceAppDetail')
|
||||
export class MarketplaceAppDetailDTO {
|
||||
@@ -37,10 +36,6 @@ export class MarketplaceAppDetailDTO {
|
||||
@Field({ nullable: true })
|
||||
latestAvailableVersion?: string;
|
||||
|
||||
@IsOptional()
|
||||
@Field(() => FileOutputDTO, { nullable: true })
|
||||
logo?: FileOutputDTO | null;
|
||||
|
||||
@IsBoolean()
|
||||
@Field(() => Boolean)
|
||||
isListed: boolean;
|
||||
|
||||
+18
-1
@@ -3,6 +3,9 @@ import { Injectable, Logger } from '@nestjs/common';
|
||||
import { ApplicationRegistrationService } from 'src/engine/core-modules/application/application-registration/application-registration.service';
|
||||
import { ApplicationRegistrationSourceType } from 'src/engine/core-modules/application/application-registration/enums/application-registration-source-type.enum';
|
||||
import { MarketplaceService } from 'src/engine/core-modules/application/application-marketplace/marketplace.service';
|
||||
import { buildRegistryCdnUrl } from 'src/engine/core-modules/application/application-marketplace/utils/build-registry-cdn-url.util';
|
||||
import { resolveManifestAssetUrls } from 'src/engine/core-modules/application/application-marketplace/utils/resolve-manifest-asset-urls.util';
|
||||
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
|
||||
|
||||
@Injectable()
|
||||
export class MarketplaceCatalogSyncService {
|
||||
@@ -11,6 +14,7 @@ export class MarketplaceCatalogSyncService {
|
||||
constructor(
|
||||
private readonly applicationRegistrationService: ApplicationRegistrationService,
|
||||
private readonly marketplaceService: MarketplaceService,
|
||||
private readonly twentyConfigService: TwentyConfigService,
|
||||
) {}
|
||||
|
||||
async syncCatalog(): Promise<void> {
|
||||
@@ -55,13 +59,26 @@ export class MarketplaceCatalogSyncService {
|
||||
}
|
||||
: fetchedManifest;
|
||||
|
||||
const cdnBaseUrl = this.twentyConfigService.get('APP_REGISTRY_CDN_URL');
|
||||
|
||||
const manifestWithResolvedUrls = resolveManifestAssetUrls(
|
||||
manifest,
|
||||
(filePath) =>
|
||||
buildRegistryCdnUrl({
|
||||
cdnBaseUrl,
|
||||
packageName: pkg.name,
|
||||
version: pkg.version,
|
||||
filePath,
|
||||
}),
|
||||
);
|
||||
|
||||
await this.applicationRegistrationService.upsertFromCatalog({
|
||||
universalIdentifier,
|
||||
name: manifest.application.displayName ?? pkg.name,
|
||||
sourceType: ApplicationRegistrationSourceType.NPM,
|
||||
sourcePackage: pkg.name,
|
||||
latestAvailableVersion: pkg.version ?? null,
|
||||
manifest,
|
||||
manifest: manifestWithResolvedUrls,
|
||||
});
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
|
||||
+1
-21
@@ -12,12 +12,9 @@ import { ApplicationRegistrationService } from 'src/engine/core-modules/applicat
|
||||
import { MarketplaceCatalogSyncCronJob } from 'src/engine/core-modules/application/application-marketplace/crons/marketplace-catalog-sync.cron.job';
|
||||
import { MarketplaceAppDTO } from 'src/engine/core-modules/application/application-marketplace/dtos/marketplace-app.dto';
|
||||
import { MarketplaceAppDetailDTO } from 'src/engine/core-modules/application/application-marketplace/dtos/marketplace-app-detail.dto';
|
||||
import { resolveApplicationRegistrationLogoUrl } from 'src/engine/core-modules/application/utils/resolve-application-registration-logo-url.util';
|
||||
import { buildFileOutputFromUrl } from 'src/engine/core-modules/file/utils/build-file-output-from-url.util';
|
||||
import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decorators/message-queue.decorator';
|
||||
import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants';
|
||||
import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service';
|
||||
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
|
||||
|
||||
@Injectable()
|
||||
export class MarketplaceQueryService {
|
||||
@@ -27,7 +24,6 @@ export class MarketplaceQueryService {
|
||||
constructor(
|
||||
private readonly applicationRegistrationService: ApplicationRegistrationService,
|
||||
private readonly applicationRegistrationVariableService: ApplicationRegistrationVariableService,
|
||||
private readonly twentyConfigService: TwentyConfigService,
|
||||
@InjectMessageQueue(MessageQueue.cronQueue)
|
||||
private readonly messageQueueService: MessageQueueService,
|
||||
) {}
|
||||
@@ -100,14 +96,7 @@ export class MarketplaceQueryService {
|
||||
description: app?.description ?? '',
|
||||
author: `${app?.author ?? 'Unknown'}`,
|
||||
category: app?.category ?? '',
|
||||
logo:
|
||||
resolveApplicationRegistrationLogoUrl({
|
||||
logo: app?.logoUrl ?? null,
|
||||
sourceType: registration.sourceType,
|
||||
sourcePackage: registration.sourcePackage,
|
||||
latestAvailableVersion: registration.latestAvailableVersion,
|
||||
cdnBaseUrl: this.twentyConfigService.get('APP_REGISTRY_CDN_URL'),
|
||||
}) ?? undefined,
|
||||
logo: app?.logoUrl ?? undefined,
|
||||
sourcePackage: registration.sourcePackage ?? undefined,
|
||||
isFeatured: registration.isFeatured,
|
||||
};
|
||||
@@ -123,15 +112,6 @@ export class MarketplaceQueryService {
|
||||
sourceType: registration.sourceType,
|
||||
sourcePackage: registration.sourcePackage ?? undefined,
|
||||
latestAvailableVersion: registration.latestAvailableVersion ?? undefined,
|
||||
logo: buildFileOutputFromUrl(
|
||||
resolveApplicationRegistrationLogoUrl({
|
||||
logo: registration.manifest?.application?.logoUrl ?? null,
|
||||
sourceType: registration.sourceType,
|
||||
sourcePackage: registration.sourcePackage,
|
||||
latestAvailableVersion: registration.latestAvailableVersion,
|
||||
cdnBaseUrl: this.twentyConfigService.get('APP_REGISTRY_CDN_URL'),
|
||||
}),
|
||||
),
|
||||
isListed: registration.isListed,
|
||||
isFeatured: registration.isFeatured,
|
||||
manifest: registration.manifest ?? undefined,
|
||||
|
||||
-74
@@ -1,74 +0,0 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { FileFolder } from 'twenty-shared/types';
|
||||
|
||||
import { ApplicationRegistrationEntity } from 'src/engine/core-modules/application/application-registration/application-registration.entity';
|
||||
import { ApplicationRegistrationSourceType } from 'src/engine/core-modules/application/application-registration/enums/application-registration-source-type.enum';
|
||||
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
|
||||
import { resolveApplicationLogoUrl } from 'src/engine/core-modules/application/utils/resolve-application-logo-url.util';
|
||||
import { resolveApplicationRegistrationLogoUrl } from 'src/engine/core-modules/application/utils/resolve-application-registration-logo-url.util';
|
||||
import { type FileOutputDTO } from 'src/engine/core-modules/file/dtos/file-output.dto';
|
||||
import { FileUrlService } from 'src/engine/core-modules/file/file-url/file-url.service';
|
||||
import { buildFileOutputFromUrl } from 'src/engine/core-modules/file/utils/build-file-output-from-url.util';
|
||||
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
|
||||
|
||||
@Injectable()
|
||||
export class ApplicationRegistrationLogoService {
|
||||
constructor(
|
||||
private readonly twentyConfigService: TwentyConfigService,
|
||||
private readonly applicationService: ApplicationService,
|
||||
private readonly fileUrlService: FileUrlService,
|
||||
) {}
|
||||
|
||||
async resolveLogoFile(
|
||||
registration: ApplicationRegistrationEntity,
|
||||
): Promise<FileOutputDTO | null> {
|
||||
if (
|
||||
registration.sourceType === ApplicationRegistrationSourceType.TARBALL &&
|
||||
registration.logoFileId
|
||||
) {
|
||||
const url = await this.fileUrlService.signFileByIdUrl({
|
||||
fileId: registration.logoFileId,
|
||||
workspaceId: registration.ownerWorkspaceId ?? '',
|
||||
fileFolder: FileFolder.AppTarball,
|
||||
});
|
||||
|
||||
return buildFileOutputFromUrl(url, registration.logoFileId);
|
||||
}
|
||||
|
||||
const manifestLogo = registration.manifest?.application?.logoUrl ?? null;
|
||||
|
||||
if (
|
||||
registration.sourceType === ApplicationRegistrationSourceType.LOCAL &&
|
||||
manifestLogo &&
|
||||
registration.ownerWorkspaceId
|
||||
) {
|
||||
const application =
|
||||
await this.applicationService.findByUniversalIdentifier({
|
||||
universalIdentifier: registration.universalIdentifier,
|
||||
workspaceId: registration.ownerWorkspaceId,
|
||||
});
|
||||
|
||||
if (application) {
|
||||
return buildFileOutputFromUrl(
|
||||
resolveApplicationLogoUrl({
|
||||
logo: manifestLogo,
|
||||
serverUrl: this.twentyConfigService.get('SERVER_URL'),
|
||||
workspaceId: registration.ownerWorkspaceId,
|
||||
applicationId: application.id,
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return buildFileOutputFromUrl(
|
||||
resolveApplicationRegistrationLogoUrl({
|
||||
logo: manifestLogo,
|
||||
sourceType: registration.sourceType,
|
||||
sourcePackage: registration.sourcePackage,
|
||||
latestAvailableVersion: registration.latestAvailableVersion,
|
||||
cdnBaseUrl: this.twentyConfigService.get('APP_REGISTRY_CDN_URL'),
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
-23
@@ -1,23 +0,0 @@
|
||||
import { Parent, ResolveField } from '@nestjs/graphql';
|
||||
|
||||
import { MetadataResolver } from 'src/engine/api/graphql/graphql-config/decorators/metadata-resolver.decorator';
|
||||
import { ApplicationRegistrationEntity } from 'src/engine/core-modules/application/application-registration/application-registration.entity';
|
||||
import { ApplicationRegistrationLogoService } from 'src/engine/core-modules/application/application-registration/application-registration-logo.service';
|
||||
import { ApplicationRegistrationSummaryDTO } from 'src/engine/core-modules/application/application-registration/dtos/application-registration-summary.dto';
|
||||
import { FileOutputDTO } from 'src/engine/core-modules/file/dtos/file-output.dto';
|
||||
|
||||
@MetadataResolver(() => ApplicationRegistrationSummaryDTO)
|
||||
export class ApplicationRegistrationSummaryResolver {
|
||||
constructor(
|
||||
private readonly applicationRegistrationLogoService: ApplicationRegistrationLogoService,
|
||||
) {}
|
||||
|
||||
@ResolveField(() => FileOutputDTO, { nullable: true })
|
||||
async logo(
|
||||
@Parent() registration: ApplicationRegistrationEntity,
|
||||
): Promise<FileOutputDTO | null> {
|
||||
return this.applicationRegistrationLogoService.resolveLogoFile(
|
||||
registration,
|
||||
);
|
||||
}
|
||||
}
|
||||
+4
-11
@@ -21,7 +21,6 @@ import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/
|
||||
import { type Manifest } from 'twenty-shared/application';
|
||||
import { ApplicationRegistrationVariableEntity } from 'src/engine/core-modules/application/application-registration-variable/application-registration-variable.entity';
|
||||
import { ApplicationRegistrationSourceType } from 'src/engine/core-modules/application/application-registration/enums/application-registration-source-type.enum';
|
||||
import { WasIntroducedInUpgrade } from 'src/engine/core-modules/upgrade/decorators/was-introduced-in-upgrade.decorator';
|
||||
import { FileEntity } from 'src/engine/core-modules/file/entities/file.entity';
|
||||
import { UserEntity } from 'src/engine/core-modules/user/user.entity';
|
||||
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
@@ -134,16 +133,10 @@ export class ApplicationRegistrationEntity {
|
||||
@Column({ type: 'jsonb', nullable: true })
|
||||
manifest: Manifest | null;
|
||||
|
||||
@Column({ nullable: true, type: 'uuid' })
|
||||
@WasIntroducedInUpgrade({
|
||||
upgradeCommandName:
|
||||
'2.8.0_AddLogoToApplicationRegistrationFastInstanceCommand_1779387505162',
|
||||
})
|
||||
logoFileId: string | null;
|
||||
|
||||
@OneToOne(() => FileEntity, { onDelete: 'SET NULL', nullable: true })
|
||||
@JoinColumn({ name: 'logoFileId' })
|
||||
logoFile: Relation<FileEntity> | null;
|
||||
@Field(() => String, { nullable: true })
|
||||
get logoUrl(): string | null {
|
||||
return this.manifest?.application?.logoUrl ?? null;
|
||||
}
|
||||
|
||||
@OneToMany(
|
||||
() => ApplicationRegistrationVariableEntity,
|
||||
|
||||
-5
@@ -2,10 +2,8 @@ import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
import { ApplicationRegistrationEntity } from 'src/engine/core-modules/application/application-registration/application-registration.entity';
|
||||
import { ApplicationRegistrationLogoService } from 'src/engine/core-modules/application/application-registration/application-registration-logo.service';
|
||||
import { ApplicationRegistrationResolver } from 'src/engine/core-modules/application/application-registration/application-registration.resolver';
|
||||
import { ApplicationRegistrationService } from 'src/engine/core-modules/application/application-registration/application-registration.service';
|
||||
import { ApplicationRegistrationSummaryResolver } from 'src/engine/core-modules/application/application-registration/application-registration-summary.resolver';
|
||||
import { ApplicationRegistrationVariableModule } from 'src/engine/core-modules/application/application-registration-variable/application-registration-variable.module';
|
||||
import { ApplicationTarballService } from 'src/engine/core-modules/application/application-registration/application-tarball.service';
|
||||
import { ApplicationPackageModule } from 'src/engine/core-modules/application/application-package/application-package.module';
|
||||
@@ -38,14 +36,11 @@ import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/
|
||||
],
|
||||
providers: [
|
||||
ApplicationRegistrationService,
|
||||
ApplicationRegistrationLogoService,
|
||||
ApplicationRegistrationResolver,
|
||||
ApplicationRegistrationSummaryResolver,
|
||||
ApplicationTarballService,
|
||||
],
|
||||
exports: [
|
||||
ApplicationRegistrationService,
|
||||
ApplicationRegistrationLogoService,
|
||||
ApplicationRegistrationVariableModule,
|
||||
],
|
||||
})
|
||||
|
||||
-12
@@ -24,7 +24,6 @@ import { CreateApplicationRegistrationVariableInput } from 'src/engine/core-modu
|
||||
import { UpdateApplicationRegistrationVariableInput } from 'src/engine/core-modules/application/application-registration-variable/dtos/update-application-registration-variable.input';
|
||||
import { ApplicationRegistrationExceptionFilter } from 'src/engine/core-modules/application/application-registration/application-registration-exception-filter';
|
||||
import { ApplicationRegistrationEntity } from 'src/engine/core-modules/application/application-registration/application-registration.entity';
|
||||
import { ApplicationRegistrationLogoService } from 'src/engine/core-modules/application/application-registration/application-registration-logo.service';
|
||||
import { ApplicationRegistrationService } from 'src/engine/core-modules/application/application-registration/application-registration.service';
|
||||
import { ApplicationTarballService } from 'src/engine/core-modules/application/application-registration/application-tarball.service';
|
||||
import { ApplicationRegistrationStatsDTO } from 'src/engine/core-modules/application/application-registration/dtos/application-registration-stats.dto';
|
||||
@@ -36,7 +35,6 @@ import { TransferApplicationRegistrationOwnershipInput } from 'src/engine/core-m
|
||||
import { UpdateApplicationRegistrationInput } from 'src/engine/core-modules/application/application-registration/dtos/update-application-registration.input';
|
||||
import { ApplicationRegistrationSourceType } from 'src/engine/core-modules/application/application-registration/enums/application-registration-source-type.enum';
|
||||
import { AuthGraphqlApiExceptionFilter } from 'src/engine/core-modules/auth/filters/auth-graphql-api-exception.filter';
|
||||
import { FileOutputDTO } from 'src/engine/core-modules/file/dtos/file-output.dto';
|
||||
import { FileUrlService } from 'src/engine/core-modules/file/file-url/file-url.service';
|
||||
import { PreventNestToAutoLogGraphqlErrorsFilter } from 'src/engine/core-modules/graphql/filters/prevent-nest-to-auto-log-graphql-errors.filter';
|
||||
import { ResolverValidationPipe } from 'src/engine/core-modules/graphql/pipes/resolver-validation.pipe';
|
||||
@@ -66,7 +64,6 @@ import {
|
||||
export class ApplicationRegistrationResolver {
|
||||
constructor(
|
||||
private readonly applicationRegistrationService: ApplicationRegistrationService,
|
||||
private readonly applicationRegistrationLogoService: ApplicationRegistrationLogoService,
|
||||
private readonly applicationRegistrationVariableService: ApplicationRegistrationVariableService,
|
||||
private readonly applicationTarballService: ApplicationTarballService,
|
||||
private readonly fileUrlService: FileUrlService,
|
||||
@@ -333,15 +330,6 @@ export class ApplicationRegistrationResolver {
|
||||
});
|
||||
}
|
||||
|
||||
@ResolveField(() => FileOutputDTO, { nullable: true })
|
||||
async logo(
|
||||
@Parent() registration: ApplicationRegistrationEntity,
|
||||
): Promise<FileOutputDTO | null> {
|
||||
return this.applicationRegistrationLogoService.resolveLogoFile(
|
||||
registration,
|
||||
);
|
||||
}
|
||||
|
||||
@ResolveField(() => Boolean)
|
||||
async isConfigured(
|
||||
@Parent() registration: ApplicationRegistrationEntity,
|
||||
|
||||
+2
-15
@@ -16,9 +16,6 @@ import {
|
||||
ApplicationRegistrationException,
|
||||
ApplicationRegistrationExceptionCode,
|
||||
} from 'src/engine/core-modules/application/application-registration/application-registration.exception';
|
||||
import { resolveApplicationRegistrationLogoUrl } from 'src/engine/core-modules/application/utils/resolve-application-registration-logo-url.util';
|
||||
import { buildFileOutputFromUrl } from 'src/engine/core-modules/file/utils/build-file-output-from-url.util';
|
||||
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
|
||||
import { type ApplicationRegistrationStatsDTO } from 'src/engine/core-modules/application/application-registration/dtos/application-registration-stats.dto';
|
||||
import { type CreateApplicationRegistrationInput } from 'src/engine/core-modules/application/application-registration/dtos/create-application-registration.input';
|
||||
import { type PublicApplicationRegistrationDTO } from 'src/engine/core-modules/application/application-registration/dtos/public-application-registration.dto';
|
||||
@@ -42,7 +39,6 @@ export class ApplicationRegistrationService {
|
||||
@InjectRepository(WorkspaceEntity)
|
||||
private readonly workspaceRepository: Repository<WorkspaceEntity>,
|
||||
private readonly applicationRegistrationVariableService: ApplicationRegistrationVariableService,
|
||||
private readonly twentyConfigService: TwentyConfigService,
|
||||
) {}
|
||||
|
||||
async findMany(
|
||||
@@ -108,6 +104,7 @@ export class ApplicationRegistrationService {
|
||||
): Promise<PublicApplicationRegistrationDTO | null> {
|
||||
const registration = await this.applicationRegistrationRepository.findOne({
|
||||
where: { oAuthClientId: clientId },
|
||||
select: ['id', 'name', 'manifest', 'oAuthScopes'],
|
||||
});
|
||||
|
||||
if (!registration) {
|
||||
@@ -117,15 +114,7 @@ export class ApplicationRegistrationService {
|
||||
return {
|
||||
id: registration.id,
|
||||
name: registration.name,
|
||||
logo: buildFileOutputFromUrl(
|
||||
resolveApplicationRegistrationLogoUrl({
|
||||
logo: registration.manifest?.application?.logoUrl ?? null,
|
||||
sourceType: registration.sourceType,
|
||||
sourcePackage: registration.sourcePackage,
|
||||
latestAvailableVersion: registration.latestAvailableVersion,
|
||||
cdnBaseUrl: this.twentyConfigService.get('APP_REGISTRY_CDN_URL'),
|
||||
}),
|
||||
),
|
||||
logoUrl: registration.manifest?.application?.logoUrl ?? null,
|
||||
websiteUrl: registration.manifest?.application?.websiteUrl ?? null,
|
||||
oAuthScopes: registration.oAuthScopes,
|
||||
};
|
||||
@@ -225,7 +214,6 @@ export class ApplicationRegistrationService {
|
||||
async updateFromManifest(
|
||||
applicationRegistrationId: string,
|
||||
manifest: Manifest,
|
||||
sourceType?: ApplicationRegistrationSourceType,
|
||||
): Promise<void> {
|
||||
const existing = await this.applicationRegistrationRepository.findOneOrFail(
|
||||
{ where: { id: applicationRegistrationId } },
|
||||
@@ -235,7 +223,6 @@ export class ApplicationRegistrationService {
|
||||
...existing,
|
||||
name: manifest.application.displayName,
|
||||
manifest,
|
||||
...(sourceType !== undefined && { sourceType }),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+1
-69
@@ -3,7 +3,7 @@ import { InjectRepository } from '@nestjs/typeorm';
|
||||
|
||||
import { promises as fs } from 'fs';
|
||||
import { tmpdir } from 'os';
|
||||
import { join, resolve, sep } from 'path';
|
||||
import { join } from 'path';
|
||||
|
||||
import semver from 'semver';
|
||||
import { FileFolder } from 'twenty-shared/types';
|
||||
@@ -28,8 +28,6 @@ import { ApplicationService } from 'src/engine/core-modules/application/applicat
|
||||
import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service';
|
||||
import type { ApplicationManifest } from 'twenty-shared/application';
|
||||
import { ApplicationRegistrationVariableService } from 'src/engine/core-modules/application/application-registration-variable/application-registration-variable.service';
|
||||
import { extractFileInfo } from 'src/engine/core-modules/file/utils/extract-file-info.utils';
|
||||
import { sanitizeFile } from 'src/engine/core-modules/file/utils/sanitize-file.utils';
|
||||
|
||||
@Injectable()
|
||||
export class ApplicationTarballService {
|
||||
@@ -204,21 +202,10 @@ export class ApplicationTarballService {
|
||||
},
|
||||
});
|
||||
|
||||
const logoFileId = await this.uploadLogoFromTarball({
|
||||
contentDir,
|
||||
logoPath: manifest.application?.logoUrl ?? null,
|
||||
registrationId: appRegistration.id,
|
||||
existingLogoFileId: appRegistration.logoFileId ?? undefined,
|
||||
applicationUniversalIdentifier:
|
||||
workspaceCustomFlatApplication.universalIdentifier,
|
||||
workspaceId: params.ownerWorkspaceId,
|
||||
});
|
||||
|
||||
await this.appRegistrationRepository.update(appRegistration.id, {
|
||||
sourceType: ApplicationRegistrationSourceType.TARBALL,
|
||||
tarballFileId: savedFile.id,
|
||||
name: manifest.application?.displayName ?? 'Unknown App',
|
||||
logoFileId,
|
||||
manifest,
|
||||
latestAvailableVersion: packageJson?.version ?? null,
|
||||
isListed: false,
|
||||
@@ -244,59 +231,4 @@ export class ApplicationTarballService {
|
||||
await fs.rm(tempDir, { recursive: true, force: true });
|
||||
}
|
||||
}
|
||||
|
||||
private async uploadLogoFromTarball(params: {
|
||||
contentDir: string;
|
||||
logoPath: string | null;
|
||||
registrationId: string;
|
||||
existingLogoFileId?: string;
|
||||
applicationUniversalIdentifier: string;
|
||||
workspaceId: string;
|
||||
}): Promise<string | null> {
|
||||
if (
|
||||
!params.logoPath ||
|
||||
params.logoPath.startsWith('http://') ||
|
||||
params.logoPath.startsWith('https://')
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const absolutePath = resolve(params.contentDir, params.logoPath);
|
||||
const safePrefx = params.contentDir.endsWith(sep)
|
||||
? params.contentDir
|
||||
: params.contentDir + sep;
|
||||
|
||||
if (!absolutePath.startsWith(safePrefx)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let content: Buffer;
|
||||
|
||||
try {
|
||||
content = await fs.readFile(absolutePath);
|
||||
} catch {
|
||||
this.logger.warn(`Logo file not found in tarball: ${params.logoPath}`);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
const { mimeType, ext } = await extractFileInfo({
|
||||
file: content,
|
||||
filename: params.logoPath,
|
||||
});
|
||||
const sanitizedContent = sanitizeFile({ file: content, ext, mimeType });
|
||||
|
||||
const savedLogoFile = await this.fileStorageService.writeFile({
|
||||
sourceFile: sanitizedContent,
|
||||
mimeType,
|
||||
fileFolder: FileFolder.AppTarball,
|
||||
applicationUniversalIdentifier: params.applicationUniversalIdentifier,
|
||||
workspaceId: params.workspaceId,
|
||||
resourcePath: `${params.registrationId}/logo${ext}`,
|
||||
fileId: params.existingLogoFileId ?? v4(),
|
||||
settings: { isTemporaryFile: false, toDelete: false },
|
||||
});
|
||||
|
||||
return savedLogoFile.id;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-3
@@ -4,7 +4,6 @@ import { IsOptional, IsString } from 'class-validator';
|
||||
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
import { ApplicationRegistrationSourceType } from 'src/engine/core-modules/application/application-registration/enums/application-registration-source-type.enum';
|
||||
import { FileOutputDTO } from 'src/engine/core-modules/file/dtos/file-output.dto';
|
||||
|
||||
@ObjectType('ApplicationRegistrationSummary')
|
||||
export class ApplicationRegistrationSummaryDTO {
|
||||
@@ -19,6 +18,8 @@ export class ApplicationRegistrationSummaryDTO {
|
||||
@Field(() => ApplicationRegistrationSourceType)
|
||||
sourceType: ApplicationRegistrationSourceType;
|
||||
|
||||
@Field(() => FileOutputDTO, { nullable: true })
|
||||
logo?: FileOutputDTO | null;
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@Field(() => String, { nullable: true })
|
||||
logoUrl?: string | null;
|
||||
}
|
||||
|
||||
+2
-3
@@ -1,7 +1,6 @@
|
||||
import { Field, ObjectType } from '@nestjs/graphql';
|
||||
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
import { FileOutputDTO } from 'src/engine/core-modules/file/dtos/file-output.dto';
|
||||
|
||||
@ObjectType('PublicApplicationRegistration')
|
||||
export class PublicApplicationRegistrationDTO {
|
||||
@@ -11,8 +10,8 @@ export class PublicApplicationRegistrationDTO {
|
||||
@Field()
|
||||
name: string;
|
||||
|
||||
@Field(() => FileOutputDTO, { nullable: true })
|
||||
logo: FileOutputDTO | null;
|
||||
@Field(() => String, { nullable: true })
|
||||
logoUrl: string | null;
|
||||
|
||||
@Field(() => String, { nullable: true })
|
||||
websiteUrl: string | null;
|
||||
|
||||
@@ -35,8 +35,9 @@ export class ApplicationDTO {
|
||||
@Field({ nullable: true })
|
||||
description?: string;
|
||||
|
||||
// Internal raw value (path or absolute URL); GraphQL exposure as FileOutput
|
||||
// is handled by ApplicationLogoResolver.
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
@Field({ nullable: true })
|
||||
logo?: string;
|
||||
|
||||
@IsOptional()
|
||||
|
||||
+1
-3
@@ -14,9 +14,8 @@ export const fromFlatApplicationToApplicationDto = ({
|
||||
availablePackages,
|
||||
universalIdentifier,
|
||||
version,
|
||||
workspaceId,
|
||||
settingsCustomTabFrontComponentId,
|
||||
}: FlatApplication): ApplicationDTO & { workspaceId: string } => {
|
||||
}: FlatApplication): ApplicationDTO => {
|
||||
return {
|
||||
canBeUninstalled,
|
||||
description: description ?? undefined,
|
||||
@@ -31,7 +30,6 @@ export const fromFlatApplicationToApplicationDto = ({
|
||||
availablePackages: availablePackages ?? {},
|
||||
universalIdentifier,
|
||||
version: version ?? undefined,
|
||||
workspaceId,
|
||||
settingsCustomTabFrontComponentId:
|
||||
settingsCustomTabFrontComponentId ?? undefined,
|
||||
};
|
||||
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
import { buildPublicAssetUrl } from 'twenty-shared/utils';
|
||||
|
||||
export const resolveApplicationLogoUrl = ({
|
||||
logo,
|
||||
serverUrl,
|
||||
workspaceId,
|
||||
applicationId,
|
||||
}: {
|
||||
logo: string | null | undefined;
|
||||
serverUrl: string;
|
||||
workspaceId: string;
|
||||
applicationId: string;
|
||||
}): string | null => {
|
||||
return buildPublicAssetUrl({
|
||||
path: logo,
|
||||
serverUrl,
|
||||
workspaceId,
|
||||
applicationId,
|
||||
});
|
||||
};
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
import { ApplicationRegistrationSourceType } from 'src/engine/core-modules/application/application-registration/enums/application-registration-source-type.enum';
|
||||
import { buildRegistryCdnUrl } from 'src/engine/core-modules/application/application-marketplace/utils/build-registry-cdn-url.util';
|
||||
|
||||
const isAbsoluteUrl = (url: string): boolean =>
|
||||
url.startsWith('http://') || url.startsWith('https://');
|
||||
|
||||
export const resolveApplicationRegistrationLogoUrl = ({
|
||||
logo,
|
||||
sourceType,
|
||||
sourcePackage,
|
||||
latestAvailableVersion,
|
||||
cdnBaseUrl,
|
||||
}: {
|
||||
logo: string | null | undefined;
|
||||
sourceType: ApplicationRegistrationSourceType;
|
||||
sourcePackage: string | null;
|
||||
latestAvailableVersion: string | null;
|
||||
cdnBaseUrl: string;
|
||||
}): string | null => {
|
||||
if (!logo) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isAbsoluteUrl(logo)) {
|
||||
return logo;
|
||||
}
|
||||
|
||||
if (
|
||||
sourceType === ApplicationRegistrationSourceType.NPM &&
|
||||
sourcePackage &&
|
||||
latestAvailableVersion
|
||||
) {
|
||||
return buildRegistryCdnUrl({
|
||||
cdnBaseUrl,
|
||||
packageName: sourcePackage,
|
||||
version: latestAvailableVersion,
|
||||
filePath: logo,
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
@@ -1,18 +0,0 @@
|
||||
import { Field, ObjectType } from '@nestjs/graphql';
|
||||
|
||||
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
|
||||
|
||||
@ObjectType('FileOutput')
|
||||
export class FileOutputDTO {
|
||||
@Field(() => UUIDScalarType, { nullable: true })
|
||||
fileId: string | null;
|
||||
|
||||
@Field(() => String, { nullable: true })
|
||||
label: string | null;
|
||||
|
||||
@Field(() => String, { nullable: true })
|
||||
extension: string | null;
|
||||
|
||||
@Field(() => String)
|
||||
url: string;
|
||||
}
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
import { type FileOutputDTO } from 'src/engine/core-modules/file/dtos/file-output.dto';
|
||||
|
||||
export const buildFileOutputFromUrl = (
|
||||
url: string | null,
|
||||
fileId: string | null = null,
|
||||
): FileOutputDTO | null => {
|
||||
if (url === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
fileId,
|
||||
label: null,
|
||||
extension: null,
|
||||
url,
|
||||
};
|
||||
};
|
||||
+20
-24
@@ -644,7 +644,7 @@ export const STANDARD_COMMAND_MENU_ITEMS = {
|
||||
position: 42,
|
||||
shortLabel: 'Ask AI',
|
||||
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
||||
conditionalAvailabilityExpression: 'permissionFlags.AI',
|
||||
conditionalAvailabilityExpression: null,
|
||||
availabilityObjectMetadataUniversalIdentifier: null,
|
||||
frontComponentUniversalIdentifier: null,
|
||||
engineComponentKey: EngineComponentKey.ASK_AI,
|
||||
@@ -658,7 +658,7 @@ export const STANDARD_COMMAND_MENU_ITEMS = {
|
||||
position: 43,
|
||||
shortLabel: 'Previous AI Chats',
|
||||
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
||||
conditionalAvailabilityExpression: 'permissionFlags.AI',
|
||||
conditionalAvailabilityExpression: null,
|
||||
availabilityObjectMetadataUniversalIdentifier: null,
|
||||
frontComponentUniversalIdentifier: null,
|
||||
engineComponentKey: EngineComponentKey.VIEW_PREVIOUS_AI_CHATS,
|
||||
@@ -687,7 +687,7 @@ export const STANDARD_COMMAND_MENU_ITEMS = {
|
||||
position: 45,
|
||||
shortLabel: 'Compose',
|
||||
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
||||
conditionalAvailabilityExpression: 'permissionFlags.SEND_EMAIL_TOOL',
|
||||
conditionalAvailabilityExpression: null,
|
||||
availabilityObjectMetadataUniversalIdentifier: null,
|
||||
frontComponentUniversalIdentifier: null,
|
||||
engineComponentKey: EngineComponentKey.COMPOSE_EMAIL,
|
||||
@@ -731,7 +731,7 @@ export const STANDARD_COMMAND_MENU_ITEMS = {
|
||||
position: 48,
|
||||
shortLabel: 'Accounts',
|
||||
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
||||
conditionalAvailabilityExpression: 'permissionFlags.CONNECTED_ACCOUNTS',
|
||||
conditionalAvailabilityExpression: null,
|
||||
availabilityObjectMetadataUniversalIdentifier: null,
|
||||
frontComponentUniversalIdentifier: null,
|
||||
engineComponentKey: EngineComponentKey.NAVIGATION,
|
||||
@@ -746,7 +746,7 @@ export const STANDARD_COMMAND_MENU_ITEMS = {
|
||||
position: 49,
|
||||
shortLabel: 'Emails',
|
||||
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
||||
conditionalAvailabilityExpression: 'permissionFlags.CONNECTED_ACCOUNTS',
|
||||
conditionalAvailabilityExpression: null,
|
||||
availabilityObjectMetadataUniversalIdentifier: null,
|
||||
frontComponentUniversalIdentifier: null,
|
||||
engineComponentKey: EngineComponentKey.NAVIGATION,
|
||||
@@ -761,7 +761,7 @@ export const STANDARD_COMMAND_MENU_ITEMS = {
|
||||
position: 50,
|
||||
shortLabel: 'Calendars',
|
||||
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
||||
conditionalAvailabilityExpression: 'permissionFlags.CONNECTED_ACCOUNTS',
|
||||
conditionalAvailabilityExpression: null,
|
||||
availabilityObjectMetadataUniversalIdentifier: null,
|
||||
frontComponentUniversalIdentifier: null,
|
||||
engineComponentKey: EngineComponentKey.NAVIGATION,
|
||||
@@ -776,7 +776,7 @@ export const STANDARD_COMMAND_MENU_ITEMS = {
|
||||
position: 51,
|
||||
shortLabel: 'General',
|
||||
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
||||
conditionalAvailabilityExpression: 'permissionFlags.WORKSPACE',
|
||||
conditionalAvailabilityExpression: null,
|
||||
availabilityObjectMetadataUniversalIdentifier: null,
|
||||
frontComponentUniversalIdentifier: null,
|
||||
engineComponentKey: EngineComponentKey.NAVIGATION,
|
||||
@@ -791,7 +791,7 @@ export const STANDARD_COMMAND_MENU_ITEMS = {
|
||||
position: 52,
|
||||
shortLabel: 'Data Model',
|
||||
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
||||
conditionalAvailabilityExpression: 'permissionFlags.DATA_MODEL',
|
||||
conditionalAvailabilityExpression: null,
|
||||
availabilityObjectMetadataUniversalIdentifier: null,
|
||||
frontComponentUniversalIdentifier: null,
|
||||
engineComponentKey: EngineComponentKey.NAVIGATION,
|
||||
@@ -806,7 +806,7 @@ export const STANDARD_COMMAND_MENU_ITEMS = {
|
||||
position: 53,
|
||||
shortLabel: 'Members',
|
||||
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
||||
conditionalAvailabilityExpression: 'permissionFlags.WORKSPACE_MEMBERS',
|
||||
conditionalAvailabilityExpression: null,
|
||||
availabilityObjectMetadataUniversalIdentifier: null,
|
||||
frontComponentUniversalIdentifier: null,
|
||||
engineComponentKey: EngineComponentKey.NAVIGATION,
|
||||
@@ -821,7 +821,7 @@ export const STANDARD_COMMAND_MENU_ITEMS = {
|
||||
position: 54,
|
||||
shortLabel: 'Roles',
|
||||
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
||||
conditionalAvailabilityExpression: 'permissionFlags.WORKSPACE_MEMBERS',
|
||||
conditionalAvailabilityExpression: null,
|
||||
availabilityObjectMetadataUniversalIdentifier: null,
|
||||
frontComponentUniversalIdentifier: null,
|
||||
engineComponentKey: EngineComponentKey.NAVIGATION,
|
||||
@@ -836,7 +836,7 @@ export const STANDARD_COMMAND_MENU_ITEMS = {
|
||||
position: 55,
|
||||
shortLabel: 'Domains',
|
||||
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
||||
conditionalAvailabilityExpression: 'permissionFlags.WORKSPACE',
|
||||
conditionalAvailabilityExpression: null,
|
||||
availabilityObjectMetadataUniversalIdentifier: null,
|
||||
frontComponentUniversalIdentifier: null,
|
||||
engineComponentKey: EngineComponentKey.NAVIGATION,
|
||||
@@ -851,7 +851,7 @@ export const STANDARD_COMMAND_MENU_ITEMS = {
|
||||
position: 56,
|
||||
shortLabel: 'Billing',
|
||||
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
||||
conditionalAvailabilityExpression: 'permissionFlags.WORKSPACE',
|
||||
conditionalAvailabilityExpression: null,
|
||||
availabilityObjectMetadataUniversalIdentifier: null,
|
||||
frontComponentUniversalIdentifier: null,
|
||||
engineComponentKey: EngineComponentKey.NAVIGATION,
|
||||
@@ -866,7 +866,7 @@ export const STANDARD_COMMAND_MENU_ITEMS = {
|
||||
position: 57,
|
||||
shortLabel: 'APIs & Webhooks',
|
||||
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
||||
conditionalAvailabilityExpression: 'permissionFlags.API_KEYS_AND_WEBHOOKS',
|
||||
conditionalAvailabilityExpression: null,
|
||||
availabilityObjectMetadataUniversalIdentifier: null,
|
||||
frontComponentUniversalIdentifier: null,
|
||||
engineComponentKey: EngineComponentKey.NAVIGATION,
|
||||
@@ -881,7 +881,7 @@ export const STANDARD_COMMAND_MENU_ITEMS = {
|
||||
position: 58,
|
||||
shortLabel: 'Apps',
|
||||
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
||||
conditionalAvailabilityExpression: 'permissionFlags.APPLICATIONS',
|
||||
conditionalAvailabilityExpression: null,
|
||||
availabilityObjectMetadataUniversalIdentifier: null,
|
||||
frontComponentUniversalIdentifier: null,
|
||||
engineComponentKey: EngineComponentKey.NAVIGATION,
|
||||
@@ -896,7 +896,7 @@ export const STANDARD_COMMAND_MENU_ITEMS = {
|
||||
position: 59,
|
||||
shortLabel: 'AI',
|
||||
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
||||
conditionalAvailabilityExpression: 'permissionFlags.WORKSPACE',
|
||||
conditionalAvailabilityExpression: null,
|
||||
availabilityObjectMetadataUniversalIdentifier: null,
|
||||
frontComponentUniversalIdentifier: null,
|
||||
engineComponentKey: EngineComponentKey.NAVIGATION,
|
||||
@@ -911,7 +911,7 @@ export const STANDARD_COMMAND_MENU_ITEMS = {
|
||||
position: 60,
|
||||
shortLabel: 'Security',
|
||||
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
||||
conditionalAvailabilityExpression: 'permissionFlags.SECURITY',
|
||||
conditionalAvailabilityExpression: null,
|
||||
availabilityObjectMetadataUniversalIdentifier: null,
|
||||
frontComponentUniversalIdentifier: null,
|
||||
engineComponentKey: EngineComponentKey.NAVIGATION,
|
||||
@@ -926,8 +926,7 @@ export const STANDARD_COMMAND_MENU_ITEMS = {
|
||||
position: 61,
|
||||
shortLabel: 'Admin Panel',
|
||||
availabilityType: CommandMenuItemAvailabilityType.GLOBAL,
|
||||
conditionalAvailabilityExpression:
|
||||
'canImpersonate or canAccessFullAdminPanel',
|
||||
conditionalAvailabilityExpression: null,
|
||||
availabilityObjectMetadataUniversalIdentifier: null,
|
||||
frontComponentUniversalIdentifier: null,
|
||||
engineComponentKey: EngineComponentKey.NAVIGATION,
|
||||
@@ -957,8 +956,7 @@ export const STANDARD_COMMAND_MENU_ITEMS = {
|
||||
position: 63,
|
||||
shortLabel: 'Send Email',
|
||||
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
||||
conditionalAvailabilityExpression:
|
||||
'numberOfSelectedRecords >= 1 and permissionFlags.SEND_EMAIL_TOOL',
|
||||
conditionalAvailabilityExpression: 'numberOfSelectedRecords >= 1',
|
||||
availabilityObjectMetadataUniversalIdentifier:
|
||||
STANDARD_OBJECTS.person.universalIdentifier,
|
||||
frontComponentUniversalIdentifier: null,
|
||||
@@ -973,8 +971,7 @@ export const STANDARD_COMMAND_MENU_ITEMS = {
|
||||
position: 64,
|
||||
shortLabel: 'Send Email',
|
||||
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
||||
conditionalAvailabilityExpression:
|
||||
'numberOfSelectedRecords == 1 and permissionFlags.SEND_EMAIL_TOOL',
|
||||
conditionalAvailabilityExpression: 'numberOfSelectedRecords == 1',
|
||||
availabilityObjectMetadataUniversalIdentifier:
|
||||
STANDARD_OBJECTS.company.universalIdentifier,
|
||||
frontComponentUniversalIdentifier: null,
|
||||
@@ -989,8 +986,7 @@ export const STANDARD_COMMAND_MENU_ITEMS = {
|
||||
position: 65,
|
||||
shortLabel: 'Send Email',
|
||||
availabilityType: CommandMenuItemAvailabilityType.RECORD_SELECTION,
|
||||
conditionalAvailabilityExpression:
|
||||
'numberOfSelectedRecords == 1 and permissionFlags.SEND_EMAIL_TOOL',
|
||||
conditionalAvailabilityExpression: 'numberOfSelectedRecords == 1',
|
||||
availabilityObjectMetadataUniversalIdentifier:
|
||||
STANDARD_OBJECTS.opportunity.universalIdentifier,
|
||||
frontComponentUniversalIdentifier: null,
|
||||
|
||||
@@ -17,8 +17,6 @@ export type CommandMenuContextApi = {
|
||||
permissionFlags: Record<string, boolean>;
|
||||
targetObjectReadPermissions: Record<string, boolean>;
|
||||
targetObjectWritePermissions: Record<string, boolean>;
|
||||
canImpersonate: boolean;
|
||||
canAccessFullAdminPanel: boolean;
|
||||
objectMetadataItem: Record<string, unknown>;
|
||||
objectMetadataLabel: string;
|
||||
};
|
||||
|
||||
-2
@@ -27,8 +27,6 @@ const buildContext = (
|
||||
permissionFlags: {},
|
||||
targetObjectReadPermissions: {},
|
||||
targetObjectWritePermissions: {},
|
||||
canImpersonate: false,
|
||||
canAccessFullAdminPanel: false,
|
||||
objectMetadataItem: {},
|
||||
objectMetadataLabel: '',
|
||||
...overrides,
|
||||
|
||||
-2
@@ -27,8 +27,6 @@ const buildContext = (
|
||||
permissionFlags: {},
|
||||
targetObjectReadPermissions: {},
|
||||
targetObjectWritePermissions: {},
|
||||
canImpersonate: false,
|
||||
canAccessFullAdminPanel: false,
|
||||
objectMetadataItem: {},
|
||||
objectMetadataLabel: '',
|
||||
...overrides,
|
||||
|
||||
@@ -199,7 +199,6 @@ export { isRecordGqlOperationSignature } from './typeguard/isRecordGqlOperationS
|
||||
export { throwIfNotDefined } from './typeguard/throwIfNotDefined';
|
||||
export { formatUpgradeCommandName } from './upgrade/formatUpgradeCommandName';
|
||||
export { absoluteUrlSchema } from './url/absoluteUrlSchema';
|
||||
export { buildPublicAssetUrl } from './url/buildPublicAssetUrl';
|
||||
export { buildSignedPath } from './url/buildSignedPath';
|
||||
export { ensureAbsoluteUrl } from './url/ensureAbsoluteUrl';
|
||||
export { getAbsoluteUrlOrThrow } from './url/getAbsoluteUrlOrThrow';
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
const isAbsoluteUrl = (url: string): boolean =>
|
||||
url.startsWith('http://') || url.startsWith('https://');
|
||||
|
||||
export const buildPublicAssetUrl = ({
|
||||
path,
|
||||
serverUrl,
|
||||
workspaceId,
|
||||
applicationId,
|
||||
}: {
|
||||
path: string | null | undefined;
|
||||
serverUrl: string;
|
||||
workspaceId: string;
|
||||
applicationId: string;
|
||||
}): string | null => {
|
||||
if (!path) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isAbsoluteUrl(path)) {
|
||||
return path;
|
||||
}
|
||||
|
||||
const baseUrl = serverUrl.endsWith('/') ? serverUrl.slice(0, -1) : serverUrl;
|
||||
|
||||
return `${baseUrl}/public-assets/${workspaceId}/${applicationId}/${path}`;
|
||||
};
|
||||
@@ -1,5 +1,4 @@
|
||||
export * from './absoluteUrlSchema';
|
||||
export * from './buildPublicAssetUrl';
|
||||
export * from './getSafeUrl';
|
||||
export * from './isSafeUrl';
|
||||
export * from './ensureAbsoluteUrl';
|
||||
|
||||
Reference in New Issue
Block a user