Compare commits
41
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
71c74bec43 | ||
|
|
7ade9e3aab | ||
|
|
c4e897a7b5 | ||
|
|
70bb011daa | ||
|
|
9e515afb13 | ||
|
|
a34bf11dae | ||
|
|
ce54f69a4e | ||
|
|
3904addeb0 | ||
|
|
d53f3e4ccc | ||
|
|
565995e715 | ||
|
|
79b612ee12 | ||
|
|
5003fcbbf2 | ||
|
|
b6b4824104 | ||
|
|
8d54ff6ca0 | ||
|
|
1adb59f7f8 | ||
|
|
93df64b9b0 | ||
|
|
a3b0a34207 | ||
|
|
009f597eec | ||
|
|
b0413575f5 | ||
|
|
b03f044d0f | ||
|
|
75c22a2119 | ||
|
|
3d8207af0f | ||
|
|
c227b0d06a | ||
|
|
f634a4a0c0 | ||
|
|
689ec16f50 | ||
|
|
1b09c69c39 | ||
|
|
b1f7a2c544 | ||
|
|
e7032d0638 | ||
|
|
5f3407878d | ||
|
|
7c053716ae | ||
|
|
6c18bacb93 | ||
|
|
93d83b2e36 | ||
|
|
0c5aec9c73 | ||
|
|
ed75fc8a25 | ||
|
|
9813467cee | ||
|
|
1ea7c7ecc4 | ||
|
|
626455b534 | ||
|
|
2c3e81960c | ||
|
|
487112d438 | ||
|
|
5c1fe45760 | ||
|
|
e72a907baa |
@@ -0,0 +1,72 @@
|
||||
---
|
||||
description: GitHub Actions security guidelines for supply chain protection
|
||||
globs: **/.github/**/*.yml, **/.github/**/*.yaml
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# GitHub Actions Security
|
||||
|
||||
## Pin Third-Party Actions to Commit SHAs
|
||||
|
||||
Always reference external actions and reusable workflows by their full commit SHA, never by a mutable tag or branch. Tags can be force-pushed by a compromised maintainer account.
|
||||
|
||||
```yaml
|
||||
# ❌ Mutable tag — vulnerable to supply chain attacks
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/setup-node@v4
|
||||
|
||||
# ✅ Pinned to commit SHA with tag comment for readability
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
```
|
||||
|
||||
## Prefer `gh api` Over Third-Party Dispatch Actions
|
||||
|
||||
For repository dispatch calls, use `gh api` directly instead of third-party actions like `peter-evans/repository-dispatch`. This eliminates a supply-chain dependency entirely.
|
||||
|
||||
```yaml
|
||||
# ✅ Use env vars + bracket notation to prevent injection
|
||||
- name: Dispatch to target repo
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.DISPATCH_TOKEN }}
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
BRANCH: ${{ github.event.workflow_run.head_branch }}
|
||||
run: |
|
||||
gh api repos/org/repo/dispatches \
|
||||
-f event_type=my-event \
|
||||
-f "client_payload[pr_number]=$PR_NUMBER" \
|
||||
-f "client_payload[branch]=$BRANCH"
|
||||
|
||||
# ✅ Simple dispatch without payload
|
||||
- name: Trigger workflow
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.DISPATCH_TOKEN }}
|
||||
run: |
|
||||
gh api repos/org/repo/dispatches -f event_type=my-event
|
||||
|
||||
# ❌ Third-party action dependency
|
||||
- uses: peter-evans/repository-dispatch@v2
|
||||
with:
|
||||
token: ${{ secrets.DISPATCH_TOKEN }}
|
||||
repository: org/repo
|
||||
event-type: my-event
|
||||
|
||||
# ❌ Inline ${{ }} in shell — vulnerable to injection
|
||||
- run: |
|
||||
gh api repos/org/repo/dispatches --input - <<EOF
|
||||
{"event_type": "x", "client_payload": {"branch": "${{ github.head_ref }}"}}
|
||||
EOF
|
||||
```
|
||||
|
||||
## Minimal Permissions
|
||||
|
||||
Always declare explicit `permissions` at the job level with the least privilege required. Never rely on the default `GITHUB_TOKEN` permissions.
|
||||
|
||||
```yaml
|
||||
# ✅ Explicit minimal permissions
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
# ❌ Overly broad or implicit permissions
|
||||
permissions: write-all
|
||||
```
|
||||
@@ -0,0 +1,6 @@
|
||||
/.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
|
||||
@@ -21,7 +21,7 @@ runs:
|
||||
run: corepack enable
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
node-version-file: '${{ inputs.app-path }}/.nvmrc'
|
||||
cache: yarn
|
||||
|
||||
@@ -21,7 +21,7 @@ runs:
|
||||
run: corepack enable
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
node-version-file: '${{ inputs.app-path }}/.nvmrc'
|
||||
cache: yarn
|
||||
|
||||
@@ -20,7 +20,7 @@ runs:
|
||||
run: git fetch origin main --depth=1
|
||||
- name: Get last successful commit
|
||||
if: env.NX_BASE == ''
|
||||
uses: nrwl/nx-set-shas@v4
|
||||
uses: nrwl/nx-set-shas@3e9ad7370203c1e93d109be57f3b72eb0eb511b1 # v4
|
||||
- name: Fallback to origin/main if no base found
|
||||
if: env.NX_BASE == ''
|
||||
shell: bash
|
||||
|
||||
@@ -25,7 +25,7 @@ runs:
|
||||
run: |
|
||||
echo "CACHE_PRIMARY_KEY_PREFIX=v4-${CACHE_KEY}-${REF_NAME}" >> "${GITHUB_OUTPUT}"
|
||||
- name: Restore cache
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 (restore)
|
||||
id: restore-cache
|
||||
with:
|
||||
key: ${{ steps.cache-primary-key-builder.outputs.CACHE_PRIMARY_KEY_PREFIX }}-${{ github.sha }}
|
||||
|
||||
@@ -9,8 +9,11 @@ inputs:
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
# Fork PRs on pull_request already can't write to the base repo's cache (GitHub built-in).
|
||||
# The fork guard is defense-in-depth for pull_request_target, which does have write access.
|
||||
- name: Save cache
|
||||
uses: actions/cache/save@v4
|
||||
if: ${{ format('{0}', github.event.pull_request.head.repo.fork) != 'true' }}
|
||||
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 (save)
|
||||
with:
|
||||
key: ${{ inputs.key }}
|
||||
path: |
|
||||
|
||||
@@ -48,7 +48,7 @@ runs:
|
||||
fi
|
||||
|
||||
- name: Checkout docker compose files
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
repository: ${{ inputs.twenty-repository }}
|
||||
ref: ${{ steps.resolve.outputs.git-ref }}
|
||||
|
||||
@@ -29,12 +29,12 @@ runs:
|
||||
echo "packages/*/node_modules" >> $GITHUB_OUTPUT
|
||||
echo 'EOF' >> $GITHUB_OUTPUT
|
||||
- name: Setup Node.js and get yarn cache
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
node-version: ${{ inputs.node-version }}
|
||||
- name: Restore node_modules
|
||||
id: cache-node-modules
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 (restore)
|
||||
with:
|
||||
key: v4-${{ steps.globals.outputs.CACHE_KEY_PREFIX }}-${{github.sha}}
|
||||
restore-keys: v4-${{ steps.globals.outputs.CACHE_KEY_PREFIX }}-
|
||||
@@ -44,10 +44,13 @@ runs:
|
||||
shell: ${{ steps.globals.outputs.ACTION_SHELL }}
|
||||
run: |
|
||||
yarn config set enableHardenedMode true
|
||||
yarn config set enableScripts false
|
||||
yarn --immutable --check-cache
|
||||
# Fork PRs on pull_request already can't write to the base repo's cache (GitHub built-in).
|
||||
# The fork guard is defense-in-depth for pull_request_target, which does have write access.
|
||||
- name: Save cache
|
||||
if: ${{ steps.cache-node-modules.outputs.cache-hit != 'true' && steps.cache-node-modules.outputs.cache-matched-key == '' }}
|
||||
uses: actions/cache/save@v4
|
||||
if: ${{ steps.cache-node-modules.outputs.cache-hit != 'true' && steps.cache-node-modules.outputs.cache-matched-key == '' && format('{0}', github.event.pull_request.head.repo.fork) != 'true' }}
|
||||
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 (save)
|
||||
with:
|
||||
key: ${{ steps.cache-node-modules.outputs.cache-primary-key }}
|
||||
path: ${{ steps.globals.outputs.PATH_TO_CACHE }}
|
||||
|
||||
@@ -14,9 +14,8 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Repository Dispatch
|
||||
uses: peter-evans/repository-dispatch@v2
|
||||
with:
|
||||
token: ${{ secrets.TWENTY_INFRA_TOKEN }}
|
||||
repository: twentyhq/twenty-infra
|
||||
event-type: auto-deploy-main
|
||||
client-payload: '{"github": ${{ toJson(github) }}}' # Passes the entire github context to the downstream workflow
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.TWENTY_INFRA_TOKEN }}
|
||||
run: |
|
||||
gh api repos/twentyhq/twenty-infra/dispatches \
|
||||
-f event_type=auto-deploy-main
|
||||
|
||||
@@ -14,9 +14,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Repository Dispatch
|
||||
uses: peter-evans/repository-dispatch@v2
|
||||
with:
|
||||
token: ${{ secrets.TWENTY_INFRA_TOKEN }}
|
||||
repository: twentyhq/twenty-infra
|
||||
event-type: auto-deploy-tag
|
||||
client-payload: '{"github": ${{ toJson(github) }}}' # Passes the entire github context to the downstream workflow
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.TWENTY_INFRA_TOKEN }}
|
||||
REF_NAME: ${{ github.ref_name }}
|
||||
run: |
|
||||
gh api repos/twentyhq/twenty-infra/dispatches \
|
||||
-f event_type=auto-deploy-tag \
|
||||
-f "client_payload[github][ref_name]=$REF_NAME"
|
||||
|
||||
@@ -21,11 +21,11 @@ jobs:
|
||||
any_changed: ${{ steps.changed-files.outputs.any_changed }}
|
||||
steps:
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Check for changed files
|
||||
id: changed-files
|
||||
uses: tj-actions/changed-files@v45
|
||||
uses: tj-actions/changed-files@48d8f15b2aaa3d255ca5af3eba4870f807ce6b3c # v45.0.9
|
||||
with:
|
||||
files: ${{ inputs.files }}
|
||||
|
||||
@@ -17,7 +17,7 @@ jobs:
|
||||
NODE_OPTIONS: '--max-old-space-size=4096'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
ref: main
|
||||
|
||||
@@ -41,7 +41,7 @@ jobs:
|
||||
|
||||
- name: Create pull request
|
||||
if: steps.changes.outputs.changed == 'true'
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7.0.6
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
commit-message: 'chore: sync AI model catalog from models.dev'
|
||||
@@ -61,8 +61,7 @@ jobs:
|
||||
|
||||
- name: Trigger automerge
|
||||
if: steps.changes.outputs.changed == 'true'
|
||||
uses: peter-evans/repository-dispatch@v2
|
||||
with:
|
||||
token: ${{ secrets.TWENTY_INFRA_TOKEN }}
|
||||
repository: twentyhq/twenty-infra
|
||||
event-type: automated-pr-ready
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.TWENTY_INFRA_TOKEN }}
|
||||
run: |
|
||||
gh api repos/twentyhq/twenty-infra/dispatches -f event_type=automated-pr-ready
|
||||
|
||||
@@ -66,7 +66,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout current branch
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 10
|
||||
|
||||
@@ -164,9 +164,17 @@ jobs:
|
||||
interval=5
|
||||
elapsed=0
|
||||
|
||||
ADMIN_TOKEN=$(jq -r '.APPLE_JANE_ADMIN_ACCESS_TOKEN' packages/twenty-server/test/integration/constants/test-tokens.json)
|
||||
|
||||
while [ $elapsed -lt $timeout ]; do
|
||||
if curl -s "http://localhost:${{ env.CURRENT_SERVER_PORT }}/graphql" > /dev/null 2>&1 && \
|
||||
curl -s "http://localhost:${{ env.CURRENT_SERVER_PORT }}/rest/open-api/core" > /dev/null 2>&1; then
|
||||
GRAPHQL_RESPONSE=$(curl -s -X POST "http://localhost:${{ env.CURRENT_SERVER_PORT }}/graphql" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer ${ADMIN_TOKEN}" \
|
||||
-d '{"query":"{ __schema { queryType { name } } }"}' 2>/dev/null || echo '{}')
|
||||
|
||||
if echo "$GRAPHQL_RESPONSE" | jq -e '.data.__schema' > /dev/null 2>&1 && \
|
||||
curl -fsS "http://localhost:${{ env.CURRENT_SERVER_PORT }}/rest/open-api/core" \
|
||||
-H "Authorization: Bearer ${ADMIN_TOKEN}" > /dev/null 2>&1; then
|
||||
echo "Current branch server is ready!"
|
||||
break
|
||||
fi
|
||||
@@ -177,10 +185,9 @@ jobs:
|
||||
done
|
||||
|
||||
if [ $elapsed -ge $timeout ]; then
|
||||
echo "Timeout waiting for current branch server to start"
|
||||
echo "::warning::Timed out waiting for current branch server to serve a valid schema. Validation will skip the API diff."
|
||||
echo "Current server log:"
|
||||
cat /tmp/current-server.log || echo "No current server log found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Download GraphQL and REST responses from current branch
|
||||
@@ -324,9 +331,17 @@ jobs:
|
||||
interval=5
|
||||
elapsed=0
|
||||
|
||||
ADMIN_TOKEN=$(jq -r '.APPLE_JANE_ADMIN_ACCESS_TOKEN' packages/twenty-server/test/integration/constants/test-tokens.json)
|
||||
|
||||
while [ $elapsed -lt $timeout ]; do
|
||||
if curl -s "http://localhost:${{ env.MAIN_SERVER_PORT }}/graphql" > /dev/null 2>&1 && \
|
||||
curl -s "http://localhost:${{ env.MAIN_SERVER_PORT }}/rest/open-api/core" > /dev/null 2>&1; then
|
||||
GRAPHQL_RESPONSE=$(curl -s -X POST "http://localhost:${{ env.MAIN_SERVER_PORT }}/graphql" \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer ${ADMIN_TOKEN}" \
|
||||
-d '{"query":"{ __schema { queryType { name } } }"}' 2>/dev/null || echo '{}')
|
||||
|
||||
if echo "$GRAPHQL_RESPONSE" | jq -e '.data.__schema' > /dev/null 2>&1 && \
|
||||
curl -fsS "http://localhost:${{ env.MAIN_SERVER_PORT }}/rest/open-api/core" \
|
||||
-H "Authorization: Bearer ${ADMIN_TOKEN}" > /dev/null 2>&1; then
|
||||
echo "Main branch server is ready!"
|
||||
break
|
||||
fi
|
||||
@@ -337,10 +352,9 @@ jobs:
|
||||
done
|
||||
|
||||
if [ $elapsed -ge $timeout ]; then
|
||||
echo "Timeout waiting for main branch server to start"
|
||||
echo "::warning::Timed out waiting for main branch server to serve a valid schema. Validation will skip the API diff."
|
||||
echo "Main server log:"
|
||||
cat /tmp/main-server.log || echo "No main server log found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Download GraphQL and REST responses from main branch
|
||||
@@ -407,11 +421,23 @@ jobs:
|
||||
valid=true
|
||||
|
||||
for file in main-schema-introspection.json current-schema-introspection.json \
|
||||
main-metadata-schema-introspection.json current-metadata-schema-introspection.json \
|
||||
main-rest-api.json current-rest-api.json \
|
||||
main-metadata-schema-introspection.json current-metadata-schema-introspection.json; do
|
||||
if [ ! -f "$file" ]; then
|
||||
echo "::warning::Missing GraphQL schema file: $file"
|
||||
valid=false
|
||||
elif ! jq -e '.data.__schema' "$file" >/dev/null 2>&1; then
|
||||
echo "::warning::File $file is not a valid GraphQL introspection result. First 200 bytes: $(head -c 200 "$file")"
|
||||
valid=false
|
||||
fi
|
||||
done
|
||||
|
||||
for file in main-rest-api.json current-rest-api.json \
|
||||
main-rest-metadata-api.json current-rest-metadata-api.json; do
|
||||
if [ ! -f "$file" ] || ! jq empty "$file" 2>/dev/null; then
|
||||
echo "::warning::Invalid or missing schema file: $file"
|
||||
if [ ! -f "$file" ]; then
|
||||
echo "::warning::Missing OpenAPI spec file: $file"
|
||||
valid=false
|
||||
elif ! jq -e '.openapi // .swagger' "$file" >/dev/null 2>&1; then
|
||||
echo "::warning::File $file is not a valid OpenAPI spec. First 200 bytes: $(head -c 200 "$file")"
|
||||
valid=false
|
||||
fi
|
||||
done
|
||||
@@ -608,7 +634,7 @@ jobs:
|
||||
|
||||
- name: Upload breaking changes report
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: breaking-changes-report
|
||||
path: |
|
||||
|
||||
@@ -57,7 +57,7 @@ jobs:
|
||||
TWENTY_API_KEY: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMDIwMjAyMC1lNmI1LTQ2ODAtOGEzMi1iODIwOTczNzE1NmIiLCJ1c2VySWQiOiIyMDIwMjAyMC1lNmI1LTQ2ODAtOGEzMi1iODIwOTczNzE1NmIiLCJ3b3Jrc3BhY2VJZCI6IjIwMjAyMDIwLTFjMjUtNGQwMi1iZjI1LTZhZWNjZjdlYTQxOSIsIndvcmtzcGFjZU1lbWJlcklkIjoiMjAyMDIwMjAtNDYzZi00MzViLTgyOGMtMTA3ZTAwN2EyNzExIiwidXNlcldvcmtzcGFjZUlkIjoiMjAyMDIwMjAtMWU3Yy00M2Q5LWE1ZGItNjg1YjUwNjlkODE2IiwidHlwZSI6IkFDQ0VTUyIsImF1dGhQcm92aWRlciI6InBhc3N3b3JkIiwiaWF0IjoxNzUxMjgxNzA0LCJleHAiOjIwNjY4NTc3MDR9.HMGqCsVlOAPVUBhKSGlD1X86VoHKt4LIUtET3CGIdik
|
||||
steps:
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 10
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
TWENTY_API_KEY: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMDIwMjAyMC1lNmI1LTQ2ODAtOGEzMi1iODIwOTczNzE1NmIiLCJ1c2VySWQiOiIyMDIwMjAyMC1lNmI1LTQ2ODAtOGEzMi1iODIwOTczNzE1NmIiLCJ3b3Jrc3BhY2VJZCI6IjIwMjAyMDIwLTFjMjUtNGQwMi1iZjI1LTZhZWNjZjdlYTQxOSIsIndvcmtzcGFjZU1lbWJlcklkIjoiMjAyMDIwMjAtNDYzZi00MzViLTgyOGMtMTA3ZTAwN2EyNzExIiwidXNlcldvcmtzcGFjZUlkIjoiMjAyMDIwMjAtMWU3Yy00M2Q5LWE1ZGItNjg1YjUwNjlkODE2IiwidHlwZSI6IkFDQ0VTUyIsImF1dGhQcm92aWRlciI6InBhc3N3b3JkIiwiaWF0IjoxNzUxMjgxNzA0LCJleHAiOjIwNjY4NTc3MDR9.HMGqCsVlOAPVUBhKSGlD1X86VoHKt4LIUtET3CGIdik
|
||||
steps:
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 10
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ jobs:
|
||||
TWENTY_API_KEY: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMDIwMjAyMC1lNmI1LTQ2ODAtOGEzMi1iODIwOTczNzE1NmIiLCJ1c2VySWQiOiIyMDIwMjAyMC1lNmI1LTQ2ODAtOGEzMi1iODIwOTczNzE1NmIiLCJ3b3Jrc3BhY2VJZCI6IjIwMjAyMDIwLTFjMjUtNGQwMi1iZjI1LTZhZWNjZjdlYTQxOSIsIndvcmtzcGFjZU1lbWJlcklkIjoiMjAyMDIwMjAtNDYzZi00MzViLTgyOGMtMTA3ZTAwN2EyNzExIiwidXNlcldvcmtzcGFjZUlkIjoiMjAyMDIwMjAtMWU3Yy00M2Q5LWE1ZGItNjg1YjUwNjlkODE2IiwidHlwZSI6IkFDQ0VTUyIsImF1dGhQcm92aWRlciI6InBhc3N3b3JkIiwiaWF0IjoxNzUxMjgxNzA0LCJleHAiOjIwNjY4NTc3MDR9.HMGqCsVlOAPVUBhKSGlD1X86VoHKt4LIUtET3CGIdik
|
||||
steps:
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 10
|
||||
|
||||
|
||||
@@ -30,12 +30,8 @@ jobs:
|
||||
matrix:
|
||||
task: [lint, typecheck, test]
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/[email protected]
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Install dependencies
|
||||
|
||||
@@ -28,13 +28,8 @@ jobs:
|
||||
timeout-minutes: 10
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/[email protected]
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
|
||||
- name: Fetch local actions
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 10
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Install dependencies
|
||||
|
||||
@@ -54,7 +54,7 @@ jobs:
|
||||
TWENTY_API_KEY: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMDIwMjAyMC1lNmI1LTQ2ODAtOGEzMi1iODIwOTczNzE1NmIiLCJ1c2VySWQiOiIyMDIwMjAyMC1lNmI1LTQ2ODAtOGEzMi1iODIwOTczNzE1NmIiLCJ3b3Jrc3BhY2VJZCI6IjIwMjAyMDIwLTFjMjUtNGQwMi1iZjI1LTZhZWNjZjdlYTQxOSIsIndvcmtzcGFjZU1lbWJlcklkIjoiMjAyMDIwMjAtNDYzZi00MzViLTgyOGMtMTA3ZTAwN2EyNzExIiwidXNlcldvcmtzcGFjZUlkIjoiMjAyMDIwMjAtMWU3Yy00M2Q5LWE1ZGItNjg1YjUwNjlkODE2IiwidHlwZSI6IkFDQ0VTUyIsImF1dGhQcm92aWRlciI6InBhc3N3b3JkIiwiaWF0IjoxNzUxMjgxNzA0LCJleHAiOjIwNjY4NTc3MDR9.HMGqCsVlOAPVUBhKSGlD1X86VoHKt4LIUtET3CGIdik
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
|
||||
- name: Install dependencies
|
||||
uses: ./.github/actions/yarn-install
|
||||
|
||||
@@ -54,7 +54,7 @@ jobs:
|
||||
TWENTY_API_KEY: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMDIwMjAyMC1lNmI1LTQ2ODAtOGEzMi1iODIwOTczNzE1NmIiLCJ1c2VySWQiOiIyMDIwMjAyMC1lNmI1LTQ2ODAtOGEzMi1iODIwOTczNzE1NmIiLCJ3b3Jrc3BhY2VJZCI6IjIwMjAyMDIwLTFjMjUtNGQwMi1iZjI1LTZhZWNjZjdlYTQxOSIsIndvcmtzcGFjZU1lbWJlcklkIjoiMjAyMDIwMjAtNDYzZi00MzViLTgyOGMtMTA3ZTAwN2EyNzExIiwidXNlcldvcmtzcGFjZUlkIjoiMjAyMDIwMjAtMWU3Yy00M2Q5LWE1ZGItNjg1YjUwNjlkODE2IiwidHlwZSI6IkFDQ0VTUyIsImF1dGhQcm92aWRlciI6InBhc3N3b3JkIiwiaWF0IjoxNzUxMjgxNzA0LCJleHAiOjIwNjY4NTc3MDR9.HMGqCsVlOAPVUBhKSGlD1X86VoHKt4LIUtET3CGIdik
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
|
||||
- name: Install dependencies
|
||||
uses: ./.github/actions/yarn-install
|
||||
|
||||
@@ -32,12 +32,8 @@ jobs:
|
||||
matrix:
|
||||
task: [build, typecheck, lint]
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/[email protected]
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Install dependencies
|
||||
@@ -50,12 +46,8 @@ jobs:
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/[email protected]
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Install dependencies
|
||||
@@ -63,7 +55,7 @@ jobs:
|
||||
- name: Build storybook
|
||||
run: npx nx storybook:build twenty-front-component-renderer
|
||||
- name: Upload storybook build
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: storybook-twenty-front-component-renderer
|
||||
path: packages/twenty-front-component-renderer/storybook-static
|
||||
@@ -76,7 +68,7 @@ jobs:
|
||||
STORYBOOK_URL: http://localhost:6008
|
||||
steps:
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Install dependencies
|
||||
@@ -84,7 +76,7 @@ jobs:
|
||||
- name: Build dependencies
|
||||
run: npx nx build twenty-sdk
|
||||
- name: Download storybook build
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
with:
|
||||
name: storybook-twenty-front-component-renderer
|
||||
path: packages/twenty-front-component-renderer/storybook-static
|
||||
|
||||
@@ -38,12 +38,8 @@ jobs:
|
||||
env:
|
||||
REACT_APP_SERVER_BASE_URL: http://localhost:3000
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/[email protected]
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
- name: Fetch local actions
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Install dependencies
|
||||
@@ -55,7 +51,7 @@ jobs:
|
||||
- name: Front / Build storybook
|
||||
run: npx nx storybook:build twenty-front
|
||||
- name: Upload storybook build
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: storybook-static
|
||||
path: packages/twenty-front/storybook-static
|
||||
@@ -79,7 +75,7 @@ jobs:
|
||||
STORYBOOK_URL: http://localhost:6006
|
||||
steps:
|
||||
- name: Fetch local actions
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Install dependencies
|
||||
@@ -96,7 +92,7 @@ jobs:
|
||||
npx nx build twenty-ui
|
||||
npx nx build twenty-front-component-renderer
|
||||
- name: Download storybook build
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
with:
|
||||
name: storybook-static
|
||||
path: packages/twenty-front/storybook-static
|
||||
@@ -121,7 +117,7 @@ jobs:
|
||||
# exit 1
|
||||
# fi
|
||||
# - name: Upload coverage artifact
|
||||
# uses: actions/upload-artifact@v4
|
||||
# uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
# with:
|
||||
# retention-days: 1
|
||||
# name: coverage-artifacts-${{ matrix.storybook_scope }}-${{ github.run_id }}-${{ matrix.shard }}
|
||||
@@ -136,12 +132,12 @@ jobs:
|
||||
# matrix:
|
||||
# storybook_scope: [modules, pages, performance]
|
||||
# steps:
|
||||
# - uses: actions/checkout@v4
|
||||
# - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
# with:
|
||||
# fetch-depth: 10
|
||||
# - name: Install dependencies
|
||||
# uses: ./.github/actions/yarn-install
|
||||
# - uses: actions/download-artifact@v4
|
||||
# - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
# with:
|
||||
# pattern: coverage-artifacts-${{ matrix.storybook_scope }}-${{ github.run_id }}-*
|
||||
# merge-multiple: true
|
||||
@@ -164,12 +160,8 @@ jobs:
|
||||
matrix:
|
||||
task: [lint, typecheck, test]
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/[email protected]
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Install dependencies
|
||||
@@ -203,12 +195,8 @@ jobs:
|
||||
NODE_OPTIONS: "--max-old-space-size=10240"
|
||||
ANALYZE: "true"
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/[email protected]
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Install dependencies
|
||||
@@ -218,7 +206,7 @@ jobs:
|
||||
- name: Build frontend
|
||||
run: npx nx build twenty-front
|
||||
# - name: Upload frontend build artifact
|
||||
# uses: actions/upload-artifact@v4
|
||||
# uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
# with:
|
||||
# name: frontend-build
|
||||
# path: packages/twenty-front/build
|
||||
|
||||
@@ -41,11 +41,11 @@ jobs:
|
||||
ports:
|
||||
- 6379:6379
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 10
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
|
||||
with:
|
||||
node-version: lts/*
|
||||
|
||||
@@ -53,7 +53,7 @@ jobs:
|
||||
uses: ./.github/actions/yarn-install
|
||||
|
||||
- name: Restore Nx build cache
|
||||
uses: actions/cache/restore@v4
|
||||
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 (restore)
|
||||
with:
|
||||
key: v4-e2e-build-${{ github.ref_name }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
@@ -83,7 +83,7 @@ jobs:
|
||||
|
||||
- name: Save Nx build cache
|
||||
if: always()
|
||||
uses: actions/cache/save@v4
|
||||
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 (save)
|
||||
with:
|
||||
key: v4-e2e-build-${{ github.ref_name }}-${{ github.sha }}
|
||||
path: |
|
||||
@@ -119,7 +119,7 @@ jobs:
|
||||
|
||||
- name: Upload Playwright results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: playwright-results
|
||||
path: |
|
||||
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
ref: ${{ github.event.inputs.ref }}
|
||||
|
||||
@@ -47,7 +47,7 @@ jobs:
|
||||
printf '%s\n' "$VERSION" > version.txt
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v6
|
||||
uses: peter-evans/create-pull-request@c5a7806660adbe173f04e3e038b0ccdcd758773c # v6.1.0
|
||||
with:
|
||||
branch: release/${{ steps.sanitize.outputs.version }}
|
||||
commit-message: "chore: release v${{ steps.sanitize.outputs.version }}"
|
||||
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
ref: main
|
||||
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
git tag "v${{ env.VERSION }}"
|
||||
git push origin "v${{ env.VERSION }}"
|
||||
|
||||
- uses: release-drafter/release-drafter@v5
|
||||
- uses: release-drafter/release-drafter@09c613e259eb8d4e7c81c2cb00618eb5fc4575a7 # v5
|
||||
if: contains(github.event.pull_request.labels.*.name, 'create_release')
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -30,12 +30,8 @@ jobs:
|
||||
matrix:
|
||||
task: [lint, typecheck, test:unit, test:integration]
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/[email protected]
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Install dependencies
|
||||
@@ -74,7 +70,7 @@ jobs:
|
||||
TWENTY_API_KEY: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIyMDIwMjAyMC1lNmI1LTQ2ODAtOGEzMi1iODIwOTczNzE1NmIiLCJ1c2VySWQiOiIyMDIwMjAyMC1lNmI1LTQ2ODAtOGEzMi1iODIwOTczNzE1NmIiLCJ3b3Jrc3BhY2VJZCI6IjIwMjAyMDIwLTFjMjUtNGQwMi1iZjI1LTZhZWNjZjdlYTQxOSIsIndvcmtzcGFjZU1lbWJlcklkIjoiMjAyMDIwMjAtNDYzZi00MzViLTgyOGMtMTA3ZTAwN2EyNzExIiwidXNlcldvcmtzcGFjZUlkIjoiMjAyMDIwMjAtMWU3Yy00M2Q5LWE1ZGItNjg1YjUwNjlkODE2IiwidHlwZSI6IkFDQ0VTUyIsImF1dGhQcm92aWRlciI6InBhc3N3b3JkIiwiaWF0IjoxNzUxMjgxNzA0LCJleHAiOjIwNjY4NTc3MDR9.HMGqCsVlOAPVUBhKSGlD1X86VoHKt4LIUtET3CGIdik
|
||||
steps:
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Install dependencies
|
||||
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Install dependencies
|
||||
@@ -65,7 +65,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Install dependencies
|
||||
@@ -83,12 +83,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Get changed upgrade-version-command files
|
||||
id: changed-files
|
||||
uses: tj-actions/changed-files@v45
|
||||
uses: tj-actions/changed-files@48d8f15b2aaa3d255ca5af3eba4870f807ce6b3c # v45.0.9
|
||||
with:
|
||||
files: |
|
||||
packages/twenty-server/src/database/commands/upgrade-version-command/**
|
||||
@@ -178,7 +178,7 @@ jobs:
|
||||
- 6379:6379
|
||||
steps:
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Install dependencies
|
||||
@@ -278,7 +278,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Install dependencies
|
||||
@@ -341,7 +341,7 @@ jobs:
|
||||
SHARD_COUNTER: 10
|
||||
steps:
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Install dependencies
|
||||
|
||||
@@ -29,12 +29,8 @@ jobs:
|
||||
matrix:
|
||||
task: [lint, typecheck, test]
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/[email protected]
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Install dependencies
|
||||
|
||||
@@ -26,9 +26,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
|
||||
with:
|
||||
username: ${{ vars.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
@@ -101,9 +101,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
|
||||
with:
|
||||
username: ${{ vars.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
|
||||
@@ -30,12 +30,8 @@ jobs:
|
||||
matrix:
|
||||
task: [lint, typecheck, test]
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/[email protected]
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Install dependencies
|
||||
@@ -48,12 +44,8 @@ jobs:
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/[email protected]
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Install dependencies
|
||||
@@ -61,7 +53,7 @@ jobs:
|
||||
- name: Build storybook
|
||||
run: npx nx storybook:build twenty-ui
|
||||
- name: Upload storybook build
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: storybook-twenty-ui
|
||||
path: packages/twenty-ui/storybook-static
|
||||
@@ -74,7 +66,7 @@ jobs:
|
||||
STORYBOOK_URL: http://localhost:6007
|
||||
steps:
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Install dependencies
|
||||
@@ -82,7 +74,7 @@ jobs:
|
||||
- name: Build dependencies
|
||||
run: npx nx build twenty-shared
|
||||
- name: Download storybook build
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
with:
|
||||
name: storybook-twenty-ui
|
||||
path: packages/twenty-ui/storybook-static
|
||||
|
||||
@@ -25,7 +25,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.action != 'closed'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
- name: Install dependencies
|
||||
uses: ./.github/actions/yarn-install
|
||||
- name: Utils / Run Danger.js
|
||||
@@ -38,7 +38,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.action == 'closed' && github.event.pull_request.merged == true
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
- name: Install dependencies
|
||||
uses: ./.github/actions/yarn-install
|
||||
- name: Run congratulate-dangerfile.js
|
||||
|
||||
@@ -32,12 +32,8 @@ jobs:
|
||||
matrix:
|
||||
task: [lint, typecheck, test]
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/[email protected]
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Install dependencies
|
||||
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
- 6379:6379
|
||||
steps:
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Install dependencies
|
||||
@@ -97,12 +97,8 @@ jobs:
|
||||
matrix:
|
||||
task: [lint, typecheck, validate]
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/[email protected]
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Install dependencies
|
||||
|
||||
@@ -8,10 +8,12 @@ on:
|
||||
pull_request_review:
|
||||
types: [submitted]
|
||||
issues:
|
||||
types: [opened, assigned]
|
||||
types: [opened]
|
||||
repository_dispatch:
|
||||
types: [claude-core-team-issues]
|
||||
|
||||
permissions: {}
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.issue.number || github.event.pull_request.number || github.event.client_payload.issue_number }}
|
||||
cancel-in-progress: false
|
||||
@@ -19,17 +21,36 @@ concurrency:
|
||||
jobs:
|
||||
claude:
|
||||
if: |
|
||||
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude') && github.event.comment.user.type != 'Bot') ||
|
||||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude') && github.event.comment.user.type != 'Bot') ||
|
||||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude') && github.event.review.user.type != 'Bot') ||
|
||||
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
|
||||
(
|
||||
github.event_name == 'issue_comment' &&
|
||||
contains(github.event.comment.body, '@claude') &&
|
||||
github.event.comment.user.type != 'Bot' &&
|
||||
contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)
|
||||
) ||
|
||||
(
|
||||
github.event_name == 'pull_request_review_comment' &&
|
||||
contains(github.event.comment.body, '@claude') &&
|
||||
github.event.comment.user.type != 'Bot' &&
|
||||
contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)
|
||||
) ||
|
||||
(
|
||||
github.event_name == 'pull_request_review' &&
|
||||
contains(github.event.review.body, '@claude') &&
|
||||
github.event.review.user.type != 'Bot' &&
|
||||
contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.review.author_association)
|
||||
) ||
|
||||
(
|
||||
github.event_name == 'issues' &&
|
||||
github.event.action == 'opened' &&
|
||||
(contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')) &&
|
||||
contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.issue.author_association)
|
||||
)
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
issues: write
|
||||
id-token: write
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16
|
||||
@@ -50,14 +71,14 @@ jobs:
|
||||
- 6379:6379
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Install dependencies
|
||||
uses: ./.github/actions/yarn-install
|
||||
- name: Run Claude Code
|
||||
id: claude-code
|
||||
uses: anthropics/claude-code-action@v1
|
||||
uses: anthropics/claude-code-action@dde2242db6af13460b916652159b6ba19a598f30 # v1
|
||||
with:
|
||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||
additional_permissions: |
|
||||
@@ -102,7 +123,6 @@ jobs:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
issues: write
|
||||
id-token: write
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16
|
||||
@@ -122,14 +142,14 @@ jobs:
|
||||
ports:
|
||||
- 6379:6379
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Install dependencies
|
||||
uses: ./.github/actions/yarn-install
|
||||
- name: Build prompt from dispatch payload
|
||||
id: prompt
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
|
||||
with:
|
||||
script: |
|
||||
const p = context.payload.client_payload;
|
||||
@@ -144,7 +164,7 @@ jobs:
|
||||
core.setOutput('issue_number', p.issue_number);
|
||||
- name: Run Claude Code
|
||||
id: claude
|
||||
uses: anthropics/claude-code-action@v1
|
||||
uses: anthropics/claude-code-action@dde2242db6af13460b916652159b6ba19a598f30 # v1
|
||||
with:
|
||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||
prompt: ${{ steps.prompt.outputs.prompt }}
|
||||
@@ -159,9 +179,16 @@ jobs:
|
||||
}
|
||||
- name: Dispatch response to ci-privileged
|
||||
if: always()
|
||||
uses: peter-evans/repository-dispatch@v2
|
||||
with:
|
||||
token: ${{ secrets.CI_PRIVILEGED_DISPATCH_TOKEN }}
|
||||
repository: twentyhq/ci-privileged
|
||||
event-type: claude-cross-repo-response
|
||||
client-payload: '{"repo": ${{ toJSON(steps.prompt.outputs.repo) }}, "issue_number": ${{ toJSON(steps.prompt.outputs.issue_number) }}, "run_id": ${{ toJSON(github.run_id) }}, "run_url": "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"}'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.CI_PRIVILEGED_DISPATCH_TOKEN }}
|
||||
REPO: ${{ steps.prompt.outputs.repo }}
|
||||
ISSUE_NUMBER: ${{ steps.prompt.outputs.issue_number }}
|
||||
RUN_ID: ${{ github.run_id }}
|
||||
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
run: |
|
||||
gh api repos/twentyhq/ci-privileged/dispatches \
|
||||
-f event_type=claude-cross-repo-response \
|
||||
-f "client_payload[repo]=$REPO" \
|
||||
-f "client_payload[issue_number]=$ISSUE_NUMBER" \
|
||||
-f "client_payload[run_id]=$RUN_ID" \
|
||||
-f "client_payload[run_url]=$RUN_URL"
|
||||
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
repository: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name || github.repository }}
|
||||
@@ -153,8 +153,7 @@ jobs:
|
||||
|
||||
- name: Trigger i18n automerge
|
||||
if: github.event_name != 'pull_request' && steps.check_changes.outputs.changes_detected == 'true'
|
||||
uses: peter-evans/repository-dispatch@v2
|
||||
with:
|
||||
token: ${{ secrets.TWENTY_INFRA_TOKEN }}
|
||||
repository: twentyhq/twenty-infra
|
||||
event-type: i18n-pr-ready
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.TWENTY_INFRA_TOKEN }}
|
||||
run: |
|
||||
gh api repos/twentyhq/twenty-infra/dispatches -f event_type=i18n-pr-ready
|
||||
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
ref: ${{ github.ref }}
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
run: yarn docs:generate-navigation-template
|
||||
|
||||
- name: Upload docs to Crowdin
|
||||
uses: crowdin/github-action@v2
|
||||
uses: crowdin/github-action@8868a33591d21088edfc398968173a3b98d51706 # v2
|
||||
with:
|
||||
upload_sources: true
|
||||
upload_translations: false
|
||||
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
ref: ${{ github.head_ref || github.ref_name }}
|
||||
@@ -69,7 +69,7 @@ jobs:
|
||||
|
||||
- name: Pull translations from Crowdin
|
||||
if: inputs.force_pull || steps.compile_translations_strict.outcome == 'failure'
|
||||
uses: crowdin/github-action@v2
|
||||
uses: crowdin/github-action@8868a33591d21088edfc398968173a3b98d51706 # v2
|
||||
with:
|
||||
upload_sources: false
|
||||
upload_translations: false
|
||||
@@ -139,8 +139,7 @@ jobs:
|
||||
|
||||
- name: Trigger i18n automerge
|
||||
if: steps.compile_translations.outputs.changes_detected == 'true'
|
||||
uses: peter-evans/repository-dispatch@v2
|
||||
with:
|
||||
token: ${{ secrets.TWENTY_INFRA_TOKEN }}
|
||||
repository: twentyhq/twenty-infra
|
||||
event-type: i18n-pr-ready
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.TWENTY_INFRA_TOKEN }}
|
||||
run: |
|
||||
gh api repos/twentyhq/twenty-infra/dispatches -f event_type=i18n-pr-ready
|
||||
|
||||
@@ -20,7 +20,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
ref: main
|
||||
@@ -80,7 +80,7 @@ jobs:
|
||||
|
||||
- name: Upload missing translations
|
||||
if: steps.check_extract_changes.outputs.changes_detected == 'true'
|
||||
uses: crowdin/github-action@v2
|
||||
uses: crowdin/github-action@8868a33591d21088edfc398968173a3b98d51706 # v2
|
||||
with:
|
||||
upload_sources: true
|
||||
upload_translations: true
|
||||
@@ -105,8 +105,7 @@ jobs:
|
||||
|
||||
- name: Trigger i18n automerge
|
||||
if: steps.check_extract_changes.outputs.changes_detected == 'true' || steps.check_compile_changes.outputs.changes_detected == 'true'
|
||||
uses: peter-evans/repository-dispatch@v2
|
||||
with:
|
||||
token: ${{ secrets.TWENTY_INFRA_TOKEN }}
|
||||
repository: twentyhq/twenty-infra
|
||||
event-type: i18n-pr-ready
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.TWENTY_INFRA_TOKEN }}
|
||||
run: |
|
||||
gh api repos/twentyhq/twenty-infra/dispatches -f event_type=i18n-pr-ready
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
steps:
|
||||
- name: Get PR number from workflow run
|
||||
id: pr-info
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
|
||||
with:
|
||||
script: |
|
||||
const runId = context.payload.workflow_run.id;
|
||||
@@ -63,9 +63,16 @@ jobs:
|
||||
|
||||
- name: Dispatch to ci-privileged
|
||||
if: steps.pr-info.outputs.has_pr == 'true'
|
||||
uses: peter-evans/repository-dispatch@v2
|
||||
with:
|
||||
token: ${{ secrets.CI_PRIVILEGED_DISPATCH_TOKEN }}
|
||||
repository: twentyhq/ci-privileged
|
||||
event-type: breaking-changes-report
|
||||
client-payload: '{"pr_number": ${{ toJSON(steps.pr-info.outputs.pr_number) }}, "run_id": ${{ toJSON(steps.pr-info.outputs.run_id) }}, "repo": ${{ toJSON(github.repository) }}, "branch_state": ${{ toJSON(github.event.workflow_run.head_branch) }}}'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.CI_PRIVILEGED_DISPATCH_TOKEN }}
|
||||
PR_NUMBER: ${{ steps.pr-info.outputs.pr_number }}
|
||||
RUN_ID: ${{ steps.pr-info.outputs.run_id }}
|
||||
REPOSITORY: ${{ github.repository }}
|
||||
BRANCH_STATE: ${{ github.event.workflow_run.head_branch }}
|
||||
run: |
|
||||
gh api repos/twentyhq/ci-privileged/dispatches \
|
||||
-f event_type=breaking-changes-report \
|
||||
-f "client_payload[pr_number]=$PR_NUMBER" \
|
||||
-f "client_payload[run_id]=$RUN_ID" \
|
||||
-f "client_payload[repo]=$REPOSITORY" \
|
||||
-f "client_payload[branch_state]=$BRANCH_STATE"
|
||||
|
||||
@@ -36,17 +36,27 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Trigger preview environment workflow
|
||||
uses: peter-evans/repository-dispatch@v2
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
repository: ${{ github.repository }}
|
||||
event-type: preview-environment
|
||||
client-payload: '{"pr_number": "${{ github.event.pull_request.number }}", "pr_head_sha": "${{ github.event.pull_request.head.sha }}", "repo_full_name": "${{ github.repository }}"}'
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
REPOSITORY: ${{ github.repository }}
|
||||
run: |
|
||||
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
|
||||
uses: peter-evans/repository-dispatch@v2
|
||||
with:
|
||||
token: ${{ secrets.CI_PRIVILEGED_DISPATCH_TOKEN }}
|
||||
repository: twentyhq/ci-privileged
|
||||
event-type: preview-env-url
|
||||
client-payload: '{"pr_number": ${{ toJSON(github.event.pull_request.number) }}, "keepalive_dispatch_time": ${{ toJSON(github.event.pull_request.updated_at) }}, "repo": ${{ toJSON(github.repository) }}}'
|
||||
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"
|
||||
|
||||
@@ -13,12 +13,12 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout PR
|
||||
uses: actions/checkout@v4
|
||||
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@v3
|
||||
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0
|
||||
with:
|
||||
username: ${{ vars.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_PASSWORD }}
|
||||
@@ -56,10 +56,54 @@ jobs:
|
||||
|
||||
- name: Create Tunnel
|
||||
id: expose-tunnel
|
||||
uses: codetalkio/[email protected]
|
||||
with:
|
||||
service: bore.pub
|
||||
port: 3000
|
||||
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:
|
||||
@@ -99,9 +143,9 @@ jobs:
|
||||
- name: Seed Dev Workspace
|
||||
run: |
|
||||
cd packages/twenty-docker/
|
||||
echo "Seeding full dev workspace..."
|
||||
if ! docker compose exec -T server yarn command:prod -- workspace:seed:dev; then
|
||||
echo "❌ Seeding full dev workspace failed. Dumping server logs..."
|
||||
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
|
||||
@@ -122,7 +166,7 @@ jobs:
|
||||
echo "$TUNNEL_URL" > tunnel-url.txt
|
||||
|
||||
- name: Upload tunnel URL artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: tunnel-url
|
||||
path: tunnel-url.txt
|
||||
@@ -134,6 +178,9 @@ jobs:
|
||||
- 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: ./
|
||||
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
steps:
|
||||
- name: Determine project and artifact name
|
||||
id: project
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
|
||||
with:
|
||||
script: |
|
||||
const workflowName = context.payload.workflow_run.name;
|
||||
@@ -43,7 +43,7 @@ jobs:
|
||||
|
||||
- name: Check if storybook artifact exists
|
||||
id: check-artifact
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
|
||||
with:
|
||||
script: |
|
||||
const artifactName = '${{ steps.project.outputs.artifact_name }}';
|
||||
@@ -65,7 +65,7 @@ jobs:
|
||||
- name: Get PR number
|
||||
if: steps.check-artifact.outputs.exists == 'true'
|
||||
id: pr-info
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0
|
||||
with:
|
||||
script: |
|
||||
const headBranch = context.payload.workflow_run.head_branch;
|
||||
@@ -107,7 +107,7 @@ jobs:
|
||||
|
||||
- name: Download storybook artifact from triggering run
|
||||
if: steps.check-artifact.outputs.exists == 'true' && steps.pr-info.outputs.has_pr == 'true'
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
|
||||
with:
|
||||
name: ${{ steps.project.outputs.artifact_name }}
|
||||
path: storybook-static
|
||||
@@ -120,7 +120,7 @@ jobs:
|
||||
|
||||
- name: Upload storybook tarball
|
||||
if: steps.check-artifact.outputs.exists == 'true' && steps.pr-info.outputs.has_pr == 'true'
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: ${{ steps.project.outputs.tarball_name }}
|
||||
path: /tmp/${{ steps.project.outputs.tarball_file }}
|
||||
@@ -128,17 +128,20 @@ jobs:
|
||||
|
||||
- name: Dispatch to ci-privileged
|
||||
if: steps.check-artifact.outputs.exists == 'true' && steps.pr-info.outputs.has_pr == 'true'
|
||||
uses: peter-evans/repository-dispatch@v2
|
||||
with:
|
||||
token: ${{ secrets.CI_PRIVILEGED_DISPATCH_TOKEN }}
|
||||
repository: twentyhq/ci-privileged
|
||||
event-type: visual-regression
|
||||
client-payload: >-
|
||||
{
|
||||
"pr_number": "${{ steps.pr-info.outputs.pr_number }}",
|
||||
"run_id": "${{ github.run_id }}",
|
||||
"repo": "${{ github.repository }}",
|
||||
"project": "${{ steps.project.outputs.project }}",
|
||||
"branch": "${{ github.event.workflow_run.head_branch }}",
|
||||
"commit": "${{ github.event.workflow_run.head_sha }}"
|
||||
}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.CI_PRIVILEGED_DISPATCH_TOKEN }}
|
||||
PR_NUMBER: ${{ steps.pr-info.outputs.pr_number }}
|
||||
RUN_ID: ${{ github.run_id }}
|
||||
REPOSITORY: ${{ github.repository }}
|
||||
PROJECT: ${{ steps.project.outputs.project }}
|
||||
BRANCH: ${{ github.event.workflow_run.head_branch }}
|
||||
COMMIT: ${{ github.event.workflow_run.head_sha }}
|
||||
run: |
|
||||
gh api repos/twentyhq/ci-privileged/dispatches \
|
||||
-f event_type=visual-regression \
|
||||
-f "client_payload[pr_number]=$PR_NUMBER" \
|
||||
-f "client_payload[run_id]=$RUN_ID" \
|
||||
-f "client_payload[repo]=$REPOSITORY" \
|
||||
-f "client_payload[project]=$PROJECT" \
|
||||
-f "client_payload[branch]=$BRANCH" \
|
||||
-f "client_payload[commit]=$COMMIT"
|
||||
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
ref: ${{ github.head_ref || github.ref_name }}
|
||||
@@ -66,7 +66,7 @@ jobs:
|
||||
|
||||
- name: Pull website translations from Crowdin
|
||||
if: inputs.force_pull || steps.compile_translations_strict.outcome == 'failure'
|
||||
uses: crowdin/github-action@v2
|
||||
uses: crowdin/github-action@8868a33591d21088edfc398968173a3b98d51706 # v2
|
||||
with:
|
||||
upload_sources: false
|
||||
upload_translations: false
|
||||
@@ -128,8 +128,7 @@ jobs:
|
||||
|
||||
- name: Trigger i18n automerge
|
||||
if: steps.compile_translations.outputs.changes_detected == 'true'
|
||||
uses: peter-evans/repository-dispatch@v2
|
||||
with:
|
||||
token: ${{ secrets.TWENTY_INFRA_TOKEN }}
|
||||
repository: twentyhq/twenty-infra
|
||||
event-type: i18n-pr-ready
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.TWENTY_INFRA_TOKEN }}
|
||||
run: |
|
||||
gh api repos/twentyhq/twenty-infra/dispatches -f event_type=i18n-pr-ready
|
||||
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
ref: main
|
||||
@@ -78,7 +78,7 @@ jobs:
|
||||
|
||||
- name: Upload missing website translations
|
||||
if: steps.check_extract_changes.outputs.changes_detected == 'true'
|
||||
uses: crowdin/github-action@v2
|
||||
uses: crowdin/github-action@8868a33591d21088edfc398968173a3b98d51706 # v2
|
||||
with:
|
||||
upload_sources: true
|
||||
upload_translations: true
|
||||
@@ -104,8 +104,7 @@ jobs:
|
||||
|
||||
- name: Trigger i18n automerge
|
||||
if: steps.check_extract_changes.outputs.changes_detected == 'true' || steps.check_compile_changes.outputs.changes_detected == 'true'
|
||||
uses: peter-evans/repository-dispatch@v2
|
||||
with:
|
||||
token: ${{ secrets.TWENTY_INFRA_TOKEN }}
|
||||
repository: twentyhq/twenty-infra
|
||||
event-type: i18n-pr-ready
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.TWENTY_INFRA_TOKEN }}
|
||||
run: |
|
||||
gh api repos/twentyhq/twenty-infra/dispatches -f event_type=i18n-pr-ready
|
||||
|
||||
@@ -6,4 +6,6 @@ enableInlineHunks: true
|
||||
|
||||
nodeLinker: node-modules
|
||||
|
||||
npmMinimalAgeGate: "3d"
|
||||
|
||||
yarnPath: .yarn/releases/yarn-4.13.0.cjs
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
"lint:diff-with-main": {
|
||||
"executor": "nx:run-commands",
|
||||
"cache": false,
|
||||
"dependsOn": ["twenty-oxlint-rules:build"],
|
||||
"options": {
|
||||
"command": "FILES=$(git diff --name-only --diff-filter=d main -- {projectRoot}/ | grep -E '{args.pattern}'); [ -z \"$FILES\" ] && echo 'No changed files.' || (npx oxlint -c {projectRoot}/.oxlintrc.json $FILES && (prettier --check $FILES || (echo 'ERROR: Prettier formatting check failed! Fix with: npx nx lint:diff-with-main --configuration=fix' && false)))",
|
||||
"pattern": "\\.(ts|tsx|js|jsx)$"
|
||||
|
||||
+2
-1
@@ -63,7 +63,8 @@
|
||||
"packages/twenty-cli",
|
||||
"packages/create-twenty-app",
|
||||
"packages/twenty-oxlint-rules",
|
||||
"packages/twenty-companion"
|
||||
"packages/twenty-companion",
|
||||
"packages/twenty-claude-skills"
|
||||
]
|
||||
},
|
||||
"prettier": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "create-twenty-app",
|
||||
"version": "2.3.0",
|
||||
"version": "2.4.0",
|
||||
"description": "Command-line interface to create Twenty application",
|
||||
"main": "dist/cli.cjs",
|
||||
"bin": "dist/cli.cjs",
|
||||
|
||||
Binary file not shown.
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "twenty-linear",
|
||||
"version": "0.1.5",
|
||||
"version": "0.1.6",
|
||||
"description": "Linear integration for Twenty. Connect a user's Linear account and create issues from logic functions.",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -20,7 +20,7 @@
|
||||
"test:watch": "vitest --config vitest.unit.config.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"twenty-sdk": "2.3.0"
|
||||
"twenty-sdk": "2.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^24.7.2",
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 198 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 427 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 255 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 420 KiB |
@@ -1,9 +1,6 @@
|
||||
import { defineApplication } from 'twenty-sdk/define';
|
||||
|
||||
import {
|
||||
APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
DEFAULT_ROLE_UNIVERSAL_IDENTIFIER,
|
||||
} from 'src/constants/universal-identifiers';
|
||||
import { ABOUT_DESCRIPTION } from './constants/ABOUT_DESCRIPTION.md';
|
||||
import { APPLICATION_UNIVERSAL_IDENTIFIER } from 'src/constants/universal-identifiers';
|
||||
|
||||
export default defineApplication({
|
||||
universalIdentifier: APPLICATION_UNIVERSAL_IDENTIFIER,
|
||||
@@ -11,10 +8,19 @@ export default defineApplication({
|
||||
description:
|
||||
'Connect Linear to Twenty. Each workspace member connects their own Linear account; logic functions can then create issues and read team data on their behalf.',
|
||||
logoUrl: 'public/linear-logomark.svg',
|
||||
defaultRoleUniversalIdentifier: DEFAULT_ROLE_UNIVERSAL_IDENTIFIER,
|
||||
// OAuth client_id/secret live at the registration level (one OAuth app per
|
||||
// Twenty server, configured by the server admin) — not per-workspace —
|
||||
// so they're declared as serverVariables, not applicationVariables.
|
||||
aboutDescription: ABOUT_DESCRIPTION,
|
||||
applicationVariables: undefined,
|
||||
author: 'Twenty',
|
||||
category: 'Product management',
|
||||
emailSupport: '[email protected]',
|
||||
screenshots: [
|
||||
'public/gallery/command-menu-item-1.png',
|
||||
'public/gallery/command-menu-item-2.png',
|
||||
'public/gallery/command-menu-item-3.png',
|
||||
'public/gallery/command-menu-item-4.png',
|
||||
],
|
||||
termsUrl: 'https://github.com/twentyhq/twenty?tab=License-1-ov-file#readme',
|
||||
websiteUrl: 'https://www.twenty.com',
|
||||
serverVariables: {
|
||||
LINEAR_CLIENT_ID: {
|
||||
description:
|
||||
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
import { defineCommandMenuItem } from 'twenty-sdk/define';
|
||||
|
||||
import {
|
||||
CREATE_ISSUE_COMMAND_UNIVERSAL_IDENTIFIER,
|
||||
CREATE_ISSUE_FORM_FRONT_COMPONENT_UNIVERSAL_IDENTIFIER,
|
||||
} from 'src/constants/universal-identifiers';
|
||||
|
||||
export default defineCommandMenuItem({
|
||||
universalIdentifier: CREATE_ISSUE_COMMAND_UNIVERSAL_IDENTIFIER,
|
||||
label: 'Create Linear issue',
|
||||
shortLabel: 'Linear issue',
|
||||
icon: 'IconPlaylistAdd',
|
||||
isPinned: false,
|
||||
availabilityType: 'GLOBAL',
|
||||
frontComponentUniversalIdentifier:
|
||||
CREATE_ISSUE_FORM_FRONT_COMPONENT_UNIVERSAL_IDENTIFIER,
|
||||
});
|
||||
+1015
File diff suppressed because it is too large
Load Diff
+1
-3
@@ -15,8 +15,6 @@ export default defineConnectionProvider({
|
||||
clientIdVariable: 'LINEAR_CLIENT_ID',
|
||||
clientSecretVariable: 'LINEAR_CLIENT_SECRET',
|
||||
tokenRequestContentType: 'form-urlencoded',
|
||||
// Linear supports PKCE but doesn't require it for confidential clients.
|
||||
// Disabled to keep the test surface minimal.
|
||||
usePkce: false,
|
||||
usePkce: true,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
export const ABOUT_DESCRIPTION = `Connect your Linear account to Twenty to create issues and look up teams straight from your workflows or the AI chat.
|
||||
|
||||
## What you can do
|
||||
|
||||
Once installed and connected, two tools become available:
|
||||
|
||||
- **Create Linear issue**
|
||||
- From the AI chat, ask something like *"create a Linear issue in the Engineering team titled 'Fix login bug'"* and the AI will file it for you.
|
||||
- From a workflow, add it as a step with \`teamId\` + \`title\` (and optional \`description\`).
|
||||
|
||||
- **List Linear teams** — discovers the teams in your Linear workspace, useful when you need to pick a \`teamId\` for the create-issue step.
|
||||
|
||||
## Installing
|
||||
|
||||
1. Open **Settings → Applications** in your Twenty workspace.
|
||||
2. Find **Linear** in the available apps and click **Install**.
|
||||
3. Open the app, go to the **Connections** tab, and click **Add connection**.
|
||||
4. Choose **Just for me** (your personal Linear account) or **Workspace shared** (a team-managed Linear account anyone in this workspace can act through), then complete the Linear sign-in.
|
||||
|
||||
That's it — you can now use the tools above.`;
|
||||
@@ -17,3 +17,24 @@ export const CREATE_LINEAR_ISSUE_UNIVERSAL_IDENTIFIER =
|
||||
|
||||
export const LIST_LINEAR_TEAMS_UNIVERSAL_IDENTIFIER =
|
||||
'15824bbc-9c64-4f97-b45f-d0a44b402bb8';
|
||||
|
||||
export const LIST_LINEAR_TEAMS_ROUTE_UNIVERSAL_IDENTIFIER =
|
||||
'a1d4e7b3-5c2f-4a89-9b0e-6f3d8c1a7e5b';
|
||||
|
||||
export const CREATE_LINEAR_ISSUE_ROUTE_UNIVERSAL_IDENTIFIER =
|
||||
'c8f2a6d1-3b7e-4e09-8d5c-2a9f0b4e6c3d';
|
||||
|
||||
export const CREATE_ISSUE_FORM_FRONT_COMPONENT_UNIVERSAL_IDENTIFIER =
|
||||
'd4a1c8e5-7f3b-4d62-a90e-1b5c3f8d2a6e';
|
||||
|
||||
export const LIST_LINEAR_WORKFLOW_STATES_ROUTE_UNIVERSAL_IDENTIFIER =
|
||||
'f5a2d8c1-4b7e-4f93-a6d0-9c3e1b8f5a2d';
|
||||
|
||||
export const LIST_LINEAR_ISSUE_OPTIONS_ROUTE_UNIVERSAL_IDENTIFIER =
|
||||
'a3b7e1d9-8c4f-4a26-b5d0-7e9f2c6a8b3d';
|
||||
|
||||
export const LIST_LINEAR_ISSUE_OPTIONS_UNIVERSAL_IDENTIFIER =
|
||||
'c2b99086-6c1b-43e4-9685-de4ade6bda63';
|
||||
|
||||
export const CREATE_ISSUE_COMMAND_UNIVERSAL_IDENTIFIER =
|
||||
'e7b3d9f2-6a1c-4e85-b4d0-8f2c5a7e3b19';
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
import { defineLogicFunction } from 'twenty-sdk/define';
|
||||
import type { RoutePayload } from 'twenty-sdk/define';
|
||||
|
||||
import { CREATE_LINEAR_ISSUE_ROUTE_UNIVERSAL_IDENTIFIER } from 'src/constants/universal-identifiers';
|
||||
import { createLinearIssueHandler } from 'src/logic-functions/handlers/create-linear-issue-handler';
|
||||
|
||||
const handler = async (event: RoutePayload) => {
|
||||
const body = event.body as Record<string, unknown> | null;
|
||||
|
||||
return createLinearIssueHandler({
|
||||
teamId: body?.teamId as string | undefined,
|
||||
title: body?.title as string | undefined,
|
||||
description: body?.description as string | undefined,
|
||||
priority: body?.priority as number | undefined,
|
||||
stateId: body?.stateId as string | undefined,
|
||||
assigneeId: body?.assigneeId as string | undefined,
|
||||
projectId: body?.projectId as string | undefined,
|
||||
estimate: body?.estimate as number | undefined,
|
||||
labelIds: body?.labelIds as string[] | undefined,
|
||||
cycleId: body?.cycleId as string | undefined,
|
||||
dueDate: body?.dueDate as string | undefined,
|
||||
});
|
||||
};
|
||||
|
||||
export default defineLogicFunction({
|
||||
universalIdentifier: CREATE_LINEAR_ISSUE_ROUTE_UNIVERSAL_IDENTIFIER,
|
||||
name: 'create-linear-issue-route',
|
||||
timeoutSeconds: 30,
|
||||
handler,
|
||||
httpRouteTriggerSettings: {
|
||||
path: '/linear/issues',
|
||||
httpMethod: 'POST',
|
||||
isAuthRequired: true,
|
||||
},
|
||||
});
|
||||
+47
@@ -27,6 +27,45 @@ export default defineLogicFunction({
|
||||
type: 'string',
|
||||
description: 'Optional issue description (Markdown supported).',
|
||||
},
|
||||
priority: {
|
||||
type: 'integer',
|
||||
description:
|
||||
'Issue priority: 0 = No priority, 1 = Urgent, 2 = High, 3 = Medium, 4 = Low.',
|
||||
minimum: 0,
|
||||
maximum: 4,
|
||||
},
|
||||
stateId: {
|
||||
type: 'string',
|
||||
description:
|
||||
'The workflow state ID for the issue status. Use list-linear-issue-options to discover available states for a team.',
|
||||
},
|
||||
assigneeId: {
|
||||
type: 'string',
|
||||
description:
|
||||
'The user ID to assign the issue to. Use list-linear-issue-options to discover team members.',
|
||||
},
|
||||
projectId: {
|
||||
type: 'string',
|
||||
description: 'The project ID to associate the issue with.',
|
||||
},
|
||||
estimate: {
|
||||
type: 'number',
|
||||
description:
|
||||
'The estimate value for the issue. Must match the team estimate scale.',
|
||||
},
|
||||
labelIds: {
|
||||
type: 'array',
|
||||
items: { type: 'string' },
|
||||
description: 'Array of label IDs to apply to the issue.',
|
||||
},
|
||||
cycleId: {
|
||||
type: 'string',
|
||||
description: 'The cycle ID to add the issue to.',
|
||||
},
|
||||
dueDate: {
|
||||
type: 'string',
|
||||
description: 'Due date in YYYY-MM-DD format.',
|
||||
},
|
||||
},
|
||||
required: ['teamId', 'title'],
|
||||
},
|
||||
@@ -40,6 +79,14 @@ export default defineLogicFunction({
|
||||
teamId: { type: 'string' },
|
||||
title: { type: 'string' },
|
||||
description: { type: 'string' },
|
||||
priority: { type: 'number' },
|
||||
stateId: { type: 'string' },
|
||||
assigneeId: { type: 'string' },
|
||||
projectId: { type: 'string' },
|
||||
estimate: { type: 'number' },
|
||||
labelIds: { type: 'array', items: { type: 'string' } },
|
||||
cycleId: { type: 'string' },
|
||||
dueDate: { type: 'string' },
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
+11
@@ -49,6 +49,17 @@ export const createLinearIssueHandler = async (
|
||||
teamId: input.teamId,
|
||||
title: input.title,
|
||||
description: input.description,
|
||||
...(input.priority !== undefined && { priority: input.priority }),
|
||||
...(input.stateId !== undefined && { stateId: input.stateId }),
|
||||
...(input.assigneeId !== undefined && {
|
||||
assigneeId: input.assigneeId,
|
||||
}),
|
||||
...(input.projectId !== undefined && { projectId: input.projectId }),
|
||||
...(input.estimate !== undefined && { estimate: input.estimate }),
|
||||
...(input.labelIds !== undefined &&
|
||||
input.labelIds.length > 0 && { labelIds: input.labelIds }),
|
||||
...(input.cycleId !== undefined && { cycleId: input.cycleId }),
|
||||
...(input.dueDate !== undefined && { dueDate: input.dueDate }),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
import { listConnections } from 'twenty-sdk/logic-function';
|
||||
|
||||
import { callLinearGraphQL } from 'src/logic-functions/utils/call-linear-graphql';
|
||||
|
||||
type LinearMember = {
|
||||
id: string;
|
||||
name: string;
|
||||
displayName: string;
|
||||
};
|
||||
|
||||
type LinearProject = {
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
type LinearLabel = {
|
||||
id: string;
|
||||
name: string;
|
||||
color: string;
|
||||
};
|
||||
|
||||
type LinearCycle = {
|
||||
id: string;
|
||||
name: string | null;
|
||||
number: number;
|
||||
startsAt: string;
|
||||
endsAt: string;
|
||||
};
|
||||
|
||||
type LinearWorkflowState = {
|
||||
id: string;
|
||||
name: string;
|
||||
type: string;
|
||||
position: number;
|
||||
};
|
||||
|
||||
type IssueOptionsQueryResult = {
|
||||
team: {
|
||||
states: { nodes: LinearWorkflowState[] };
|
||||
members: { nodes: LinearMember[] };
|
||||
cycles: { nodes: LinearCycle[] };
|
||||
issueEstimationType: string;
|
||||
issueEstimationAllowZero: boolean;
|
||||
};
|
||||
projects: { nodes: LinearProject[] };
|
||||
issueLabels: { nodes: LinearLabel[] };
|
||||
};
|
||||
|
||||
type IssueOptions = {
|
||||
states: LinearWorkflowState[];
|
||||
members: LinearMember[];
|
||||
projects: LinearProject[];
|
||||
labels: LinearLabel[];
|
||||
cycles: LinearCycle[];
|
||||
estimationType: string;
|
||||
estimationAllowZero: boolean;
|
||||
};
|
||||
|
||||
type HandlerResult =
|
||||
| { success: true; options: IssueOptions }
|
||||
| { success: false; error: string };
|
||||
|
||||
export const listLinearIssueOptionsHandler = async (input: {
|
||||
teamId?: string;
|
||||
}): Promise<HandlerResult> => {
|
||||
if (!input.teamId) {
|
||||
return { success: false, error: '`teamId` is required.' };
|
||||
}
|
||||
|
||||
const connections = await listConnections({ providerName: 'linear' });
|
||||
const connection =
|
||||
connections.find((c) => c.visibility === 'workspace') ?? connections[0];
|
||||
|
||||
if (!connection) {
|
||||
return {
|
||||
success: false,
|
||||
error:
|
||||
'Linear is not connected. Open the app settings and click "Add connection" first.',
|
||||
};
|
||||
}
|
||||
|
||||
const result = await callLinearGraphQL<IssueOptionsQueryResult>({
|
||||
accessToken: connection.accessToken,
|
||||
query: `
|
||||
query IssueOptions($teamId: String!) {
|
||||
team(id: $teamId) {
|
||||
states { nodes { id name type position } }
|
||||
members { nodes { id name displayName } }
|
||||
cycles { nodes { id name number startsAt endsAt } }
|
||||
issueEstimationType
|
||||
issueEstimationAllowZero
|
||||
}
|
||||
projects { nodes { id name } }
|
||||
issueLabels { nodes { id name color } }
|
||||
}
|
||||
`,
|
||||
variables: { teamId: input.teamId },
|
||||
});
|
||||
|
||||
if (result.errors || !result.data) {
|
||||
return {
|
||||
success: false,
|
||||
error: result.errors?.[0]?.message ?? 'Unknown Linear API error',
|
||||
};
|
||||
}
|
||||
|
||||
const { team, projects, issueLabels } = result.data;
|
||||
|
||||
const now = new Date().toISOString();
|
||||
const activeCycles = team.cycles.nodes.filter((c) => c.endsAt >= now);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
options: {
|
||||
states: team.states.nodes.sort((a, b) => a.position - b.position),
|
||||
members: team.members.nodes.sort((a, b) =>
|
||||
a.displayName.localeCompare(b.displayName),
|
||||
),
|
||||
projects: projects.nodes.sort((a, b) => a.name.localeCompare(b.name)),
|
||||
labels: issueLabels.nodes.sort((a, b) => a.name.localeCompare(b.name)),
|
||||
cycles: activeCycles.sort(
|
||||
(a, b) =>
|
||||
new Date(a.startsAt).getTime() - new Date(b.startsAt).getTime(),
|
||||
),
|
||||
estimationType: team.issueEstimationType,
|
||||
estimationAllowZero: team.issueEstimationAllowZero,
|
||||
},
|
||||
};
|
||||
};
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
import { listConnections } from 'twenty-sdk/logic-function';
|
||||
|
||||
import { callLinearGraphQL } from 'src/logic-functions/utils/call-linear-graphql';
|
||||
|
||||
type LinearWorkflowState = {
|
||||
id: string;
|
||||
name: string;
|
||||
type: string;
|
||||
position: number;
|
||||
};
|
||||
|
||||
type WorkflowStatesQueryResult = {
|
||||
team: { states: { nodes: LinearWorkflowState[] } };
|
||||
};
|
||||
|
||||
type HandlerResult =
|
||||
| { success: true; states: LinearWorkflowState[] }
|
||||
| { success: false; error: string };
|
||||
|
||||
export const listLinearWorkflowStatesHandler = async (input: {
|
||||
teamId?: string;
|
||||
}): Promise<HandlerResult> => {
|
||||
if (!input.teamId) {
|
||||
return { success: false, error: '`teamId` is required.' };
|
||||
}
|
||||
|
||||
const connections = await listConnections({ providerName: 'linear' });
|
||||
const connection =
|
||||
connections.find((c) => c.visibility === 'workspace') ?? connections[0];
|
||||
|
||||
if (!connection) {
|
||||
return {
|
||||
success: false,
|
||||
error:
|
||||
'Linear is not connected. Open the app settings and click "Add connection" first.',
|
||||
};
|
||||
}
|
||||
|
||||
const result = await callLinearGraphQL<WorkflowStatesQueryResult>({
|
||||
accessToken: connection.accessToken,
|
||||
query: `
|
||||
query WorkflowStates($teamId: String!) {
|
||||
team(id: $teamId) {
|
||||
states { nodes { id name type position } }
|
||||
}
|
||||
}
|
||||
`,
|
||||
variables: { teamId: input.teamId },
|
||||
});
|
||||
|
||||
if (result.errors || !result.data) {
|
||||
return {
|
||||
success: false,
|
||||
error: result.errors?.[0]?.message ?? 'Unknown Linear API error',
|
||||
};
|
||||
}
|
||||
|
||||
const states = result.data.team.states.nodes.sort(
|
||||
(a, b) => a.position - b.position,
|
||||
);
|
||||
|
||||
return { success: true, states };
|
||||
};
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
import { defineLogicFunction } from 'twenty-sdk/define';
|
||||
import type { RoutePayload } from 'twenty-sdk/define';
|
||||
|
||||
import { LIST_LINEAR_ISSUE_OPTIONS_ROUTE_UNIVERSAL_IDENTIFIER } from 'src/constants/universal-identifiers';
|
||||
import { listLinearIssueOptionsHandler } from 'src/logic-functions/handlers/list-linear-issue-options-handler';
|
||||
|
||||
const handler = async (event: RoutePayload) => {
|
||||
return listLinearIssueOptionsHandler({
|
||||
teamId: event.queryStringParameters?.teamId,
|
||||
});
|
||||
};
|
||||
|
||||
export default defineLogicFunction({
|
||||
universalIdentifier: LIST_LINEAR_ISSUE_OPTIONS_ROUTE_UNIVERSAL_IDENTIFIER,
|
||||
name: 'list-linear-issue-options-route',
|
||||
timeoutSeconds: 15,
|
||||
handler,
|
||||
httpRouteTriggerSettings: {
|
||||
path: '/linear/issue-options',
|
||||
httpMethod: 'GET',
|
||||
isAuthRequired: true,
|
||||
},
|
||||
});
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
import { defineLogicFunction } from 'twenty-sdk/define';
|
||||
|
||||
import { LIST_LINEAR_ISSUE_OPTIONS_UNIVERSAL_IDENTIFIER } from 'src/constants/universal-identifiers';
|
||||
import { listLinearIssueOptionsHandler } from 'src/logic-functions/handlers/list-linear-issue-options-handler';
|
||||
|
||||
export default defineLogicFunction({
|
||||
universalIdentifier: LIST_LINEAR_ISSUE_OPTIONS_UNIVERSAL_IDENTIFIER,
|
||||
name: 'list-linear-issue-options',
|
||||
description:
|
||||
'Returns available options for creating a Linear issue in a specific team: workflow states, members, projects, labels, cycles, and estimation settings. Requires a teamId (call list-linear-teams to discover one).',
|
||||
timeoutSeconds: 15,
|
||||
handler: listLinearIssueOptionsHandler,
|
||||
toolTriggerSettings: {
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
teamId: {
|
||||
type: 'string',
|
||||
description:
|
||||
'The Linear team ID to fetch issue options for. Use list-linear-teams to discover available teams.',
|
||||
},
|
||||
},
|
||||
required: ['teamId'],
|
||||
},
|
||||
},
|
||||
workflowActionTriggerSettings: {
|
||||
label: 'List Linear Issue Options',
|
||||
inputSchema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
teamId: { type: 'string' },
|
||||
},
|
||||
},
|
||||
],
|
||||
outputSchema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
success: { type: 'boolean' },
|
||||
options: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
states: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string' },
|
||||
name: { type: 'string' },
|
||||
type: { type: 'string' },
|
||||
position: { type: 'number' },
|
||||
},
|
||||
},
|
||||
},
|
||||
members: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string' },
|
||||
name: { type: 'string' },
|
||||
displayName: { type: 'string' },
|
||||
},
|
||||
},
|
||||
},
|
||||
projects: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string' },
|
||||
name: { type: 'string' },
|
||||
},
|
||||
},
|
||||
},
|
||||
labels: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string' },
|
||||
name: { type: 'string' },
|
||||
color: { type: 'string' },
|
||||
},
|
||||
},
|
||||
},
|
||||
cycles: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string' },
|
||||
name: { type: 'string' },
|
||||
number: { type: 'number' },
|
||||
startsAt: { type: 'string' },
|
||||
endsAt: { type: 'string' },
|
||||
},
|
||||
},
|
||||
},
|
||||
estimationType: { type: 'string' },
|
||||
estimationAllowZero: { type: 'boolean' },
|
||||
},
|
||||
},
|
||||
error: { type: 'string' },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
import { defineLogicFunction } from 'twenty-sdk/define';
|
||||
import type { RoutePayload } from 'twenty-sdk/define';
|
||||
|
||||
import { LIST_LINEAR_TEAMS_ROUTE_UNIVERSAL_IDENTIFIER } from 'src/constants/universal-identifiers';
|
||||
import { listLinearTeamsHandler } from 'src/logic-functions/handlers/list-linear-teams-handler';
|
||||
|
||||
const handler = async (_event: RoutePayload) => {
|
||||
return listLinearTeamsHandler();
|
||||
};
|
||||
|
||||
export default defineLogicFunction({
|
||||
universalIdentifier: LIST_LINEAR_TEAMS_ROUTE_UNIVERSAL_IDENTIFIER,
|
||||
name: 'list-linear-teams-route',
|
||||
timeoutSeconds: 15,
|
||||
handler,
|
||||
httpRouteTriggerSettings: {
|
||||
path: '/linear/teams',
|
||||
httpMethod: 'GET',
|
||||
isAuthRequired: true,
|
||||
},
|
||||
});
|
||||
@@ -16,4 +16,33 @@ export default defineLogicFunction({
|
||||
properties: {},
|
||||
},
|
||||
},
|
||||
workflowActionTriggerSettings: {
|
||||
label: 'List Linear Teams',
|
||||
inputSchema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {},
|
||||
},
|
||||
],
|
||||
outputSchema: [
|
||||
{
|
||||
type: 'object',
|
||||
properties: {
|
||||
success: { type: 'boolean' },
|
||||
teams: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string' },
|
||||
name: { type: 'string' },
|
||||
key: { type: 'string' },
|
||||
},
|
||||
},
|
||||
},
|
||||
error: { type: 'string' },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
import { defineLogicFunction } from 'twenty-sdk/define';
|
||||
import type { RoutePayload } from 'twenty-sdk/define';
|
||||
|
||||
import { LIST_LINEAR_WORKFLOW_STATES_ROUTE_UNIVERSAL_IDENTIFIER } from 'src/constants/universal-identifiers';
|
||||
import { listLinearWorkflowStatesHandler } from 'src/logic-functions/handlers/list-linear-workflow-states-handler';
|
||||
|
||||
const handler = async (event: RoutePayload) => {
|
||||
return listLinearWorkflowStatesHandler({
|
||||
teamId: event.queryStringParameters?.teamId,
|
||||
});
|
||||
};
|
||||
|
||||
export default defineLogicFunction({
|
||||
universalIdentifier: LIST_LINEAR_WORKFLOW_STATES_ROUTE_UNIVERSAL_IDENTIFIER,
|
||||
name: 'list-linear-workflow-states-route',
|
||||
timeoutSeconds: 15,
|
||||
handler,
|
||||
httpRouteTriggerSettings: {
|
||||
path: '/linear/workflow-states',
|
||||
httpMethod: 'GET',
|
||||
isAuthRequired: true,
|
||||
},
|
||||
});
|
||||
+8
@@ -2,4 +2,12 @@ export type CreateIssueInput = {
|
||||
teamId?: string;
|
||||
title?: string;
|
||||
description?: string;
|
||||
priority?: number;
|
||||
stateId?: string;
|
||||
assigneeId?: string;
|
||||
projectId?: string;
|
||||
estimate?: number;
|
||||
labelIds?: string[];
|
||||
cycleId?: string;
|
||||
dueDate?: string;
|
||||
};
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import { defineRole } from 'twenty-sdk/define';
|
||||
import { defineApplicationRole } from 'twenty-sdk/define';
|
||||
|
||||
import { DEFAULT_ROLE_UNIVERSAL_IDENTIFIER } from 'src/constants/universal-identifiers';
|
||||
|
||||
// The Linear logic functions never read workspace data — they only call
|
||||
// Linear's GraphQL API on behalf of the connected user.
|
||||
export default defineRole({
|
||||
export default defineApplicationRole({
|
||||
universalIdentifier: DEFAULT_ROLE_UNIVERSAL_IDENTIFIER,
|
||||
label: 'Linear function role',
|
||||
description: 'No-op role for Linear logic functions',
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
"declaration": true,
|
||||
"outDir": "./dist",
|
||||
"rootDir": ".",
|
||||
"jsx": "react-jsx",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
@@ -17,7 +18,7 @@
|
||||
"strictBindCallApply": false,
|
||||
"target": "es2020",
|
||||
"module": "esnext",
|
||||
"lib": ["es2020"],
|
||||
"lib": ["es2020", "dom"],
|
||||
"skipLibCheck": true,
|
||||
"skipDefaultLibCheck": true,
|
||||
"resolveJsonModule": true,
|
||||
|
||||
@@ -3736,15 +3736,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"twenty-client-sdk@npm:2.3.0":
|
||||
version: 2.3.0
|
||||
resolution: "twenty-client-sdk@npm:2.3.0"
|
||||
"twenty-client-sdk@npm:2.3.1":
|
||||
version: 2.3.1
|
||||
resolution: "twenty-client-sdk@npm:2.3.1"
|
||||
dependencies:
|
||||
"@genql/cli": "npm:^3.0.3"
|
||||
"@genql/runtime": "npm:^2.10.0"
|
||||
esbuild: "npm:^0.25.0"
|
||||
graphql: "npm:^16.8.1"
|
||||
checksum: 10c0/ab9a4f4ea9222eebdab6d80f396e5281cc0b78bc571163bc8a4f302afc38989ded21c67e0a8e2aad3cdad20f5ec24f60cd2286d9b38a86f7a77333aff5500b20
|
||||
checksum: 10c0/b82a40b6411857345e40b81d32f7069364c6795e79306447d1c21b441315016d8c27ee2c128cd97b82379221812cb18bb556eb37dea337e83b05873b9bfc6c6f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -3754,16 +3754,16 @@ __metadata:
|
||||
dependencies:
|
||||
"@types/node": "npm:^24.7.2"
|
||||
oxlint: "npm:^0.16.0"
|
||||
twenty-sdk: "npm:2.3.0"
|
||||
twenty-sdk: "npm:2.3.1"
|
||||
typescript: "npm:^5.9.3"
|
||||
vite-tsconfig-paths: "npm:^4.3.2"
|
||||
vitest: "npm:^3.1.1"
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"twenty-sdk@npm:2.3.0":
|
||||
version: 2.3.0
|
||||
resolution: "twenty-sdk@npm:2.3.0"
|
||||
"twenty-sdk@npm:2.3.1":
|
||||
version: 2.3.1
|
||||
resolution: "twenty-sdk@npm:2.3.1"
|
||||
dependencies:
|
||||
"@genql/cli": "npm:^3.0.3"
|
||||
"@genql/runtime": "npm:^2.10.0"
|
||||
@@ -3783,7 +3783,7 @@ __metadata:
|
||||
react: "npm:^19.0.0"
|
||||
react-dom: "npm:^19.0.0"
|
||||
tinyglobby: "npm:^0.2.15"
|
||||
twenty-client-sdk: "npm:2.3.0"
|
||||
twenty-client-sdk: "npm:2.3.1"
|
||||
typescript: "npm:^5.9.2"
|
||||
uuid: "npm:^13.0.0"
|
||||
vite: "npm:^7.0.0"
|
||||
@@ -3791,7 +3791,7 @@ __metadata:
|
||||
zod: "npm:^4.1.11"
|
||||
bin:
|
||||
twenty: dist/cli.cjs
|
||||
checksum: 10c0/8020481e7500472ec841574458ed18a20588e31f51a8ff9b86e8ceddc933afd9e34840e4130b1aab53b66c35ea7e6b571d2f2dd7b35836bac96f487d84239c1f
|
||||
checksum: 10c0/137a7a7e6d46175019406a21694103100e744e49154f2de5529962249ab06b9fc8240bc097fd2f231b315b6b8504ba3b45279e22aa80bdb9e735cd2570497eac
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# twenty-claude-skills
|
||||
|
||||
Claude skills for working with Twenty.
|
||||
|
||||
Add skills under `skills/<skill-name>/SKILL.md`.
|
||||
|
||||
## Skills
|
||||
|
||||
- `twenty-record-presentation`: Retrieve and present Twenty CRM records as readable summaries or tables.
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "twenty-claude-skills",
|
||||
"private": true,
|
||||
"version": "0.1.0",
|
||||
"description": "Claude skills for working with Twenty.",
|
||||
"license": "AGPL-3.0",
|
||||
"files": [
|
||||
"skills"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
---
|
||||
name: twenty-record-presentation
|
||||
description: "Retrieve and present Twenty CRM records as readable summaries or tables, using the connected Twenty MCP server to discover fields, fetch relevant data, format dates and values, build record links, and avoid raw API output."
|
||||
---
|
||||
|
||||
# Twenty Record Presentation
|
||||
|
||||
## Overview
|
||||
|
||||
Retrieve the Twenty records needed to answer the user's question, then present them as a useful answer, not as raw API output. Always translate technical fields, timestamps, IDs, and nested structures into readable summaries that help the user scan, compare, and act.
|
||||
|
||||
## Retrieval Workflow
|
||||
|
||||
Use the selected connected Twenty MCP server when it is available
|
||||
|
||||
- `get_tool_catalog` → `learn_tools` → `execute_tool`
|
||||
- Discover the relevant object, fields, filters, and sort options instead of guessing exact API names.
|
||||
- Retrieve only the fields needed for the answer, plus the fields needed for ordering or disambiguation.
|
||||
- For "latest", "most recent", or "recent" requests, include the relevant timestamp field used for sorting.
|
||||
- If the user asks for a broad list, apply a practical limit and state how many records are shown.
|
||||
- If required context is missing and cannot be discovered from the tools, ask one concise clarifying question.
|
||||
- If no Twenty MCP tools are available, say that no callable Twenty MCP server is available in the current thread and ask the user to connect or expose the intended workspace.
|
||||
|
||||
## Response Shape
|
||||
|
||||
Start with the answer or count, then show the records in the clearest compact shape:
|
||||
|
||||
- For one record, use a labeled block.
|
||||
- For 2 to 10 comparable records, use a Markdown table.
|
||||
- For larger sets, show the most relevant rows first, mention the total, and offer the next useful filter or page only when needed.
|
||||
- For nested records, summarize the important nested values instead of dumping JSON.
|
||||
- When comparing records across workspaces, prefer one combined table with a Workspace column if it improves scanning. Use separate sections only when each workspace needs different columns.
|
||||
|
||||
Use English labels and prose. Keep user-provided names, record values, emails, URLs, and proper nouns unchanged.
|
||||
|
||||
## Record Links
|
||||
|
||||
Link records back to their original Twenty context whenever the workspace origin and record identity are known.
|
||||
|
||||
- Build record links with the Twenty show-page path: `/object/:objectNameSingular/:objectRecordId`.
|
||||
- For absolute links, combine the workspace origin with that path, for example `https://example.twenty.com/object/person/record-id`.
|
||||
- Use `recordReferences` from MCP responses when available to get `objectNameSingular`, `recordId`, and `displayName`.
|
||||
- If `recordReferences` is missing, use the record's `id` and the object name from the tool that returned it.
|
||||
- Prefer linking the record display name in tables and summaries instead of adding a raw ID column.
|
||||
- When showing records from multiple workspaces, generate links with each record's own workspace origin.
|
||||
- If the workspace origin is unknown, do not invent a hostname. Add a compact Record column with the object name and record ID, or say that direct links need the workspace URL.
|
||||
|
||||
## Dates and Times
|
||||
|
||||
Never expose ISO/RFC3339 timestamps as the main date display.
|
||||
|
||||
- Parse common technical formats such as `2026-05-05T09:43:18.123Z`, `2026-05-05T09:43:18+02:00`, Unix seconds, and Unix milliseconds.
|
||||
- Convert instants with `Z` or an explicit offset to the user's timezone when known. If timezone is unknown, keep the source timezone or ask only when it changes the meaning.
|
||||
- Preserve date-only values as dates. Do not shift date-only values across timezones.
|
||||
- Display absolute dates. Use relative words such as "today", "yesterday", or "last week" only as a supplement when helpful.
|
||||
- Include the year unless it is truly redundant in a small same-year table.
|
||||
- Show seconds and milliseconds only when they matter for debugging, audit logs, or ordering events with near-identical times.
|
||||
|
||||
Examples, with user timezone Europe/Paris, UTC+2 in May:
|
||||
|
||||
- Timestamp: `2026-05-05T09:43:18.123Z` → May 5, 2026, 11:43 AM
|
||||
- Date-only value: `2026-05-05` → May 5, 2026
|
||||
|
||||
If the exact raw timestamp is relevant, put it after the readable value:
|
||||
|
||||
- Created: May 5, 2026, 11:43 AM (raw: `2026-05-05T09:43:18.123Z`)
|
||||
|
||||
## Field Labels
|
||||
|
||||
Convert raw field names into user-facing labels:
|
||||
|
||||
- `createdAt` → Created
|
||||
- `updatedAt` → Last updated
|
||||
- `deletedAt` → Deleted
|
||||
- `createdBy` → Created by
|
||||
- `workspaceMemberId` → Workspace member
|
||||
- `opportunityStage` → Opportunity stage
|
||||
|
||||
Prefer the label users see in Twenty when it is available from metadata. Otherwise, split camelCase, snake_case, and kebab-case into normal words.
|
||||
|
||||
## Value Formatting
|
||||
|
||||
Format values by meaning:
|
||||
|
||||
- **Empty or null**: Not set, or omit if the field is irrelevant.
|
||||
- **Booleans**: Yes / No.
|
||||
- **Money**: include currency and grouping, for example EUR 12,450 or USD 12,450 based on the record currency.
|
||||
- **Percentages**: use `%`, round only enough to stay meaningful.
|
||||
- **URLs and emails**: make them clickable Markdown links when useful.
|
||||
- **IDs and UUIDs**: hide by default unless the user asks for identifiers, deduplication, debugging, or exact references.
|
||||
- **Arrays**: show the count and the most important names, not the full serialized array.
|
||||
|
||||
## Record Ordering
|
||||
|
||||
When the user asks for "latest", "recent", or "last records":
|
||||
|
||||
- State which date field was used when it is not obvious, for example *sorted by Last updated*.
|
||||
- Prefer `updatedAt` for "recent activity" and `createdAt` for "newest records" unless the user's wording or object semantics points to another date.
|
||||
- Display the chosen date column in readable form.
|
||||
- If multiple records share the same date, keep a deterministic secondary order such as name or ID.
|
||||
|
||||
## Table Alignment
|
||||
|
||||
Make tables easy to scan before making them visually decorative.
|
||||
|
||||
- Use Markdown alignment markers intentionally: text columns left-aligned (`:---`), numeric money/count columns right-aligned (`---:`), and short status columns centered only when that actually improves scanning (`:---:`).
|
||||
- Keep record names on a stable left edge. If rows have favicons, use a dedicated narrow Icon column followed by a linked record-name column.
|
||||
- If the table is compact and the image is known to be consistently small, it is acceptable to put ` [Name](record-url)` in one cell. Do not also add emoji or extra symbols before the name.
|
||||
- Keep fixed-format fields such as Created, Updated, Amount, and Source to the right of variable-width fields such as Name, Company, Person, and Domain.
|
||||
- Use a consistent date format within a table so rows line up visually, for example *May 5, 2026, 11:43 AM* or *May 5, 11:43*.
|
||||
- Prefer natural links over extra link columns: link the record name to Twenty, and link the domain or email only when that external destination is useful.
|
||||
- Avoid raw ID columns in normal user-facing tables. IDs are long, visually dominant, and destroy alignment unless the user asks for them.
|
||||
|
||||
## Markdown Patterns
|
||||
|
||||
### Compact table
|
||||
|
||||
Use a compact table for comparable records:
|
||||
|
||||
```markdown
|
||||
I found 5 recent opportunities, sorted by last updated date.
|
||||
|
||||
| Name | Stage | Amount | Last updated |
|
||||
| :--- | :--- | ---: | :--- |
|
||||
| [Acme renewal](https://example.twenty.com/object/opportunity/record-id-1) | Negotiation | EUR 12,450 | May 5, 2026, 11:43 AM |
|
||||
| [Globex expansion](https://example.twenty.com/object/opportunity/record-id-2) | Discovery | EUR 8,000 | May 4, 2026, 4:10 PM |
|
||||
```
|
||||
|
||||
### Labeled block
|
||||
|
||||
Use a labeled block for one important record:
|
||||
|
||||
```markdown
|
||||
**[Acme renewal](https://example.twenty.com/object/opportunity/record-id-1)**
|
||||
|
||||
- Stage: Negotiation
|
||||
- Amount: EUR 12,450
|
||||
- Next action: Not set
|
||||
- Last updated: May 5, 2026, 11:43 AM
|
||||
```
|
||||
|
||||
## Raw Data Exceptions
|
||||
|
||||
Show raw JSON, raw timestamps, internal IDs, or full nested objects only when the user asks for debugging, export, exact API payloads, schema inspection, or reproducible commands. Even then, put a readable summary before the raw block.
|
||||
|
||||
Example:
|
||||
|
||||
> Acme renewal — Negotiation stage, EUR 12,450, last updated May 5, 2026, 11:43 AM. Full payload below:
|
||||
>
|
||||
> ```json
|
||||
> {
|
||||
> "id": "record-id-1",
|
||||
> "name": "Acme renewal",
|
||||
> "stage": "NEGOTIATION",
|
||||
> "amountMicros": "12450000000",
|
||||
> "currencyCode": "EUR",
|
||||
> "updatedAt": "2026-05-05T09:43:18.123Z"
|
||||
> }
|
||||
> ```
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "twenty-client-sdk",
|
||||
"version": "2.3.0",
|
||||
"version": "2.4.0",
|
||||
"sideEffects": false,
|
||||
"license": "AGPL-3.0",
|
||||
"scripts": {
|
||||
|
||||
@@ -932,6 +932,7 @@ type Workspace {
|
||||
isMicrosoftAuthEnabled: Boolean!
|
||||
isMicrosoftAuthBypassEnabled: Boolean!
|
||||
isCustomDomainEnabled: Boolean!
|
||||
isInternalMessagesImportEnabled: Boolean!
|
||||
editableProfileFields: [String!]
|
||||
defaultRole: Role
|
||||
fastModel: String!
|
||||
@@ -1747,17 +1748,13 @@ type FeatureFlag {
|
||||
enum FeatureFlagKey {
|
||||
IS_UNIQUE_INDEXES_ENABLED
|
||||
IS_JSON_FILTER_ENABLED
|
||||
IS_COMMAND_MENU_ITEM_ENABLED
|
||||
IS_MARKETPLACE_SETTING_TAB_VISIBLE
|
||||
IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED
|
||||
IS_PUBLIC_DOMAIN_ENABLED
|
||||
IS_EMAILING_DOMAIN_ENABLED
|
||||
IS_EMAIL_GROUP_ENABLED
|
||||
IS_JUNCTION_RELATIONS_ENABLED
|
||||
IS_CONNECTED_ACCOUNT_MIGRATED
|
||||
IS_RICH_TEXT_V1_MIGRATED
|
||||
IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED
|
||||
IS_DATASOURCE_MIGRATED
|
||||
IS_BILLING_V2_ENABLED
|
||||
}
|
||||
|
||||
@@ -1970,74 +1967,16 @@ type RotateClientSecret {
|
||||
clientSecret: String!
|
||||
}
|
||||
|
||||
type ResendEmailVerificationToken {
|
||||
success: Boolean!
|
||||
}
|
||||
|
||||
type DeleteSso {
|
||||
identityProviderId: UUID!
|
||||
}
|
||||
|
||||
type EditSso {
|
||||
type ApplicationRegistrationVariableDTO {
|
||||
id: UUID!
|
||||
type: IdentityProviderType!
|
||||
issuer: String!
|
||||
name: String!
|
||||
status: SSOIdentityProviderStatus!
|
||||
}
|
||||
|
||||
type WorkspaceNameAndId {
|
||||
displayName: String
|
||||
id: UUID!
|
||||
}
|
||||
|
||||
type FindAvailableSSOIDP {
|
||||
type: IdentityProviderType!
|
||||
id: UUID!
|
||||
issuer: String!
|
||||
name: String!
|
||||
status: SSOIdentityProviderStatus!
|
||||
workspace: WorkspaceNameAndId!
|
||||
}
|
||||
|
||||
type SetupSso {
|
||||
id: UUID!
|
||||
type: IdentityProviderType!
|
||||
issuer: String!
|
||||
name: String!
|
||||
status: SSOIdentityProviderStatus!
|
||||
}
|
||||
|
||||
type SSOConnection {
|
||||
type: IdentityProviderType!
|
||||
id: UUID!
|
||||
issuer: String!
|
||||
name: String!
|
||||
status: SSOIdentityProviderStatus!
|
||||
}
|
||||
|
||||
type AvailableWorkspace {
|
||||
id: UUID!
|
||||
displayName: String
|
||||
loginToken: String
|
||||
personalInviteToken: String
|
||||
inviteHash: String
|
||||
workspaceUrls: WorkspaceUrls!
|
||||
logo: String
|
||||
sso: [SSOConnection!]!
|
||||
}
|
||||
|
||||
type AvailableWorkspaces {
|
||||
availableWorkspacesForSignIn: [AvailableWorkspace!]!
|
||||
availableWorkspacesForSignUp: [AvailableWorkspace!]!
|
||||
}
|
||||
|
||||
type DeletedWorkspaceMember {
|
||||
id: UUID!
|
||||
name: FullName!
|
||||
userEmail: String!
|
||||
avatarUrl: String
|
||||
userWorkspaceId: UUID
|
||||
key: String!
|
||||
value: String
|
||||
description: String!
|
||||
isSecret: Boolean!
|
||||
isRequired: Boolean!
|
||||
isFilled: Boolean!
|
||||
createdAt: DateTime!
|
||||
updatedAt: DateTime!
|
||||
}
|
||||
|
||||
type Relation {
|
||||
@@ -2161,6 +2100,76 @@ type FieldConnection {
|
||||
edges: [FieldEdge!]!
|
||||
}
|
||||
|
||||
type ResendEmailVerificationToken {
|
||||
success: Boolean!
|
||||
}
|
||||
|
||||
type DeleteSso {
|
||||
identityProviderId: UUID!
|
||||
}
|
||||
|
||||
type EditSso {
|
||||
id: UUID!
|
||||
type: IdentityProviderType!
|
||||
issuer: String!
|
||||
name: String!
|
||||
status: SSOIdentityProviderStatus!
|
||||
}
|
||||
|
||||
type WorkspaceNameAndId {
|
||||
displayName: String
|
||||
id: UUID!
|
||||
}
|
||||
|
||||
type FindAvailableSSOIDP {
|
||||
type: IdentityProviderType!
|
||||
id: UUID!
|
||||
issuer: String!
|
||||
name: String!
|
||||
status: SSOIdentityProviderStatus!
|
||||
workspace: WorkspaceNameAndId!
|
||||
}
|
||||
|
||||
type SetupSso {
|
||||
id: UUID!
|
||||
type: IdentityProviderType!
|
||||
issuer: String!
|
||||
name: String!
|
||||
status: SSOIdentityProviderStatus!
|
||||
}
|
||||
|
||||
type SSOConnection {
|
||||
type: IdentityProviderType!
|
||||
id: UUID!
|
||||
issuer: String!
|
||||
name: String!
|
||||
status: SSOIdentityProviderStatus!
|
||||
}
|
||||
|
||||
type AvailableWorkspace {
|
||||
id: UUID!
|
||||
displayName: String
|
||||
loginToken: String
|
||||
personalInviteToken: String
|
||||
inviteHash: String
|
||||
workspaceUrls: WorkspaceUrls!
|
||||
logo: String
|
||||
sso: [SSOConnection!]!
|
||||
}
|
||||
|
||||
type AvailableWorkspaces {
|
||||
availableWorkspacesForSignIn: [AvailableWorkspace!]!
|
||||
availableWorkspacesForSignUp: [AvailableWorkspace!]!
|
||||
}
|
||||
|
||||
type DeletedWorkspaceMember {
|
||||
id: UUID!
|
||||
name: FullName!
|
||||
userEmail: String!
|
||||
avatarUrl: String
|
||||
userWorkspaceId: UUID
|
||||
}
|
||||
|
||||
type BillingEntitlement {
|
||||
key: BillingEntitlementKey!
|
||||
value: Boolean!
|
||||
@@ -3037,7 +3046,7 @@ type Query {
|
||||
findManyApplicationRegistrations: [ApplicationRegistration!]!
|
||||
findOneApplicationRegistration(id: String!): ApplicationRegistration!
|
||||
findApplicationRegistrationStats(id: String!): ApplicationRegistrationStats!
|
||||
findApplicationRegistrationVariables(applicationRegistrationId: String!): [ApplicationRegistrationVariable!]!
|
||||
findApplicationRegistrationVariables(applicationRegistrationId: String!): [ApplicationRegistrationVariableDTO!]!
|
||||
applicationRegistrationTarballUrl(id: String!): String
|
||||
currentUser: User!
|
||||
currentWorkspace: Workspace!
|
||||
@@ -4318,6 +4327,7 @@ input UpdateWorkspaceInput {
|
||||
editableProfileFields: [String!]
|
||||
enabledAiModelIds: [String!]
|
||||
useRecommendedModels: Boolean
|
||||
isInternalMessagesImportEnabled: Boolean
|
||||
}
|
||||
|
||||
input WorkspaceMigrationInput {
|
||||
|
||||
@@ -652,6 +652,7 @@ export interface Workspace {
|
||||
isMicrosoftAuthEnabled: Scalars['Boolean']
|
||||
isMicrosoftAuthBypassEnabled: Scalars['Boolean']
|
||||
isCustomDomainEnabled: Scalars['Boolean']
|
||||
isInternalMessagesImportEnabled: Scalars['Boolean']
|
||||
editableProfileFields?: Scalars['String'][]
|
||||
defaultRole?: Role
|
||||
fastModel: Scalars['String']
|
||||
@@ -1388,7 +1389,7 @@ export interface FeatureFlag {
|
||||
__typename: 'FeatureFlag'
|
||||
}
|
||||
|
||||
export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_COMMAND_MENU_ITEM_ENABLED' | 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' | 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAILING_DOMAIN_ENABLED' | 'IS_EMAIL_GROUP_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_CONNECTED_ACCOUNT_MIGRATED' | 'IS_RICH_TEXT_V1_MIGRATED' | 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' | 'IS_DATASOURCE_MIGRATED' | 'IS_BILLING_V2_ENABLED'
|
||||
export type FeatureFlagKey = 'IS_UNIQUE_INDEXES_ENABLED' | 'IS_JSON_FILTER_ENABLED' | 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' | 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' | 'IS_PUBLIC_DOMAIN_ENABLED' | 'IS_EMAILING_DOMAIN_ENABLED' | 'IS_EMAIL_GROUP_ENABLED' | 'IS_JUNCTION_RELATIONS_ENABLED' | 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' | 'IS_BILLING_V2_ENABLED'
|
||||
|
||||
export interface WorkspaceUrls {
|
||||
customUrl?: Scalars['String']
|
||||
@@ -1604,84 +1605,17 @@ export interface RotateClientSecret {
|
||||
__typename: 'RotateClientSecret'
|
||||
}
|
||||
|
||||
export interface ResendEmailVerificationToken {
|
||||
success: Scalars['Boolean']
|
||||
__typename: 'ResendEmailVerificationToken'
|
||||
}
|
||||
|
||||
export interface DeleteSso {
|
||||
identityProviderId: Scalars['UUID']
|
||||
__typename: 'DeleteSso'
|
||||
}
|
||||
|
||||
export interface EditSso {
|
||||
export interface ApplicationRegistrationVariableDTO {
|
||||
id: Scalars['UUID']
|
||||
type: IdentityProviderType
|
||||
issuer: Scalars['String']
|
||||
name: Scalars['String']
|
||||
status: SSOIdentityProviderStatus
|
||||
__typename: 'EditSso'
|
||||
}
|
||||
|
||||
export interface WorkspaceNameAndId {
|
||||
displayName?: Scalars['String']
|
||||
id: Scalars['UUID']
|
||||
__typename: 'WorkspaceNameAndId'
|
||||
}
|
||||
|
||||
export interface FindAvailableSSOIDP {
|
||||
type: IdentityProviderType
|
||||
id: Scalars['UUID']
|
||||
issuer: Scalars['String']
|
||||
name: Scalars['String']
|
||||
status: SSOIdentityProviderStatus
|
||||
workspace: WorkspaceNameAndId
|
||||
__typename: 'FindAvailableSSOIDP'
|
||||
}
|
||||
|
||||
export interface SetupSso {
|
||||
id: Scalars['UUID']
|
||||
type: IdentityProviderType
|
||||
issuer: Scalars['String']
|
||||
name: Scalars['String']
|
||||
status: SSOIdentityProviderStatus
|
||||
__typename: 'SetupSso'
|
||||
}
|
||||
|
||||
export interface SSOConnection {
|
||||
type: IdentityProviderType
|
||||
id: Scalars['UUID']
|
||||
issuer: Scalars['String']
|
||||
name: Scalars['String']
|
||||
status: SSOIdentityProviderStatus
|
||||
__typename: 'SSOConnection'
|
||||
}
|
||||
|
||||
export interface AvailableWorkspace {
|
||||
id: Scalars['UUID']
|
||||
displayName?: Scalars['String']
|
||||
loginToken?: Scalars['String']
|
||||
personalInviteToken?: Scalars['String']
|
||||
inviteHash?: Scalars['String']
|
||||
workspaceUrls: WorkspaceUrls
|
||||
logo?: Scalars['String']
|
||||
sso: SSOConnection[]
|
||||
__typename: 'AvailableWorkspace'
|
||||
}
|
||||
|
||||
export interface AvailableWorkspaces {
|
||||
availableWorkspacesForSignIn: AvailableWorkspace[]
|
||||
availableWorkspacesForSignUp: AvailableWorkspace[]
|
||||
__typename: 'AvailableWorkspaces'
|
||||
}
|
||||
|
||||
export interface DeletedWorkspaceMember {
|
||||
id: Scalars['UUID']
|
||||
name: FullName
|
||||
userEmail: Scalars['String']
|
||||
avatarUrl?: Scalars['String']
|
||||
userWorkspaceId?: Scalars['UUID']
|
||||
__typename: 'DeletedWorkspaceMember'
|
||||
key: Scalars['String']
|
||||
value?: Scalars['String']
|
||||
description: Scalars['String']
|
||||
isSecret: Scalars['Boolean']
|
||||
isRequired: Scalars['Boolean']
|
||||
isFilled: Scalars['Boolean']
|
||||
createdAt: Scalars['DateTime']
|
||||
updatedAt: Scalars['DateTime']
|
||||
__typename: 'ApplicationRegistrationVariableDTO'
|
||||
}
|
||||
|
||||
export interface Relation {
|
||||
@@ -1803,6 +1737,86 @@ export interface FieldConnection {
|
||||
__typename: 'FieldConnection'
|
||||
}
|
||||
|
||||
export interface ResendEmailVerificationToken {
|
||||
success: Scalars['Boolean']
|
||||
__typename: 'ResendEmailVerificationToken'
|
||||
}
|
||||
|
||||
export interface DeleteSso {
|
||||
identityProviderId: Scalars['UUID']
|
||||
__typename: 'DeleteSso'
|
||||
}
|
||||
|
||||
export interface EditSso {
|
||||
id: Scalars['UUID']
|
||||
type: IdentityProviderType
|
||||
issuer: Scalars['String']
|
||||
name: Scalars['String']
|
||||
status: SSOIdentityProviderStatus
|
||||
__typename: 'EditSso'
|
||||
}
|
||||
|
||||
export interface WorkspaceNameAndId {
|
||||
displayName?: Scalars['String']
|
||||
id: Scalars['UUID']
|
||||
__typename: 'WorkspaceNameAndId'
|
||||
}
|
||||
|
||||
export interface FindAvailableSSOIDP {
|
||||
type: IdentityProviderType
|
||||
id: Scalars['UUID']
|
||||
issuer: Scalars['String']
|
||||
name: Scalars['String']
|
||||
status: SSOIdentityProviderStatus
|
||||
workspace: WorkspaceNameAndId
|
||||
__typename: 'FindAvailableSSOIDP'
|
||||
}
|
||||
|
||||
export interface SetupSso {
|
||||
id: Scalars['UUID']
|
||||
type: IdentityProviderType
|
||||
issuer: Scalars['String']
|
||||
name: Scalars['String']
|
||||
status: SSOIdentityProviderStatus
|
||||
__typename: 'SetupSso'
|
||||
}
|
||||
|
||||
export interface SSOConnection {
|
||||
type: IdentityProviderType
|
||||
id: Scalars['UUID']
|
||||
issuer: Scalars['String']
|
||||
name: Scalars['String']
|
||||
status: SSOIdentityProviderStatus
|
||||
__typename: 'SSOConnection'
|
||||
}
|
||||
|
||||
export interface AvailableWorkspace {
|
||||
id: Scalars['UUID']
|
||||
displayName?: Scalars['String']
|
||||
loginToken?: Scalars['String']
|
||||
personalInviteToken?: Scalars['String']
|
||||
inviteHash?: Scalars['String']
|
||||
workspaceUrls: WorkspaceUrls
|
||||
logo?: Scalars['String']
|
||||
sso: SSOConnection[]
|
||||
__typename: 'AvailableWorkspace'
|
||||
}
|
||||
|
||||
export interface AvailableWorkspaces {
|
||||
availableWorkspacesForSignIn: AvailableWorkspace[]
|
||||
availableWorkspacesForSignUp: AvailableWorkspace[]
|
||||
__typename: 'AvailableWorkspaces'
|
||||
}
|
||||
|
||||
export interface DeletedWorkspaceMember {
|
||||
id: Scalars['UUID']
|
||||
name: FullName
|
||||
userEmail: Scalars['String']
|
||||
avatarUrl?: Scalars['String']
|
||||
userWorkspaceId?: Scalars['UUID']
|
||||
__typename: 'DeletedWorkspaceMember'
|
||||
}
|
||||
|
||||
export interface BillingEntitlement {
|
||||
key: BillingEntitlementKey
|
||||
value: Scalars['Boolean']
|
||||
@@ -2632,7 +2646,7 @@ export interface Query {
|
||||
findManyApplicationRegistrations: ApplicationRegistration[]
|
||||
findOneApplicationRegistration: ApplicationRegistration
|
||||
findApplicationRegistrationStats: ApplicationRegistrationStats
|
||||
findApplicationRegistrationVariables: ApplicationRegistrationVariable[]
|
||||
findApplicationRegistrationVariables: ApplicationRegistrationVariableDTO[]
|
||||
applicationRegistrationTarballUrl?: Scalars['String']
|
||||
currentUser: User
|
||||
currentWorkspace: Workspace
|
||||
@@ -3566,6 +3580,7 @@ export interface WorkspaceGenqlSelection{
|
||||
isMicrosoftAuthEnabled?: boolean | number
|
||||
isMicrosoftAuthBypassEnabled?: boolean | number
|
||||
isCustomDomainEnabled?: boolean | number
|
||||
isInternalMessagesImportEnabled?: boolean | number
|
||||
editableProfileFields?: boolean | number
|
||||
defaultRole?: RoleGenqlSelection
|
||||
fastModel?: boolean | number
|
||||
@@ -4564,92 +4579,16 @@ export interface RotateClientSecretGenqlSelection{
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface ResendEmailVerificationTokenGenqlSelection{
|
||||
success?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface DeleteSsoGenqlSelection{
|
||||
identityProviderId?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface EditSsoGenqlSelection{
|
||||
export interface ApplicationRegistrationVariableDTOGenqlSelection{
|
||||
id?: boolean | number
|
||||
type?: boolean | number
|
||||
issuer?: boolean | number
|
||||
name?: boolean | number
|
||||
status?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface WorkspaceNameAndIdGenqlSelection{
|
||||
displayName?: boolean | number
|
||||
id?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface FindAvailableSSOIDPGenqlSelection{
|
||||
type?: boolean | number
|
||||
id?: boolean | number
|
||||
issuer?: boolean | number
|
||||
name?: boolean | number
|
||||
status?: boolean | number
|
||||
workspace?: WorkspaceNameAndIdGenqlSelection
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface SetupSsoGenqlSelection{
|
||||
id?: boolean | number
|
||||
type?: boolean | number
|
||||
issuer?: boolean | number
|
||||
name?: boolean | number
|
||||
status?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface SSOConnectionGenqlSelection{
|
||||
type?: boolean | number
|
||||
id?: boolean | number
|
||||
issuer?: boolean | number
|
||||
name?: boolean | number
|
||||
status?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface AvailableWorkspaceGenqlSelection{
|
||||
id?: boolean | number
|
||||
displayName?: boolean | number
|
||||
loginToken?: boolean | number
|
||||
personalInviteToken?: boolean | number
|
||||
inviteHash?: boolean | number
|
||||
workspaceUrls?: WorkspaceUrlsGenqlSelection
|
||||
logo?: boolean | number
|
||||
sso?: SSOConnectionGenqlSelection
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface AvailableWorkspacesGenqlSelection{
|
||||
availableWorkspacesForSignIn?: AvailableWorkspaceGenqlSelection
|
||||
availableWorkspacesForSignUp?: AvailableWorkspaceGenqlSelection
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface DeletedWorkspaceMemberGenqlSelection{
|
||||
id?: boolean | number
|
||||
name?: FullNameGenqlSelection
|
||||
userEmail?: boolean | number
|
||||
avatarUrl?: boolean | number
|
||||
userWorkspaceId?: boolean | number
|
||||
key?: boolean | number
|
||||
value?: boolean | number
|
||||
description?: boolean | number
|
||||
isSecret?: boolean | number
|
||||
isRequired?: boolean | number
|
||||
isFilled?: boolean | number
|
||||
createdAt?: boolean | number
|
||||
updatedAt?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
@@ -4783,6 +4722,96 @@ export interface FieldConnectionGenqlSelection{
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface ResendEmailVerificationTokenGenqlSelection{
|
||||
success?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface DeleteSsoGenqlSelection{
|
||||
identityProviderId?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface EditSsoGenqlSelection{
|
||||
id?: boolean | number
|
||||
type?: boolean | number
|
||||
issuer?: boolean | number
|
||||
name?: boolean | number
|
||||
status?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface WorkspaceNameAndIdGenqlSelection{
|
||||
displayName?: boolean | number
|
||||
id?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface FindAvailableSSOIDPGenqlSelection{
|
||||
type?: boolean | number
|
||||
id?: boolean | number
|
||||
issuer?: boolean | number
|
||||
name?: boolean | number
|
||||
status?: boolean | number
|
||||
workspace?: WorkspaceNameAndIdGenqlSelection
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface SetupSsoGenqlSelection{
|
||||
id?: boolean | number
|
||||
type?: boolean | number
|
||||
issuer?: boolean | number
|
||||
name?: boolean | number
|
||||
status?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface SSOConnectionGenqlSelection{
|
||||
type?: boolean | number
|
||||
id?: boolean | number
|
||||
issuer?: boolean | number
|
||||
name?: boolean | number
|
||||
status?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface AvailableWorkspaceGenqlSelection{
|
||||
id?: boolean | number
|
||||
displayName?: boolean | number
|
||||
loginToken?: boolean | number
|
||||
personalInviteToken?: boolean | number
|
||||
inviteHash?: boolean | number
|
||||
workspaceUrls?: WorkspaceUrlsGenqlSelection
|
||||
logo?: boolean | number
|
||||
sso?: SSOConnectionGenqlSelection
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface AvailableWorkspacesGenqlSelection{
|
||||
availableWorkspacesForSignIn?: AvailableWorkspaceGenqlSelection
|
||||
availableWorkspacesForSignUp?: AvailableWorkspaceGenqlSelection
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface DeletedWorkspaceMemberGenqlSelection{
|
||||
id?: boolean | number
|
||||
name?: FullNameGenqlSelection
|
||||
userEmail?: boolean | number
|
||||
avatarUrl?: boolean | number
|
||||
userWorkspaceId?: boolean | number
|
||||
__typename?: boolean | number
|
||||
__scalar?: boolean | number
|
||||
}
|
||||
|
||||
export interface BillingEntitlementGenqlSelection{
|
||||
key?: boolean | number
|
||||
value?: boolean | number
|
||||
@@ -5680,7 +5709,7 @@ export interface QueryGenqlSelection{
|
||||
findManyApplicationRegistrations?: ApplicationRegistrationGenqlSelection
|
||||
findOneApplicationRegistration?: (ApplicationRegistrationGenqlSelection & { __args: {id: Scalars['String']} })
|
||||
findApplicationRegistrationStats?: (ApplicationRegistrationStatsGenqlSelection & { __args: {id: Scalars['String']} })
|
||||
findApplicationRegistrationVariables?: (ApplicationRegistrationVariableGenqlSelection & { __args: {applicationRegistrationId: Scalars['String']} })
|
||||
findApplicationRegistrationVariables?: (ApplicationRegistrationVariableDTOGenqlSelection & { __args: {applicationRegistrationId: Scalars['String']} })
|
||||
applicationRegistrationTarballUrl?: { __args: {id: Scalars['String']} }
|
||||
currentUser?: UserGenqlSelection
|
||||
currentWorkspace?: WorkspaceGenqlSelection
|
||||
@@ -6269,7 +6298,7 @@ export interface UpdateWorkspaceMemberSettingsInput {workspaceMemberId: Scalars[
|
||||
|
||||
export interface ActivateWorkspaceInput {displayName?: (Scalars['String'] | null)}
|
||||
|
||||
export interface UpdateWorkspaceInput {subdomain?: (Scalars['String'] | null),customDomain?: (Scalars['String'] | null),displayName?: (Scalars['String'] | null),logo?: (Scalars['String'] | null),inviteHash?: (Scalars['String'] | null),isPublicInviteLinkEnabled?: (Scalars['Boolean'] | null),allowImpersonation?: (Scalars['Boolean'] | null),isGoogleAuthEnabled?: (Scalars['Boolean'] | null),isMicrosoftAuthEnabled?: (Scalars['Boolean'] | null),isPasswordAuthEnabled?: (Scalars['Boolean'] | null),isGoogleAuthBypassEnabled?: (Scalars['Boolean'] | null),isMicrosoftAuthBypassEnabled?: (Scalars['Boolean'] | null),isPasswordAuthBypassEnabled?: (Scalars['Boolean'] | null),defaultRoleId?: (Scalars['UUID'] | null),isTwoFactorAuthenticationEnforced?: (Scalars['Boolean'] | null),trashRetentionDays?: (Scalars['Float'] | null),eventLogRetentionDays?: (Scalars['Float'] | null),fastModel?: (Scalars['String'] | null),smartModel?: (Scalars['String'] | null),aiAdditionalInstructions?: (Scalars['String'] | null),editableProfileFields?: (Scalars['String'][] | null),enabledAiModelIds?: (Scalars['String'][] | null),useRecommendedModels?: (Scalars['Boolean'] | null)}
|
||||
export interface UpdateWorkspaceInput {subdomain?: (Scalars['String'] | null),customDomain?: (Scalars['String'] | null),displayName?: (Scalars['String'] | null),logo?: (Scalars['String'] | null),inviteHash?: (Scalars['String'] | null),isPublicInviteLinkEnabled?: (Scalars['Boolean'] | null),allowImpersonation?: (Scalars['Boolean'] | null),isGoogleAuthEnabled?: (Scalars['Boolean'] | null),isMicrosoftAuthEnabled?: (Scalars['Boolean'] | null),isPasswordAuthEnabled?: (Scalars['Boolean'] | null),isGoogleAuthBypassEnabled?: (Scalars['Boolean'] | null),isMicrosoftAuthBypassEnabled?: (Scalars['Boolean'] | null),isPasswordAuthBypassEnabled?: (Scalars['Boolean'] | null),defaultRoleId?: (Scalars['UUID'] | null),isTwoFactorAuthenticationEnforced?: (Scalars['Boolean'] | null),trashRetentionDays?: (Scalars['Float'] | null),eventLogRetentionDays?: (Scalars['Float'] | null),fastModel?: (Scalars['String'] | null),smartModel?: (Scalars['String'] | null),aiAdditionalInstructions?: (Scalars['String'] | null),editableProfileFields?: (Scalars['String'][] | null),enabledAiModelIds?: (Scalars['String'][] | null),useRecommendedModels?: (Scalars['Boolean'] | null),isInternalMessagesImportEnabled?: (Scalars['Boolean'] | null)}
|
||||
|
||||
export interface WorkspaceMigrationInput {actions: WorkspaceMigrationDeleteActionInput[]}
|
||||
|
||||
@@ -7398,82 +7427,10 @@ export interface LogicFunctionLogsInput {applicationId?: (Scalars['UUID'] | null
|
||||
|
||||
|
||||
|
||||
const ResendEmailVerificationToken_possibleTypes: string[] = ['ResendEmailVerificationToken']
|
||||
export const isResendEmailVerificationToken = (obj?: { __typename?: any } | null): obj is ResendEmailVerificationToken => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isResendEmailVerificationToken"')
|
||||
return ResendEmailVerificationToken_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const DeleteSso_possibleTypes: string[] = ['DeleteSso']
|
||||
export const isDeleteSso = (obj?: { __typename?: any } | null): obj is DeleteSso => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isDeleteSso"')
|
||||
return DeleteSso_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const EditSso_possibleTypes: string[] = ['EditSso']
|
||||
export const isEditSso = (obj?: { __typename?: any } | null): obj is EditSso => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isEditSso"')
|
||||
return EditSso_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const WorkspaceNameAndId_possibleTypes: string[] = ['WorkspaceNameAndId']
|
||||
export const isWorkspaceNameAndId = (obj?: { __typename?: any } | null): obj is WorkspaceNameAndId => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isWorkspaceNameAndId"')
|
||||
return WorkspaceNameAndId_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const FindAvailableSSOIDP_possibleTypes: string[] = ['FindAvailableSSOIDP']
|
||||
export const isFindAvailableSSOIDP = (obj?: { __typename?: any } | null): obj is FindAvailableSSOIDP => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isFindAvailableSSOIDP"')
|
||||
return FindAvailableSSOIDP_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const SetupSso_possibleTypes: string[] = ['SetupSso']
|
||||
export const isSetupSso = (obj?: { __typename?: any } | null): obj is SetupSso => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isSetupSso"')
|
||||
return SetupSso_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const SSOConnection_possibleTypes: string[] = ['SSOConnection']
|
||||
export const isSSOConnection = (obj?: { __typename?: any } | null): obj is SSOConnection => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isSSOConnection"')
|
||||
return SSOConnection_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const AvailableWorkspace_possibleTypes: string[] = ['AvailableWorkspace']
|
||||
export const isAvailableWorkspace = (obj?: { __typename?: any } | null): obj is AvailableWorkspace => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isAvailableWorkspace"')
|
||||
return AvailableWorkspace_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const AvailableWorkspaces_possibleTypes: string[] = ['AvailableWorkspaces']
|
||||
export const isAvailableWorkspaces = (obj?: { __typename?: any } | null): obj is AvailableWorkspaces => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isAvailableWorkspaces"')
|
||||
return AvailableWorkspaces_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const DeletedWorkspaceMember_possibleTypes: string[] = ['DeletedWorkspaceMember']
|
||||
export const isDeletedWorkspaceMember = (obj?: { __typename?: any } | null): obj is DeletedWorkspaceMember => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isDeletedWorkspaceMember"')
|
||||
return DeletedWorkspaceMember_possibleTypes.includes(obj.__typename)
|
||||
const ApplicationRegistrationVariableDTO_possibleTypes: string[] = ['ApplicationRegistrationVariableDTO']
|
||||
export const isApplicationRegistrationVariableDTO = (obj?: { __typename?: any } | null): obj is ApplicationRegistrationVariableDTO => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isApplicationRegistrationVariableDTO"')
|
||||
return ApplicationRegistrationVariableDTO_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
@@ -7590,6 +7547,86 @@ export interface LogicFunctionLogsInput {applicationId?: (Scalars['UUID'] | null
|
||||
|
||||
|
||||
|
||||
const ResendEmailVerificationToken_possibleTypes: string[] = ['ResendEmailVerificationToken']
|
||||
export const isResendEmailVerificationToken = (obj?: { __typename?: any } | null): obj is ResendEmailVerificationToken => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isResendEmailVerificationToken"')
|
||||
return ResendEmailVerificationToken_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const DeleteSso_possibleTypes: string[] = ['DeleteSso']
|
||||
export const isDeleteSso = (obj?: { __typename?: any } | null): obj is DeleteSso => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isDeleteSso"')
|
||||
return DeleteSso_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const EditSso_possibleTypes: string[] = ['EditSso']
|
||||
export const isEditSso = (obj?: { __typename?: any } | null): obj is EditSso => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isEditSso"')
|
||||
return EditSso_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const WorkspaceNameAndId_possibleTypes: string[] = ['WorkspaceNameAndId']
|
||||
export const isWorkspaceNameAndId = (obj?: { __typename?: any } | null): obj is WorkspaceNameAndId => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isWorkspaceNameAndId"')
|
||||
return WorkspaceNameAndId_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const FindAvailableSSOIDP_possibleTypes: string[] = ['FindAvailableSSOIDP']
|
||||
export const isFindAvailableSSOIDP = (obj?: { __typename?: any } | null): obj is FindAvailableSSOIDP => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isFindAvailableSSOIDP"')
|
||||
return FindAvailableSSOIDP_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const SetupSso_possibleTypes: string[] = ['SetupSso']
|
||||
export const isSetupSso = (obj?: { __typename?: any } | null): obj is SetupSso => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isSetupSso"')
|
||||
return SetupSso_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const SSOConnection_possibleTypes: string[] = ['SSOConnection']
|
||||
export const isSSOConnection = (obj?: { __typename?: any } | null): obj is SSOConnection => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isSSOConnection"')
|
||||
return SSOConnection_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const AvailableWorkspace_possibleTypes: string[] = ['AvailableWorkspace']
|
||||
export const isAvailableWorkspace = (obj?: { __typename?: any } | null): obj is AvailableWorkspace => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isAvailableWorkspace"')
|
||||
return AvailableWorkspace_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const AvailableWorkspaces_possibleTypes: string[] = ['AvailableWorkspaces']
|
||||
export const isAvailableWorkspaces = (obj?: { __typename?: any } | null): obj is AvailableWorkspaces => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isAvailableWorkspaces"')
|
||||
return AvailableWorkspaces_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const DeletedWorkspaceMember_possibleTypes: string[] = ['DeletedWorkspaceMember']
|
||||
export const isDeletedWorkspaceMember = (obj?: { __typename?: any } | null): obj is DeletedWorkspaceMember => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isDeletedWorkspaceMember"')
|
||||
return DeletedWorkspaceMember_possibleTypes.includes(obj.__typename)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const BillingEntitlement_possibleTypes: string[] = ['BillingEntitlement']
|
||||
export const isBillingEntitlement = (obj?: { __typename?: any } | null): obj is BillingEntitlement => {
|
||||
if (!obj?.__typename) throw new Error('__typename is missing in "isBillingEntitlement"')
|
||||
@@ -8721,17 +8758,13 @@ export const enumLogicFunctionExecutionStatus = {
|
||||
export const enumFeatureFlagKey = {
|
||||
IS_UNIQUE_INDEXES_ENABLED: 'IS_UNIQUE_INDEXES_ENABLED' as const,
|
||||
IS_JSON_FILTER_ENABLED: 'IS_JSON_FILTER_ENABLED' as const,
|
||||
IS_COMMAND_MENU_ITEM_ENABLED: 'IS_COMMAND_MENU_ITEM_ENABLED' as const,
|
||||
IS_MARKETPLACE_SETTING_TAB_VISIBLE: 'IS_MARKETPLACE_SETTING_TAB_VISIBLE' as const,
|
||||
IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED: 'IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED' as const,
|
||||
IS_PUBLIC_DOMAIN_ENABLED: 'IS_PUBLIC_DOMAIN_ENABLED' as const,
|
||||
IS_EMAILING_DOMAIN_ENABLED: 'IS_EMAILING_DOMAIN_ENABLED' as const,
|
||||
IS_EMAIL_GROUP_ENABLED: 'IS_EMAIL_GROUP_ENABLED' as const,
|
||||
IS_JUNCTION_RELATIONS_ENABLED: 'IS_JUNCTION_RELATIONS_ENABLED' as const,
|
||||
IS_CONNECTED_ACCOUNT_MIGRATED: 'IS_CONNECTED_ACCOUNT_MIGRATED' as const,
|
||||
IS_RICH_TEXT_V1_MIGRATED: 'IS_RICH_TEXT_V1_MIGRATED' as const,
|
||||
IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED: 'IS_RECORD_PAGE_LAYOUT_GLOBAL_EDITION_ENABLED' as const,
|
||||
IS_DATASOURCE_MIGRATED: 'IS_DATASOURCE_MIGRATED' as const,
|
||||
IS_BILLING_V2_ENABLED: 'IS_BILLING_V2_ENABLED' as const
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,7 +21,7 @@ Für benutzerdefinierte Domänen müssen Sie die DNS-Einstellungen bei Ihrem Dom
|
||||
|
||||
## Genehmigte Domänen
|
||||
|
||||
Konfigurieren Sie dies unter **Einstellungen → Mitglieder → Zugriff**.
|
||||
Konfigurieren Sie dies unter **Einstellungen → Mitglieder → Einladen**.
|
||||
|
||||
Jede Person mit einer E-Mail-Adresse in diesen Domänen darf sich automatisch für diesen Arbeitsbereich registrieren.
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ Verwalten Sie Einladungen, die noch nicht angenommen wurden:
|
||||
|
||||
Erlauben Sie Teammitgliedern, basierend auf ihrer E-Mail-Domäne automatisch beizutreten:
|
||||
|
||||
1. Gehen Sie zu **Einstellungen → Mitglieder → Zugriff**
|
||||
1. Gehen Sie zu **Einstellungen → Mitglieder → Einladen**
|
||||
2. Fügen Sie die Domäne Ihres Unternehmens hinzu (z. B. `yourcompany.com`)
|
||||
3. Jede Person mit dieser E-Mail-Domäne kann ohne Einladung beitreten
|
||||
|
||||
|
||||
@@ -146,7 +146,7 @@ Eine Subdomain ist schnell eingerichtet, während eine benutzerdefinierte Domän
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Wie funktionieren genehmigte Zugriffsdomänen?">
|
||||
Sie können genehmigte Zugriffsdomänen konfigurieren, damit Teammitglieder mit Firmen-E-Mail-Adressen Ihrem Arbeitsbereich automatisch beitreten können. Gehen Sie zu **Einstellungen → Mitglieder → Zugriff** und fügen Sie Ihre Firmendomäne hinzu (z. B. `yourcompany.com`).
|
||||
Sie können genehmigte Zugriffsdomänen konfigurieren, damit Teammitglieder mit Firmen-E-Mail-Adressen Ihrem Arbeitsbereich automatisch beitreten können. Gehen Sie zu **Einstellungen → Mitglieder → Einladen** und fügen Sie Ihre Firmendomäne hinzu (z. B. `yourcompany.com`).
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ Para domínios personalizados, você precisará configurar as configurações de
|
||||
|
||||
## Domínios Aprovados
|
||||
|
||||
Configure em **Configurações → Membros → Acesso**.
|
||||
Configure em **Configurações → Membros → Convite**.
|
||||
|
||||
Qualquer pessoa com um endereço de e-mail nesses domínios pode inscrever-se neste espaço de trabalho automaticamente.
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ Gerencie convites que ainda não foram aceitos:
|
||||
|
||||
Permita que membros da equipe ingressem automaticamente com base no domínio de e-mail:
|
||||
|
||||
1. Vá para **Configurações → Membros → Acesso**
|
||||
1. Vá para **Configurações → Membros → Convites**
|
||||
2. Adicione o domínio da sua empresa (por exemplo, `yourcompany.com`)
|
||||
3. Qualquer pessoa com esse domínio de e-mail pode ingressar sem convite
|
||||
|
||||
|
||||
@@ -146,7 +146,7 @@ Um subdomínio é rápido de configurar, enquanto um domínio personalizado ofer
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Como funcionam os domínios de acesso aprovados?">
|
||||
Você pode configurar domínios de acesso aprovados para que membros da equipe com endereços de e-mail da empresa possam ingressar automaticamente no seu espaço de trabalho. Vá para **Configurações → Membros → Acesso** e adicione o domínio da sua empresa (por exemplo, `yourcompany.com`).
|
||||
Você pode configurar domínios de acesso aprovados para que membros da equipe com endereços de e-mail da empresa possam ingressar automaticamente no seu espaço de trabalho. Vá para **Configurações → Membros → Convidar** e adicione o domínio da sua empresa (por exemplo, `yourcompany.com`).
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ Pentru domeniile personalizate, va trebui să configurați setările DNS la furn
|
||||
|
||||
## Domenii Aprobate
|
||||
|
||||
Configurați în **Setări → Membri → Acces**.
|
||||
Configurați în **Setări → Membri → Invită**.
|
||||
|
||||
Oricine are o adresă de email pe aceste domenii se poate înscrie automat în acest spațiu de lucru.
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ Gestionați invitațiile care nu au fost acceptate:
|
||||
|
||||
Permiteți membrilor echipei să se alăture automat pe baza domeniului lor de e-mail:
|
||||
|
||||
1. Accesați **Setări → Membri → Acces**
|
||||
1. Accesați **Setări → Membri → Invită**
|
||||
2. Adăugați domeniul companiei dvs. (de ex., `yourcompany.com`)
|
||||
3. Oricine are acel domeniu de e-mail se poate alătura fără invitație
|
||||
|
||||
|
||||
@@ -146,7 +146,7 @@ Un subdomeniu se configurează rapid, în timp ce un domeniu personalizat oferă
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Cum funcționează domeniile de acces aprobate?">
|
||||
Puteți configura domenii de acces aprobate astfel încât membrii echipei cu adrese de e-mail ale companiei să se poată alătura automat spațiului dvs. de lucru. Accesați **Setări → Membri → Acces** și adăugați domeniul companiei (de ex., `yourcompany.com`).
|
||||
Puteți configura domenii de acces aprobate astfel încât membrii echipei cu adrese de e-mail ale companiei să se poată alătura automat spațiului dvs. de lucru. Accesați **Setări → Membri → Invită** și adăugați domeniul companiei (de ex., `yourcompany.com`).
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ description: Настройте домен рабочего пространст
|
||||
|
||||
## Утвержденные домены
|
||||
|
||||
Настройте в **Настройки → Участники → Доступ**.
|
||||
Настройте в **Настройки → Участники → Пригласить**.
|
||||
|
||||
Любой пользователь с адресом электронной почты в этих доменах может автоматически зарегистрироваться в этом рабочем пространстве.
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ description: Пригласите членов команды и управля
|
||||
|
||||
Разрешите участникам команды присоединяться автоматически на основе домена их электронной почты:
|
||||
|
||||
1. Перейдите в **Настройки → Участники → Доступ**
|
||||
1. Перейдите в **Настройки → Участники → Пригласить**
|
||||
2. Добавьте домен вашей компании (например, `yourcompany.com`)
|
||||
3. Любой с таким доменом электронной почты сможет присоединиться без приглашения
|
||||
|
||||
|
||||
@@ -146,7 +146,7 @@ description: Часто задаваемые вопросы о настройк
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Как работают утвержденные домены доступа?">
|
||||
Вы можете настроить утвержденные домены доступа, чтобы участники команды с корпоративными адресами электронной почты могли автоматически присоединяться к вашему рабочему пространству. Перейдите в **Настройки → Участники → Доступ** и добавьте домен вашей компании (например, `yourcompany.com`).
|
||||
Вы можете настроить утвержденные домены доступа, чтобы участники команды с корпоративными адресами электронной почты могли автоматически присоединяться к вашему рабочему пространству. Перейдите в **Настройки → Участники → Пригласить** и добавьте домен вашей компании (например, `yourcompany.com`).
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ Alt alan adınızı düzenleyin veya çalışma alanınız için özel bir alan
|
||||
|
||||
## Onaylanmış Alan Adları
|
||||
|
||||
**Ayarlar → Üyeler → Erişim** altında yapılandırın.
|
||||
**Ayarlar → Üyeler → Davet** altında yapılandırın.
|
||||
|
||||
Bu alan adlarındaki bir e-posta adresine sahip olan herkes bu çalışma alanına otomatik olarak kaydolabilir.
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ Kabul edilmemiş davetleri yönetin:
|
||||
|
||||
Ekip üyelerinin e-posta alan adına göre otomatik olarak katılmasına izin verin:
|
||||
|
||||
1. **Ayarlar → Üyeler → Erişim** bölümüne gidin
|
||||
1. **Ayarlar → Üyeler → Davet** bölümüne gidin
|
||||
2. Şirketinizin alan adını ekleyin (örneğin, `yourcompany.com`)
|
||||
3. Bu e-posta alan adına sahip olan herkes davet olmadan katılabilir
|
||||
|
||||
|
||||
@@ -146,7 +146,7 @@ Alt alan adı kurmak hızlıdır; özel alan adı ise ekibiniz için tam markal
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Onaylı erişim alan adları nasıl çalışır?">
|
||||
Şirket e-posta adreslerine sahip ekip üyelerinin çalışma alanınıza otomatik olarak katılabilmeleri için onaylı erişim alan adlarını yapılandırabilirsiniz. **Ayarlar → Üyeler → Erişim**'e gidin ve şirket alan adınızı ekleyin (ör. `yourcompany.com`).
|
||||
Şirket e-posta adreslerine sahip ekip üyelerinin çalışma alanınıza otomatik olarak katılabilmeleri için onaylı erişim alan adlarını yapılandırabilirsiniz. **Ayarlar → Üyeler → Davet**'e gidin ve şirket alan adınızı ekleyin (ör. `yourcompany.com`).
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ For custom domains, you'll need to configure DNS settings with your domain provi
|
||||
|
||||
## 批准的域名
|
||||
|
||||
在 **设置 → 成员 → 访问权限** 下进行配置。
|
||||
在 **设置 → 成员 → 邀请** 下进行配置。
|
||||
|
||||
Anyone with an email address at these domains is allowed to sign up for this workspace automatically.
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ description: 邀请团队成员并管理工作区访问权限。
|
||||
|
||||
根据其电子邮件域允许团队成员自动加入:
|
||||
|
||||
1. 转到 **设置 → 成员 → 访问权限**
|
||||
1. 转到 **设置 → 成员 → 邀请**
|
||||
2. 添加您公司的域名(例如,`yourcompany.com`)
|
||||
3. 使用该电子邮件域的任何人都可无需邀请加入。
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user