Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
01ffca0cef | ||
|
|
4bdd866a20 | ||
|
|
52cf3775b3 | ||
|
|
c36bb8f3a1 | ||
|
|
df456cfa2f | ||
|
|
ce7f0c03f7 | ||
|
|
52604e1c52 | ||
|
|
47a8a15598 | ||
|
|
db960cf509 | ||
|
|
daaa009fb4 | ||
|
|
34a1c64b7e | ||
|
|
3a1e2618e2 | ||
|
|
b4afbaefff | ||
|
|
12544da527 | ||
|
|
4fe8e3d3b6 | ||
|
|
6682d4eb02 | ||
|
|
4e15f7fe13 | ||
|
|
1e615f7102 | ||
|
|
75ae2b401b | ||
|
|
e5f655fcae | ||
|
|
82b0ee5995 | ||
|
|
1088f7bbab | ||
|
|
c13b955a36 | ||
|
|
b0e256221a | ||
|
|
a560e8ac83 | ||
|
|
100d4f7f42 | ||
|
|
1f1a1ea138 | ||
|
|
59d3a14922 | ||
|
|
0e6a8c04c4 | ||
|
|
ca976afa10 | ||
|
|
967298fe09 | ||
|
|
a60f750ed7 | ||
|
|
2e62bb133b | ||
|
|
6de424bc32 | ||
|
|
2717afce59 | ||
|
|
659ed6b080 | ||
|
|
30c2c22fc2 | ||
|
|
d43e21b695 | ||
|
|
0145920d7e | ||
|
|
1cbbd04761 | ||
|
|
58c85e7cca | ||
|
|
576019e465 | ||
|
|
5a5bf112cf | ||
|
|
9b00084fb0 | ||
|
|
38a0bba57b | ||
|
|
a6127c2128 | ||
|
|
04c596817a | ||
|
|
3ac72683da | ||
|
|
d998e3b92c | ||
|
|
75bba5a8ee | ||
|
|
553efe0cee | ||
|
|
48a7a24380 | ||
|
|
e8fd5fa3ed | ||
|
|
31467f2173 | ||
|
|
9c3cd959ba | ||
|
|
289e8bf1d4 | ||
|
|
0ecb60f50b | ||
|
|
cd0318ea65 | ||
|
|
a0b963ef86 | ||
|
|
66d242da24 | ||
|
|
e289f3056e | ||
|
|
e33f18bfa8 | ||
|
|
039a3d99a8 | ||
|
|
fc74a06f53 | ||
|
|
75f2c26d3f | ||
|
|
95e0793f81 | ||
|
|
2e104c8e76 | ||
|
|
4281a71f40 | ||
|
|
3e55e772d4 | ||
|
|
a83732d7a6 | ||
|
|
042972d7b2 | ||
|
|
d7b34fc636 | ||
|
|
8c79353bfb | ||
|
|
cf6fb419e0 | ||
|
|
9fd2853315 | ||
|
|
1119e3d77e | ||
|
|
d189e3f57e | ||
|
|
da9ade72c8 | ||
|
|
7f50486de5 | ||
|
|
d36d0d49d1 | ||
|
|
44f0cfdd9e | ||
|
|
afcca283c4 | ||
|
|
62408e7fd3 | ||
|
|
ee47a773bd | ||
|
|
f0af947331 | ||
|
|
0035fc1145 | ||
|
|
3e17140385 | ||
|
|
59663ec34e | ||
|
|
4b292ac780 | ||
|
|
d30453f38f | ||
|
|
6acdde72ef | ||
|
|
8dbcd506ed | ||
|
|
4f91b48470 | ||
|
|
ec243e9874 | ||
|
|
19f20cd37b | ||
|
|
c274adf4d8 | ||
|
|
bd8ed03990 | ||
|
|
4b2a604ef0 | ||
|
|
865265d0d9 | ||
|
|
5f4f4c0af8 | ||
|
|
70a78aafe9 | ||
|
|
4d90a8f6e3 | ||
|
|
14b2487d25 | ||
|
|
aad581a353 | ||
|
|
a13727335b | ||
|
|
999bc84b17 | ||
|
|
083a038f8a | ||
|
|
3dd2684254 | ||
|
|
2da56c1886 | ||
|
|
7f9e948e05 | ||
|
|
ec8773437e | ||
|
|
3cea19baf4 | ||
|
|
2943125410 | ||
|
|
f06a5ccacd | ||
|
|
9c1197c0b2 | ||
|
|
b83dc3aaff | ||
|
|
c13ef0c4a4 | ||
|
|
918b145fb5 | ||
|
|
310bf5fe9a | ||
|
|
5af2d37253 | ||
|
|
6c728fff78 | ||
|
|
5a697e914b | ||
|
|
bc57b8ee4e | ||
|
|
5daef28328 | ||
|
|
7021cd41ea | ||
|
|
1077cf1560 | ||
|
|
7a7f36d38c | ||
|
|
bed5270f3c | ||
|
|
2948880a0b | ||
|
|
b760e6df46 | ||
|
|
9bd8f94b3a | ||
|
|
4f13022774 | ||
|
|
3648fa064c | ||
|
|
b17e45f272 | ||
|
|
0a11add616 | ||
|
|
478c753a50 | ||
|
|
ac0ec88a87 | ||
|
|
5df8fd90c3 | ||
|
|
59b54f254e | ||
|
|
5e44781be1 | ||
|
|
89cc59d8ab | ||
|
|
f48adb5f07 | ||
|
|
1839f8e946 | ||
|
|
20f2ca6864 | ||
|
|
20879c8147 | ||
|
|
1e166ccb53 | ||
|
|
bc274b9937 | ||
|
|
d932ec28e3 | ||
|
|
30e3aa5961 | ||
|
|
915e0fd436 | ||
|
|
fd54a2af5c | ||
|
|
7b98804ec1 |
@@ -56,7 +56,9 @@ npx nx storybook:build twenty-front # Build Storybook
|
||||
npx nx storybook:serve-and-test:static # Run Storybook tests
|
||||
|
||||
# Development
|
||||
npx nx lint twenty-front # Run linter
|
||||
npx nx lint:changed twenty-front # Lint changed files only (fastest)
|
||||
npx nx lint:changed twenty-front --configuration=fix # Auto-fix changed files
|
||||
npx nx lint twenty-front # Lint all files (slower)
|
||||
npx nx typecheck twenty-front # Type checking
|
||||
npx nx run twenty-front:graphql:generate # Generate GraphQL types
|
||||
```
|
||||
@@ -70,7 +72,9 @@ npx nx run twenty-server:database:migrate:prod # Run migrations
|
||||
|
||||
# Development
|
||||
npx nx run twenty-server:start # Start the server
|
||||
npx nx run twenty-server:lint # Run linter (add --fix to auto-fix)
|
||||
npx nx lint:changed twenty-server # Lint changed files only (fastest)
|
||||
npx nx lint:changed twenty-server --configuration=fix # Auto-fix changed files
|
||||
npx nx run twenty-server:lint # Lint all files (slower)
|
||||
npx nx run twenty-server:typecheck # Type checking
|
||||
npx nx run twenty-server:test # Run unit tests
|
||||
npx nx run twenty-server:test:integration:with-db-reset # Run integration tests
|
||||
|
||||
@@ -12,7 +12,13 @@ alwaysApply: true
|
||||
npx nx run twenty-front:build
|
||||
npx nx run twenty-server:test
|
||||
|
||||
# Run target for all projects
|
||||
# Lint changed files only (recommended - much faster!)
|
||||
npx nx lint:changed twenty-front # Lint only files changed vs main
|
||||
npx nx lint:changed twenty-server
|
||||
npx nx lint:changed twenty-front --configuration=fix # Auto-fix changed files
|
||||
npx nx lint:changed twenty-front --configuration=staged # Lint staged files
|
||||
|
||||
# Run target for all projects (slower)
|
||||
npx nx run-many --target=build --all
|
||||
npx nx run-many --target=test --projects=twenty-front,twenty-server
|
||||
|
||||
@@ -43,12 +49,19 @@ npx nx g @nx/react:component my-component
|
||||
}
|
||||
```
|
||||
|
||||
## Linting Strategy
|
||||
For faster development, always prefer linting only changed files:
|
||||
- Use `npx nx lint:changed <project>` to lint only files changed vs main branch
|
||||
- Use `--configuration=fix` to auto-fix issues in changed files
|
||||
- Use `--configuration=staged` to lint only staged files (useful for pre-commit hooks)
|
||||
- Only use `npx nx lint <project>` when you need to lint the entire project
|
||||
|
||||
## Dependency Graph
|
||||
```bash
|
||||
# View project dependencies
|
||||
npx nx graph
|
||||
|
||||
# Check what's affected by changes
|
||||
# Check what's affected by changes (runs target on affected projects)
|
||||
npx nx affected --target=test
|
||||
npx nx affected --target=build --base=main
|
||||
```
|
||||
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
task: [lint, typecheck, test, build]
|
||||
task: [lint, typecheck, test]
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/cancel-workflow-action@0.11.0
|
||||
@@ -39,6 +39,8 @@ jobs:
|
||||
fetch-depth: 0
|
||||
- name: Install dependencies
|
||||
uses: ./.github/workflows/actions/yarn-install
|
||||
- name: Build
|
||||
run: npx nx build create-twenty-app
|
||||
- name: Run ${{ matrix.task }} task
|
||||
uses: ./.github/workflows/actions/nx-affected
|
||||
with:
|
||||
|
||||
@@ -78,7 +78,7 @@ jobs:
|
||||
- name: Setup environment files
|
||||
run: |
|
||||
cp packages/twenty-front/.env.example packages/twenty-front/.env
|
||||
npx nx reset:env twenty-server
|
||||
npx nx reset:env:e2e-testing-server twenty-server
|
||||
|
||||
- name: Build frontend
|
||||
run: NODE_ENV=production NODE_OPTIONS="--max-old-space-size=10240" npx nx build twenty-front
|
||||
@@ -103,7 +103,7 @@ jobs:
|
||||
npm_config_yes=true npx serve -s packages/twenty-front/build -l 3001 &
|
||||
echo "Waiting for frontend to be ready..."
|
||||
timeout 60 bash -c 'until curl -s http://localhost:3001; do sleep 2; done'
|
||||
|
||||
|
||||
- name: Start worker
|
||||
run: |
|
||||
npx nx run twenty-server:worker &
|
||||
|
||||
@@ -185,6 +185,28 @@ jobs:
|
||||
uses: ./.github/workflows/actions/save-cache
|
||||
with:
|
||||
key: ${{ steps.restore-task-cache.outputs.cache-primary-key }}
|
||||
front-build:
|
||||
needs: changed-files-check
|
||||
if: needs.changed-files-check.outputs.any_changed == 'true'
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
NODE_OPTIONS: "--max-old-space-size=10240"
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/cancel-workflow-action@0.11.0
|
||||
with:
|
||||
access_token: ${{ github.token }}
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Install dependencies
|
||||
uses: ./.github/workflows/actions/yarn-install
|
||||
- name: Front / Write .env
|
||||
run: npx nx reset:env twenty-front
|
||||
- name: Build frontend
|
||||
run: npx nx build twenty-front
|
||||
ci-front-status-check:
|
||||
if: always() && !cancelled()
|
||||
timeout-minutes: 5
|
||||
@@ -193,6 +215,7 @@ jobs:
|
||||
[
|
||||
changed-files-check,
|
||||
front-task,
|
||||
front-build,
|
||||
front-chromatic-deployment,
|
||||
merge-reports-and-check-coverage,
|
||||
front-sb-test,
|
||||
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
task: [lint, typecheck, test, build]
|
||||
task: [lint, typecheck, test]
|
||||
steps:
|
||||
- name: Cancel Previous Runs
|
||||
uses: styfle/cancel-workflow-action@0.11.0
|
||||
@@ -39,6 +39,8 @@ jobs:
|
||||
fetch-depth: 0
|
||||
- name: Install dependencies
|
||||
uses: ./.github/workflows/actions/yarn-install
|
||||
- name: Build
|
||||
run: npx nx build twenty-sdk
|
||||
- name: Run ${{ matrix.task }} task
|
||||
uses: ./.github/workflows/actions/nx-affected
|
||||
with:
|
||||
|
||||
@@ -171,7 +171,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
shard: [1, 2, 3, 4, 5]
|
||||
shard: [1, 2, 3, 4, 5, 6]
|
||||
services:
|
||||
postgres:
|
||||
image: twentycrm/twenty-postgres-spilo
|
||||
@@ -209,7 +209,7 @@ jobs:
|
||||
ANALYTICS_ENABLED: true
|
||||
CLICKHOUSE_URL: "http://default:clickhousePassword@localhost:8123/twenty"
|
||||
CLICKHOUSE_PASSWORD: clickhousePassword
|
||||
SHARD_COUNTER: 5
|
||||
SHARD_COUNTER: 6
|
||||
steps:
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
|
||||
@@ -36,10 +36,16 @@ When testing the UI end to end, click on "Continue with Email" and use the prefi
|
||||
|
||||
### Code Quality
|
||||
```bash
|
||||
# Linting
|
||||
npx nx lint twenty-front # Frontend linting
|
||||
npx nx lint twenty-server # Backend linting
|
||||
npx nx lint twenty-front --fix # Auto-fix linting issues
|
||||
# Linting (changed files only - fastest)
|
||||
npx nx lint:changed twenty-front # Lint only changed files vs main
|
||||
npx nx lint:changed twenty-server # Lint only changed files vs main
|
||||
npx nx lint:changed twenty-front --configuration=fix # Auto-fix changed files
|
||||
npx nx lint:changed twenty-front --configuration=staged # Lint staged files only
|
||||
|
||||
# Linting (full project)
|
||||
npx nx lint twenty-front # Lint all files in frontend
|
||||
npx nx lint twenty-server # Lint all files in backend
|
||||
npx nx lint twenty-front --fix # Auto-fix all linting issues
|
||||
|
||||
# Type checking
|
||||
npx nx typecheck twenty-front
|
||||
|
||||
@@ -75,10 +75,6 @@ export default [
|
||||
sourceTag: 'scope:frontend',
|
||||
onlyDependOnLibsWithTags: ['scope:shared', 'scope:frontend'],
|
||||
},
|
||||
{
|
||||
sourceTag: 'scope:zapier',
|
||||
onlyDependOnLibsWithTags: ['scope:shared'],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
+489
-4
@@ -128,6 +128,375 @@ export default [
|
||||
additionalHooks: 'useRecoilCallback',
|
||||
},
|
||||
],
|
||||
// Lingui - detect untranslated strings
|
||||
'lingui/no-unlocalized-strings': [
|
||||
'error',
|
||||
{
|
||||
ignore: [
|
||||
// Ignore strings which are a single "word" (no spaces) and don't start with uppercase
|
||||
'^(?![A-Z])\\S+$',
|
||||
// Ignore UPPERCASE literals (constants, env vars)
|
||||
'^[A-Z0-9_-]+$',
|
||||
// Ignore strings that look like code/technical (contain special chars)
|
||||
'^[\\s]*$', // whitespace only
|
||||
'.*[{}/<>].*', // contains code-like characters
|
||||
'^\\d+(\\.\\d+)?(px|rem|em|%|vh|vw|s|ms)?$', // CSS units
|
||||
'^[\\d.]+(px|rem|em|%|vh|vw|fr|s|ms)?(\\s+[\\d.]+(px|rem|em|%|vh|vw|fr|s|ms)?)*$', // CSS values like "200px 1fr 20px"
|
||||
'^#[0-9a-fA-F]{3,8}$', // hex colors
|
||||
'^rgba?\\(.*\\)$', // rgb/rgba colors
|
||||
'^(auto|none|inherit|initial|unset|flex|grid|block|inline|inline-block|relative|absolute|fixed|sticky)$', // CSS keywords
|
||||
'^color:.*$', // CSS color declarations
|
||||
'^font-.*$', // CSS font declarations
|
||||
'^\\d+$', // numbers only
|
||||
'^https?:\\/\\/.*', // URLs
|
||||
'^@.*', // @ mentions or decorators
|
||||
'^\\/.*', // paths starting with /
|
||||
'^[HhMmSsYyDdAaPp:.,\\s-]+$', // date format patterns (HH:mm, yyyy-MM-dd, etc.)
|
||||
'^Arrow(Up|Down|Left|Right)$', // keyboard keys
|
||||
'^(Enter|Escape|Tab|Space|Backspace|Delete)$', // keyboard keys
|
||||
'^Text$', // clipboard data type
|
||||
'^(allow-|sandbox)', // iframe sandbox values
|
||||
'^Id$', // technical identifier suffix (e.g., fieldNameId)
|
||||
'^(string|number|boolean|void|any|unknown|never|object)$', // TypeScript type keywords
|
||||
'^(Dark|Light)$', // color schemes
|
||||
'^translate\\(.*\\)$', // CSS transform strings
|
||||
'^svg .*$', // CSS selectors
|
||||
'^Icon[A-Z]\\w*$', // Icon names like IconDefault, IconTable, IconSettings
|
||||
'^\\w*Icon$', // Icon names that end with Icon like FieldIcon
|
||||
'^%c.*$', // Console format strings
|
||||
// Common item IDs for selectable lists
|
||||
'^(Group|CalendarView|CalendarDateField|Compact view)$',
|
||||
'^(Layout|Visibility|Fields|Delete view|Copy link to view|Create custom view)$',
|
||||
'^(GroupBy|Sort|HideEmptyGroups|HiddenGroups)$',
|
||||
// HTTP headers and auth (technical, not user-facing)
|
||||
'^Authorization$',
|
||||
'^Bearer .*',
|
||||
// Allow object keys that are technical identifiers
|
||||
'^(topLeft|topRight|bottomLeft|bottomRight)$',
|
||||
// Color schemes and CSS media queries
|
||||
'^System$',
|
||||
'^\\(prefers-color-scheme:',
|
||||
// GraphQL query names (used in refetchQueries)
|
||||
'^Get[A-Z]\\w*$',
|
||||
// React Context names (technical identifiers)
|
||||
'.*Context$',
|
||||
// SVG paths (geometric coordinates, not translatable)
|
||||
'^M[0-9 LML]+$',
|
||||
'^[ML][0-9 ]+$',
|
||||
// Database ordering values (technical, backend API)
|
||||
'^(Asc|Desc)Nulls(First|Last)$',
|
||||
// Calendar response status values (backend enum values, not user-facing)
|
||||
'^(Yes|No|Maybe)$',
|
||||
// Email validation error prefixes (combined with dynamic content)
|
||||
'^Invalid email(s)?:',
|
||||
// GraphQL type construction patterns
|
||||
'.*FilterInput$',
|
||||
'.*OrderByInput.*',
|
||||
'^\\$filter.*',
|
||||
'^\\$orderBy.*',
|
||||
'^\\$after.*',
|
||||
'^\\$before.*',
|
||||
'^\\$first.*',
|
||||
'^\\$last.*',
|
||||
// Logger names (technical identifiers)
|
||||
'^Twenty(-\\w+)?$',
|
||||
// Cookie names and cookie string patterns
|
||||
'^twenty_session_id$',
|
||||
'^; domain=',
|
||||
// Context names for createRequiredContext
|
||||
'^[A-Z][a-zA-Z]+$',
|
||||
// JSON-like filter patterns
|
||||
'^%"type":',
|
||||
'^%"objectNameSingular":',
|
||||
],
|
||||
ignoreNames: [
|
||||
// HTML/React attributes that shouldn't be translated
|
||||
{ regex: { pattern: 'className', flags: 'i' } },
|
||||
{ regex: { pattern: 'styleName', flags: 'i' } },
|
||||
{ regex: { pattern: 'testId', flags: 'i' } },
|
||||
'data-testid',
|
||||
'dataTestId',
|
||||
'src',
|
||||
'srcSet',
|
||||
'href',
|
||||
'target',
|
||||
'rel',
|
||||
'type',
|
||||
'id',
|
||||
'key',
|
||||
'name',
|
||||
'htmlFor',
|
||||
'width',
|
||||
'height',
|
||||
'fill',
|
||||
'stroke',
|
||||
'viewBox',
|
||||
'clipPath',
|
||||
'd', // SVG path
|
||||
'transform',
|
||||
'displayName',
|
||||
'defaultValue',
|
||||
'to', // router links
|
||||
'path',
|
||||
'pathname',
|
||||
'hash',
|
||||
'componentInstanceId',
|
||||
'hotkeyScope',
|
||||
'dropdownId',
|
||||
'recoilScopeId',
|
||||
'modalId',
|
||||
'dialogId',
|
||||
'itemId',
|
||||
'selectableItemIdArray',
|
||||
'listenerId',
|
||||
'focusId',
|
||||
'color', // color prop values
|
||||
'variant', // component variants
|
||||
'size', // size prop values
|
||||
'position', // position values
|
||||
'align', // alignment values
|
||||
'justify', // justification values
|
||||
'direction', // direction values
|
||||
'orientation', // orientation values
|
||||
'status', // status values
|
||||
'state', // state values
|
||||
'mode', // mode values
|
||||
'accent', // accent values
|
||||
|
||||
// CSS-related props
|
||||
'gridAutoColumns',
|
||||
'gridAutoRows',
|
||||
'gridTemplateColumns',
|
||||
'gridTemplateRows',
|
||||
'gridColumn',
|
||||
'gridRow',
|
||||
'gap',
|
||||
'margin',
|
||||
'padding',
|
||||
'border',
|
||||
'borderRadius',
|
||||
'boxShadow',
|
||||
'flex',
|
||||
'flexDirection',
|
||||
'flexWrap',
|
||||
'justifyContent',
|
||||
'alignItems',
|
||||
'alignContent',
|
||||
'overflow',
|
||||
'display',
|
||||
'cursor',
|
||||
'zIndex',
|
||||
'opacity',
|
||||
'fontWeight',
|
||||
'fontSize',
|
||||
'lineHeight',
|
||||
'textAlign',
|
||||
'textDecoration',
|
||||
'whiteSpace',
|
||||
'wordBreak',
|
||||
'objectFit',
|
||||
'backgroundSize',
|
||||
'backgroundPosition',
|
||||
'minWidth',
|
||||
'maxWidth',
|
||||
'minHeight',
|
||||
'maxHeight',
|
||||
'mobileGridAutoColumns',
|
||||
'tabletGridAutoColumns',
|
||||
|
||||
// Styled components
|
||||
'css',
|
||||
'theme',
|
||||
'animation',
|
||||
'transition',
|
||||
|
||||
// GraphQL
|
||||
'query',
|
||||
'mutation',
|
||||
'subscription',
|
||||
'fragment',
|
||||
'operationName',
|
||||
'variables',
|
||||
'__typename',
|
||||
|
||||
// Technical identifiers
|
||||
'fieldName',
|
||||
'columnName',
|
||||
'objectNameSingular',
|
||||
'objectNamePlural',
|
||||
'metadataId',
|
||||
'nameSingular',
|
||||
'namePlural',
|
||||
|
||||
// Event types
|
||||
'eventName',
|
||||
'event',
|
||||
'action',
|
||||
'actionType',
|
||||
|
||||
// Icon names
|
||||
'iconName',
|
||||
{ regex: { pattern: '^Icon[A-Z]' } },
|
||||
|
||||
// UPPER_CASE names (constants)
|
||||
{ regex: { pattern: '^[A-Z][A-Z0-9_]*$' } },
|
||||
|
||||
// Sort direction values (backend API)
|
||||
'orderBy',
|
||||
{ regex: { pattern: '^(Asc|Desc)(NullsFirst|NullsLast)?$' } },
|
||||
|
||||
// HTTP headers (technical, not user-facing)
|
||||
'Authorization',
|
||||
],
|
||||
ignoreFunctions: [
|
||||
// Console and logging
|
||||
'console.*',
|
||||
'*.log',
|
||||
'*.warn',
|
||||
'*.error',
|
||||
'*.debug',
|
||||
'*.info',
|
||||
'*.trace',
|
||||
'logDebug',
|
||||
'formatTitle',
|
||||
|
||||
// Error handling (technical messages, not user-facing)
|
||||
'Error',
|
||||
'TypeError',
|
||||
'RangeError',
|
||||
'SyntaxError',
|
||||
'throw',
|
||||
'assertUnreachable',
|
||||
'CustomError',
|
||||
'parseInitialBlocknote',
|
||||
|
||||
// Testing
|
||||
'describe',
|
||||
'it',
|
||||
'test',
|
||||
'expect',
|
||||
'jest.*',
|
||||
'*.toBe',
|
||||
'*.toEqual',
|
||||
'*.toContain',
|
||||
'*.toMatch',
|
||||
'*.toThrow',
|
||||
|
||||
// React/Libraries internals
|
||||
'require',
|
||||
'import',
|
||||
'styled',
|
||||
'styled.*',
|
||||
'css',
|
||||
'keyframes',
|
||||
'createGlobalStyle',
|
||||
|
||||
// Router
|
||||
'useNavigate',
|
||||
'navigate',
|
||||
'useLocation',
|
||||
'useParams',
|
||||
|
||||
// Date formatting (patterns are not translatable)
|
||||
'format',
|
||||
'formatDate',
|
||||
'formatDateTime',
|
||||
'formatTime',
|
||||
'parseISO',
|
||||
'parse',
|
||||
|
||||
// Navigation
|
||||
'useNavigationSection',
|
||||
|
||||
// Recoil
|
||||
'atom',
|
||||
'atomFamily',
|
||||
'selector',
|
||||
'selectorFamily',
|
||||
'useSetRecoilState',
|
||||
'useRecoilState',
|
||||
'useRecoilValue',
|
||||
|
||||
// GraphQL operations
|
||||
'gql',
|
||||
'useQuery',
|
||||
'useMutation',
|
||||
'useLazyQuery',
|
||||
'useSubscription',
|
||||
|
||||
// Type checking and validation
|
||||
'*.includes',
|
||||
'*.indexOf',
|
||||
'*.startsWith',
|
||||
'*.endsWith',
|
||||
'*.split',
|
||||
'*.join',
|
||||
'*.match',
|
||||
'*.replace',
|
||||
'*.test',
|
||||
'Object.keys',
|
||||
'Object.values',
|
||||
'Object.entries',
|
||||
'Array.isArray',
|
||||
|
||||
// DOM operations
|
||||
'*.getElementById',
|
||||
'*.getElementsByClassName',
|
||||
'*.querySelector',
|
||||
'*.querySelectorAll',
|
||||
'*.getAttribute',
|
||||
'*.setAttribute',
|
||||
'*.addEventListener',
|
||||
'*.removeEventListener',
|
||||
'*.dispatchEvent',
|
||||
'*.createElement',
|
||||
|
||||
// Storage
|
||||
'localStorage.*',
|
||||
'sessionStorage.*',
|
||||
'searchParams.*',
|
||||
'*.get',
|
||||
'*.set',
|
||||
'*.has',
|
||||
'*.delete',
|
||||
|
||||
// Misc utilities
|
||||
'cva',
|
||||
'cn',
|
||||
'clsx',
|
||||
'classNames',
|
||||
'track',
|
||||
'*.postMessage',
|
||||
'*.dispatch',
|
||||
'*.commit',
|
||||
|
||||
// Event handlers (typically receive enum values, not user-facing text)
|
||||
'onChange',
|
||||
'onClick',
|
||||
'onSelect',
|
||||
'onSubmit',
|
||||
'onFocus',
|
||||
'onBlur',
|
||||
'onKeyDown',
|
||||
'onKeyUp',
|
||||
'onMouseEnter',
|
||||
'onMouseLeave',
|
||||
|
||||
// Logging functions (technical messages, not user-facing)
|
||||
'logError',
|
||||
'logDebug',
|
||||
'logInfo',
|
||||
'logWarn',
|
||||
'loggerLink',
|
||||
|
||||
// Context creation (technical names)
|
||||
'createRequiredContext',
|
||||
|
||||
// GraphQL refetch queries (technical identifiers)
|
||||
'refetchQueries',
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
@@ -175,7 +544,7 @@ export default [
|
||||
'@typescript-eslint/ban-ts-comment': 'error',
|
||||
'@typescript-eslint/consistent-type-imports': [
|
||||
'error',
|
||||
{
|
||||
{
|
||||
prefer: 'type-imports',
|
||||
fixStyle: 'inline-type-imports'
|
||||
},
|
||||
@@ -208,11 +577,115 @@ export default [
|
||||
},
|
||||
},
|
||||
|
||||
// Storybook files
|
||||
// Storybook files and story-related files
|
||||
{
|
||||
files: ['*.stories.@(ts|tsx|js|jsx)'],
|
||||
files: [
|
||||
'**/*.stories.ts',
|
||||
'**/*.stories.tsx',
|
||||
'**/*.stories.js',
|
||||
'**/*.stories.jsx',
|
||||
'**/__stories__/**/*',
|
||||
],
|
||||
rules: {
|
||||
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||
'lingui/no-unlocalized-strings': 'off',
|
||||
},
|
||||
},
|
||||
|
||||
// Debug files - development only, not user-facing
|
||||
{
|
||||
files: [
|
||||
'**/Debug*.tsx',
|
||||
'**/*Debug*.tsx',
|
||||
'**/*DebugDisplay*.tsx',
|
||||
'**/*DebugHelper*.tsx',
|
||||
'**/*DebugObserver*.tsx',
|
||||
],
|
||||
rules: {
|
||||
'lingui/no-unlocalized-strings': 'off',
|
||||
},
|
||||
},
|
||||
|
||||
// Testing utilities and mock data - not user-facing
|
||||
{
|
||||
files: [
|
||||
'**/testing/**/*.tsx',
|
||||
'**/testing/**/*.ts',
|
||||
'**/__mocks__/**/*',
|
||||
'**/*mock*.ts',
|
||||
'**/*Mock*.ts',
|
||||
'**/perf/**/*',
|
||||
],
|
||||
rules: {
|
||||
'lingui/no-unlocalized-strings': 'off',
|
||||
},
|
||||
},
|
||||
|
||||
// Constants files - technical values, not user-facing
|
||||
{
|
||||
files: [
|
||||
'**/constants/**/*.ts',
|
||||
'**/*.constants.ts',
|
||||
'**/validation-schemas/**/*.ts',
|
||||
'**/*Schema.ts',
|
||||
'**/*-schema.ts',
|
||||
],
|
||||
rules: {
|
||||
'lingui/no-unlocalized-strings': 'off',
|
||||
},
|
||||
},
|
||||
|
||||
// Layout configuration files - titles are translated at consumption time
|
||||
{
|
||||
files: ['**/layouts/**/*.ts'],
|
||||
rules: {
|
||||
'lingui/no-unlocalized-strings': 'off',
|
||||
},
|
||||
},
|
||||
|
||||
// Service files - contain technical strings (logger names, HTTP headers, etc.)
|
||||
{
|
||||
files: ['**/services/**/*.ts'],
|
||||
rules: {
|
||||
'lingui/no-unlocalized-strings': 'off',
|
||||
},
|
||||
},
|
||||
|
||||
// State files - contain technical default values
|
||||
{
|
||||
files: ['**/states/**/*.ts'],
|
||||
rules: {
|
||||
'lingui/no-unlocalized-strings': 'off',
|
||||
},
|
||||
},
|
||||
|
||||
// Utility files - technical/developer-facing
|
||||
{
|
||||
files: [
|
||||
'**/utils/**/*.ts',
|
||||
'**/*Utils.ts',
|
||||
'**/*-utils.ts',
|
||||
'**/*Util.ts',
|
||||
'**/*-util.ts',
|
||||
'**/errors/**/*.ts',
|
||||
'**/*Error.ts',
|
||||
'**/*-error.ts',
|
||||
],
|
||||
rules: {
|
||||
'lingui/no-unlocalized-strings': 'off',
|
||||
},
|
||||
},
|
||||
|
||||
// Config and setup files - not user-facing
|
||||
{
|
||||
files: [
|
||||
'**/*.config.ts',
|
||||
'**/*.config.js',
|
||||
'**/vite.config.ts',
|
||||
'**/.storybook/**/*',
|
||||
],
|
||||
rules: {
|
||||
'lingui/no-unlocalized-strings': 'off',
|
||||
},
|
||||
},
|
||||
|
||||
@@ -250,7 +723,18 @@ export default [
|
||||
// Test files
|
||||
{
|
||||
files: [
|
||||
'*.test.@(ts|tsx|js|jsx)',
|
||||
'**/*.test.ts',
|
||||
'**/*.test.tsx',
|
||||
'**/*.test.js',
|
||||
'**/*.test.jsx',
|
||||
'**/*.spec.ts',
|
||||
'**/*.spec.tsx',
|
||||
'**/*.spec.js',
|
||||
'**/*.spec.jsx',
|
||||
'**/__tests__/**/*.ts',
|
||||
'**/__tests__/**/*.tsx',
|
||||
'**/__mocks__/**/*.ts',
|
||||
'**/__mocks__/**/*.tsx',
|
||||
],
|
||||
languageOptions: {
|
||||
globals: {
|
||||
@@ -266,6 +750,7 @@ export default [
|
||||
},
|
||||
rules: {
|
||||
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||
'lingui/no-unlocalized-strings': 'off',
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "create-twenty-app",
|
||||
"version": "0.2.0",
|
||||
"version": "0.2.2",
|
||||
"description": "Command-line interface to create Twenty application",
|
||||
"main": "dist/cli.cjs",
|
||||
"bin": "dist/cli.cjs",
|
||||
|
||||
@@ -127,7 +127,7 @@ const createPackageJson = async ({
|
||||
auth: 'twenty auth login',
|
||||
},
|
||||
dependencies: {
|
||||
'twenty-sdk': '0.2.0',
|
||||
'twenty-sdk': '0.2.2',
|
||||
},
|
||||
devDependencies: {
|
||||
'@types/node': '^24.7.2',
|
||||
|
||||
+42
-29
@@ -12,19 +12,28 @@ function App() {
|
||||
useEffect(() => {
|
||||
browser.tabs.query({ active: true, currentWindow: true }, function(tabs) {
|
||||
const currentTab = tabs[0];
|
||||
if(currentTab.url?.includes('https://www.linkedin.com/in')) {
|
||||
sendMessage('getPersonviaRelay').then(data => {
|
||||
setValue({...data, type: 'person' })
|
||||
})
|
||||
}
|
||||
|
||||
if(currentTab.url?.includes('https://www.linkedin.com/company')) {
|
||||
sendMessage('getCompanyviaRelay').then(data => {
|
||||
setValue({...data, type: 'company'})
|
||||
})
|
||||
if (!currentTab.url) {
|
||||
return;
|
||||
}
|
||||
|
||||
let url = new URL(currentTab.url);
|
||||
|
||||
const isLinkedinHost =
|
||||
url.protocol === 'https:' && url.hostname === 'www.linkedin.com';
|
||||
|
||||
if (isLinkedinHost && url.pathname.startsWith('/in/')) {
|
||||
sendMessage('getPersonviaRelay').then((data) => {
|
||||
setValue({ ...data, type: 'person' });
|
||||
});
|
||||
}
|
||||
|
||||
if (isLinkedinHost && url.pathname.startsWith('/company/')) {
|
||||
sendMessage('getCompanyviaRelay').then((data) => {
|
||||
setValue({ ...data, type: 'company' });
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}, []);
|
||||
|
||||
const isPersonValue = (val: Value): val is PersonValue => {
|
||||
@@ -38,25 +47,29 @@ function App() {
|
||||
return (
|
||||
<StyledMain>
|
||||
<h1>{JSON.stringify(value)}</h1>
|
||||
{
|
||||
isPersonValue(value) &&
|
||||
<button onClick={async () => {
|
||||
await sendMessage('createPerson', {
|
||||
firstName: value.firstName,
|
||||
lastName: value.lastName,
|
||||
});
|
||||
|
||||
}}>save person to twenty</button>
|
||||
}
|
||||
{
|
||||
isCompanyValue(value) &&
|
||||
<button onClick={async () => {
|
||||
await sendMessage('createCompany', {
|
||||
name: value.companyName
|
||||
});
|
||||
|
||||
}}>save company to twenty</button>
|
||||
}
|
||||
{isPersonValue(value) && (
|
||||
<button
|
||||
onClick={async () => {
|
||||
await sendMessage('createPerson', {
|
||||
firstName: value.firstName,
|
||||
lastName: value.lastName,
|
||||
});
|
||||
}}
|
||||
>
|
||||
save person to twenty
|
||||
</button>
|
||||
)}
|
||||
{isCompanyValue(value) && (
|
||||
<button
|
||||
onClick={async () => {
|
||||
await sendMessage('createCompany', {
|
||||
name: value.companyName,
|
||||
});
|
||||
}}
|
||||
>
|
||||
save company to twenty
|
||||
</button>
|
||||
)}
|
||||
</StyledMain>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "hello-world",
|
||||
"version": "0.1.0",
|
||||
"version": "0.2.1",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^24.5.0",
|
||||
@@ -17,7 +17,7 @@
|
||||
"auth": "twenty auth login"
|
||||
},
|
||||
"dependencies": {
|
||||
"twenty-sdk": "0.1.2"
|
||||
"twenty-sdk": "0.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^24.7.2"
|
||||
|
||||
@@ -1,21 +1,30 @@
|
||||
import { type FunctionConfig } from 'twenty-sdk';
|
||||
import { createClient } from '../../generated';
|
||||
import type {
|
||||
FunctionConfig,
|
||||
DatabaseEventPayload,
|
||||
ObjectRecordCreateEvent,
|
||||
CronPayload,
|
||||
} from 'twenty-sdk';
|
||||
import Twenty, { type Person } from '../../generated';
|
||||
|
||||
export const main = async (params: { recipient?: string }) => {
|
||||
type CreateNewPostCardParams =
|
||||
| { name?: string }
|
||||
| DatabaseEventPayload<ObjectRecordCreateEvent<Person>>
|
||||
| CronPayload;
|
||||
|
||||
export const main = async (params: CreateNewPostCardParams) => {
|
||||
try {
|
||||
const client = createClient({
|
||||
url: `${process.env.TWENTY_API_URL}/graphql`,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${process.env.TWENTY_API_KEY}`,
|
||||
},
|
||||
});
|
||||
const client = new Twenty();
|
||||
|
||||
const name =
|
||||
'name' in params
|
||||
? params.name ?? process.env.DEFAULT_RECIPIENT_NAME ?? 'Hello world'
|
||||
: 'Hello world';
|
||||
|
||||
const createPostCard = await client.mutation({
|
||||
createPostCard: {
|
||||
__args: {
|
||||
data: {
|
||||
name: params.recipient ?? 'Hello-world',
|
||||
name,
|
||||
},
|
||||
},
|
||||
name: true,
|
||||
|
||||
+5
-8
@@ -6,17 +6,14 @@ const config: ApplicationConfig = {
|
||||
description: 'A simple hello world app',
|
||||
icon: 'IconWorld',
|
||||
applicationVariables: {
|
||||
TWENTY_API_KEY: {
|
||||
universalIdentifier: 'dedc53eb-9c12-4fe2-ba86-4a2add19d305',
|
||||
description: 'Twenty API Key',
|
||||
isSecret: true,
|
||||
},
|
||||
TWENTY_API_URL: {
|
||||
universalIdentifier: 'ef8ab489-e68a-4841-b402-261f440e6185',
|
||||
description: 'Twenty API Url',
|
||||
DEFAULT_RECIPIENT_NAME: {
|
||||
universalIdentifier: '19e94e59-d4fe-4251-8981-b96d0a9f74de',
|
||||
description: 'Default recipient name for postcards',
|
||||
value: 'Alex Karp',
|
||||
isSecret: false,
|
||||
},
|
||||
},
|
||||
functionRoleUniversalIdentifier: 'b648f87b-1d26-4961-b974-0908fd991061',
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -0,0 +1,34 @@
|
||||
import { PermissionFlag, type RoleConfig } from 'twenty-sdk';
|
||||
|
||||
export const functionRole: RoleConfig = {
|
||||
universalIdentifier: 'b648f87b-1d26-4961-b974-0908fd991061',
|
||||
label: 'Default function role',
|
||||
description: 'Default role for function Twenty client',
|
||||
canReadAllObjectRecords: false,
|
||||
canUpdateAllObjectRecords: false,
|
||||
canSoftDeleteAllObjectRecords: false,
|
||||
canDestroyAllObjectRecords: false,
|
||||
canUpdateAllSettings: false,
|
||||
canBeAssignedToAgents: false,
|
||||
canBeAssignedToUsers: false,
|
||||
canBeAssignedToApiKeys: false,
|
||||
canBeAssignedToApplications: true,
|
||||
objectPermissions: [
|
||||
{
|
||||
objectNameSingular: 'postCard',
|
||||
canReadObjectRecords: true,
|
||||
canUpdateObjectRecords: true,
|
||||
canSoftDeleteObjectRecords: false,
|
||||
canDestroyObjectRecords: false,
|
||||
},
|
||||
],
|
||||
fieldPermissions: [
|
||||
{
|
||||
objectNameSingular: 'postCard',
|
||||
fieldName: 'content',
|
||||
canReadFieldValue: false,
|
||||
canUpdateFieldValue: false,
|
||||
},
|
||||
],
|
||||
permissionFlags: [PermissionFlag.APPLICATIONS],
|
||||
};
|
||||
@@ -1021,6 +1021,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"graphql-sse@npm:^2.5.4":
|
||||
version: 2.6.0
|
||||
resolution: "graphql-sse@npm:2.6.0"
|
||||
peerDependencies:
|
||||
graphql: ">=0.11 <=16"
|
||||
checksum: 10c0/e05f0b5c8539d61e5ce34af8e0bb418c02bf922d6a7f9232a9abd53c77df5654684ca14f674ac771645c8fba9c37ce666c5d06f46eef54ea07e63653468065b0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"graphql@npm:^16.6.0, graphql@npm:^16.8.1":
|
||||
version: 16.12.0
|
||||
resolution: "graphql@npm:16.12.0"
|
||||
@@ -1074,7 +1083,7 @@ __metadata:
|
||||
resolution: "hello-world@workspace:."
|
||||
dependencies:
|
||||
"@types/node": "npm:^24.7.2"
|
||||
twenty-sdk: "npm:0.1.2"
|
||||
twenty-sdk: "npm:0.2.1"
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
@@ -1895,9 +1904,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"twenty-sdk@npm:0.1.2":
|
||||
version: 0.1.2
|
||||
resolution: "twenty-sdk@npm:0.1.2"
|
||||
"twenty-sdk@npm:0.2.1":
|
||||
version: 0.2.1
|
||||
resolution: "twenty-sdk@npm:0.2.1"
|
||||
dependencies:
|
||||
"@genql/cli": "npm:^3.0.3"
|
||||
axios: "npm:^1.6.0"
|
||||
@@ -1907,6 +1916,7 @@ __metadata:
|
||||
dotenv: "npm:^16.4.0"
|
||||
fs-extra: "npm:^11.2.0"
|
||||
graphql: "npm:^16.8.1"
|
||||
graphql-sse: "npm:^2.5.4"
|
||||
inquirer: "npm:^10.0.0"
|
||||
jsonc-parser: "npm:^3.2.0"
|
||||
lodash.camelcase: "npm:^4.3.0"
|
||||
@@ -1917,7 +1927,7 @@ __metadata:
|
||||
uuid: "npm:^13.0.0"
|
||||
bin:
|
||||
twenty: dist/cli.cjs
|
||||
checksum: 10c0/18cb8c589b6d6c6e59d58c28eae333718d62df485d827ba41e99421ef9fb359c3f71fa42d80b1e5463d2140b68de084aee81bf541e70c0d04a246c332e2978e7
|
||||
checksum: 10c0/5a4f4674129cc747e8e5091bf75025260db20087f76f1cee49896a073c8cf83b8c95e1dce3f2f2cbaaf9570aa1886c4c9a5585f0e61e0ee79552eab4d292fb4e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
@@ -32,4 +32,3 @@ export const MyComponent = () => {
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
|
||||
@@ -123,6 +123,19 @@ Figma プラットフォームの学習に関するより包括的な詳細と
|
||||
これは推奨拡張機能の一部です。
|
||||
これは推奨拡張機能の一部です。
|
||||
これは推奨拡張機能の一部です。
|
||||
これは推奨拡張機能の一部です。
|
||||
これは推奨拡張機能の一部です。
|
||||
これは推奨拡張機能の一部です。
|
||||
これは推奨拡張機能の一部です。
|
||||
これは推奨拡張機能の一部です。
|
||||
これは推奨拡張機能の一部です。
|
||||
これは推奨拡張機能の一部です。
|
||||
これは推奨拡張機能の一部です。
|
||||
これは推奨拡張機能の一部です。
|
||||
これは推奨拡張機能の一部です。
|
||||
これは推奨拡張機能の一部です。
|
||||
これは推奨拡張機能の一部です。
|
||||
これは推奨拡張機能の一部です。
|
||||
|
||||
## コラボレーション
|
||||
|
||||
|
||||
@@ -158,7 +158,7 @@ SSL(HTTPS)は、特定のブラウザ機能が正しく動作するために
|
||||
|
||||
2. **.env ファイルを更新**
|
||||
|
||||
.env`ファイルを開き、`SERVER_URL\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\`を更新します:
|
||||
.env`ファイルを開き、`SERVER_URL\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\`を更新します:
|
||||
|
||||
```ini
|
||||
SERVER_URL=http(s)://your-domain-or-ip:your-port
|
||||
|
||||
@@ -30,7 +30,7 @@ Twentyは、日常をサポートする最適なデータモデルを形成す
|
||||
既存のオブジェクトの特性に過ぎないもの(例:会社の「業種」や機会の「ステータス」)はフィールドにします。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。 カテゴリ、ラベル、属性にはフィールドが最適です。
|
||||
|
||||
**3. 単独で存在する場合には新しいオブジェクトを作成してください。**
|
||||
概念が独自のライフサイクル、プロパティ、または関係を持つ場合、それは通常オブジェクトに値します。 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば:
|
||||
概念が独自のライフサイクル、プロパティ、または関係を持つ場合、それは通常オブジェクトに値します。 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば: 例えば:
|
||||
|
||||
- **プロジェクト**:独自の期限、所有者、タスクを持つもの
|
||||
- **サブスクリプション**:会社、製品、請求書を結ぶもの
|
||||
|
||||
@@ -51,7 +51,7 @@ npx nx run twenty-front:storybook:coverage # (needs yarn storybook:serve:dev to
|
||||
|
||||
## Технологический стек
|
||||
|
||||
The project has a clean and simple stack, with minimal boilerplate code.
|
||||
Проект имеет чистый и простой стек с минимальным кодом.
|
||||
|
||||
**Приложение**
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ const PageListeningEnter = () => {
|
||||
|
||||
### Прослушивание горячих клавиш в компоненте типа модального окна
|
||||
|
||||
For this example we'll use a modal component that listens for the Escape key to tell its parent to close it.
|
||||
Для этого примера мы используем модальный компонент, который прослушивает ключ Escape, чтобы сообщить своему родителю закрыть его.
|
||||
|
||||
В этом случае взаимодействие пользователя меняет область операций.
|
||||
|
||||
|
||||
@@ -45,8 +45,9 @@ sectionInfo: 配置您的Twenty工作空间设置和偏好
|
||||
刪除您的帳號將永久移除您對所有工作空間的訪問。
|
||||
刪除您的帳號將永久移除您對所有工作空間的訪問。 此操作無法撤銷,您將失去所有工作空間權限,如您只想退出特定的團隊,應考慮退出個別的工作空間。 刪除您的帳號將永久移除您對所有工作空間的訪問。
|
||||
刪除您的帳號將永久移除您對所有工作空間的訪問。 此操作無法撤銷,您將失去所有工作空間權限,如您只想退出特定的團隊,應考慮退出個別的工作空間。
|
||||
</Warning> 刪除您的帳號將永久移除您對所有工作空間的訪問。
|
||||
</Warning> 刪除您的帳號將永久移除您對所有工作空間的訪問。
|
||||
刪除您的帳號將永久移除您對所有工作空間的訪問。 此操作無法撤銷,您將失去所有工作空間權限,如您只想退出特定的團隊,應考慮退出個別的工作空間。
|
||||
|
||||
</Warning>
|
||||
|
||||
要删除您的帐户:
|
||||
|
||||
@@ -3,4 +3,4 @@ FRONTEND_BASE_URL=http://localhost:3001
|
||||
BACKEND_BASE_URL=http://localhost:3000
|
||||
DEFAULT_LOGIN=tim@apple.dev
|
||||
DEFAULT_PASSWORD=tim@apple.dev
|
||||
WEBSITE_URL=https://twenty.com
|
||||
WEBSITE_URL=https://twenty.com
|
||||
|
||||
@@ -27,6 +27,7 @@ export const test = base.extend<{ screenshotHook: void }>({
|
||||
},
|
||||
{ auto: true },
|
||||
],
|
||||
baseURL: process.env.LINK ? new URL(process.env.LINK).origin : 'http://localhost:3001',
|
||||
});
|
||||
|
||||
export { expect } from '@playwright/test';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Page } from '@playwright/test';
|
||||
import { getAuthToken } from '../utils/getAuthToken';
|
||||
import { type Page } from '@playwright/test';
|
||||
import { getAccessAuthToken } from '../utils/getAccessAuthToken';
|
||||
import { backendGraphQLUrl } from './backend';
|
||||
|
||||
export const createWorkflow = async ({
|
||||
@@ -11,7 +11,7 @@ export const createWorkflow = async ({
|
||||
workflowId: string;
|
||||
workflowName: string;
|
||||
}) => {
|
||||
const { authToken } = await getAuthToken(page);
|
||||
const { authToken } = await getAccessAuthToken(page);
|
||||
|
||||
return page.request.post(backendGraphQLUrl, {
|
||||
headers: {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Page } from '@playwright/test';
|
||||
import { getAuthToken } from '../utils/getAuthToken';
|
||||
import { type Page } from '@playwright/test';
|
||||
import { getAccessAuthToken } from '../utils/getAccessAuthToken';
|
||||
import { backendGraphQLUrl } from './backend';
|
||||
|
||||
export const deleteWorkflow = async ({
|
||||
@@ -9,7 +9,7 @@ export const deleteWorkflow = async ({
|
||||
page: Page;
|
||||
workflowId: string;
|
||||
}) => {
|
||||
const { authToken } = await getAuthToken(page);
|
||||
const { authToken } = await getAccessAuthToken(page);
|
||||
|
||||
return page.request.post(backendGraphQLUrl, {
|
||||
headers: {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Page } from '@playwright/test';
|
||||
import { getAuthToken } from '../utils/getAuthToken';
|
||||
import { type Page } from '@playwright/test';
|
||||
import { getAccessAuthToken } from '../utils/getAccessAuthToken';
|
||||
import { backendGraphQLUrl } from './backend';
|
||||
|
||||
export const destroyWorkflow = async ({
|
||||
@@ -9,7 +9,7 @@ export const destroyWorkflow = async ({
|
||||
page: Page;
|
||||
workflowId: string;
|
||||
}) => {
|
||||
const { authToken } = await getAuthToken(page);
|
||||
const { authToken } = await getAccessAuthToken(page);
|
||||
|
||||
return page.request.post(backendGraphQLUrl, {
|
||||
headers: {
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import { type Page } from '@playwright/test';
|
||||
|
||||
const decodeToken = (cookie: any) =>
|
||||
JSON.parse(decodeURIComponent(cookie.value)).accessOrWorkspaceAgnosticToken
|
||||
?.token;
|
||||
|
||||
const decodePayload = (jwt: string) =>
|
||||
JSON.parse(Buffer.from(jwt.split('.')[1], 'base64url').toString());
|
||||
|
||||
|
||||
export const getAccessAuthToken = async (page: Page) => {
|
||||
const storageState = await page.context().storageState();
|
||||
const tokenCookies = storageState.cookies.filter(
|
||||
(cookie) => cookie.name === 'tokenPair',
|
||||
);
|
||||
if (!tokenCookies) {
|
||||
throw new Error('No auth cookie found');
|
||||
}
|
||||
const accessTokenCookie = tokenCookies.find(
|
||||
(cookie) => {
|
||||
const payload = decodePayload(decodeToken(cookie) ?? '');
|
||||
return payload.type === 'ACCESS';
|
||||
}
|
||||
);
|
||||
|
||||
const token = JSON.parse(decodeURIComponent(accessTokenCookie?.value ?? '')).accessOrWorkspaceAgnosticToken
|
||||
.token;
|
||||
|
||||
return { authToken: token };
|
||||
};
|
||||
@@ -1,15 +0,0 @@
|
||||
import { Page } from '@playwright/test';
|
||||
|
||||
export const getAuthToken = async (page: Page) => {
|
||||
const storageState = await page.context().storageState();
|
||||
const authCookie = storageState.cookies.find(
|
||||
(cookie) => cookie.name === 'tokenPair',
|
||||
);
|
||||
if (!authCookie) {
|
||||
throw new Error('No auth cookie found');
|
||||
}
|
||||
const token = JSON.parse(decodeURIComponent(authCookie.value)).accessOrWorkspaceAgnosticToken
|
||||
.token;
|
||||
|
||||
return { authToken: token };
|
||||
};
|
||||
@@ -34,7 +34,10 @@ export default defineConfig({
|
||||
expect: {
|
||||
timeout: 5000,
|
||||
},
|
||||
reporter: process.env.CI ? 'github' : 'list',
|
||||
reporter: [
|
||||
[process.env.CI ? 'github' : 'list'],
|
||||
['./reporters/log-summary-reporter.ts'],
|
||||
],
|
||||
projects: [
|
||||
{
|
||||
name: 'setup',
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import type {
|
||||
Reporter,
|
||||
TestCase,
|
||||
TestResult,
|
||||
} from '@playwright/test/reporter';
|
||||
|
||||
class LogSummaryReporter implements Reporter {
|
||||
private passed: string[] = [];
|
||||
private failed: string[] = [];
|
||||
|
||||
onTestEnd(test: TestCase, result: TestResult): void {
|
||||
const name = test.titlePath().join(' › ');
|
||||
|
||||
if (result.status === 'passed') {
|
||||
this.passed.push(name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (result.status === 'failed' || result.status === 'timedOut') {
|
||||
this.failed.push(name);
|
||||
}
|
||||
}
|
||||
|
||||
onEnd(): void {
|
||||
const passedSet = new Set(this.passed);
|
||||
const failedSet = new Set(this.failed);
|
||||
const flaky: string[] = [];
|
||||
|
||||
for (const testName of passedSet) {
|
||||
if (failedSet.has(testName)) {
|
||||
flaky.push(testName);
|
||||
}
|
||||
}
|
||||
|
||||
const uniquePassed = this.passed.filter((testName) => !flaky.includes(testName));
|
||||
const uniqueFailed = this.failed.filter((testName) => !flaky.includes(testName));
|
||||
|
||||
console.log('\n=== Playwright summary ===');
|
||||
if (uniquePassed.length) {
|
||||
console.log('Passed:');
|
||||
uniquePassed.forEach((testName) => console.log(` ✅ ${testName}`));
|
||||
}
|
||||
if (uniqueFailed.length) {
|
||||
console.log('Failed:');
|
||||
uniqueFailed.forEach((testName) => console.log(` ❌ ${testName}`));
|
||||
}
|
||||
if (flaky.length) {
|
||||
console.log('Flaky:');
|
||||
flaky.forEach((testName) => console.log(` ⚠️ ${testName}`));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default LogSummaryReporter;
|
||||
@@ -49,12 +49,10 @@ test('Sign up with invite link via email', async ({
|
||||
await leftMenu.goToSettings();
|
||||
await settingsPage.goToProfileSection();
|
||||
await profileSection.deleteAccount();
|
||||
await expect(page.getByText('Account Deletion')).toBeVisible();
|
||||
await confirmationModal.typePlaceholderToInput();
|
||||
await confirmationModal.clickConfirmButton();
|
||||
|
||||
await Promise.all([
|
||||
page.waitForURL('/welcome'),
|
||||
|
||||
confirmationModal.clickConfirmButton(),
|
||||
]);
|
||||
await page.waitForURL('**/welcome');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import { expect, test } from '../lib/fixtures/screenshot';
|
||||
test.describe.serial('Create Kanban View', () => {
|
||||
test('Create Industry Select Field', async ({ page }) => {
|
||||
await page.getByRole('link', { name: 'Settings' }).click();
|
||||
await page.getByRole('link', { name: 'Data model' }).click();
|
||||
await page.getByRole('link', { name: 'Opportunities' }).click();
|
||||
await page.getByRole('button', { name: 'Add Field' }).click();
|
||||
await page.getByRole('link', { name: 'Select', exact: true }).click();
|
||||
await page.getByRole('textbox', { name: 'Employees' }).click();
|
||||
await page.getByRole('textbox', { name: 'Employees' }).fill('Industry');
|
||||
await page.getByRole('textbox').nth(1).click();
|
||||
await page.getByRole('textbox').nth(1).press('ControlOrMeta+a');
|
||||
await page.getByRole('textbox').nth(1).fill('Food');
|
||||
await page.getByRole('button', { name: 'Add option' }).click();
|
||||
await page.getByRole('button', { name: 'Option 2' }).getByRole('textbox').fill('Tech');
|
||||
await page.getByRole('button', { name: 'Add option' }).click();
|
||||
await page.getByRole('button', { name: 'Option 3' }).getByRole('textbox').fill('Travel');
|
||||
await page.getByRole('button', { name: 'Save' }).click();
|
||||
await page.waitForURL('**/objects/opportunities');
|
||||
await page.waitForSelector('text=Industry');
|
||||
await expect(page.getByText('Industry')).toBeVisible();
|
||||
});
|
||||
|
||||
test('Create Kanban View from Industry Select Field', async ({ page }) => {
|
||||
await page.getByRole('link', { name: 'Opportunities' }).click();
|
||||
await page.getByRole('button', { name: 'All Opportunities ·' }).click();
|
||||
await page.getByText('Add view').click();
|
||||
await page.getByRole('textbox').press('ControlOrMeta+a');
|
||||
await page.getByRole('textbox').fill('By industry');
|
||||
await page.getByRole('button', { name: 'Table', exact: true }).click();
|
||||
await page.getByText('Kanban').click();
|
||||
await page.locator('[aria-controls="view-picker-kanban-field-options"]').click();
|
||||
await page.getByRole('option', { name: 'Industry' }).click();
|
||||
// Use exact: true to ensure we only click the button with the label "Create"
|
||||
await page.getByRole('button', { name: 'Create new view' }).click();
|
||||
await expect(page.getByText('Food')).toBeVisible();
|
||||
await expect(page.getByText('Tech')).toBeVisible();
|
||||
await expect(page.getByText('Travel')).toBeVisible();
|
||||
await expect(page.getByText('No value')).toBeVisible();
|
||||
const byIndustryElements = await page.locator('text=By industry').all();
|
||||
expect(byIndustryElements.length).toBeGreaterThanOrEqual(1);
|
||||
for (const element of byIndustryElements) {
|
||||
await expect(element).toBeVisible();
|
||||
}
|
||||
await page.getByText('Options').click();
|
||||
await page.getByText('Group', { exact: true }).click();
|
||||
await Promise.all([page.getByTestId('hide-group-').click(),
|
||||
page.waitForRequest((req) => {
|
||||
return req.url().includes('/metadata') &&
|
||||
req.method() === 'POST';
|
||||
})]);
|
||||
await expect(page.getByText('No value')).not.toBeVisible();
|
||||
});
|
||||
})
|
||||
@@ -0,0 +1,158 @@
|
||||
import { expect, test } from '../lib/fixtures/screenshot';
|
||||
import { backendGraphQLUrl } from '../lib/requests/backend';
|
||||
import { getAccessAuthToken } from '../lib/utils/getAccessAuthToken';
|
||||
|
||||
const query = `query FindOnePerson($objectRecordId: UUID!) {
|
||||
person(
|
||||
filter: {or: [{deletedAt: {is: NULL}}, {deletedAt: {is: NOT_NULL}}], id: {eq: $objectRecordId}}
|
||||
) {
|
||||
company {
|
||||
name
|
||||
}
|
||||
emails {
|
||||
primaryEmail
|
||||
additionalEmails
|
||||
__typename
|
||||
}
|
||||
id
|
||||
intro
|
||||
jobTitle
|
||||
linkedinLink {
|
||||
primaryLinkUrl
|
||||
primaryLinkLabel
|
||||
secondaryLinks
|
||||
__typename
|
||||
}
|
||||
name {
|
||||
firstName
|
||||
lastName
|
||||
__typename
|
||||
}
|
||||
performanceRating
|
||||
phones {
|
||||
primaryPhoneNumber
|
||||
primaryPhoneCountryCode
|
||||
primaryPhoneCallingCode
|
||||
additionalPhones
|
||||
__typename
|
||||
}
|
||||
position
|
||||
workPreference
|
||||
updatedAt
|
||||
}
|
||||
}`
|
||||
|
||||
test('Create and update record', async ({ page }) => {
|
||||
await page.getByRole('link', { name: 'People' }).click();
|
||||
await page.getByRole('button', { name: 'Create new record' }).click();
|
||||
|
||||
// Generate a random email for testing
|
||||
const randomEmail = `testuser_${Math.random().toString(36).substring(2, 10)}@example.com`;
|
||||
// Fill first name and last name
|
||||
const firstNameInput = page.getByRole('textbox', { name: 'First name' })
|
||||
await expect(firstNameInput).toBeFocused();
|
||||
await firstNameInput.fill('John');
|
||||
const lastNameInput = page.getByPlaceholder('Last name');
|
||||
await expect(lastNameInput).toBeVisible();
|
||||
await lastNameInput.fill('Doe');
|
||||
await lastNameInput.press('Enter');
|
||||
|
||||
// Focus on recordFieldList
|
||||
const recordFieldList = page.getByTestId('record-fields-list-container');
|
||||
await expect(recordFieldList).toBeVisible();
|
||||
await recordFieldList.getByText('Emails').first().click();
|
||||
|
||||
// Fill email
|
||||
const emailInput = recordFieldList.getByText('Emails').nth(1);
|
||||
await expect(emailInput).toBeVisible();
|
||||
await emailInput.click({ force: true });
|
||||
await page.getByPlaceholder('Email').fill(randomEmail);
|
||||
await page.keyboard.press('Enter');
|
||||
await page.keyboard.press('Escape');
|
||||
await recordFieldList.getByText('Emails').first().click();
|
||||
|
||||
|
||||
// Fill intro
|
||||
const introInput = recordFieldList.getByText('Intro').nth(1);
|
||||
await expect(introInput).toBeVisible();
|
||||
await introInput.click({ force: true });
|
||||
await introInput.click({ force: true });
|
||||
await page.getByPlaceholder('Intro').fill('This is an intro');
|
||||
await page.getByPlaceholder('Intro').press('Enter');
|
||||
|
||||
// Fill URL
|
||||
const urlInput = recordFieldList.getByText('Linkedin').nth(1);
|
||||
await expect(urlInput).toBeVisible();
|
||||
await urlInput.click({ force: true });
|
||||
await page.getByPlaceholder('URL').fill('linkedin.com/johndoe');
|
||||
await page.getByPlaceholder('URL').press('Enter');
|
||||
|
||||
// Click on 4th star to rate
|
||||
recordFieldList.getByText('Performance Rating').first().click({ force: true });
|
||||
const ratingContainer = recordFieldList.locator('div[aria-label="Rating"]');
|
||||
await ratingContainer.locator('svg').nth(3).click({force: true});
|
||||
|
||||
// Fill phone field
|
||||
const phoneInput = recordFieldList.getByText('Phones').nth(1);
|
||||
await expect(phoneInput).toBeVisible();
|
||||
await phoneInput.click({ force: true });
|
||||
await page.getByPlaceholder('Phone').fill('+336 1 122 3344');
|
||||
await page.getByPlaceholder('Phone').press('Enter');
|
||||
|
||||
// Fill work preference
|
||||
await recordFieldList.getByText('Work Preference').first().click({force: true});
|
||||
await recordFieldList.getByText('Work Preference').nth(1).click({force: true});
|
||||
const options = page.getByRole('listbox');
|
||||
await options.getByText('Hybrid').first().click({force: true});
|
||||
recordFieldList.getByText('Work Preference').first().click({force: true});
|
||||
|
||||
// Fill company relation
|
||||
const companyRelationHeader = page.getByTestId('company-relation');
|
||||
await expect(companyRelationHeader).toBeVisible();
|
||||
|
||||
await companyRelationHeader.locator('.tabler-icon-pencil').click();
|
||||
await page.getByRole('textbox', { name: 'Search' }).fill('Goog');
|
||||
await expect(page.getByRole('option', { name: 'Google' })).toBeVisible();
|
||||
const [updatePersonResponse] = await Promise.all([
|
||||
page.waitForResponse(async (response) => {
|
||||
if (!response.url().endsWith('/graphql')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const requestBody = response.request().postDataJSON();
|
||||
|
||||
return requestBody.operationName === 'UpdateOnePerson';
|
||||
}),
|
||||
await page.getByRole('option', { name: 'Google' }).click({force: true})
|
||||
]);
|
||||
|
||||
const body = await updatePersonResponse.json()
|
||||
const newPersonId = body.data.updatePerson.id;
|
||||
|
||||
// Check data was saved
|
||||
const { authToken } = await getAccessAuthToken(page);
|
||||
const findOnePersonResponse = await page.request.post(backendGraphQLUrl, {
|
||||
headers: {
|
||||
Authorization: `Bearer ${authToken}`,
|
||||
},
|
||||
data: {
|
||||
operationName: 'FindOnePerson',
|
||||
query,
|
||||
variables: {
|
||||
objectRecordId: newPersonId,
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const findOnePersonReponseBody = await findOnePersonResponse.json();
|
||||
|
||||
expect(findOnePersonReponseBody.data.person.name.firstName).toBe('John');
|
||||
expect(findOnePersonReponseBody.data.person.name.lastName).toBe('Doe');
|
||||
expect(findOnePersonReponseBody.data.person.emails.primaryEmail).toBe(randomEmail);
|
||||
expect(findOnePersonReponseBody.data.person.intro).toBe('This is an intro');
|
||||
expect(findOnePersonReponseBody.data.person.linkedinLink.primaryLinkUrl).toBe('linkedin.com/johndoe');
|
||||
expect(findOnePersonReponseBody.data.person.phones.primaryPhoneNumber).toBe('611223344');
|
||||
expect(findOnePersonReponseBody.data.person.workPreference).toEqual(['HYBRID']);
|
||||
expect(findOnePersonReponseBody.data.person.company.name).toBe('Google');
|
||||
|
||||
});
|
||||
@@ -29,7 +29,13 @@ test('Login test', async ({ loginPage, page }) => {
|
||||
await loginPage.typePassword(process.env.DEFAULT_PASSWORD);
|
||||
await page.waitForLoadState('networkidle');
|
||||
await loginPage.clickSignInButton();
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page.getByText(/Welcome to .+/)).not.toBeVisible();
|
||||
await expect(page.getByText('Choose a workspace')).toBeVisible();
|
||||
await page.getByText('Apple', {exact: true}).click();
|
||||
await page.waitForFunction(() => window.location.href.includes('verify'));
|
||||
await page.waitForFunction(() => !window.location.href.includes('verify'));
|
||||
process.env.LINK = page.url();
|
||||
},
|
||||
);
|
||||
|
||||
@@ -37,6 +43,5 @@ test('Login test', async ({ loginPage, page }) => {
|
||||
await page.context().storageState({
|
||||
path: path.resolve(__dirname, '..', '.auth', 'user.json'),
|
||||
});
|
||||
process.env.LINK = page.url();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
import { expect, test } from '../lib/fixtures/screenshot';
|
||||
import { deleteWorkflow } from '../lib/requests/delete-workflow';
|
||||
import { destroyWorkflow } from '../lib/requests/destroy-workflow';
|
||||
|
||||
test('Create workflow', async ({ page }) => {
|
||||
const NEW_WORKFLOW_NAME = 'Test Workflow';
|
||||
|
||||
await page.goto('/');
|
||||
await page.goto(process.env.LINK);
|
||||
|
||||
const workflowsLink = page.getByRole('link', { name: 'Workflows' });
|
||||
await workflowsLink.click();
|
||||
@@ -25,7 +25,7 @@ test('Create workflow', async ({ page }) => {
|
||||
return requestBody.operationName === 'CreateOneWorkflow';
|
||||
}),
|
||||
|
||||
createWorkflowButton.click(),
|
||||
createWorkflowButton.click()
|
||||
]);
|
||||
|
||||
const recordName = page.getByTestId('top-bar-title').getByText('Untitled');
|
||||
|
||||
@@ -1,150 +1,150 @@
|
||||
import { expect } from '@playwright/test';
|
||||
import { test } from '../lib/fixtures/blank-workflow';
|
||||
// import { expect } from '@playwright/test';
|
||||
// import { test } from '../lib/fixtures/blank-workflow';
|
||||
|
||||
test('The workflow run visualizer shows the executed draft version without the last draft changes', async ({
|
||||
workflowVisualizer,
|
||||
page,
|
||||
}) => {
|
||||
await workflowVisualizer.createInitialTrigger('manual');
|
||||
// test('The workflow run visualizer shows the executed draft version without the last draft changes', async ({
|
||||
// workflowVisualizer,
|
||||
// page,
|
||||
// }) => {
|
||||
// await workflowVisualizer.createInitialTrigger('manual');
|
||||
|
||||
const manualTriggerAvailabilitySelect = page.getByRole('button', {
|
||||
name: 'When record is selected',
|
||||
});
|
||||
// const manualTriggerAvailabilitySelect = page.getByRole('button', {
|
||||
// name: 'When record is selected',
|
||||
// });
|
||||
|
||||
await manualTriggerAvailabilitySelect.click();
|
||||
// await manualTriggerAvailabilitySelect.click();
|
||||
|
||||
const alwaysAvailableOption = page.getByText('When no record is selected');
|
||||
// const alwaysAvailableOption = page.getByText('When no record is selected');
|
||||
|
||||
await alwaysAvailableOption.click();
|
||||
// await alwaysAvailableOption.click();
|
||||
|
||||
await workflowVisualizer.closeSidePanel();
|
||||
// await workflowVisualizer.closeSidePanel();
|
||||
|
||||
const { createdStepId: firstStepId } =
|
||||
await workflowVisualizer.createStep('create-record');
|
||||
// const { createdStepId: firstStepId } =
|
||||
// await workflowVisualizer.createStep('create-record');
|
||||
|
||||
await workflowVisualizer.closeSidePanel();
|
||||
// await workflowVisualizer.closeSidePanel();
|
||||
|
||||
const launchTestButton = page.getByLabel(workflowVisualizer.workflowName);
|
||||
// const launchTestButton = page.getByLabel(workflowVisualizer.workflowName);
|
||||
|
||||
await launchTestButton.click();
|
||||
// await launchTestButton.click();
|
||||
|
||||
await workflowVisualizer.closeSidePanel();
|
||||
// await workflowVisualizer.closeSidePanel();
|
||||
|
||||
await workflowVisualizer.deleteStep(firstStepId);
|
||||
// await workflowVisualizer.deleteStep(firstStepId);
|
||||
|
||||
await page.goto('/objects/workflowRuns');
|
||||
// await page.goto('/objects/workflowRuns');
|
||||
|
||||
const recordTableRowForWorkflowRun = page
|
||||
.getByRole('row', {
|
||||
name: workflowVisualizer.workflowName,
|
||||
})
|
||||
.first();
|
||||
// const recordTableRowForWorkflowRun = page
|
||||
// .getByRole('row', {
|
||||
// name: workflowVisualizer.workflowName,
|
||||
// })
|
||||
// .first();
|
||||
|
||||
const linkToWorkflowRun = recordTableRowForWorkflowRun
|
||||
.getByRole('link', {
|
||||
name: workflowVisualizer.workflowName,
|
||||
})
|
||||
.first();
|
||||
// const linkToWorkflowRun = recordTableRowForWorkflowRun
|
||||
// .getByRole('link', {
|
||||
// name: workflowVisualizer.workflowName,
|
||||
// })
|
||||
// .first();
|
||||
|
||||
await linkToWorkflowRun.click({ force: true });
|
||||
// await linkToWorkflowRun.click({ force: true });
|
||||
|
||||
const workflowRunNameElement = page
|
||||
.getByText(`#1 - ${workflowVisualizer.workflowName}`)
|
||||
.nth(1);
|
||||
// const workflowRunNameElement = page
|
||||
// .getByText(`#1 - ${workflowVisualizer.workflowName}`)
|
||||
// .nth(1);
|
||||
|
||||
await expect(workflowRunNameElement).toBeVisible();
|
||||
// await expect(workflowRunNameElement).toBeVisible();
|
||||
|
||||
const executedFirstStepNode = workflowVisualizer.getStepNode(firstStepId);
|
||||
// const executedFirstStepNode = workflowVisualizer.getStepNode(firstStepId);
|
||||
|
||||
await expect(executedFirstStepNode).toBeVisible();
|
||||
// await expect(executedFirstStepNode).toBeVisible();
|
||||
|
||||
await executedFirstStepNode.click();
|
||||
// await executedFirstStepNode.click();
|
||||
|
||||
await expect(workflowVisualizer.stepHeaderInCommandMenu).toContainText(
|
||||
'Create Record',
|
||||
);
|
||||
});
|
||||
// await expect(workflowVisualizer.stepHeaderInCommandMenu).toContainText(
|
||||
// 'Create Record',
|
||||
// );
|
||||
// });
|
||||
|
||||
test('Workflow Runs with a pending form step can be opened in the side panel and then in full screen', async ({
|
||||
workflowVisualizer,
|
||||
page,
|
||||
}) => {
|
||||
await workflowVisualizer.createInitialTrigger('manual');
|
||||
// test('Workflow Runs with a pending form step can be opened in the side panel and then in full screen', async ({
|
||||
// workflowVisualizer,
|
||||
// page,
|
||||
// }) => {
|
||||
// await workflowVisualizer.createInitialTrigger('manual');
|
||||
|
||||
const manualTriggerAvailabilitySelect = page.getByRole('button', {
|
||||
name: 'When record is selected',
|
||||
});
|
||||
// const manualTriggerAvailabilitySelect = page.getByRole('button', {
|
||||
// name: 'When record is selected',
|
||||
// });
|
||||
|
||||
await manualTriggerAvailabilitySelect.click();
|
||||
// await manualTriggerAvailabilitySelect.click();
|
||||
|
||||
const alwaysAvailableOption = page.getByText('When no record is selected');
|
||||
// const alwaysAvailableOption = page.getByText('When no record is selected');
|
||||
|
||||
await alwaysAvailableOption.click();
|
||||
// await alwaysAvailableOption.click();
|
||||
|
||||
await workflowVisualizer.closeSidePanel();
|
||||
// await workflowVisualizer.closeSidePanel();
|
||||
|
||||
const { createdStepId: firstStepId } =
|
||||
await workflowVisualizer.createStep('form');
|
||||
// const { createdStepId: firstStepId } =
|
||||
// await workflowVisualizer.createStep('form');
|
||||
|
||||
const addFormFieldButton = page.getByText('Add Field', { exact: true });
|
||||
// const addFormFieldButton = page.getByText('Add Field', { exact: true });
|
||||
|
||||
await addFormFieldButton.click();
|
||||
// await addFormFieldButton.click();
|
||||
|
||||
await workflowVisualizer.closeSidePanel();
|
||||
// await workflowVisualizer.closeSidePanel();
|
||||
|
||||
const launchTestButton = page.getByLabel(workflowVisualizer.workflowName);
|
||||
// const launchTestButton = page.getByLabel(workflowVisualizer.workflowName);
|
||||
|
||||
await launchTestButton.click();
|
||||
// await launchTestButton.click();
|
||||
|
||||
const workflowRunName = `#1 - ${workflowVisualizer.workflowName}`;
|
||||
// const workflowRunName = `#1 - ${workflowVisualizer.workflowName}`;
|
||||
|
||||
await expect(workflowVisualizer.stepHeaderInCommandMenu).toContainText(
|
||||
'Form',
|
||||
{
|
||||
timeout: 30_000,
|
||||
},
|
||||
);
|
||||
// await expect(workflowVisualizer.stepHeaderInCommandMenu).toContainText(
|
||||
// 'Form',
|
||||
// {
|
||||
// timeout: 30_000,
|
||||
// },
|
||||
// );
|
||||
|
||||
await workflowVisualizer.goBackInCommandMenu.click();
|
||||
// await workflowVisualizer.goBackInCommandMenu.click();
|
||||
|
||||
const workflowRunNameInCommandMenu =
|
||||
workflowVisualizer.commandMenu.getByText(workflowRunName);
|
||||
// const workflowRunNameInCommandMenu =
|
||||
// workflowVisualizer.commandMenu.getByText(workflowRunName);
|
||||
|
||||
await expect(workflowRunNameInCommandMenu).toBeVisible();
|
||||
// await expect(workflowRunNameInCommandMenu).toBeVisible();
|
||||
|
||||
await workflowVisualizer.commandMenu
|
||||
.locator(workflowVisualizer.triggerNode)
|
||||
.click();
|
||||
// await workflowVisualizer.commandMenu
|
||||
// .locator(workflowVisualizer.triggerNode)
|
||||
// .click();
|
||||
|
||||
await expect(workflowVisualizer.stepHeaderInCommandMenu).toContainText(
|
||||
'Launch manually',
|
||||
);
|
||||
// await expect(workflowVisualizer.stepHeaderInCommandMenu).toContainText(
|
||||
// 'Launch manually',
|
||||
// );
|
||||
|
||||
await workflowVisualizer.goBackInCommandMenu.click();
|
||||
// await workflowVisualizer.goBackInCommandMenu.click();
|
||||
|
||||
const formStep = workflowVisualizer.commandMenu.locator(
|
||||
workflowVisualizer.getStepNode(firstStepId),
|
||||
);
|
||||
// const formStep = workflowVisualizer.commandMenu.locator(
|
||||
// workflowVisualizer.getStepNode(firstStepId),
|
||||
// );
|
||||
|
||||
await formStep.click();
|
||||
// await formStep.click();
|
||||
|
||||
await workflowVisualizer.goBackInCommandMenu.click();
|
||||
// await workflowVisualizer.goBackInCommandMenu.click();
|
||||
|
||||
const openInFullScreenButton = workflowVisualizer.commandMenu.getByRole(
|
||||
'button',
|
||||
{ name: 'Open' },
|
||||
);
|
||||
// const openInFullScreenButton = workflowVisualizer.commandMenu.getByRole(
|
||||
// 'button',
|
||||
// { name: 'Open' },
|
||||
// );
|
||||
|
||||
await openInFullScreenButton.click();
|
||||
// await openInFullScreenButton.click();
|
||||
|
||||
const workflowRunNameInShowPage = page
|
||||
.getByText(`#1 - ${workflowVisualizer.workflowName}`)
|
||||
.nth(1);
|
||||
// const workflowRunNameInShowPage = page
|
||||
// .getByText(`#1 - ${workflowVisualizer.workflowName}`)
|
||||
// .nth(1);
|
||||
|
||||
await expect(workflowRunNameInShowPage).toBeVisible();
|
||||
// await expect(workflowRunNameInShowPage).toBeVisible();
|
||||
|
||||
// Expect the side panel to be opened by default on the form.
|
||||
await expect(workflowVisualizer.stepHeaderInCommandMenu).toContainText(
|
||||
'Form',
|
||||
);
|
||||
});
|
||||
// // Expect the side panel to be opened by default on the form.
|
||||
// await expect(workflowVisualizer.stepHeaderInCommandMenu).toContainText(
|
||||
// 'Form',
|
||||
// );
|
||||
// });
|
||||
|
||||
@@ -1,163 +1,161 @@
|
||||
import { expect } from '@playwright/test';
|
||||
import { test } from '../lib/fixtures/blank-workflow';
|
||||
|
||||
test('Use an old version as draft', async ({ workflowVisualizer, page }) => {
|
||||
await workflowVisualizer.createInitialTrigger('record-created');
|
||||
// test('Use an old version as draft', async ({ workflowVisualizer, page }) => {
|
||||
// await workflowVisualizer.createInitialTrigger('record-created');
|
||||
|
||||
await workflowVisualizer.createStep('create-record');
|
||||
// await workflowVisualizer.createStep('create-record');
|
||||
|
||||
await workflowVisualizer.background.click();
|
||||
// await workflowVisualizer.background.click();
|
||||
|
||||
await workflowVisualizer.activateWorkflowButton.click();
|
||||
// await workflowVisualizer.activateWorkflowButton.click();
|
||||
|
||||
await expect(workflowVisualizer.workflowStatus).toHaveText('Active');
|
||||
// await expect(workflowVisualizer.workflowStatus).toHaveText('Active');
|
||||
|
||||
await workflowVisualizer.createStep('delete-record');
|
||||
// await workflowVisualizer.createStep('delete-record');
|
||||
|
||||
await expect(workflowVisualizer.workflowStatus).toHaveText('Draft');
|
||||
// await expect(workflowVisualizer.workflowStatus).toHaveText('Draft');
|
||||
|
||||
await workflowVisualizer.closeSidePanel();
|
||||
// await workflowVisualizer.closeSidePanel();
|
||||
|
||||
await workflowVisualizer.activateWorkflowButton.click();
|
||||
// await workflowVisualizer.activateWorkflowButton.click();
|
||||
|
||||
await expect(workflowVisualizer.workflowStatus).toHaveText('Active');
|
||||
// await expect(workflowVisualizer.workflowStatus).toHaveText('Active');
|
||||
|
||||
await expect(workflowVisualizer.triggerNode).toContainText(
|
||||
'Record is created',
|
||||
);
|
||||
await expect(workflowVisualizer.getAllStepNodes()).toContainText([
|
||||
'Create Record',
|
||||
'Delete Record',
|
||||
]);
|
||||
await expect(workflowVisualizer.getAllStepNodes()).toHaveCount(2);
|
||||
await expect(workflowVisualizer.useAsDraftButton).not.toBeVisible();
|
||||
// await expect(workflowVisualizer.triggerNode).toContainText(
|
||||
// 'Record is created',
|
||||
// );
|
||||
// await expect(workflowVisualizer.getAllStepNodes()).toContainText([
|
||||
// 'Create Record',
|
||||
// 'Delete Record',
|
||||
// ]);
|
||||
// await expect(workflowVisualizer.getAllStepNodes()).toHaveCount(2);
|
||||
// await expect(workflowVisualizer.useAsDraftButton).not.toBeVisible();
|
||||
|
||||
const workflowsLink = page.getByRole('link', { name: 'Workflows' });
|
||||
await workflowsLink.click();
|
||||
// const workflowsLink = page.getByRole('link', { name: 'Workflows' });
|
||||
// await workflowsLink.click();
|
||||
|
||||
await workflowVisualizer.setWorkflowsOpenInMode('record-page');
|
||||
// await workflowVisualizer.setWorkflowsOpenInMode('record-page');
|
||||
|
||||
const recordTableRowForWorkflow = page.getByRole('row', {
|
||||
name: workflowVisualizer.workflowName,
|
||||
});
|
||||
// const recordTableRowForWorkflow = page.getByRole('row', {
|
||||
// name: workflowVisualizer.workflowName,
|
||||
// });
|
||||
|
||||
const linkToWorkflow = recordTableRowForWorkflow.getByRole('link', {
|
||||
name: workflowVisualizer.workflowName,
|
||||
});
|
||||
await expect(linkToWorkflow).toBeVisible();
|
||||
// const linkToWorkflow = recordTableRowForWorkflow.getByRole('link', {
|
||||
// name: workflowVisualizer.workflowName,
|
||||
// });
|
||||
// await expect(linkToWorkflow).toBeVisible();
|
||||
|
||||
const linkToFirstWorkflowVersion = recordTableRowForWorkflow.getByRole(
|
||||
'link',
|
||||
{
|
||||
name: 'v1',
|
||||
},
|
||||
);
|
||||
// const linkToFirstWorkflowVersion = recordTableRowForWorkflow.getByRole(
|
||||
// 'link',
|
||||
// {
|
||||
// name: 'v1',
|
||||
// },
|
||||
// );
|
||||
|
||||
await linkToFirstWorkflowVersion.click({ force: true });
|
||||
// await linkToFirstWorkflowVersion.click({ force: true });
|
||||
|
||||
await expect(workflowVisualizer.workflowStatus).toHaveText('Archived');
|
||||
await expect(workflowVisualizer.useAsDraftButton).toBeVisible();
|
||||
await expect(workflowVisualizer.triggerNode).toContainText(
|
||||
'Record is created',
|
||||
);
|
||||
await expect(workflowVisualizer.getAllStepNodes()).toContainText([
|
||||
'Create Record',
|
||||
]);
|
||||
await expect(workflowVisualizer.getAllStepNodes()).toHaveCount(1);
|
||||
// await expect(workflowVisualizer.workflowStatus).toHaveText('Archived');
|
||||
// await expect(workflowVisualizer.useAsDraftButton).toBeVisible();
|
||||
// await expect(workflowVisualizer.triggerNode).toContainText(
|
||||
// 'Record is created',
|
||||
// );
|
||||
// await expect(workflowVisualizer.getAllStepNodes()).toContainText([
|
||||
// 'Create Record',
|
||||
// ]);
|
||||
// await expect(workflowVisualizer.getAllStepNodes()).toHaveCount(1);
|
||||
|
||||
await workflowVisualizer.useAsDraftButton.click();
|
||||
// await workflowVisualizer.useAsDraftButton.click();
|
||||
|
||||
await page.waitForURL(`/object/workflow/${workflowVisualizer.workflowId}`);
|
||||
// await page.waitForURL(`/object/workflow/${workflowVisualizer.workflowId}`);
|
||||
|
||||
await expect(workflowVisualizer.workflowStatus).toHaveText('Draft');
|
||||
await expect(workflowVisualizer.useAsDraftButton).not.toBeVisible();
|
||||
await expect(workflowVisualizer.triggerNode).toContainText(
|
||||
'Record is created',
|
||||
);
|
||||
await expect(workflowVisualizer.getAllStepNodes()).toContainText([
|
||||
'Create Record',
|
||||
]);
|
||||
await expect(workflowVisualizer.getAllStepNodes()).toHaveCount(1);
|
||||
});
|
||||
// await expect(workflowVisualizer.workflowStatus).toHaveText('Draft');
|
||||
// await expect(workflowVisualizer.useAsDraftButton).not.toBeVisible();
|
||||
// await expect(workflowVisualizer.triggerNode).toContainText(
|
||||
// 'Record is created',
|
||||
// );
|
||||
// await expect(workflowVisualizer.getAllStepNodes()).toContainText([
|
||||
// 'Create Record',
|
||||
// ]);
|
||||
// await expect(workflowVisualizer.getAllStepNodes()).toHaveCount(1);
|
||||
// });
|
||||
|
||||
test('Use an old version as draft while having a pending draft version', async ({
|
||||
workflowVisualizer,
|
||||
page,
|
||||
}) => {
|
||||
await workflowVisualizer.createInitialTrigger('record-created');
|
||||
// test('Use an old version as draft while having a pending draft version', async ({
|
||||
// workflowVisualizer,
|
||||
// page,
|
||||
// }) => {
|
||||
// await workflowVisualizer.createInitialTrigger('record-created');
|
||||
|
||||
await workflowVisualizer.createStep('create-record');
|
||||
// await workflowVisualizer.createStep('create-record');
|
||||
|
||||
await workflowVisualizer.background.click();
|
||||
// await workflowVisualizer.background.click();
|
||||
|
||||
await workflowVisualizer.activateWorkflowButton.click();
|
||||
// await workflowVisualizer.activateWorkflowButton.click();
|
||||
|
||||
await expect(workflowVisualizer.workflowStatus).toHaveText('Active');
|
||||
// await expect(workflowVisualizer.workflowStatus).toHaveText('Active');
|
||||
|
||||
await workflowVisualizer.createStep('delete-record');
|
||||
// await workflowVisualizer.createStep('delete-record');
|
||||
|
||||
await expect(workflowVisualizer.workflowStatus).toHaveText('Draft');
|
||||
// await expect(workflowVisualizer.workflowStatus).toHaveText('Draft');
|
||||
|
||||
await expect(workflowVisualizer.triggerNode).toContainText(
|
||||
'Record is created',
|
||||
);
|
||||
await expect(workflowVisualizer.getAllStepNodes()).toContainText([
|
||||
'Create Record',
|
||||
'Delete Record',
|
||||
]);
|
||||
await expect(workflowVisualizer.getAllStepNodes()).toHaveCount(2);
|
||||
await expect(workflowVisualizer.useAsDraftButton).not.toBeVisible();
|
||||
// await expect(workflowVisualizer.triggerNode).toContainText(
|
||||
// 'Record is created',
|
||||
// );
|
||||
// await expect(workflowVisualizer.getAllStepNodes()).toContainText([
|
||||
// 'Create Record',
|
||||
// 'Delete Record',
|
||||
// ]);
|
||||
// await expect(workflowVisualizer.getAllStepNodes()).toHaveCount(2);
|
||||
// await expect(workflowVisualizer.useAsDraftButton).not.toBeVisible();
|
||||
|
||||
await workflowVisualizer.closeSidePanel();
|
||||
// await workflowVisualizer.closeSidePanel();
|
||||
|
||||
const workflowsLink = page.getByRole('link', { name: 'Workflows' });
|
||||
await workflowsLink.click();
|
||||
// const workflowsLink = page.getByRole('link', { name: 'Workflows' });
|
||||
// await workflowsLink.click();
|
||||
|
||||
const recordTableRowForWorkflow = page.getByRole('row', {
|
||||
name: workflowVisualizer.workflowName,
|
||||
});
|
||||
// const recordTableRowForWorkflow = page.getByRole('row', {
|
||||
// name: workflowVisualizer.workflowName,
|
||||
// });
|
||||
|
||||
const linkToWorkflow = recordTableRowForWorkflow.getByRole('link', {
|
||||
name: workflowVisualizer.workflowName,
|
||||
});
|
||||
await expect(linkToWorkflow).toBeVisible();
|
||||
// const linkToWorkflow = recordTableRowForWorkflow.getByRole('link', {
|
||||
// name: workflowVisualizer.workflowName,
|
||||
// });
|
||||
// await expect(linkToWorkflow).toBeVisible();
|
||||
|
||||
const linkToFirstWorkflowVersion = recordTableRowForWorkflow.getByRole(
|
||||
'link',
|
||||
{
|
||||
name: 'v1',
|
||||
},
|
||||
);
|
||||
// const linkToFirstWorkflowVersion = recordTableRowForWorkflow.getByRole(
|
||||
// 'link',
|
||||
// {
|
||||
// name: 'v1',
|
||||
// },
|
||||
// );
|
||||
|
||||
await linkToFirstWorkflowVersion.click({ force: true });
|
||||
// await linkToFirstWorkflowVersion.click({ force: true });
|
||||
|
||||
await expect(workflowVisualizer.workflowStatus).toHaveText('Active');
|
||||
await expect(workflowVisualizer.useAsDraftButton).toBeVisible();
|
||||
await expect(workflowVisualizer.triggerNode).toContainText(
|
||||
'Record is created',
|
||||
);
|
||||
await expect(workflowVisualizer.getAllStepNodes()).toContainText([
|
||||
'Create Record',
|
||||
]);
|
||||
await expect(workflowVisualizer.getAllStepNodes()).toHaveCount(1);
|
||||
// await expect(workflowVisualizer.workflowStatus).toHaveText('Active');
|
||||
// await expect(workflowVisualizer.useAsDraftButton).toBeVisible();
|
||||
// await expect(workflowVisualizer.triggerNode).toContainText(
|
||||
// 'Record is created',
|
||||
// );
|
||||
// await expect(workflowVisualizer.getAllStepNodes()).toContainText([
|
||||
// 'Create Record',
|
||||
// ]);
|
||||
// await expect(workflowVisualizer.getAllStepNodes()).toHaveCount(1);
|
||||
|
||||
await workflowVisualizer.useAsDraftButton.click();
|
||||
// await workflowVisualizer.useAsDraftButton.click();
|
||||
|
||||
await expect(workflowVisualizer.overrideDraftButton).toBeVisible();
|
||||
// await expect(workflowVisualizer.overrideDraftButton).toBeVisible();
|
||||
|
||||
await workflowVisualizer.overrideDraftButton.click();
|
||||
// await workflowVisualizer.overrideDraftButton.click();
|
||||
|
||||
await page.waitForURL(`/object/workflow/${workflowVisualizer.workflowId}`);
|
||||
// await page.waitForURL(`/object/workflow/${workflowVisualizer.workflowId}`);
|
||||
|
||||
await expect(workflowVisualizer.workflowStatus).toHaveText('Draft');
|
||||
await expect(workflowVisualizer.useAsDraftButton).not.toBeVisible();
|
||||
await expect(workflowVisualizer.triggerNode).toContainText(
|
||||
'Record is created',
|
||||
);
|
||||
await expect(workflowVisualizer.getAllStepNodes()).toContainText([
|
||||
'Create Record',
|
||||
]);
|
||||
await expect(workflowVisualizer.getAllStepNodes()).toHaveCount(1);
|
||||
await expect(workflowVisualizer.activateWorkflowButton).toBeVisible();
|
||||
await expect(workflowVisualizer.discardDraftButton).toBeVisible();
|
||||
});
|
||||
// await expect(workflowVisualizer.workflowStatus).toHaveText('Draft');
|
||||
// await expect(workflowVisualizer.useAsDraftButton).not.toBeVisible();
|
||||
// await expect(workflowVisualizer.triggerNode).toContainText(
|
||||
// 'Record is created',
|
||||
// );
|
||||
// await expect(workflowVisualizer.getAllStepNodes()).toContainText([
|
||||
// 'Create Record',
|
||||
// ]);
|
||||
// await expect(workflowVisualizer.getAllStepNodes()).toHaveCount(1);
|
||||
// await expect(workflowVisualizer.activateWorkflowButton).toBeVisible();
|
||||
// await expect(workflowVisualizer.discardDraftButton).toBeVisible();
|
||||
// });
|
||||
|
||||
@@ -1,218 +1,218 @@
|
||||
import { expect } from '@playwright/test';
|
||||
import { test } from '../lib/fixtures/blank-workflow';
|
||||
// import { expect } from '@playwright/test';
|
||||
// import { test } from '../lib/fixtures/blank-workflow';
|
||||
|
||||
test('Create workflow with every possible step', async ({
|
||||
workflowVisualizer,
|
||||
page,
|
||||
}) => {
|
||||
await workflowVisualizer.createInitialTrigger('record-created');
|
||||
// test('Create workflow with every possible step', async ({
|
||||
// workflowVisualizer,
|
||||
// page,
|
||||
// }) => {
|
||||
// await workflowVisualizer.createInitialTrigger('record-created');
|
||||
|
||||
await workflowVisualizer.createStep('create-record');
|
||||
await workflowVisualizer.createStep('update-record');
|
||||
await workflowVisualizer.createStep('delete-record');
|
||||
await workflowVisualizer.createStep('code');
|
||||
await workflowVisualizer.createStep('send-email');
|
||||
// await workflowVisualizer.createStep('create-record');
|
||||
// await workflowVisualizer.createStep('update-record');
|
||||
// await workflowVisualizer.createStep('delete-record');
|
||||
// await workflowVisualizer.createStep('code');
|
||||
// await workflowVisualizer.createStep('send-email');
|
||||
|
||||
await workflowVisualizer.background.click();
|
||||
// await workflowVisualizer.background.click();
|
||||
|
||||
const draftWorkflowStatus =
|
||||
workflowVisualizer.workflowStatus.getByText('Draft');
|
||||
// const draftWorkflowStatus =
|
||||
// workflowVisualizer.workflowStatus.getByText('Draft');
|
||||
|
||||
await expect(draftWorkflowStatus).toBeVisible();
|
||||
// await expect(draftWorkflowStatus).toBeVisible();
|
||||
|
||||
await workflowVisualizer.activateWorkflowButton.click();
|
||||
// await workflowVisualizer.activateWorkflowButton.click();
|
||||
|
||||
const activeWorkflowStatus =
|
||||
workflowVisualizer.workflowStatus.getByText('Active');
|
||||
// const activeWorkflowStatus =
|
||||
// workflowVisualizer.workflowStatus.getByText('Active');
|
||||
|
||||
await expect(draftWorkflowStatus).not.toBeVisible();
|
||||
await expect(activeWorkflowStatus).toBeVisible();
|
||||
await expect(workflowVisualizer.activateWorkflowButton).not.toBeVisible();
|
||||
await expect(workflowVisualizer.deactivateWorkflowButton).toBeVisible();
|
||||
});
|
||||
// await expect(draftWorkflowStatus).not.toBeVisible();
|
||||
// await expect(activeWorkflowStatus).toBeVisible();
|
||||
// await expect(workflowVisualizer.activateWorkflowButton).not.toBeVisible();
|
||||
// await expect(workflowVisualizer.deactivateWorkflowButton).toBeVisible();
|
||||
// });
|
||||
|
||||
test('Delete steps from draft version', async ({
|
||||
workflowVisualizer,
|
||||
page,
|
||||
}) => {
|
||||
await workflowVisualizer.createInitialTrigger('record-created');
|
||||
// test('Delete steps from draft version', async ({
|
||||
// workflowVisualizer,
|
||||
// page,
|
||||
// }) => {
|
||||
// await workflowVisualizer.createInitialTrigger('record-created');
|
||||
|
||||
const { createdStepId: firstStepId } =
|
||||
await workflowVisualizer.createStep('create-record');
|
||||
const { createdStepId: secondStepId } =
|
||||
await workflowVisualizer.createStep('update-record');
|
||||
const { createdStepId: thirdStepId } =
|
||||
await workflowVisualizer.createStep('delete-record');
|
||||
const { createdStepId: fourthStepId } =
|
||||
await workflowVisualizer.createStep('code');
|
||||
const { createdStepId: fifthStepId } =
|
||||
await workflowVisualizer.createStep('send-email');
|
||||
// const { createdStepId: firstStepId } =
|
||||
// await workflowVisualizer.createStep('create-record');
|
||||
// const { createdStepId: secondStepId } =
|
||||
// await workflowVisualizer.createStep('update-record');
|
||||
// const { createdStepId: thirdStepId } =
|
||||
// await workflowVisualizer.createStep('delete-record');
|
||||
// const { createdStepId: fourthStepId } =
|
||||
// await workflowVisualizer.createStep('code');
|
||||
// const { createdStepId: fifthStepId } =
|
||||
// await workflowVisualizer.createStep('send-email');
|
||||
|
||||
await expect(workflowVisualizer.getAllStepNodes()).toContainText([
|
||||
'Create Record',
|
||||
'Update Record',
|
||||
'Delete Record',
|
||||
'Code - Serverless Function',
|
||||
'Send Email',
|
||||
]);
|
||||
await expect(workflowVisualizer.getAllStepNodes()).toHaveCount(5);
|
||||
// await expect(workflowVisualizer.getAllStepNodes()).toContainText([
|
||||
// 'Create Record',
|
||||
// 'Update Record',
|
||||
// 'Delete Record',
|
||||
// 'Code - Serverless Function',
|
||||
// 'Send Email',
|
||||
// ]);
|
||||
// await expect(workflowVisualizer.getAllStepNodes()).toHaveCount(5);
|
||||
|
||||
await workflowVisualizer.deleteStep(firstStepId);
|
||||
// await workflowVisualizer.deleteStep(firstStepId);
|
||||
|
||||
await expect(workflowVisualizer.getAllStepNodes()).toContainText([
|
||||
'Update Record',
|
||||
'Delete Record',
|
||||
'Code - Serverless Function',
|
||||
'Send Email',
|
||||
]);
|
||||
await expect(workflowVisualizer.getAllStepNodes()).toHaveCount(4);
|
||||
// await expect(workflowVisualizer.getAllStepNodes()).toContainText([
|
||||
// 'Update Record',
|
||||
// 'Delete Record',
|
||||
// 'Code - Serverless Function',
|
||||
// 'Send Email',
|
||||
// ]);
|
||||
// await expect(workflowVisualizer.getAllStepNodes()).toHaveCount(4);
|
||||
|
||||
await workflowVisualizer.deleteStep(fifthStepId);
|
||||
// await workflowVisualizer.deleteStep(fifthStepId);
|
||||
|
||||
await expect(workflowVisualizer.getAllStepNodes()).toContainText([
|
||||
'Update Record',
|
||||
'Delete Record',
|
||||
'Code - Serverless Function',
|
||||
]);
|
||||
await expect(workflowVisualizer.getAllStepNodes()).toHaveCount(3);
|
||||
// await expect(workflowVisualizer.getAllStepNodes()).toContainText([
|
||||
// 'Update Record',
|
||||
// 'Delete Record',
|
||||
// 'Code - Serverless Function',
|
||||
// ]);
|
||||
// await expect(workflowVisualizer.getAllStepNodes()).toHaveCount(3);
|
||||
|
||||
await workflowVisualizer.deleteStep(secondStepId);
|
||||
// await workflowVisualizer.deleteStep(secondStepId);
|
||||
|
||||
await expect(workflowVisualizer.getAllStepNodes()).toContainText([
|
||||
'Delete Record',
|
||||
'Code - Serverless Function',
|
||||
]);
|
||||
await expect(workflowVisualizer.getAllStepNodes()).toHaveCount(2);
|
||||
// await expect(workflowVisualizer.getAllStepNodes()).toContainText([
|
||||
// 'Delete Record',
|
||||
// 'Code - Serverless Function',
|
||||
// ]);
|
||||
// await expect(workflowVisualizer.getAllStepNodes()).toHaveCount(2);
|
||||
|
||||
await workflowVisualizer.deleteStep(fourthStepId);
|
||||
// await workflowVisualizer.deleteStep(fourthStepId);
|
||||
|
||||
await expect(workflowVisualizer.getAllStepNodes()).toContainText([
|
||||
'Delete Record',
|
||||
]);
|
||||
await expect(workflowVisualizer.getAllStepNodes()).toHaveCount(1);
|
||||
// await expect(workflowVisualizer.getAllStepNodes()).toContainText([
|
||||
// 'Delete Record',
|
||||
// ]);
|
||||
// await expect(workflowVisualizer.getAllStepNodes()).toHaveCount(1);
|
||||
|
||||
await workflowVisualizer.deleteStep(thirdStepId);
|
||||
// await workflowVisualizer.deleteStep(thirdStepId);
|
||||
|
||||
await expect(workflowVisualizer.getAllStepNodes()).toHaveCount(0);
|
||||
// await expect(workflowVisualizer.getAllStepNodes()).toHaveCount(0);
|
||||
|
||||
await Promise.all([
|
||||
page.reload(),
|
||||
// await Promise.all([
|
||||
// page.reload(),
|
||||
|
||||
expect(workflowVisualizer.triggerNode).toBeVisible(),
|
||||
]);
|
||||
// expect(workflowVisualizer.triggerNode).toBeVisible(),
|
||||
// ]);
|
||||
|
||||
await expect(workflowVisualizer.getAllStepNodes()).toHaveCount(0);
|
||||
});
|
||||
// await expect(workflowVisualizer.getAllStepNodes()).toHaveCount(0);
|
||||
// });
|
||||
|
||||
test('Add a step to an active version', async ({
|
||||
workflowVisualizer,
|
||||
page,
|
||||
}) => {
|
||||
await workflowVisualizer.createInitialTrigger('record-created');
|
||||
// test('Add a step to an active version', async ({
|
||||
// workflowVisualizer,
|
||||
// page,
|
||||
// }) => {
|
||||
// await workflowVisualizer.createInitialTrigger('record-created');
|
||||
|
||||
await workflowVisualizer.createStep('create-record');
|
||||
// await workflowVisualizer.createStep('create-record');
|
||||
|
||||
await expect(workflowVisualizer.workflowStatus).toHaveText('Draft');
|
||||
// await expect(workflowVisualizer.workflowStatus).toHaveText('Draft');
|
||||
|
||||
await workflowVisualizer.background.click();
|
||||
// await workflowVisualizer.background.click();
|
||||
|
||||
await Promise.all([
|
||||
expect(workflowVisualizer.workflowStatus).toHaveText('Active'),
|
||||
// await Promise.all([
|
||||
// expect(workflowVisualizer.workflowStatus).toHaveText('Active'),
|
||||
|
||||
workflowVisualizer.activateWorkflowButton.click(),
|
||||
]);
|
||||
// workflowVisualizer.activateWorkflowButton.click(),
|
||||
// ]);
|
||||
|
||||
await expect(workflowVisualizer.activateWorkflowButton).not.toBeVisible();
|
||||
// await expect(workflowVisualizer.activateWorkflowButton).not.toBeVisible();
|
||||
|
||||
const assertEndState = async () => {
|
||||
await expect(workflowVisualizer.workflowStatus).toHaveText('Active');
|
||||
await expect(workflowVisualizer.triggerNode).toContainText(
|
||||
'Record is created',
|
||||
);
|
||||
await expect(workflowVisualizer.getAllStepNodes()).toContainText([
|
||||
'Create Record',
|
||||
]);
|
||||
await expect(workflowVisualizer.getAllStepNodes()).toHaveCount(1);
|
||||
};
|
||||
// const assertEndState = async () => {
|
||||
// await expect(workflowVisualizer.workflowStatus).toHaveText('Active');
|
||||
// await expect(workflowVisualizer.triggerNode).toContainText(
|
||||
// 'Record is created',
|
||||
// );
|
||||
// await expect(workflowVisualizer.getAllStepNodes()).toContainText([
|
||||
// 'Create Record',
|
||||
// ]);
|
||||
// await expect(workflowVisualizer.getAllStepNodes()).toHaveCount(1);
|
||||
// };
|
||||
|
||||
await assertEndState();
|
||||
// await assertEndState();
|
||||
|
||||
await page.reload();
|
||||
// await page.reload();
|
||||
|
||||
await assertEndState();
|
||||
});
|
||||
// await assertEndState();
|
||||
// });
|
||||
|
||||
test('Replace the trigger of an active version', async ({
|
||||
workflowVisualizer,
|
||||
page,
|
||||
}) => {
|
||||
await workflowVisualizer.createInitialTrigger('record-created');
|
||||
// test('Replace the trigger of an active version', async ({
|
||||
// workflowVisualizer,
|
||||
// page,
|
||||
// }) => {
|
||||
// await workflowVisualizer.createInitialTrigger('record-created');
|
||||
|
||||
await workflowVisualizer.createStep('create-record');
|
||||
// await workflowVisualizer.createStep('create-record');
|
||||
|
||||
await workflowVisualizer.background.click();
|
||||
// await workflowVisualizer.background.click();
|
||||
|
||||
await Promise.all([
|
||||
expect(workflowVisualizer.workflowStatus).toHaveText('Active'),
|
||||
// await Promise.all([
|
||||
// expect(workflowVisualizer.workflowStatus).toHaveText('Active'),
|
||||
|
||||
workflowVisualizer.activateWorkflowButton.click(),
|
||||
]);
|
||||
// workflowVisualizer.activateWorkflowButton.click(),
|
||||
// ]);
|
||||
|
||||
await Promise.all([
|
||||
expect(workflowVisualizer.workflowStatus).toHaveText('Draft'),
|
||||
// await Promise.all([
|
||||
// expect(workflowVisualizer.workflowStatus).toHaveText('Draft'),
|
||||
|
||||
workflowVisualizer.deleteTrigger(),
|
||||
]);
|
||||
// workflowVisualizer.deleteTrigger(),
|
||||
// ]);
|
||||
|
||||
await workflowVisualizer.createInitialTrigger('record-deleted');
|
||||
// await workflowVisualizer.createInitialTrigger('record-deleted');
|
||||
|
||||
await workflowVisualizer.background.click();
|
||||
// await workflowVisualizer.background.click();
|
||||
|
||||
await Promise.all([
|
||||
expect(workflowVisualizer.workflowStatus).toHaveText('Active'),
|
||||
// await Promise.all([
|
||||
// expect(workflowVisualizer.workflowStatus).toHaveText('Active'),
|
||||
|
||||
workflowVisualizer.activateWorkflowButton.click(),
|
||||
]);
|
||||
// workflowVisualizer.activateWorkflowButton.click(),
|
||||
// ]);
|
||||
|
||||
await page.reload();
|
||||
// await page.reload();
|
||||
|
||||
await expect(workflowVisualizer.triggerNode).toContainText(
|
||||
'Record is deleted',
|
||||
);
|
||||
await expect(workflowVisualizer.getAllStepNodes()).toHaveCount(1);
|
||||
await expect(workflowVisualizer.getAllStepNodes()).toContainText([
|
||||
'Create Record',
|
||||
]);
|
||||
});
|
||||
// await expect(workflowVisualizer.triggerNode).toContainText(
|
||||
// 'Record is deleted',
|
||||
// );
|
||||
// await expect(workflowVisualizer.getAllStepNodes()).toHaveCount(1);
|
||||
// await expect(workflowVisualizer.getAllStepNodes()).toContainText([
|
||||
// 'Create Record',
|
||||
// ]);
|
||||
// });
|
||||
|
||||
test("Nodes can't be deleted by pressing Backspace or Delete keys", async ({
|
||||
workflowVisualizer,
|
||||
page,
|
||||
}) => {
|
||||
await workflowVisualizer.triggerNode.click();
|
||||
// test("Nodes can't be deleted by pressing Backspace or Delete keys", async ({
|
||||
// workflowVisualizer,
|
||||
// page,
|
||||
// }) => {
|
||||
// await workflowVisualizer.triggerNode.click();
|
||||
|
||||
await page.keyboard.press('Backspace');
|
||||
await page.keyboard.press('Delete');
|
||||
// await page.keyboard.press('Backspace');
|
||||
// await page.keyboard.press('Delete');
|
||||
|
||||
await expect(workflowVisualizer.triggerNode).toBeVisible();
|
||||
// await expect(workflowVisualizer.triggerNode).toBeVisible();
|
||||
|
||||
const { createdStepId: firstStepId } =
|
||||
await workflowVisualizer.createStep('create-record');
|
||||
const firstStep = workflowVisualizer.getStepNode(firstStepId);
|
||||
// const { createdStepId: firstStepId } =
|
||||
// await workflowVisualizer.createStep('create-record');
|
||||
// const firstStep = workflowVisualizer.getStepNode(firstStepId);
|
||||
|
||||
await firstStep.click();
|
||||
// await firstStep.click();
|
||||
|
||||
await expect(workflowVisualizer.getDeleteNodeButton(firstStep)).toBeVisible();
|
||||
// await expect(workflowVisualizer.getDeleteNodeButton(firstStep)).toBeVisible();
|
||||
|
||||
await page.keyboard.press('Backspace');
|
||||
await page.keyboard.press('Delete');
|
||||
// await page.keyboard.press('Backspace');
|
||||
// await page.keyboard.press('Delete');
|
||||
|
||||
await expect(firstStep).toBeVisible();
|
||||
// await expect(firstStep).toBeVisible();
|
||||
|
||||
await workflowVisualizer.addStepButton.click();
|
||||
// await workflowVisualizer.addStepButton.click();
|
||||
|
||||
await page.keyboard.press('Backspace');
|
||||
await page.keyboard.press('Delete');
|
||||
// await page.keyboard.press('Backspace');
|
||||
// await page.keyboard.press('Delete');
|
||||
|
||||
await expect(workflowVisualizer.addStepButton).toBeVisible();
|
||||
});
|
||||
// await expect(workflowVisualizer.addStepButton).toBeVisible();
|
||||
// });
|
||||
|
||||
@@ -1 +1 @@
|
||||
/*eslint-disable*/import type{Messages}from"@lingui/core";export const messages=JSON.parse("{\"Suspended Workspace\":[\"Espaço de Trabalho Suspenso\"],\"Dear {userName},\":[\"Caro \",[\"userName\"],\",\"],\"Hello,\":[\"Olá,\"],\"It appears that your workspace <0>{workspaceDisplayName}</0> has been suspended for {daysSinceInactive} days.\":[\"Parece que seu workspace <0>\",[\"workspaceDisplayName\"],\"</0> foi suspenso por \",[\"daysSinceInactive\"],\" dias.\"],\"The workspace will be deactivated in {remainingDays} {dayOrDays}, and all its data will be deleted.\":[\"O workspace será desativado em \",[\"remainingDays\"],\" \",[\"dayOrDays\"],\", e todos os seus dados serão excluídos.\"],\"If you wish to continue using Twenty, please update your subscription within the next {remainingDays} {dayOrDays}.\":[\"Se quiser continuar usando o Twenty, atualize sua assinatura nos próximos \",[\"remainingDays\"],\" \",[\"dayOrDays\"],\".\"],\"Update your subscription\":[\"Atualize sua assinatura\"],\"Validate domain\":[\"Validar domínio\"],\"{senderName} (<0>{senderEmail}</0>): Please validate this domain to allow users with <1>@{domain}</1> email addresses to join your workspace without requiring an invitation.\":[[\"senderName\"],\" (<0>\",[\"senderEmail\"],\"</0>): Por favor, valide este domínio para permitir que usuários com endereços de e-mail <1>@\",[\"domain\"],\"</1> entrem no seu espaço de trabalho sem precisar de um convite.\"],\"Test email\":[\"Email de teste\"],\"Join your team on Twenty\":[\"Junte-se à sua equipe no Twenty\"],\"{senderName} (<0>{senderEmail}</0>) has invited you to join a workspace called <1>{workspaceName}</1>.\":[[\"senderName\"],\" (<0>\",[\"senderEmail\"],\"</0>) convidou você para se juntar a um espaço de trabalho chamado <1>\",[\"workspaceName\"],\"</1>.\"],\"Accept invite\":[\"Aceitar convite\"],\"Confirm your new email address\":[\"Confirm your new email address\"],\"Confirm your email address\":[\"Confirme seu endereço de e-mail\"],\"Confirm new email\":[\"Confirm new email\"],\"Verify Email\":[\"Verificar e-mail\"],\"Password updated\":[\"Senha atualizada\"],\"This is a confirmation that password for your account ({email}) was successfully changed on {formattedDate}.\":[\"Esta é uma confirmação de que a senha da sua conta (\",[\"email\"],\") foi alterada com sucesso em \",[\"formattedDate\"],\".\"],\"If you did not initiate this change, please contact your workspace owner immediately.\":[\"Se você não iniciou essa alteração, entre em contato com o proprietário do workspace imediatamente.\"],\"Connect to Twenty\":[\"Conecte-se ao Twenty\"],\"Reset your password 🗝\":[\"Redefina sua senha 🗝\"],\"Set your password 🗝\":[\"Defina sua senha 🗝\"],\"Reset\":[\"Redefinir\"],\"Set\":[\"Definir\"],\"This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:\":[\"Este link é válido apenas para os próximos \",[\"duration\"],\". Se o link não funcionar, você pode usar o link de verificação de login diretamente:\"],\"Deleted Workspace\":[\"Espaço de Trabalho Excluído\"],\"Your workspace <0>{workspaceDisplayName}</0> has been deleted as your subscription expired {daysSinceInactive} days ago.\":[\"Seu workspace <0>\",[\"workspaceDisplayName\"],\"</0> foi excluído porque sua assinatura expirou há \",[\"daysSinceInactive\"],\" dias.\"],\"All data in this workspace has been permanently deleted.\":[\"Todos os dados deste workspace foram excluídos permanentemente.\"],\"If you wish to use Twenty again, you can create a new workspace.\":[\"Se quiser usar o Twenty novamente, você pode criar um novo workspace.\"],\"Create a new workspace\":[\"Criar um novo espaço de trabalho\"],\"What is Twenty?\":[\"O que é Twenty?\"],\"It's a CRM, a software to help businesses manage their customer data and relationships efficiently.\":[\"É um CRM, um software para ajudar empresas a gerenciar seus dados de clientes e os relacionamentos de maneira eficiente.\"],\"Website\":[\"Site\"],\"Visit Twenty's website\":[\"Visite o website do Twenty\"],\"Github\":[\"Github\"],\"Visit Twenty's GitHub repository\":[\"Visite o repositório GitHub do Twenty\"],\"User guide\":[\"Guia do Usuário\"],\"Read Twenty's user guide\":[\"Leia o guia do usuário do Twenty\"],\"Developers\":[\"Desenvolvedores\"],\"Visit Twenty's developer documentation\":[\"Visite a documentação do desenvolvedor do Twenty\"],\"Twenty.com, Public Benefit Corporation\":[\"Twenty.com, Empresa de Benefício Público\"],\"San Francisco / Paris\":[\"São Francisco / Paris\"]}")as Messages;
|
||||
/*eslint-disable*/import type{Messages}from"@lingui/core";export const messages=JSON.parse("{\"Suspended Workspace\":[\"Espaço de Trabalho Suspenso\"],\"Dear {userName},\":[\"Caro \",[\"userName\"],\",\"],\"Hello,\":[\"Olá,\"],\"It appears that your workspace <0>{workspaceDisplayName}</0> has been suspended for {daysSinceInactive} days.\":[\"Parece que seu workspace <0>\",[\"workspaceDisplayName\"],\"</0> foi suspenso por \",[\"daysSinceInactive\"],\" dias.\"],\"The workspace will be deactivated in {remainingDays} {dayOrDays}, and all its data will be deleted.\":[\"O workspace será desativado em \",[\"remainingDays\"],\" \",[\"dayOrDays\"],\", e todos os seus dados serão excluídos.\"],\"If you wish to continue using Twenty, please update your subscription within the next {remainingDays} {dayOrDays}.\":[\"Se quiser continuar usando o Twenty, atualize sua assinatura nos próximos \",[\"remainingDays\"],\" \",[\"dayOrDays\"],\".\"],\"Update your subscription\":[\"Atualize sua assinatura\"],\"Validate domain\":[\"Validar domínio\"],\"{senderName} (<0>{senderEmail}</0>): Please validate this domain to allow users with <1>@{domain}</1> email addresses to join your workspace without requiring an invitation.\":[[\"senderName\"],\" (<0>\",[\"senderEmail\"],\"</0>): Por favor, valide este domínio para permitir que usuários com endereços de e-mail <1>@\",[\"domain\"],\"</1> entrem no seu espaço de trabalho sem precisar de um convite.\"],\"Test email\":[\"Email de teste\"],\"Join your team on Twenty\":[\"Junte-se à sua equipe no Twenty\"],\"{senderName} (<0>{senderEmail}</0>) has invited you to join a workspace called <1>{workspaceName}</1>.\":[[\"senderName\"],\" (<0>\",[\"senderEmail\"],\"</0>) convidou você para se juntar a um espaço de trabalho chamado <1>\",[\"workspaceName\"],\"</1>.\"],\"Accept invite\":[\"Aceitar convite\"],\"Confirm your new email address\":[\"Confirme seu novo endereço de e-mail\"],\"Confirm your email address\":[\"Confirme seu endereço de e-mail\"],\"Confirm new email\":[\"Confirme o novo email\"],\"Verify Email\":[\"Verificar e-mail\"],\"Password updated\":[\"Senha atualizada\"],\"This is a confirmation that password for your account ({email}) was successfully changed on {formattedDate}.\":[\"Esta é uma confirmação de que a senha da sua conta (\",[\"email\"],\") foi alterada com sucesso em \",[\"formattedDate\"],\".\"],\"If you did not initiate this change, please contact your workspace owner immediately.\":[\"Se você não iniciou essa alteração, entre em contato com o proprietário do workspace imediatamente.\"],\"Connect to Twenty\":[\"Conecte-se ao Twenty\"],\"Reset your password 🗝\":[\"Redefina sua senha 🗝\"],\"Set your password 🗝\":[\"Defina sua senha 🗝\"],\"Reset\":[\"Redefinir\"],\"Set\":[\"Definir\"],\"This link is only valid for the next {duration}. If the link does not work, you can use the login verification link directly:\":[\"Este link é válido apenas para os próximos \",[\"duration\"],\". Se o link não funcionar, você pode usar o link de verificação de login diretamente:\"],\"Deleted Workspace\":[\"Espaço de Trabalho Excluído\"],\"Your workspace <0>{workspaceDisplayName}</0> has been deleted as your subscription expired {daysSinceInactive} days ago.\":[\"Seu workspace <0>\",[\"workspaceDisplayName\"],\"</0> foi excluído porque sua assinatura expirou há \",[\"daysSinceInactive\"],\" dias.\"],\"All data in this workspace has been permanently deleted.\":[\"Todos os dados deste workspace foram excluídos permanentemente.\"],\"If you wish to use Twenty again, you can create a new workspace.\":[\"Se quiser usar o Twenty novamente, você pode criar um novo workspace.\"],\"Create a new workspace\":[\"Criar um novo espaço de trabalho\"],\"What is Twenty?\":[\"O que é Twenty?\"],\"It's a CRM, a software to help businesses manage their customer data and relationships efficiently.\":[\"É um CRM, um software para ajudar empresas a gerenciar seus dados de clientes e os relacionamentos de maneira eficiente.\"],\"Website\":[\"Site\"],\"Visit Twenty's website\":[\"Visite o website do Twenty\"],\"Github\":[\"Github\"],\"Visit Twenty's GitHub repository\":[\"Visite o repositório GitHub do Twenty\"],\"User guide\":[\"Guia do Usuário\"],\"Read Twenty's user guide\":[\"Leia o guia do usuário do Twenty\"],\"Developers\":[\"Desenvolvedores\"],\"Visit Twenty's developer documentation\":[\"Visite a documentação do desenvolvedor do Twenty\"],\"Twenty.com, Public Benefit Corporation\":[\"Twenty.com, Empresa de Benefício Público\"],\"San Francisco / Paris\":[\"São Francisco / Paris\"]}")as Messages;
|
||||
File diff suppressed because one or more lines are too long
@@ -91,7 +91,7 @@ msgstr "Aceitar convite"
|
||||
#. js-lingui-explicit-id
|
||||
#: src/emails/send-email-verification-link.email.tsx
|
||||
msgid "Confirm your new email address"
|
||||
msgstr ""
|
||||
msgstr "Confirme seu novo endereço de e-mail"
|
||||
|
||||
#. js-lingui-explicit-id
|
||||
#: src/emails/send-email-verification-link.email.tsx
|
||||
@@ -101,7 +101,7 @@ msgstr "Confirme seu endereço de e-mail"
|
||||
#. js-lingui-explicit-id
|
||||
#: src/emails/send-email-verification-link.email.tsx
|
||||
msgid "Confirm new email"
|
||||
msgstr ""
|
||||
msgstr "Confirme o novo email"
|
||||
|
||||
#. js-lingui-explicit-id
|
||||
#: src/emails/send-email-verification-link.email.tsx
|
||||
|
||||
@@ -91,7 +91,7 @@ msgstr "Принять приглашение"
|
||||
#. js-lingui-explicit-id
|
||||
#: src/emails/send-email-verification-link.email.tsx
|
||||
msgid "Confirm your new email address"
|
||||
msgstr ""
|
||||
msgstr "Подтвердите ваш новый адрес электронной почты"
|
||||
|
||||
#. js-lingui-explicit-id
|
||||
#: src/emails/send-email-verification-link.email.tsx
|
||||
@@ -101,7 +101,7 @@ msgstr "Подтвердите ваш адрес электронной почт
|
||||
#. js-lingui-explicit-id
|
||||
#: src/emails/send-email-verification-link.email.tsx
|
||||
msgid "Confirm new email"
|
||||
msgstr ""
|
||||
msgstr "Подтвердить новый адрес эл. почты"
|
||||
|
||||
#. js-lingui-explicit-id
|
||||
#: src/emails/send-email-verification-link.email.tsx
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import { type JSONContent } from '@tiptap/core';
|
||||
import { type ReactNode } from 'react';
|
||||
|
||||
export const hardBreak = (_node: JSONContent): ReactNode => {
|
||||
return <br />;
|
||||
};
|
||||
@@ -1,14 +1,15 @@
|
||||
import { type JSONContent } from '@tiptap/core';
|
||||
import { Fragment, type ReactNode } from 'react';
|
||||
import { TIPTAP_NODE_TYPES, type TipTapNodeType } from 'twenty-shared/utils';
|
||||
import { bulletList } from '../nodes/bullet-list';
|
||||
import { hardBreak } from '../nodes/hard-break';
|
||||
import { heading } from '../nodes/heading';
|
||||
import { image } from '../nodes/image';
|
||||
import { listItem } from '../nodes/list-item';
|
||||
import { orderedList } from '../nodes/ordered-list';
|
||||
import { paragraph } from '../nodes/paragraph';
|
||||
import { text } from '../nodes/text';
|
||||
import { variableTag } from '../nodes/variable-tag';
|
||||
import { bulletList } from '../nodes/bullet-list';
|
||||
import { listItem } from '../nodes/list-item';
|
||||
import { orderedList } from '../nodes/ordered-list';
|
||||
|
||||
const NODE_RENDERERS = {
|
||||
[TIPTAP_NODE_TYPES.PARAGRAPH]: paragraph,
|
||||
@@ -19,6 +20,7 @@ const NODE_RENDERERS = {
|
||||
[TIPTAP_NODE_TYPES.BULLET_LIST]: bulletList,
|
||||
[TIPTAP_NODE_TYPES.ORDERED_LIST]: orderedList,
|
||||
[TIPTAP_NODE_TYPES.LIST_ITEM]: listItem,
|
||||
[TIPTAP_NODE_TYPES.HARD_BREAK]: hardBreak,
|
||||
};
|
||||
|
||||
const renderNode = (node: JSONContent): ReactNode => {
|
||||
|
||||
@@ -11,7 +11,7 @@ const modulesCoverage = {
|
||||
branches: 25,
|
||||
statements: 43,
|
||||
lines: 44,
|
||||
functions: 38,
|
||||
functions: 37,
|
||||
include: ['src/modules/**/*'],
|
||||
exclude: ['src/**/*.ts'],
|
||||
};
|
||||
|
||||
@@ -59,6 +59,22 @@
|
||||
"fix": {}
|
||||
}
|
||||
},
|
||||
"lint:changed": {
|
||||
"executor": "nx:run-commands",
|
||||
"cache": false,
|
||||
"options": {
|
||||
"command": "git diff --name-only --diff-filter=d {args.base} | grep -E '\\.(ts|tsx|js|jsx)$' | grep '^packages/twenty-front/' | xargs -r npx eslint --config packages/twenty-front/eslint.config.mjs",
|
||||
"base": "main"
|
||||
},
|
||||
"configurations": {
|
||||
"fix": {
|
||||
"command": "git diff --name-only --diff-filter=d {args.base} | grep -E '\\.(ts|tsx|js|jsx)$' | grep '^packages/twenty-front/' | xargs -r npx eslint --config packages/twenty-front/eslint.config.mjs --fix"
|
||||
},
|
||||
"staged": {
|
||||
"command": "git diff --cached --name-only --diff-filter=d | grep -E '\\.(ts|tsx|js|jsx)$' | grep '^packages/twenty-front/' | xargs -r npx eslint --config packages/twenty-front/eslint.config.mjs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"fmt": {
|
||||
"options": {
|
||||
"files": "src"
|
||||
|
||||
@@ -70,9 +70,14 @@ export type Agent = {
|
||||
|
||||
export type AgentChatThread = {
|
||||
__typename?: 'AgentChatThread';
|
||||
contextWindowTokens?: Maybe<Scalars['Int']>;
|
||||
createdAt: Scalars['DateTime'];
|
||||
id: Scalars['UUID'];
|
||||
title?: Maybe<Scalars['String']>;
|
||||
totalInputCredits: Scalars['Int'];
|
||||
totalInputTokens: Scalars['Int'];
|
||||
totalOutputCredits: Scalars['Int'];
|
||||
totalOutputTokens: Scalars['Int'];
|
||||
updatedAt: Scalars['DateTime'];
|
||||
};
|
||||
|
||||
@@ -236,6 +241,8 @@ export type Application = {
|
||||
agents: Array<Agent>;
|
||||
applicationVariables: Array<ApplicationVariable>;
|
||||
canBeUninstalled: Scalars['Boolean'];
|
||||
defaultServerlessFunctionRole?: Maybe<Role>;
|
||||
defaultServerlessFunctionRoleId?: Maybe<Scalars['String']>;
|
||||
description: Scalars['String'];
|
||||
id: Scalars['UUID'];
|
||||
name: Scalars['String'];
|
||||
@@ -571,6 +578,7 @@ export type CheckUserExistOutput = {
|
||||
|
||||
export type ClientAiModelConfig = {
|
||||
__typename?: 'ClientAIModelConfig';
|
||||
deprecated?: Maybe<Scalars['Boolean']>;
|
||||
inputCostPer1kTokensInCredits: Scalars['Float'];
|
||||
label: Scalars['String'];
|
||||
modelId: Scalars['String'];
|
||||
@@ -618,6 +626,7 @@ export enum ConfigVariablesGroup {
|
||||
BILLING_CONFIG = 'BILLING_CONFIG',
|
||||
CAPTCHA_CONFIG = 'CAPTCHA_CONFIG',
|
||||
CLOUDFLARE_CONFIG = 'CLOUDFLARE_CONFIG',
|
||||
CODE_INTERPRETER_CONFIG = 'CODE_INTERPRETER_CONFIG',
|
||||
EMAIL_SETTINGS = 'EMAIL_SETTINGS',
|
||||
EXCEPTION_HANDLER = 'EXCEPTION_HANDLER',
|
||||
GOOGLE_AUTH = 'GOOGLE_AUTH',
|
||||
@@ -695,6 +704,7 @@ export type CoreView = {
|
||||
objectMetadataId: Scalars['UUID'];
|
||||
openRecordIn: ViewOpenRecordIn;
|
||||
position: Scalars['Float'];
|
||||
shouldHideEmptyGroups: Scalars['Boolean'];
|
||||
type: ViewType;
|
||||
updatedAt: Scalars['DateTime'];
|
||||
viewFields: Array<CoreViewField>;
|
||||
@@ -986,6 +996,7 @@ export type CreateViewInput = {
|
||||
objectMetadataId: Scalars['UUID'];
|
||||
openRecordIn?: InputMaybe<ViewOpenRecordIn>;
|
||||
position?: InputMaybe<Scalars['Float']>;
|
||||
shouldHideEmptyGroups?: InputMaybe<Scalars['Boolean']>;
|
||||
type?: InputMaybe<ViewType>;
|
||||
visibility?: InputMaybe<ViewVisibility>;
|
||||
};
|
||||
@@ -1209,6 +1220,16 @@ export type DuplicateWorkflowVersionStepInput = {
|
||||
workflowVersionId: Scalars['String'];
|
||||
};
|
||||
|
||||
export type DuplicatedDashboard = {
|
||||
__typename?: 'DuplicatedDashboard';
|
||||
createdAt: Scalars['String'];
|
||||
id: Scalars['UUID'];
|
||||
pageLayoutId?: Maybe<Scalars['UUID']>;
|
||||
position: Scalars['Float'];
|
||||
title?: Maybe<Scalars['String']>;
|
||||
updatedAt: Scalars['String'];
|
||||
};
|
||||
|
||||
export type EditSsoInput = {
|
||||
id: Scalars['UUID'];
|
||||
status: SsoIdentityProviderStatus;
|
||||
@@ -1295,6 +1316,7 @@ export enum FeatureFlagKey {
|
||||
IS_PUBLIC_DOMAIN_ENABLED = 'IS_PUBLIC_DOMAIN_ENABLED',
|
||||
IS_RECORD_PAGE_LAYOUT_ENABLED = 'IS_RECORD_PAGE_LAYOUT_ENABLED',
|
||||
IS_STRIPE_INTEGRATION_ENABLED = 'IS_STRIPE_INTEGRATION_ENABLED',
|
||||
IS_TIMELINE_ACTIVITY_MIGRATED = 'IS_TIMELINE_ACTIVITY_MIGRATED',
|
||||
IS_UNIQUE_INDEXES_ENABLED = 'IS_UNIQUE_INDEXES_ENABLED',
|
||||
IS_WORKFLOW_RUN_STOPPAGE_ENABLED = 'IS_WORKFLOW_RUN_STOPPAGE_ENABLED'
|
||||
}
|
||||
@@ -1850,6 +1872,7 @@ export type Mutation = {
|
||||
destroyPageLayoutWidget: Scalars['Boolean'];
|
||||
disablePostgresProxy: PostgresCredentials;
|
||||
dismissReconnectAccountBanner: Scalars['Boolean'];
|
||||
duplicateDashboard: DuplicatedDashboard;
|
||||
duplicateWorkflow: WorkflowVersionDto;
|
||||
duplicateWorkflowVersionStep: WorkflowVersionStepChanges;
|
||||
editSSOIdentityProvider: EditSsoOutput;
|
||||
@@ -2388,6 +2411,11 @@ export type MutationDismissReconnectAccountBannerArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationDuplicateDashboardArgs = {
|
||||
id: Scalars['UUID'];
|
||||
};
|
||||
|
||||
|
||||
export type MutationDuplicateWorkflowArgs = {
|
||||
input: DuplicateWorkflowInput;
|
||||
};
|
||||
@@ -3126,6 +3154,7 @@ export enum PermissionFlagType {
|
||||
API_KEYS_AND_WEBHOOKS = 'API_KEYS_AND_WEBHOOKS',
|
||||
APPLICATIONS = 'APPLICATIONS',
|
||||
BILLING = 'BILLING',
|
||||
CODE_INTERPRETER_TOOL = 'CODE_INTERPRETER_TOOL',
|
||||
CONNECTED_ACCOUNTS = 'CONNECTED_ACCOUNTS',
|
||||
DATA_MODEL = 'DATA_MODEL',
|
||||
DOWNLOAD_FILE = 'DOWNLOAD_FILE',
|
||||
@@ -3160,6 +3189,7 @@ export type PieChartConfiguration = {
|
||||
graphType: GraphType;
|
||||
groupByFieldMetadataId: Scalars['UUID'];
|
||||
groupBySubFieldName?: Maybe<Scalars['String']>;
|
||||
hideEmptyCategory?: Maybe<Scalars['Boolean']>;
|
||||
orderBy?: Maybe<GraphOrderBy>;
|
||||
showCenterMetric?: Maybe<Scalars['Boolean']>;
|
||||
timezone?: Maybe<Scalars['String']>;
|
||||
@@ -4478,6 +4508,7 @@ export type UpdateViewInput = {
|
||||
name?: InputMaybe<Scalars['String']>;
|
||||
openRecordIn?: InputMaybe<ViewOpenRecordIn>;
|
||||
position?: InputMaybe<Scalars['Float']>;
|
||||
shouldHideEmptyGroups?: InputMaybe<Scalars['Boolean']>;
|
||||
type?: InputMaybe<ViewType>;
|
||||
visibility?: InputMaybe<ViewVisibility>;
|
||||
};
|
||||
@@ -5093,7 +5124,7 @@ export type GetChatMessagesQuery = { __typename?: 'Query', chatMessages: Array<{
|
||||
export type GetChatThreadsQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type GetChatThreadsQuery = { __typename?: 'Query', chatThreads: Array<{ __typename?: 'AgentChatThread', id: string, title?: string | null, createdAt: string, updatedAt: string }> };
|
||||
export type GetChatThreadsQuery = { __typename?: 'Query', chatThreads: Array<{ __typename?: 'AgentChatThread', id: string, title?: string | null, totalInputTokens: number, totalOutputTokens: number, contextWindowTokens?: number | null, totalInputCredits: number, totalOutputCredits: number, createdAt: string, updatedAt: string }> };
|
||||
|
||||
export type TrackAnalyticsMutationVariables = Exact<{
|
||||
type: AnalyticsType;
|
||||
@@ -6082,7 +6113,7 @@ export type ViewFilterFragmentFragment = { __typename?: 'CoreViewFilter', id: st
|
||||
|
||||
export type ViewFilterGroupFragmentFragment = { __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string };
|
||||
|
||||
export type ViewFragmentFragment = { __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, mainGroupByFieldMetadataId?: string | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: string | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }> };
|
||||
export type ViewFragmentFragment = { __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, mainGroupByFieldMetadataId?: string | null, shouldHideEmptyGroups: boolean, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: string | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }> };
|
||||
|
||||
export type ViewGroupFragmentFragment = { __typename?: 'CoreViewGroup', id: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null };
|
||||
|
||||
@@ -6093,7 +6124,7 @@ export type CreateCoreViewMutationVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type CreateCoreViewMutation = { __typename?: 'Mutation', createCoreView: { __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, mainGroupByFieldMetadataId?: string | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: string | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }> } };
|
||||
export type CreateCoreViewMutation = { __typename?: 'Mutation', createCoreView: { __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, mainGroupByFieldMetadataId?: string | null, shouldHideEmptyGroups: boolean, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: string | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }> } };
|
||||
|
||||
export type CreateCoreViewFieldMutationVariables = Exact<{
|
||||
input: CreateViewFieldInput;
|
||||
@@ -6234,7 +6265,7 @@ export type UpdateCoreViewMutationVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type UpdateCoreViewMutation = { __typename?: 'Mutation', updateCoreView: { __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, mainGroupByFieldMetadataId?: string | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: string | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }> } };
|
||||
export type UpdateCoreViewMutation = { __typename?: 'Mutation', updateCoreView: { __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, mainGroupByFieldMetadataId?: string | null, shouldHideEmptyGroups: boolean, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: string | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }> } };
|
||||
|
||||
export type UpdateCoreViewFieldMutationVariables = Exact<{
|
||||
input: UpdateViewFieldInput;
|
||||
@@ -6276,7 +6307,7 @@ export type UpdateCoreViewSortMutation = { __typename?: 'Mutation', updateCoreVi
|
||||
export type FindAllCoreViewsQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type FindAllCoreViewsQuery = { __typename?: 'Query', getCoreViews: Array<{ __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, mainGroupByFieldMetadataId?: string | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: string | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }> }> };
|
||||
export type FindAllCoreViewsQuery = { __typename?: 'Query', getCoreViews: Array<{ __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, mainGroupByFieldMetadataId?: string | null, shouldHideEmptyGroups: boolean, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: string | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }> }> };
|
||||
|
||||
export type FindManyCoreViewFieldsQueryVariables = Exact<{
|
||||
viewId: Scalars['String'];
|
||||
@@ -6318,14 +6349,14 @@ export type FindManyCoreViewsQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type FindManyCoreViewsQuery = { __typename?: 'Query', getCoreViews: Array<{ __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, mainGroupByFieldMetadataId?: string | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: string | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }> }> };
|
||||
export type FindManyCoreViewsQuery = { __typename?: 'Query', getCoreViews: Array<{ __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, mainGroupByFieldMetadataId?: string | null, shouldHideEmptyGroups: boolean, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: string | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }> }> };
|
||||
|
||||
export type FindOneCoreViewQueryVariables = Exact<{
|
||||
id: Scalars['String'];
|
||||
}>;
|
||||
|
||||
|
||||
export type FindOneCoreViewQuery = { __typename?: 'Query', getCoreView?: { __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, mainGroupByFieldMetadataId?: string | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: string | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }> } | null };
|
||||
export type FindOneCoreViewQuery = { __typename?: 'Query', getCoreView?: { __typename?: 'CoreView', id: string, name: string, objectMetadataId: string, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: string | null, mainGroupByFieldMetadataId?: string | null, shouldHideEmptyGroups: boolean, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: string | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: string | null, viewFields: Array<{ __typename?: 'CoreViewField', id: string, fieldMetadataId: string, viewId: string, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: string, fieldMetadataId: string, operand: ViewFilterOperand, value: any, viewFilterGroupId?: string | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: string, parentViewFilterGroupId?: string | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: string }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: string, fieldMetadataId: string, direction: ViewSortDirection, viewId: string }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: string, isVisible: boolean, fieldValue: string, position: number, viewId: string, createdAt: string, updatedAt: string, deletedAt?: string | null }> } | null };
|
||||
|
||||
export type FindOneCoreViewFieldQueryVariables = Exact<{
|
||||
id: Scalars['String'];
|
||||
@@ -7178,6 +7209,7 @@ export const ViewFragmentFragmentDoc = gql`
|
||||
kanbanAggregateOperation
|
||||
kanbanAggregateOperationFieldMetadataId
|
||||
mainGroupByFieldMetadataId
|
||||
shouldHideEmptyGroups
|
||||
anyFieldFilterValue
|
||||
calendarFieldMetadataId
|
||||
calendarLayout
|
||||
@@ -7700,6 +7732,11 @@ export const GetChatThreadsDocument = gql`
|
||||
chatThreads {
|
||||
id
|
||||
title
|
||||
totalInputTokens
|
||||
totalOutputTokens
|
||||
contextWindowTokens
|
||||
totalInputCredits
|
||||
totalOutputCredits
|
||||
createdAt
|
||||
updatedAt
|
||||
}
|
||||
|
||||
@@ -70,9 +70,14 @@ export type Agent = {
|
||||
|
||||
export type AgentChatThread = {
|
||||
__typename?: 'AgentChatThread';
|
||||
contextWindowTokens?: Maybe<Scalars['Int']>;
|
||||
createdAt: Scalars['DateTime'];
|
||||
id: Scalars['UUID'];
|
||||
title?: Maybe<Scalars['String']>;
|
||||
totalInputCredits: Scalars['Int'];
|
||||
totalInputTokens: Scalars['Int'];
|
||||
totalOutputCredits: Scalars['Int'];
|
||||
totalOutputTokens: Scalars['Int'];
|
||||
updatedAt: Scalars['DateTime'];
|
||||
};
|
||||
|
||||
@@ -236,6 +241,8 @@ export type Application = {
|
||||
agents: Array<Agent>;
|
||||
applicationVariables: Array<ApplicationVariable>;
|
||||
canBeUninstalled: Scalars['Boolean'];
|
||||
defaultServerlessFunctionRole?: Maybe<Role>;
|
||||
defaultServerlessFunctionRoleId?: Maybe<Scalars['String']>;
|
||||
description: Scalars['String'];
|
||||
id: Scalars['UUID'];
|
||||
name: Scalars['String'];
|
||||
@@ -571,6 +578,7 @@ export type CheckUserExistOutput = {
|
||||
|
||||
export type ClientAiModelConfig = {
|
||||
__typename?: 'ClientAIModelConfig';
|
||||
deprecated?: Maybe<Scalars['Boolean']>;
|
||||
inputCostPer1kTokensInCredits: Scalars['Float'];
|
||||
label: Scalars['String'];
|
||||
modelId: Scalars['String'];
|
||||
@@ -618,6 +626,7 @@ export enum ConfigVariablesGroup {
|
||||
BILLING_CONFIG = 'BILLING_CONFIG',
|
||||
CAPTCHA_CONFIG = 'CAPTCHA_CONFIG',
|
||||
CLOUDFLARE_CONFIG = 'CLOUDFLARE_CONFIG',
|
||||
CODE_INTERPRETER_CONFIG = 'CODE_INTERPRETER_CONFIG',
|
||||
EMAIL_SETTINGS = 'EMAIL_SETTINGS',
|
||||
EXCEPTION_HANDLER = 'EXCEPTION_HANDLER',
|
||||
GOOGLE_AUTH = 'GOOGLE_AUTH',
|
||||
@@ -695,6 +704,7 @@ export type CoreView = {
|
||||
objectMetadataId: Scalars['UUID'];
|
||||
openRecordIn: ViewOpenRecordIn;
|
||||
position: Scalars['Float'];
|
||||
shouldHideEmptyGroups: Scalars['Boolean'];
|
||||
type: ViewType;
|
||||
updatedAt: Scalars['DateTime'];
|
||||
viewFields: Array<CoreViewField>;
|
||||
@@ -969,6 +979,7 @@ export type CreateViewInput = {
|
||||
objectMetadataId: Scalars['UUID'];
|
||||
openRecordIn?: InputMaybe<ViewOpenRecordIn>;
|
||||
position?: InputMaybe<Scalars['Float']>;
|
||||
shouldHideEmptyGroups?: InputMaybe<Scalars['Boolean']>;
|
||||
type?: InputMaybe<ViewType>;
|
||||
visibility?: InputMaybe<ViewVisibility>;
|
||||
};
|
||||
@@ -1192,6 +1203,16 @@ export type DuplicateWorkflowVersionStepInput = {
|
||||
workflowVersionId: Scalars['String'];
|
||||
};
|
||||
|
||||
export type DuplicatedDashboard = {
|
||||
__typename?: 'DuplicatedDashboard';
|
||||
createdAt: Scalars['String'];
|
||||
id: Scalars['UUID'];
|
||||
pageLayoutId?: Maybe<Scalars['UUID']>;
|
||||
position: Scalars['Float'];
|
||||
title?: Maybe<Scalars['String']>;
|
||||
updatedAt: Scalars['String'];
|
||||
};
|
||||
|
||||
export type EditSsoInput = {
|
||||
id: Scalars['UUID'];
|
||||
status: SsoIdentityProviderStatus;
|
||||
@@ -1278,6 +1299,7 @@ export enum FeatureFlagKey {
|
||||
IS_PUBLIC_DOMAIN_ENABLED = 'IS_PUBLIC_DOMAIN_ENABLED',
|
||||
IS_RECORD_PAGE_LAYOUT_ENABLED = 'IS_RECORD_PAGE_LAYOUT_ENABLED',
|
||||
IS_STRIPE_INTEGRATION_ENABLED = 'IS_STRIPE_INTEGRATION_ENABLED',
|
||||
IS_TIMELINE_ACTIVITY_MIGRATED = 'IS_TIMELINE_ACTIVITY_MIGRATED',
|
||||
IS_UNIQUE_INDEXES_ENABLED = 'IS_UNIQUE_INDEXES_ENABLED',
|
||||
IS_WORKFLOW_RUN_STOPPAGE_ENABLED = 'IS_WORKFLOW_RUN_STOPPAGE_ENABLED'
|
||||
}
|
||||
@@ -1823,6 +1845,7 @@ export type Mutation = {
|
||||
destroyPageLayoutWidget: Scalars['Boolean'];
|
||||
disablePostgresProxy: PostgresCredentials;
|
||||
dismissReconnectAccountBanner: Scalars['Boolean'];
|
||||
duplicateDashboard: DuplicatedDashboard;
|
||||
duplicateWorkflow: WorkflowVersionDto;
|
||||
duplicateWorkflowVersionStep: WorkflowVersionStepChanges;
|
||||
editSSOIdentityProvider: EditSsoOutput;
|
||||
@@ -2340,6 +2363,11 @@ export type MutationDismissReconnectAccountBannerArgs = {
|
||||
};
|
||||
|
||||
|
||||
export type MutationDuplicateDashboardArgs = {
|
||||
id: Scalars['UUID'];
|
||||
};
|
||||
|
||||
|
||||
export type MutationDuplicateWorkflowArgs = {
|
||||
input: DuplicateWorkflowInput;
|
||||
};
|
||||
@@ -3047,6 +3075,7 @@ export enum PermissionFlagType {
|
||||
API_KEYS_AND_WEBHOOKS = 'API_KEYS_AND_WEBHOOKS',
|
||||
APPLICATIONS = 'APPLICATIONS',
|
||||
BILLING = 'BILLING',
|
||||
CODE_INTERPRETER_TOOL = 'CODE_INTERPRETER_TOOL',
|
||||
CONNECTED_ACCOUNTS = 'CONNECTED_ACCOUNTS',
|
||||
DATA_MODEL = 'DATA_MODEL',
|
||||
DOWNLOAD_FILE = 'DOWNLOAD_FILE',
|
||||
@@ -3081,6 +3110,7 @@ export type PieChartConfiguration = {
|
||||
graphType: GraphType;
|
||||
groupByFieldMetadataId: Scalars['UUID'];
|
||||
groupBySubFieldName?: Maybe<Scalars['String']>;
|
||||
hideEmptyCategory?: Maybe<Scalars['Boolean']>;
|
||||
orderBy?: Maybe<GraphOrderBy>;
|
||||
showCenterMetric?: Maybe<Scalars['Boolean']>;
|
||||
timezone?: Maybe<Scalars['String']>;
|
||||
@@ -4307,6 +4337,7 @@ export type UpdateViewInput = {
|
||||
name?: InputMaybe<Scalars['String']>;
|
||||
openRecordIn?: InputMaybe<ViewOpenRecordIn>;
|
||||
position?: InputMaybe<Scalars['Float']>;
|
||||
shouldHideEmptyGroups?: InputMaybe<Scalars['Boolean']>;
|
||||
type?: InputMaybe<ViewType>;
|
||||
visibility?: InputMaybe<ViewVisibility>;
|
||||
};
|
||||
@@ -4860,7 +4891,7 @@ export type ViewFilterFragmentFragment = { __typename?: 'CoreViewFilter', id: an
|
||||
|
||||
export type ViewFilterGroupFragmentFragment = { __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any };
|
||||
|
||||
export type ViewFragmentFragment = { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, mainGroupByFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: any | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: any | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }> };
|
||||
export type ViewFragmentFragment = { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, mainGroupByFieldMetadataId?: any | null, shouldHideEmptyGroups: boolean, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: any | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: any | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }> };
|
||||
|
||||
export type ViewGroupFragmentFragment = { __typename?: 'CoreViewGroup', id: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null };
|
||||
|
||||
@@ -4871,7 +4902,7 @@ export type CreateCoreViewMutationVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type CreateCoreViewMutation = { __typename?: 'Mutation', createCoreView: { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, mainGroupByFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: any | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: any | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }> } };
|
||||
export type CreateCoreViewMutation = { __typename?: 'Mutation', createCoreView: { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, mainGroupByFieldMetadataId?: any | null, shouldHideEmptyGroups: boolean, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: any | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: any | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }> } };
|
||||
|
||||
export type CreateCoreViewFieldMutationVariables = Exact<{
|
||||
input: CreateViewFieldInput;
|
||||
@@ -5012,7 +5043,7 @@ export type UpdateCoreViewMutationVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type UpdateCoreViewMutation = { __typename?: 'Mutation', updateCoreView: { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, mainGroupByFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: any | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: any | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }> } };
|
||||
export type UpdateCoreViewMutation = { __typename?: 'Mutation', updateCoreView: { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, mainGroupByFieldMetadataId?: any | null, shouldHideEmptyGroups: boolean, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: any | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: any | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }> } };
|
||||
|
||||
export type UpdateCoreViewFieldMutationVariables = Exact<{
|
||||
input: UpdateViewFieldInput;
|
||||
@@ -5054,7 +5085,7 @@ export type UpdateCoreViewSortMutation = { __typename?: 'Mutation', updateCoreVi
|
||||
export type FindAllCoreViewsQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type FindAllCoreViewsQuery = { __typename?: 'Query', getCoreViews: Array<{ __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, mainGroupByFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: any | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: any | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }> }> };
|
||||
export type FindAllCoreViewsQuery = { __typename?: 'Query', getCoreViews: Array<{ __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, mainGroupByFieldMetadataId?: any | null, shouldHideEmptyGroups: boolean, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: any | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: any | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }> }> };
|
||||
|
||||
export type FindManyCoreViewFieldsQueryVariables = Exact<{
|
||||
viewId: Scalars['String'];
|
||||
@@ -5096,14 +5127,14 @@ export type FindManyCoreViewsQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type FindManyCoreViewsQuery = { __typename?: 'Query', getCoreViews: Array<{ __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, mainGroupByFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: any | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: any | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }> }> };
|
||||
export type FindManyCoreViewsQuery = { __typename?: 'Query', getCoreViews: Array<{ __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, mainGroupByFieldMetadataId?: any | null, shouldHideEmptyGroups: boolean, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: any | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: any | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }> }> };
|
||||
|
||||
export type FindOneCoreViewQueryVariables = Exact<{
|
||||
id: Scalars['String'];
|
||||
}>;
|
||||
|
||||
|
||||
export type FindOneCoreViewQuery = { __typename?: 'Query', getCoreView?: { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, mainGroupByFieldMetadataId?: any | null, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: any | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: any | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }> } | null };
|
||||
export type FindOneCoreViewQuery = { __typename?: 'Query', getCoreView?: { __typename?: 'CoreView', id: any, name: string, objectMetadataId: any, type: ViewType, key?: ViewKey | null, icon: string, position: number, isCompact: boolean, openRecordIn: ViewOpenRecordIn, kanbanAggregateOperation?: AggregateOperations | null, kanbanAggregateOperationFieldMetadataId?: any | null, mainGroupByFieldMetadataId?: any | null, shouldHideEmptyGroups: boolean, anyFieldFilterValue?: string | null, calendarFieldMetadataId?: any | null, calendarLayout?: ViewCalendarLayout | null, visibility: ViewVisibility, createdByUserWorkspaceId?: any | null, viewFields: Array<{ __typename?: 'CoreViewField', id: any, fieldMetadataId: any, viewId: any, isVisible: boolean, position: number, size: number, aggregateOperation?: AggregateOperations | null, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilters: Array<{ __typename?: 'CoreViewFilter', id: any, fieldMetadataId: any, operand: ViewFilterOperand, value: any, viewFilterGroupId?: any | null, positionInViewFilterGroup?: number | null, subFieldName?: string | null, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }>, viewFilterGroups: Array<{ __typename?: 'CoreViewFilterGroup', id: any, parentViewFilterGroupId?: any | null, logicalOperator: ViewFilterGroupLogicalOperator, positionInViewFilterGroup?: number | null, viewId: any }>, viewSorts: Array<{ __typename?: 'CoreViewSort', id: any, fieldMetadataId: any, direction: ViewSortDirection, viewId: any }>, viewGroups: Array<{ __typename?: 'CoreViewGroup', id: any, isVisible: boolean, fieldValue: string, position: number, viewId: any, createdAt: string, updatedAt: string, deletedAt?: string | null }> } | null };
|
||||
|
||||
export type FindOneCoreViewFieldQueryVariables = Exact<{
|
||||
id: Scalars['String'];
|
||||
@@ -5339,6 +5370,7 @@ export const ViewFragmentFragmentDoc = gql`
|
||||
kanbanAggregateOperation
|
||||
kanbanAggregateOperationFieldMetadataId
|
||||
mainGroupByFieldMetadataId
|
||||
shouldHideEmptyGroups
|
||||
anyFieldFilterValue
|
||||
calendarFieldMetadataId
|
||||
calendarLayout
|
||||
|
||||
@@ -3,7 +3,7 @@ import { motion } from 'framer-motion';
|
||||
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton';
|
||||
|
||||
import { SKELETON_LOADER_HEIGHT_SIZES } from '@/activities/components/SkeletonLoader';
|
||||
import { NAV_DRAWER_WIDTHS } from '@/ui/navigation/navigation-drawer/constants/NavDrawerWidths';
|
||||
import { NAVIGATION_DRAWER_CONSTRAINTS } from '@/ui/layout/resizable-panel/constants/NavigationDrawerConstraints';
|
||||
import { useIsMobile } from '@/ui/utilities/responsive/hooks/useIsMobile';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import { ANIMATION } from 'twenty-ui/theme';
|
||||
@@ -54,9 +54,7 @@ export const LeftPanelSkeletonLoader = () => {
|
||||
<StyledAnimatedContainer
|
||||
initial={false}
|
||||
animate={{
|
||||
width: isMobile
|
||||
? NAV_DRAWER_WIDTHS.menu.mobile.collapsed
|
||||
: NAV_DRAWER_WIDTHS.menu.desktop.expanded,
|
||||
width: isMobile ? 0 : NAVIGATION_DRAWER_CONSTRAINTS.default,
|
||||
opacity: isMobile ? 0 : 1,
|
||||
}}
|
||||
transition={{ duration: ANIMATION.duration.fast }}
|
||||
|
||||
@@ -2,7 +2,7 @@ import styled from '@emotion/styled';
|
||||
|
||||
import { useShowAuthModal } from '@/ui/layout/hooks/useShowAuthModal';
|
||||
import { Modal } from '@/ui/layout/modal/components/Modal';
|
||||
import { NAV_DRAWER_WIDTHS } from '@/ui/navigation/navigation-drawer/constants/NavDrawerWidths';
|
||||
import { NAVIGATION_DRAWER_CONSTRAINTS } from '@/ui/layout/resizable-panel/constants/NavigationDrawerConstraints';
|
||||
import { MOBILE_VIEWPORT } from 'twenty-ui/theme';
|
||||
import { LeftPanelSkeletonLoader } from '~/loading/components/LeftPanelSkeletonLoader';
|
||||
import { RightPanelSkeletonLoader } from '~/loading/components/RightPanelSkeletonLoader';
|
||||
@@ -14,7 +14,7 @@ const StyledContainer = styled.div`
|
||||
flex-direction: row;
|
||||
gap: 12px;
|
||||
height: 100dvh;
|
||||
min-width: ${NAV_DRAWER_WIDTHS.menu.desktop.expanded}px;
|
||||
min-width: ${NAVIGATION_DRAWER_CONSTRAINTS.default}px;
|
||||
width: 100%;
|
||||
padding: 12px 8px 12px 8px;
|
||||
overflow: hidden;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user