Compare commits
38
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d64f23894e | ||
|
|
8998009805 | ||
|
|
a710c105cf | ||
|
|
a5cd64daf5 | ||
|
|
df3e217d64 | ||
|
|
1c06506256 | ||
|
|
d271ba06f1 | ||
|
|
7d35979fcf | ||
|
|
8d3047c1fc | ||
|
|
e632b7dbb9 | ||
|
|
5b3ee3f1a7 | ||
|
|
875795cc30 | ||
|
|
350b835fbc | ||
|
|
ef49dad0bc | ||
|
|
e3a668a054 | ||
|
|
74536e6f98 | ||
|
|
b6ec2acb56 | ||
|
|
bb5f294c5a | ||
|
|
13aaea597e | ||
|
|
ec893c2767 | ||
|
|
f8c1ad5b3c | ||
|
|
a90895e167 | ||
|
|
9b7f7d059a | ||
|
|
95fee18126 | ||
|
|
5b8804ff06 | ||
|
|
6545ca274c | ||
|
|
15c52d3a39 | ||
|
|
3db1af9a17 | ||
|
|
1e7c1691f4 | ||
|
|
577312f121 | ||
|
|
fb8b9cb86c | ||
|
|
499067ae14 | ||
|
|
ca84d28157 | ||
|
|
d1a4902460 | ||
|
|
89ad87aa64 | ||
|
|
0c5c9c844e | ||
|
|
41571ea377 | ||
|
|
570038ad65 |
@@ -78,6 +78,83 @@ jobs:
|
||||
tag: scope:backend
|
||||
tasks: lint,typecheck
|
||||
|
||||
server-previous-version-upgrade-mutation-guard:
|
||||
timeout-minutes: 5
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Fetch custom Github Actions and base branch history
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 10
|
||||
- name: Get changed upgrade-version-command files
|
||||
id: changed-files
|
||||
uses: tj-actions/changed-files@v45
|
||||
with:
|
||||
files: |
|
||||
packages/twenty-server/src/database/commands/upgrade-version-command/**
|
||||
- name: Check upgrade version commands are in current version only
|
||||
if: >
|
||||
steps.changed-files.outputs.any_changed == 'true' &&
|
||||
!contains(github.event.pull_request.labels.*.name, 'ci:allow-previous-version-upgrade-mutation')
|
||||
run: |
|
||||
VERSION_CONSTANT_FILE="packages/twenty-server/src/engine/core-modules/upgrade/constants/twenty-current-version.constant.ts"
|
||||
|
||||
CURRENT_VERSION=$(sed -n "s/.*TWENTY_CURRENT_VERSION = '\([0-9.]*\)'.*/\1/p" "$VERSION_CONSTANT_FILE")
|
||||
|
||||
if [ -z "$CURRENT_VERSION" ]; then
|
||||
echo "::error::Could not extract TWENTY_CURRENT_VERSION from $VERSION_CONSTANT_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CURRENT_DIR=$(echo "$CURRENT_VERSION" | sed -E 's/^([0-9]+)\.([0-9]+)\..*/\1-\2/')
|
||||
|
||||
echo "Current version: $CURRENT_VERSION (directory: $CURRENT_DIR)"
|
||||
|
||||
ADDED_OFFENDERS=""
|
||||
MODIFIED_OFFENDERS=""
|
||||
|
||||
check_files() {
|
||||
local category="$1"
|
||||
shift
|
||||
for file in "$@"; do
|
||||
VERSION_DIR=$(echo "$file" | sed -n 's|.*upgrade-version-command/\([0-9]*-[0-9]*\)/.*|\1|p')
|
||||
|
||||
if [ -n "$VERSION_DIR" ] && [ "$VERSION_DIR" != "$CURRENT_DIR" ]; then
|
||||
if [ "$category" = "added" ]; then
|
||||
ADDED_OFFENDERS="$ADDED_OFFENDERS\n - $file (version directory: $VERSION_DIR)"
|
||||
else
|
||||
MODIFIED_OFFENDERS="$MODIFIED_OFFENDERS\n - $file (version directory: $VERSION_DIR)"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
check_files "added" ${{ steps.changed-files.outputs.added_files }}
|
||||
check_files "modified" ${{ steps.changed-files.outputs.modified_files }}
|
||||
|
||||
if [ -n "$ADDED_OFFENDERS" ] || [ -n "$MODIFIED_OFFENDERS" ]; then
|
||||
echo "This PR touches upgrade command files outside the current version directory ($CURRENT_DIR / $CURRENT_VERSION)."
|
||||
|
||||
if [ -n "$ADDED_OFFENDERS" ]; then
|
||||
echo ""
|
||||
echo "New files added to non-current version directories:"
|
||||
echo -e "$ADDED_OFFENDERS"
|
||||
fi
|
||||
|
||||
if [ -n "$MODIFIED_OFFENDERS" ]; then
|
||||
echo ""
|
||||
echo "Existing files modified in non-current version directories:"
|
||||
echo -e "$MODIFIED_OFFENDERS"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "If this is intentional, add the label 'ci:allow-previous-version-upgrade-mutation' to this PR and re-run CI."
|
||||
echo "Otherwise, please move your changes to the current version directory ($CURRENT_DIR)."
|
||||
|
||||
echo "::error::Upgrade commands were added or modified in non-current version directories."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
server-validation:
|
||||
needs: server-build
|
||||
timeout-minutes: 30
|
||||
@@ -311,6 +388,7 @@ jobs:
|
||||
changed-files-check,
|
||||
server-build,
|
||||
server-lint-typecheck,
|
||||
server-previous-version-upgrade-mutation-guard,
|
||||
server-validation,
|
||||
server-test,
|
||||
server-integration-test,
|
||||
|
||||
@@ -58,6 +58,7 @@ jobs:
|
||||
npx nx run twenty-server:lingui:compile --strict
|
||||
npx nx run twenty-emails:lingui:compile --strict
|
||||
npx nx run twenty-front:lingui:compile --strict
|
||||
npx nx run twenty-website-new:lingui:compile --strict
|
||||
continue-on-error: true
|
||||
|
||||
- name: Stash any changes before pulling translations
|
||||
@@ -115,6 +116,7 @@ jobs:
|
||||
npx nx run twenty-server:lingui:compile
|
||||
npx nx run twenty-emails:lingui:compile
|
||||
npx nx run twenty-front:lingui:compile
|
||||
npx nx run twenty-website-new:lingui:compile
|
||||
git status
|
||||
git add .
|
||||
if ! git diff --staged --quiet --exit-code; then
|
||||
|
||||
@@ -41,6 +41,7 @@ jobs:
|
||||
npx nx run twenty-server:lingui:extract
|
||||
npx nx run twenty-emails:lingui:extract
|
||||
npx nx run twenty-front:lingui:extract
|
||||
npx nx run twenty-website-new:lingui:extract
|
||||
|
||||
- name: Check and commit extracted files
|
||||
id: check_extract_changes
|
||||
@@ -60,6 +61,7 @@ jobs:
|
||||
npx nx run twenty-server:lingui:compile
|
||||
npx nx run twenty-emails:lingui:compile
|
||||
npx nx run twenty-front:lingui:compile
|
||||
npx nx run twenty-website-new:lingui:compile
|
||||
|
||||
- name: Check and commit compiled files
|
||||
id: check_compile_changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "github-connector",
|
||||
"version": "0.1.0",
|
||||
"version": "0.2.0",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^24.5.0",
|
||||
|
||||
+1
@@ -77,6 +77,7 @@ describe('PullRequestReview object', () => {
|
||||
expect(names).toContain('firstSubmittedAt');
|
||||
expect(names).toContain('lastSubmittedAt');
|
||||
expect(names).toContain('eventCount');
|
||||
expect(names).toContain('isSelfReview');
|
||||
expect(names).toContain('reviewer');
|
||||
expect(names).toContain('pullRequest');
|
||||
expect(names).toContain('reviewEvents');
|
||||
|
||||
+30
-1
@@ -82,7 +82,17 @@ describe('verifyGitHubSignature', () => {
|
||||
});
|
||||
|
||||
describe('getRawBodyForSignature', () => {
|
||||
it('returns the string as-is for string body', () => {
|
||||
it('prefers event.rawBody when the runtime forwarded it', () => {
|
||||
const original = '{ "action": "opened", "number": 42 }';
|
||||
expect(
|
||||
getRawBodyForSignature({
|
||||
body: { action: 'opened', number: 42 },
|
||||
rawBody: original,
|
||||
}),
|
||||
).toBe(original);
|
||||
});
|
||||
|
||||
it('falls back to string body when rawBody is not provided', () => {
|
||||
expect(
|
||||
getRawBodyForSignature({ body: '{"a":1}', isBase64Encoded: false }),
|
||||
).toBe('{"a":1}');
|
||||
@@ -119,3 +129,22 @@ describe('verifyGitHubSignature with parsed body', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('end-to-end: server forwards rawBody, signature verifies', () => {
|
||||
it('verifies a signature when rawBody is present alongside parsed body', () => {
|
||||
const original = '{ "action": "opened", "number": 42 }';
|
||||
const event = {
|
||||
body: { action: 'opened', number: 42 },
|
||||
rawBody: original,
|
||||
isBase64Encoded: false,
|
||||
};
|
||||
|
||||
const rawBody = getRawBodyForSignature(event);
|
||||
const result = verifyGitHubSignature({
|
||||
rawBody,
|
||||
signatureHeader: sign(original),
|
||||
secret: SECRET,
|
||||
});
|
||||
expect(result.ok).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
+4
@@ -7,7 +7,11 @@ export type SignatureVerificationResult =
|
||||
export function getRawBodyForSignature(event: {
|
||||
body: unknown;
|
||||
isBase64Encoded?: boolean;
|
||||
rawBody?: string;
|
||||
}): string | null {
|
||||
if (typeof event.rawBody === 'string') {
|
||||
return event.rawBody;
|
||||
}
|
||||
const raw = event.body;
|
||||
if (raw == null) return '';
|
||||
if (typeof raw === 'string') {
|
||||
|
||||
+6
-1
@@ -298,7 +298,12 @@ const handler = async (
|
||||
const res = await client.query({
|
||||
pullRequestReviews: {
|
||||
__args: {
|
||||
filter: { reviewerId: { eq: contributorId } },
|
||||
filter: {
|
||||
and: [
|
||||
{ reviewerId: { eq: contributorId } },
|
||||
{ isSelfReview: { eq: false } },
|
||||
],
|
||||
},
|
||||
orderBy: [{ firstSubmittedAt: 'DescNullsLast' }],
|
||||
first: PAGE_SIZE,
|
||||
after: cursor,
|
||||
|
||||
+1
@@ -198,6 +198,7 @@ const handler = async (
|
||||
const res = await client.query({
|
||||
pullRequestReviews: {
|
||||
__args: {
|
||||
filter: { isSelfReview: { eq: false } },
|
||||
orderBy: [{ firstSubmittedAt: 'DescNullsLast' }],
|
||||
first: PAGE_SIZE,
|
||||
after: cursor,
|
||||
|
||||
+1
@@ -15,5 +15,6 @@ export async function batchUpsertConsolidatedReviews(
|
||||
eventCount: true,
|
||||
reviewerId: true,
|
||||
pullRequestId: true,
|
||||
isSelfReview: true,
|
||||
}) as Promise<PullRequestReviewRow[]>;
|
||||
}
|
||||
|
||||
+11
-2
@@ -23,7 +23,10 @@ type ReviewEventNode = {
|
||||
reviewerId: string | null;
|
||||
pullRequestId: string | null;
|
||||
reviewer: { ghLogin: string | null } | null;
|
||||
pullRequest: { githubNumber: number | null } | null;
|
||||
pullRequest: {
|
||||
githubNumber: number | null;
|
||||
authorId: string | null;
|
||||
} | null;
|
||||
};
|
||||
|
||||
type GroupContext = {
|
||||
@@ -31,6 +34,7 @@ type GroupContext = {
|
||||
reviewerId: string | null;
|
||||
prNumber: number | null;
|
||||
reviewerLogin: string | null;
|
||||
prAuthorId: string | null;
|
||||
events: { state: ReviewEventState; submittedAt: string | null }[];
|
||||
};
|
||||
|
||||
@@ -68,7 +72,7 @@ const handler = async (_event: RoutePayload<unknown>) => {
|
||||
reviewerId: true,
|
||||
pullRequestId: true,
|
||||
reviewer: { ghLogin: true },
|
||||
pullRequest: { githubNumber: true },
|
||||
pullRequest: { githubNumber: true, authorId: true },
|
||||
},
|
||||
},
|
||||
pageInfo: { hasNextPage: true, endCursor: true },
|
||||
@@ -95,6 +99,7 @@ const handler = async (_event: RoutePayload<unknown>) => {
|
||||
reviewerId: node.reviewerId,
|
||||
prNumber: node.pullRequest?.githubNumber ?? null,
|
||||
reviewerLogin: node.reviewer?.ghLogin ?? null,
|
||||
prAuthorId: node.pullRequest?.authorId ?? null,
|
||||
events: [],
|
||||
};
|
||||
groups.set(key, group);
|
||||
@@ -105,6 +110,9 @@ const handler = async (_event: RoutePayload<unknown>) => {
|
||||
if (group.prNumber === null && node.pullRequest?.githubNumber != null) {
|
||||
group.prNumber = node.pullRequest.githubNumber;
|
||||
}
|
||||
if (group.prAuthorId === null && node.pullRequest?.authorId) {
|
||||
group.prAuthorId = node.pullRequest.authorId;
|
||||
}
|
||||
group.events.push({
|
||||
state: node.state,
|
||||
submittedAt: node.submittedAt,
|
||||
@@ -123,6 +131,7 @@ const handler = async (_event: RoutePayload<unknown>) => {
|
||||
prNumber: group.prNumber,
|
||||
reviewerLogin: group.reviewerLogin,
|
||||
events: group.events,
|
||||
prAuthorId: group.prAuthorId,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
+13
@@ -24,6 +24,9 @@ export const REVIEW_EVENT_COUNT_FIELD_UNIVERSAL_IDENTIFIER =
|
||||
export const PULL_REQUEST_REVIEW_CREATED_AT_FIELD_UNIVERSAL_IDENTIFIER =
|
||||
'b4d61187-1b78-5d6e-9752-79f994ff6d55';
|
||||
|
||||
export const REVIEW_IS_SELF_REVIEW_FIELD_UNIVERSAL_IDENTIFIER =
|
||||
'c1f3e8a2-9b5d-4e7f-8a6c-2d4b6f8e1a93';
|
||||
|
||||
enum ReviewState {
|
||||
APPROVED = 'APPROVED',
|
||||
CHANGES_REQUESTED = 'CHANGES_REQUESTED',
|
||||
@@ -116,5 +119,15 @@ export default defineObject({
|
||||
icon: 'IconHash',
|
||||
defaultValue: 0,
|
||||
},
|
||||
{
|
||||
universalIdentifier: REVIEW_IS_SELF_REVIEW_FIELD_UNIVERSAL_IDENTIFIER,
|
||||
name: 'isSelfReview',
|
||||
type: FieldType.BOOLEAN,
|
||||
label: 'Self review',
|
||||
description:
|
||||
'True when the reviewer is the same contributor as the PR author. Self reviews are excluded from review-count aggregations (top reviewers, contributor stats, etc.) so contributors are credited only for reviews on other people\u2019s PRs.',
|
||||
icon: 'IconUserCheck',
|
||||
defaultValue: false,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
+1
@@ -8,4 +8,5 @@ export type PullRequestReviewRow = {
|
||||
eventCount?: number | null;
|
||||
reviewerId?: string | null;
|
||||
pullRequestId?: string | null;
|
||||
isSelfReview?: boolean | null;
|
||||
};
|
||||
|
||||
+17
@@ -12,6 +12,7 @@ export type ConsolidatedReviewUpsertInput = {
|
||||
eventCount: number;
|
||||
reviewerId: string | null;
|
||||
pullRequestId: string;
|
||||
isSelfReview: boolean;
|
||||
};
|
||||
|
||||
export type BuildConsolidatedRowParams = {
|
||||
@@ -20,8 +21,23 @@ export type BuildConsolidatedRowParams = {
|
||||
prNumber: number | null;
|
||||
reviewerLogin: string | null;
|
||||
events: ReviewEventForConsolidation[];
|
||||
/**
|
||||
* Author of the PR being reviewed. When non-null and equal to `reviewerId`
|
||||
* the consolidated row is flagged as a self-review so downstream
|
||||
* aggregations (top reviewers, contributor stats, etc.) can exclude it.
|
||||
*/
|
||||
prAuthorId?: string | null;
|
||||
};
|
||||
|
||||
export const isSelfReview = (
|
||||
reviewerId: string | null,
|
||||
prAuthorId: string | null | undefined,
|
||||
): boolean =>
|
||||
reviewerId !== null &&
|
||||
prAuthorId !== null &&
|
||||
prAuthorId !== undefined &&
|
||||
reviewerId === prAuthorId;
|
||||
|
||||
export const buildReviewKey = (
|
||||
pullRequestId: string,
|
||||
reviewerId: string | null,
|
||||
@@ -49,5 +65,6 @@ export const buildConsolidatedRow = (
|
||||
eventCount: verdict.eventCount,
|
||||
reviewerId: params.reviewerId,
|
||||
pullRequestId: params.pullRequestId,
|
||||
isSelfReview: isSelfReview(params.reviewerId, params.prAuthorId ?? null),
|
||||
};
|
||||
};
|
||||
|
||||
+66
@@ -8,6 +8,7 @@ import {
|
||||
buildConsolidatedRow,
|
||||
buildReviewKey,
|
||||
buildConsolidatedTitle,
|
||||
isSelfReview,
|
||||
} from 'src/modules/github/pull-request-review/utils/build-consolidated-row';
|
||||
|
||||
const evt = (
|
||||
@@ -140,6 +141,71 @@ describe('buildConsolidatedRow', () => {
|
||||
eventCount: 3,
|
||||
reviewerId: 'rev-2',
|
||||
pullRequestId: 'pr-1',
|
||||
isSelfReview: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('flags isSelfReview when prAuthorId equals reviewerId', () => {
|
||||
const row = buildConsolidatedRow({
|
||||
pullRequestId: 'pr-1',
|
||||
reviewerId: 'alice',
|
||||
prNumber: 7,
|
||||
reviewerLogin: 'alice',
|
||||
prAuthorId: 'alice',
|
||||
events: [evt('COMMENTED', '2025-04-01T10:00:00Z')],
|
||||
});
|
||||
expect(row.isSelfReview).toBe(true);
|
||||
});
|
||||
|
||||
it('does not flag isSelfReview when prAuthorId differs from reviewerId', () => {
|
||||
const row = buildConsolidatedRow({
|
||||
pullRequestId: 'pr-1',
|
||||
reviewerId: 'alice',
|
||||
prNumber: 7,
|
||||
reviewerLogin: 'alice',
|
||||
prAuthorId: 'bob',
|
||||
events: [evt('APPROVED', '2025-04-01T10:00:00Z')],
|
||||
});
|
||||
expect(row.isSelfReview).toBe(false);
|
||||
});
|
||||
|
||||
it('does not flag isSelfReview when prAuthorId is missing', () => {
|
||||
const row = buildConsolidatedRow({
|
||||
pullRequestId: 'pr-1',
|
||||
reviewerId: 'alice',
|
||||
prNumber: 7,
|
||||
reviewerLogin: 'alice',
|
||||
events: [evt('APPROVED', '2025-04-01T10:00:00Z')],
|
||||
});
|
||||
expect(row.isSelfReview).toBe(false);
|
||||
});
|
||||
|
||||
it('does not flag isSelfReview when reviewerId is null (ghost reviewer)', () => {
|
||||
const row = buildConsolidatedRow({
|
||||
pullRequestId: 'pr-1',
|
||||
reviewerId: null,
|
||||
prNumber: 7,
|
||||
reviewerLogin: null,
|
||||
prAuthorId: null,
|
||||
events: [evt('COMMENTED', '2025-04-01T10:00:00Z')],
|
||||
});
|
||||
expect(row.isSelfReview).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isSelfReview', () => {
|
||||
it('returns true only when both ids are present and equal', () => {
|
||||
expect(isSelfReview('a', 'a')).toBe(true);
|
||||
});
|
||||
|
||||
it('returns false when ids differ', () => {
|
||||
expect(isSelfReview('a', 'b')).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false when either side is null/undefined', () => {
|
||||
expect(isSelfReview(null, 'a')).toBe(false);
|
||||
expect(isSelfReview('a', null)).toBe(false);
|
||||
expect(isSelfReview('a', undefined)).toBe(false);
|
||||
expect(isSelfReview(null, null)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
+9
@@ -110,9 +110,16 @@ const handler = async (event: RoutePayload<FetchPrsPayload>) => {
|
||||
reviewerId: string | null;
|
||||
prNumber: number;
|
||||
reviewerLogin: string | null;
|
||||
prAuthorId: string | null;
|
||||
events: { state: ReviewEventState; submittedAt: string | null }[];
|
||||
};
|
||||
|
||||
const authorIdByPullRequestId = new Map<string, string | null>();
|
||||
for (const pr of prData) {
|
||||
const id = prIdByNumber.get(pr.githubNumber);
|
||||
if (id) authorIdByPullRequestId.set(id, pr.authorId);
|
||||
}
|
||||
|
||||
let skippedReviews = 0;
|
||||
const reviewEventData: ReviewEventInput[] = [];
|
||||
const groups = new Map<GroupKey, GroupContext>();
|
||||
@@ -141,6 +148,7 @@ const handler = async (event: RoutePayload<FetchPrsPayload>) => {
|
||||
reviewerId,
|
||||
prNumber: pr.number,
|
||||
reviewerLogin: review.author?.login ?? null,
|
||||
prAuthorId: authorIdByPullRequestId.get(pullRequestId) ?? null,
|
||||
events: [],
|
||||
};
|
||||
groups.set(key, group);
|
||||
@@ -177,6 +185,7 @@ const handler = async (event: RoutePayload<FetchPrsPayload>) => {
|
||||
prNumber: group.prNumber,
|
||||
reviewerLogin: group.reviewerLogin,
|
||||
events: group.events,
|
||||
prAuthorId: group.prAuthorId,
|
||||
}),
|
||||
);
|
||||
const consolidatedRecords = await timed(
|
||||
|
||||
@@ -49,8 +49,6 @@ RUN yarn workspaces focus --production twenty-emails twenty-shared twenty-sdk tw
|
||||
|
||||
FROM common-deps AS twenty-front-build
|
||||
|
||||
ARG REACT_APP_SERVER_BASE_URL
|
||||
|
||||
COPY ./packages/twenty-front /app/packages/twenty-front
|
||||
COPY ./packages/twenty-front-component-renderer /app/packages/twenty-front-component-renderer
|
||||
COPY ./packages/twenty-ui /app/packages/twenty-ui
|
||||
@@ -138,9 +136,6 @@ USER 1000
|
||||
|
||||
FROM twenty-server AS twenty
|
||||
|
||||
ARG REACT_APP_SERVER_BASE_URL
|
||||
ENV REACT_APP_SERVER_BASE_URL=$REACT_APP_SERVER_BASE_URL
|
||||
|
||||
COPY --chown=1000 --from=twenty-front-build /app/packages/twenty-front/build /app/packages/twenty-server/dist/front
|
||||
|
||||
LABEL org.opencontainers.image.description="Twenty image with backend and frontend."
|
||||
@@ -232,7 +227,6 @@ RUN mkdir -p /data/postgres /data/redis /app/packages/twenty-server/.local-stora
|
||||
&& chown -R postgres:postgres /data/postgres \
|
||||
&& chown 1000:1000 /data/redis /app/packages/twenty-server/.local-storage
|
||||
|
||||
ARG REACT_APP_SERVER_BASE_URL
|
||||
ARG APP_VERSION=0.0.0
|
||||
|
||||
ENV S6_KEEP_ENV=1
|
||||
@@ -241,7 +235,6 @@ ENV PG_DATABASE_URL=postgres://twenty:twenty@localhost:5432/default \
|
||||
REDIS_URL=redis://localhost:6379 \
|
||||
STORAGE_TYPE=local \
|
||||
APP_SECRET=twenty-app-dev-secret-not-for-production \
|
||||
REACT_APP_SERVER_BASE_URL=$REACT_APP_SERVER_BASE_URL \
|
||||
APP_VERSION=$APP_VERSION \
|
||||
NODE_ENV=development \
|
||||
NODE_PORT=2020 \
|
||||
|
||||
@@ -101,6 +101,7 @@ The `RoutePayload` type has the following structure:
|
||||
| `queryStringParameters` | `Record<string, string \| undefined>` | Query string parameters (multiple values joined with commas) | `/users?ids=1&ids=2&ids=3&name=Alice` -> `{ ids: '1,2,3', name: 'Alice' }`|
|
||||
| `pathParameters` | `Record<string, string \| undefined>` | Path parameters extracted from the route pattern | `/users/:id`, `/users/123` -> `{ id: '123' }` |
|
||||
| `body` | `object \| null` | Parsed request body (JSON) | `{ id: 1 }` -> `{ id: 1 }` |
|
||||
| `rawBody` | `string \| undefined` | Original UTF-8 request body, before JSON parsing. Useful for verifying HMAC-style webhook signatures (e.g. GitHub's `X-Hub-Signature-256`, Stripe). `undefined` when the runtime did not preserve it. | |
|
||||
| `isBase64Encoded` | `boolean` | Whether the body is base64 encoded | |
|
||||
| `requestContext.http.method` | `string` | HTTP method (GET, POST, PUT, PATCH, DELETE) | |
|
||||
| `requestContext.http.path` | `string` | Raw request path | |
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 141 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 5.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 41 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 245 KiB |
@@ -94,15 +94,16 @@ const handler = async (event: RoutePayload) => {
|
||||
|
||||
يحتوي نوع `RoutePayload` على البنية التالية:
|
||||
|
||||
| الخاصية | النوع | الوصف | مثال |
|
||||
| ---------------------------- | ------------------------------------------------------- | ------------------------------------------------------------ | -------------------------------------------------------------------------- |
|
||||
| `headers` | `Record\<string, string \| undefined>` | رؤوس HTTP (فقط تلك المدرجة في `forwardedRequestHeaders`) | انظر القسم أدناه |
|
||||
| `queryStringParameters` | `Record\<string, string \| undefined>` | معلمات سلسلة الاستعلام (تُضمّ القيم المتعددة باستخدام فواصل) | `/users?ids=1&ids=2&ids=3&name=Alice` -> `{ ids: '1,2,3', name: 'Alice' }` |
|
||||
| `pathParameters` | `Record\<string, string \| undefined>` | معلمات المسار المستخرجة من نمط المسار | `/users/:id`, `/users/123` -> `{ id: '123' }` |
|
||||
| `body` | `object \| null` | جسم الطلب المُحلَّل (JSON) | `{ id: 1 }` -> `{ id: 1 }` |
|
||||
| `isBase64Encoded` | `boolean` | ما إذا كان جسم الطلب مُرمَّزًا بترميز base64 | |
|
||||
| `requestContext.http.method` | `string` | طريقة HTTP (GET, POST, PUT, PATCH, DELETE) | |
|
||||
| `requestContext.http.path` | `string` | المسار الخام للطلب | |
|
||||
| الخاصية | النوع | الوصف | مثال |
|
||||
| ---------------------------- | ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
||||
| `headers` | `Record\<string, string \| undefined>` | رؤوس HTTP (فقط تلك المدرجة في `forwardedRequestHeaders`) | انظر القسم أدناه |
|
||||
| `queryStringParameters` | `Record\<string, string \| undefined>` | معلمات سلسلة الاستعلام (تُضمّ القيم المتعددة باستخدام فواصل) | `/users?ids=1&ids=2&ids=3&name=Alice` -> `{ ids: '1,2,3', name: 'Alice' }` |
|
||||
| `pathParameters` | `Record\<string, string \| undefined>` | معلمات المسار المستخرجة من نمط المسار | `/users/:id`, `/users/123` -> `{ id: '123' }` |
|
||||
| `body` | `object \| null` | جسم الطلب المُحلَّل (JSON) | `{ id: 1 }` -> `{ id: 1 }` |
|
||||
| `rawBody` | `string \| undefined` | Original UTF-8 request body, before JSON parsing. Useful for verifying HMAC-style webhook signatures (e.g. GitHub's `X-Hub-Signature-256`, Stripe). `undefined` when the runtime did not preserve it. | |
|
||||
| `isBase64Encoded` | `boolean` | ما إذا كان جسم الطلب مُرمَّزًا بترميز base64 | |
|
||||
| `requestContext.http.method` | `string` | طريقة HTTP (GET, POST, PUT, PATCH, DELETE) | |
|
||||
| `requestContext.http.path` | `string` | المسار الخام للطلب | |
|
||||
|
||||
|
||||
#### forwardedRequestHeaders
|
||||
|
||||
@@ -19,7 +19,7 @@ description: تعرّف على خطط تسعير Twenty وكيفية التبد
|
||||
* دعم قياسي
|
||||
|
||||
<Note>
|
||||
الميزات المتميزة (SSO وأذونات على مستوى الصف) غير مشمولة في خطة Pro.
|
||||
Premium features (SSO, row-level permissions and AI usage data) are not included in the Pro plan.
|
||||
</Note>
|
||||
|
||||
### المؤسسة (سحابي)
|
||||
@@ -27,7 +27,7 @@ description: تعرّف على خطط تسعير Twenty وكيفية التبد
|
||||
للفرق الأكبر ذات الاحتياجات المتقدّمة:
|
||||
|
||||
* كل ما في Pro
|
||||
* **ميزات متميزة**: تكامل SSO وأذونات على مستوى الصف
|
||||
* **Premium features**: SSO integration, row-level permissions and AI usage data
|
||||
* دعم متميز
|
||||
|
||||
## خطط الاستضافة الذاتية
|
||||
@@ -45,7 +45,7 @@ description: تعرّف على خطط تسعير Twenty وكيفية التبد
|
||||
للفرق التي تحتاج إلى ميزات متميزة أثناء الاستضافة الذاتية:
|
||||
|
||||
* جميع ميزات Pro
|
||||
* **ميزات متميزة**: تكامل SSO وأذونات على مستوى الصف
|
||||
* **Premium features**: SSO integration, row-level permissions and AI usage data
|
||||
* دعم فريق Twenty
|
||||
* لا يُشترط نشر الشيفرة المخصّصة كمفتوح المصدر قبل التوزيع
|
||||
|
||||
@@ -55,6 +55,7 @@ description: تعرّف على خطط تسعير Twenty وكيفية التبد
|
||||
|
||||
* **تكامل SSO**: تسجيل دخول أحادي مع موفّر الهوية لديك
|
||||
* **أذونات على مستوى الصف**: تحكّم دقيق في الوصول على مستوى السجل
|
||||
* **AI usage data**: Track AI consumption across the workspace
|
||||
|
||||
## التبديل بين الخطط
|
||||
|
||||
@@ -77,3 +78,15 @@ description: تعرّف على خطط تسعير Twenty وكيفية التبد
|
||||
### التبديل إلى الفوترة الشهرية
|
||||
|
||||
تواصل مع الدعم للعودة إلى الفوترة الشهرية.
|
||||
|
||||
## Obtain an Enterprise Key for Organization (Self-Hosted)
|
||||
|
||||
To use the Organization (Self-Hosted) plan, you need to obtain an Enterprise key:
|
||||
|
||||
1. Go to **Settings → Admin Panel → Enterprise**
|
||||
|
||||
<img src="/images/user-guide/billing/enterprise-key.png" alt="Enterprise key" />
|
||||
|
||||
2. Click **Get Enterprise Key**
|
||||
3. When you are redirected to Stripe, enter your payment details and confirm
|
||||
4. When your Enterprise key is displayed, paste it into the Enterprise settings page and activate the Organization license
|
||||
|
||||
@@ -16,6 +16,11 @@ description: الأسئلة الشائعة حول تسعير Twenty والفوت
|
||||
لا تتوفر الميزات المتميزة إلا في خطط Organization (السحابة أو الاستضافة الذاتية):
|
||||
* **تكامل SSO**: تسجيل الدخول الأحادي مع موفر الهوية لديك
|
||||
* **أذونات على مستوى السجل**: تحكم دقيق في الوصول على مستوى السجل
|
||||
* **بيانات استخدام الذكاء الاصطناعي**: تتبع استهلاك الذكاء الاصطناعي عبر مساحة العمل
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="هل خطة Organization على السحابة وخطة Organization ذاتية الاستضافة متماثلتان؟">
|
||||
كلتاهما تقدمان الميزات المتميزة نفسها. ومع ذلك، لا يمكن استخدام اشتراك السحابة لعمليات النشر ذاتية الاستضافة. يتطلب النشر ذاتي الاستضافة مفتاح Enterprise.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="هل تقدمون مقاعد مجانية للمستخدمين العارضين فقط؟">
|
||||
|
||||
+34
-39
@@ -53,38 +53,45 @@ People ←→ Project Assignments ←→ Projects
|
||||
1. اذهب إلى **الإعدادات → نموذج البيانات**
|
||||
2. انقر **+ كائن جديد**
|
||||
3. سمِّه تسمية وصفية (مثلًا: "تعيين مشروع"، "عضو فريق"، "طلب منتج")
|
||||
4. انقر على **حفظ**
|
||||
4. فعِّل خيار "تخطي إنشاء حقل الاسم"
|
||||
|
||||
<img src="/images/user-guide/fields/new-pivot-object.png" alt="كائن ربط جديد" />
|
||||
|
||||
5. انقر على **حفظ**
|
||||
|
||||
<Tip>
|
||||
**اتفاقية التسمية**: استخدم اسمًا يصف العلاقة، مثل "تعيين مشروع" أو "عضوية الفريق". هذا يجعل نموذج البيانات أسهل في الفهم.
|
||||
</Tip>
|
||||
|
||||
## الخطوة 2: إنشاء علاقات من كائن الربط
|
||||
## الخطوة 2: إنشاء علاقات بين الكائنات وكائن الربط
|
||||
|
||||
أضِف حقول علاقة من كائن الربط إلى كلا الكائنين اللذين تريد ربطهما.
|
||||
أضف حقول العلاقة من كلٍ من الكائنين لديك إلى كائن الربط.
|
||||
|
||||
### العلاقة الأولى (كائن الربط → الكائن A)
|
||||
### العلاقة الأولى (الكائن A → كائن الربط)
|
||||
|
||||
1. حدِّد كائن الربط في **الإعدادات → نموذج البيانات**
|
||||
2. انقر **+ إضافة حقل**
|
||||
3. اختر **العلاقة** كنوع الحقل
|
||||
4. اختر الكائن الأول (مثلًا، "الأشخاص")
|
||||
5. عيِّن نوع العلاقة إلى **متعدد-إلى-واحد** (يمكن لعديد من التعيينات الارتباط بشخص واحد)
|
||||
6. قم بتسمية الحقول:
|
||||
* الحقل على كائن الربط: مثلًا، "شخص"
|
||||
* الحقل على الأشخاص: مثلًا، "تعيينات المشروع"
|
||||
7. انقر على **حفظ**
|
||||
|
||||
### العلاقة الثانية (كائن الربط → الكائن B)
|
||||
|
||||
1. وأنت ما زلت في كائن الربط، انقر **+ إضافة حقل**
|
||||
2. اختر **العلاقة** كنوع الحقل
|
||||
3. اختر الكائن الثاني (مثلًا، "المشاريع")
|
||||
4. عيِّن نوع العلاقة إلى **متعدد-إلى-واحد**
|
||||
1. حدِّد الكائن الأول لديك في **الإعدادات → نموذج البيانات**
|
||||
2. انقر **+ إضافة علاقة**
|
||||
3. اختر كائن الربط (مثلًا، "تعيينات المشروع")
|
||||
4. عيِّن نوع العلاقة إلى **واحد-إلى-متعدد** (يمكن لشخص واحد الارتباط بالعديد من التعيينات)
|
||||
5. قم بتسمية الحقول:
|
||||
* الحقل على الأشخاص: مثلًا، "تعيينات المشروع"
|
||||
* الحقل على كائن الربط: مثلًا، "شخص"
|
||||
6. انقر على **حفظ**
|
||||
|
||||
### العلاقة الثانية (الكائن B → كائن الربط)
|
||||
|
||||
1. حدِّد الكائن الثاني لديك في **الإعدادات → نموذج البيانات**
|
||||
2. انقر **+ إضافة علاقة**
|
||||
3. اختر كائن الربط (مثلًا، "تعيينات المشروع")
|
||||
4. عيِّن نوع العلاقة إلى **واحد-إلى-متعدد** (يمكن لمشروع واحد الارتباط بالعديد من التعيينات)
|
||||
5. فعّل **"هذه علاقة بكائن ربط"**
|
||||
|
||||
<img src="/images/user-guide/fields/junction-relation-toggle.png" style={{width:'100%'}} />
|
||||
|
||||
6. قم بتسمية الحقول:
|
||||
* الحقل على كائن الربط: مثلًا، "مشروع"
|
||||
* الحقل على المشاريع: مثلًا، "أعضاء الفريق"
|
||||
6. انقر على **حفظ**
|
||||
7. انقر على **حفظ**
|
||||
|
||||
## الخطوة 3: ضبط عرض علاقة الربط
|
||||
|
||||
@@ -98,18 +105,6 @@ People ←→ Project Assignments ←→ Projects
|
||||
6. حدِّد **العلاقة الهدف** (مثلًا، "مشروع" — الحقل على كائن الربط الذي يشير إلى الجانب الآخر)
|
||||
7. انقر على **حفظ**
|
||||
|
||||
{/* TODO: Add image
|
||||
<img src="/images/user-guide/fields/junction-relation-toggle.png" style={{width:'100%'}}/>
|
||||
*/}
|
||||
|
||||
كرِّر على الكائن الآخر:
|
||||
|
||||
1. اختر "المشاريع" في نموذج البيانات
|
||||
2. حرِّر حقل العلاقة "أعضاء الفريق"
|
||||
3. فعّل مفتاح الربط
|
||||
4. حدِّد "شخص" كالعلاقة الهدف
|
||||
5. حفظ
|
||||
|
||||
## النتيجة
|
||||
|
||||
بعد التكوين:
|
||||
@@ -130,15 +125,15 @@ People ←→ Project Assignments ←→ Projects
|
||||
|
||||
### إضافة علاقات
|
||||
|
||||
1. **تعيين مشروع → الأشخاص**
|
||||
* النوع: متعدد-إلى-واحد
|
||||
* الحقل على التعيين: "شخص"
|
||||
1. **الأشخاص → تعيين مشروع**
|
||||
* النوع: واحد-إلى-متعدد
|
||||
* الحقل على الأشخاص: "تعيينات المشروع"
|
||||
* الحقل على التعيين: "شخص"
|
||||
|
||||
2. **تعيين مشروع → المشاريع**
|
||||
* النوع: متعدد-إلى-واحد
|
||||
* الحقل على التعيين: "مشروع"
|
||||
2. **المشاريع → تعيين مشروع**
|
||||
* النوع: واحد-إلى-متعدد
|
||||
* الحقل على المشاريع: "أعضاء الفريق"
|
||||
* الحقل على التعيين: "مشروع"
|
||||
|
||||
### ضبط عرض علاقة الربط
|
||||
|
||||
|
||||
@@ -30,3 +30,9 @@ description: خصص الشريط الجانبي الأيسر ليتوافق مع
|
||||
## قائمة الأوامر
|
||||
|
||||
اضغط `Cmd+K` (أو `Ctrl+K`) لفتح قائمة الأوامر — شريط بحث للوصول السريع يتيح لك الانتقال إلى أي سجل أو طريقة عرض أو إجراء دون التنقل عبر الشريط الجانبي.
|
||||
|
||||
## تخصيص الشريط الجانبي
|
||||
|
||||
لتخصيص الشريط الجانبي، مرّر المؤشر فوق قسم "مساحة العمل" في الشريط الجانبي وانقر على أيقونة مفتاح الربط.
|
||||
|
||||
<img src="/images/user-guide/layout/navigation-edit-icon.png" alt="أيقونة تحرير التنقّل" />
|
||||
|
||||
@@ -3,6 +3,8 @@ title: صفحات السجل
|
||||
description: خصص تخطيط صفحات تفاصيل السجلات باستخدام علامات تبويب وأدوات.
|
||||
---
|
||||
|
||||
## نظرة عامة
|
||||
|
||||
عند فتح سجل في Twenty، تتكون صفحة التفاصيل من **علامات تبويب** و**أدوات**. كلاهما قابل للتخصيص بالكامل حسب نوع الكائن.
|
||||
|
||||
## علامات التبويب
|
||||
@@ -38,12 +40,20 @@ description: خصص تخطيط صفحات تفاصيل السجلات باستخ
|
||||
|
||||
1. افتح أي سجل
|
||||
2. اضغط على `Cmd+K` وابحث عن "تحرير تخطيط صفحة السجل"
|
||||
|
||||
أو
|
||||
|
||||
1. انتقل إلى الإعدادات > نموذج البيانات > الكائن الذي تختاره > التخطيط
|
||||
|
||||
2. انقر على الزر "تخصيص صفحة السجل" لذلك الكائن
|
||||
|
||||
3. أنت الآن في وضع التخصيص:
|
||||
* **أضف أدوات** من منتقي الأدوات
|
||||
* **اسحب الأدوات** لإعادة وضعها على الشبكة
|
||||
* **غيّر حجم الأدوات** بسحب حوافها
|
||||
* **اضبط الحقول** المعروضة داخل كل أداة
|
||||
* **أدِر علامات التبويب** — أضف، أزل، أعد التسمية، وأعد الترتيب
|
||||
|
||||
4. احفظ تغييراتك — سيتم تطبيقها على جميع السجلات لذلك النوع من الكائنات
|
||||
|
||||
## ظهور الحقول
|
||||
|
||||
@@ -95,15 +95,16 @@ const handler = async (event: RoutePayload) => {
|
||||
|
||||
Typ `RoutePayload` má následující strukturu:
|
||||
|
||||
| Vlastnost | Typ | Popis | Příklad |
|
||||
| ---------------------------- | ------------------------------------------------------- | ----------------------------------------------------------- | -------------------------------------------------------------------------- |
|
||||
| `headers` | `Record\<string, string \| undefined>` | Záhlaví HTTP (pouze ta uvedená v `forwardedRequestHeaders`) | viz sekci níže |
|
||||
| `queryStringParameters` | `Record\<string, string \| undefined>` | Parametry query stringu (více hodnot spojených čárkami) | `/users?ids=1&ids=2&ids=3&name=Alice` -> `{ ids: '1,2,3', name: 'Alice' }` |
|
||||
| `pathParameters` | `Record\<string, string \| undefined>` | Parametry cesty extrahované ze vzoru trasy | `/users/:id`, `/users/123` -> `{ id: '123' }` |
|
||||
| `body` | `object \| null` | Parsované tělo požadavku (JSON) | `{ id: 1 }` -> `{ id: 1 }` |
|
||||
| `isBase64Encoded` | `boolean` | Zda je tělo kódováno base64 | |
|
||||
| `requestContext.http.method` | `string` | Metoda HTTP (GET, POST, PUT, PATCH, DELETE) | |
|
||||
| `requestContext.http.path` | `string` | Nezpracovaná cesta požadavku | |
|
||||
| Vlastnost | Typ | Popis | Příklad |
|
||||
| ---------------------------- | ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
||||
| `headers` | `Record\<string, string \| undefined>` | Záhlaví HTTP (pouze ta uvedená v `forwardedRequestHeaders`) | viz sekci níže |
|
||||
| `queryStringParameters` | `Record\<string, string \| undefined>` | Parametry query stringu (více hodnot spojených čárkami) | `/users?ids=1&ids=2&ids=3&name=Alice` -> `{ ids: '1,2,3', name: 'Alice' }` |
|
||||
| `pathParameters` | `Record\<string, string \| undefined>` | Parametry cesty extrahované ze vzoru trasy | `/users/:id`, `/users/123` -> `{ id: '123' }` |
|
||||
| `body` | `object \| null` | Parsované tělo požadavku (JSON) | `{ id: 1 }` -> `{ id: 1 }` |
|
||||
| `rawBody` | `string \| undefined` | Original UTF-8 request body, before JSON parsing. Useful for verifying HMAC-style webhook signatures (e.g. GitHub's `X-Hub-Signature-256`, Stripe). `undefined` when the runtime did not preserve it. | |
|
||||
| `isBase64Encoded` | `boolean` | Zda je tělo kódováno base64 | |
|
||||
| `requestContext.http.method` | `string` | Metoda HTTP (GET, POST, PUT, PATCH, DELETE) | |
|
||||
| `requestContext.http.path` | `string` | Nezpracovaná cesta požadavku | |
|
||||
|
||||
|
||||
#### forwardedRequestHeaders
|
||||
|
||||
@@ -19,7 +19,7 @@ Pro týmy připravené škálovat:
|
||||
* Standardní podpora
|
||||
|
||||
<Note>
|
||||
Prémiové funkce (SSO a oprávnění na úrovni řádků) nejsou součástí plánu Pro.
|
||||
Premium features (SSO, row-level permissions and AI usage data) are not included in the Pro plan.
|
||||
</Note>
|
||||
|
||||
### Organizace (Cloud)
|
||||
@@ -27,7 +27,7 @@ Prémiové funkce (SSO a oprávnění na úrovni řádků) nejsou součástí pl
|
||||
Pro větší týmy s pokročilými potřebami:
|
||||
|
||||
* Vše z plánu Pro
|
||||
* **Prémiové funkce**: integrace SSO a oprávnění na úrovni řádků
|
||||
* **Premium features**: SSO integration, row-level permissions and AI usage data
|
||||
* Prioritní podpora
|
||||
|
||||
## Plány pro self‑hosting
|
||||
@@ -45,7 +45,7 @@ Hostujte Twenty na vlastní infrastruktuře bez poplatků:
|
||||
Pro týmy, které při self‑hostingu potřebují prémiové funkce:
|
||||
|
||||
* Všechny funkce plánu Pro
|
||||
* **Prémiové funkce**: integrace SSO a oprávnění na úrovni řádků
|
||||
* **Premium features**: SSO integration, row-level permissions and AI usage data
|
||||
* Podpora týmu Twenty
|
||||
* Není vyžadováno zveřejnit vlastní kód jako open‑source před distribucí
|
||||
|
||||
@@ -55,6 +55,7 @@ Prémiové funkce jsou dostupné pouze v plánech Organizace (Cloud nebo self‑
|
||||
|
||||
* **Integrace SSO**: jednotné přihlášení s vaším poskytovatelem identity
|
||||
* **Oprávnění na úrovni řádků**: jemně odstupňované řízení přístupu na úrovni záznamu
|
||||
* **AI usage data**: Track AI consumption across the workspace
|
||||
|
||||
## Přepínání plánů
|
||||
|
||||
@@ -77,3 +78,15 @@ Chcete-li přejít na nižší plán, kontaktujte podporu.
|
||||
### Přepnout na měsíční fakturaci
|
||||
|
||||
Chcete-li přepnout zpět na měsíční fakturaci, kontaktujte podporu.
|
||||
|
||||
## Obtain an Enterprise Key for Organization (Self-Hosted)
|
||||
|
||||
To use the Organization (Self-Hosted) plan, you need to obtain an Enterprise key:
|
||||
|
||||
1. Go to **Settings → Admin Panel → Enterprise**
|
||||
|
||||
<img src="/images/user-guide/billing/enterprise-key.png" alt="Enterprise key" />
|
||||
|
||||
2. Click **Get Enterprise Key**
|
||||
3. When you are redirected to Stripe, enter your payment details and confirm
|
||||
4. When your Enterprise key is displayed, paste it into the Enterprise settings page and activate the Organization license
|
||||
|
||||
@@ -16,6 +16,11 @@ Pokud chcete hostovat sami a potřebujete prémiové funkce (SSO a oprávnění
|
||||
Prémiové funkce jsou dostupné pouze v plánech Organization (Cloud nebo Self-Hosted):
|
||||
* **Integrace SSO**: Jednotné přihlášení s vaším poskytovatelem identity
|
||||
* **Oprávnění na úrovni řádků**: Jemně granulované řízení přístupu na úrovni záznamu
|
||||
* **AI usage data**: Track AI consumption across the workspace
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Is Organization plan on cloud and Organization plan on self-hosted the same?">
|
||||
They offer the same premium features. However, a cloud subscription cannot be used for self-hosted deployments. Self-hosted requires an Enterprise key.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Nabízíte volná místa pro uživatele pouze s přístupem ke čtení?">
|
||||
|
||||
+34
-39
@@ -53,38 +53,45 @@ Nejprve vytvořte mezilehlý objekt, který bude uchovávat propojení.
|
||||
1. Přejděte do **Nastavení → Datový model**
|
||||
2. Klikněte na **+ New object**
|
||||
3. Pojmenujte jej výstižně (např. "Project Assignment", "Team Member", "Product Order")
|
||||
4. Klikněte na **Uložit**
|
||||
4. Přepněte "Přeskočit vytvoření pole Název" na zapnuto
|
||||
|
||||
<img src="/images/user-guide/fields/new-pivot-object.png" alt="Nový spojovací objekt" />
|
||||
|
||||
5. Klikněte na **Uložit**
|
||||
|
||||
<Tip>
|
||||
**Konvence pojmenování**: Použijte název, který popisuje vztah, například "Project Assignment" nebo "Team Membership". Tím bude datový model srozumitelnější.
|
||||
</Tip>
|
||||
|
||||
## Krok 2: Vytvořte vztahy ze spojovacího objektu
|
||||
## Krok 2: Vytvořte vztahy mezi objekty a spojovacím objektem
|
||||
|
||||
Přidejte relační pole ze spojovacího objektu do obou objektů, které chcete propojit.
|
||||
Přidejte vztahová pole z obou objektů do spojovacího objektu.
|
||||
|
||||
### První vztah (Junction → Objekt A)
|
||||
### První vztah (Objekt A → Junction)
|
||||
|
||||
1. Vyberte svůj spojovací objekt v **Settings → Data Model**
|
||||
2. Klikněte na **+ Add Field**
|
||||
3. Zvolte **Relation** jako typ pole
|
||||
4. Vyberte první objekt (např. "People")
|
||||
5. Nastavte typ vztahu na **Many-to-One** (mnoho přiřazení může odkazovat na jednu osobu)
|
||||
6. Pojmenujte pole:
|
||||
* Pole na spojovacím objektu: např. "Person"
|
||||
* Pole na People: např. "Project Assignments"
|
||||
7. Klikněte na **Uložit**
|
||||
|
||||
### Druhý vztah (Junction → Objekt B)
|
||||
|
||||
1. Stále na spojovacím objektu klikněte na **+ Add Field**
|
||||
2. Zvolte **Relation** jako typ pole
|
||||
3. Vyberte druhý objekt (např. "Projects")
|
||||
4. Nastavte typ vztahu na **Many-to-One**
|
||||
1. Vyberte svůj první objekt v **Settings → Data Model**
|
||||
2. Klikněte na **+ Přidat vztah**
|
||||
3. Vyberte spojovací objekt (např. "Project Assignments")
|
||||
4. Nastavte typ vztahu na **One-To-Many** (jedna osoba může být propojena s mnoha přiřazeními)
|
||||
5. Pojmenujte pole:
|
||||
* Pole na People: např. "Project Assignments"
|
||||
* Pole na spojovacím objektu: např. "Person"
|
||||
6. Klikněte na **Uložit**
|
||||
|
||||
### Druhý vztah (Objekt B → Junction)
|
||||
|
||||
1. Vyberte svůj druhý objekt v **Settings → Data Model**
|
||||
2. Klikněte na **+ Přidat vztah**
|
||||
3. Vyberte spojovací objekt (např. "Project Assignments")
|
||||
4. Nastavte typ vztahu na **One-To-Many** (jeden projekt může být propojen s mnoha přiřazeními)
|
||||
5. Povolte **"This is a relation to a Junction Object"**
|
||||
|
||||
<img src="/images/user-guide/fields/junction-relation-toggle.png" style={{width:'100%'}} />
|
||||
|
||||
6. Pojmenujte pole:
|
||||
* Pole na spojovacím objektu: např. "Project"
|
||||
* Pole na Projects: např. "Team Members"
|
||||
6. Klikněte na **Uložit**
|
||||
7. Klikněte na **Uložit**
|
||||
|
||||
## Krok 3: Nakonfigurujte zobrazení vztahu přes spojovací objekt
|
||||
|
||||
@@ -98,18 +105,6 @@ Nyní nakonfigurujte zdrojové objekty tak, aby zobrazovaly propojené záznamy
|
||||
6. Vyberte **Target relation** (např. "Project" — pole na spojovacím objektu, které ukazuje na druhou stranu)
|
||||
7. Klikněte na **Uložit**
|
||||
|
||||
{/* TODO: Add image
|
||||
<img src="/images/user-guide/fields/junction-relation-toggle.png" style={{width:'100%'}}/>
|
||||
*/}
|
||||
|
||||
Opakujte pro druhý objekt:
|
||||
|
||||
1. Vyberte "Projects" v Data Model
|
||||
2. Upravte relační pole "Team Members"
|
||||
3. Povolte přepínač pro vztah přes spojovací objekt
|
||||
4. Vyberte "Person" jako cílový vztah
|
||||
5. Uložit
|
||||
|
||||
## Výsledek
|
||||
|
||||
Po konfiguraci:
|
||||
@@ -130,15 +125,15 @@ Zde je kompletní postup:
|
||||
|
||||
### Přidejte vztahy
|
||||
|
||||
1. **Project Assignment → People**
|
||||
* Typ: Many-to-One
|
||||
* Pole na Assignment: "Person"
|
||||
1. **People → Project Assignment**
|
||||
* Typ: One-to-Many
|
||||
* Pole na People: "Project Assignments"
|
||||
* Pole na Assignment: "Person"
|
||||
|
||||
2. **Project Assignment → Projects**
|
||||
* Typ: Many-to-One
|
||||
* Pole na Assignment: "Project"
|
||||
2. **Projects → Project Assignment**
|
||||
* Typ: One-to-Many
|
||||
* Pole na Projects: "Team Members"
|
||||
* Pole na Assignment: "Project"
|
||||
|
||||
### Nakonfigurujte zobrazení spojovacího objektu
|
||||
|
||||
|
||||
@@ -30,3 +30,9 @@ Přidejte odkazy na externí nástroje přímo do postranního panelu. Užitečn
|
||||
## Nabídka příkazů
|
||||
|
||||
Stiskněte `Cmd+K` (nebo `Ctrl+K`) pro otevření nabídky příkazů — rychlá vyhledávací lišta pro přechod na libovolný záznam, zobrazení nebo akci bez procházení postranního panelu.
|
||||
|
||||
## Přizpůsobení postranního panelu
|
||||
|
||||
Chcete-li přizpůsobit postranní panel, najeďte myší na sekci "Pracovní prostor" v postranním panelu a klikněte na ikonu klíče.
|
||||
|
||||
<img src="/images/user-guide/layout/navigation-edit-icon.png" alt="Ikona pro úpravu navigace" />
|
||||
|
||||
@@ -3,6 +3,8 @@ title: Stránky záznamů
|
||||
description: Přizpůsobte rozvržení jednotlivých stránek detailu záznamu pomocí karet a widgetů.
|
||||
---
|
||||
|
||||
## Přehled
|
||||
|
||||
Když v Twenty otevřete záznam, stránka detailu se skládá z **karet** a **widgetů**. Obojí lze pro každý typ objektu plně přizpůsobit.
|
||||
|
||||
## Karty
|
||||
@@ -38,12 +40,20 @@ Widgety jsou stavební prvky uvnitř každé karty. Mezi dostupné typy widgetů
|
||||
|
||||
1. Otevřete libovolný záznam
|
||||
2. Stiskněte `Cmd+K` a vyhledejte "Upravit rozložení stránky záznamu"
|
||||
|
||||
nebo
|
||||
|
||||
1. Přejděte do Nastavení > Datový model > objekt dle vašeho výběru > Rozložení
|
||||
|
||||
2. Klikněte na tlačítko "Přizpůsobit stránku záznamu" pro daný objekt
|
||||
|
||||
3. Nyní jste v režimu přizpůsobení:
|
||||
* **Přidávejte widgety** z výběru widgetů
|
||||
* **Přetahujte widgety** pro jejich přemístění v mřížce
|
||||
* **Změňte velikost widgetů** tažením jejich okrajů
|
||||
* **Nakonfigurujte pole** zobrazovaná v jednotlivých widgetech
|
||||
* **Spravujte karty** — přidávejte, odebírejte, přejmenovávejte, měňte pořadí
|
||||
|
||||
4. Uložte změny — budou platit pro všechny záznamy daného typu objektu
|
||||
|
||||
## Viditelnost polí
|
||||
|
||||
@@ -94,15 +94,16 @@ const handler = async (event: RoutePayload) => {
|
||||
|
||||
Der Typ `RoutePayload` hat die folgende Struktur:
|
||||
|
||||
| Eigenschaft | Typ | Beschreibung | Beispiel |
|
||||
| ---------------------------- | ------------------------------------------------------- | ---------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
||||
| `headers` | `Record\<string, string \| undefined>` | HTTP-Header (nur die in `forwardedRequestHeaders` aufgelisteten) | siehe Abschnitt unten |
|
||||
| `queryStringParameters` | `Record\<string, string \| undefined>` | Query-String-Parameter (mehrere Werte mit Kommas verbunden) | `/users?ids=1&ids=2&ids=3&name=Alice` -> `{ ids: '1,2,3', name: 'Alice' }` |
|
||||
| `pathParameters` | `Record\<string, string \| undefined>` | Aus dem Routenmuster extrahierte Pfadparameter | `/users/:id`, `/users/123` -> `{ id: '123' }` |
|
||||
| `body` | `object \| null` | Geparster Request-Body (JSON) | `{ id: 1 }` -> `{ id: 1 }` |
|
||||
| `isBase64Encoded` | `boolean` | Gibt an, ob der Body Base64-codiert ist | |
|
||||
| `requestContext.http.method` | `Zeichenkette` | HTTP-Methode (GET, POST, PUT, PATCH, DELETE) | |
|
||||
| `requestContext.http.path` | `Zeichenkette` | Rohpfad der Anfrage | |
|
||||
| Eigenschaft | Typ | Beschreibung | Beispiel |
|
||||
| ---------------------------- | ------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
||||
| `headers` | `Record\<string, string \| undefined>` | HTTP-Header (nur die in `forwardedRequestHeaders` aufgelisteten) | siehe Abschnitt unten |
|
||||
| `queryStringParameters` | `Record\<string, string \| undefined>` | Query-String-Parameter (mehrere Werte mit Kommas verbunden) | `/users?ids=1&ids=2&ids=3&name=Alice` -> `{ ids: '1,2,3', name: 'Alice' }` |
|
||||
| `pathParameters` | `Record\<string, string \| undefined>` | Aus dem Routenmuster extrahierte Pfadparameter | `/users/:id`, `/users/123` -> `{ id: '123' }` |
|
||||
| `body` | `object \| null` | Geparster Request-Body (JSON) | `{ id: 1 }` -> `{ id: 1 }` |
|
||||
| `rawBody` | `string \| undefined` | Ursprünglicher UTF-8-Request-Body vor dem JSON-Parsing. Nützlich zur Verifizierung von Webhook-Signaturen im HMAC-Stil (z. B. GitHubs `X-Hub-Signature-256`, Stripe). `undefined`, wenn die Laufzeitumgebung es nicht beibehalten hat. | |
|
||||
| `isBase64Encoded` | `boolean` | Gibt an, ob der Body Base64-codiert ist | |
|
||||
| `requestContext.http.method` | `Zeichenkette` | HTTP-Methode (GET, POST, PUT, PATCH, DELETE) | |
|
||||
| `requestContext.http.path` | `Zeichenkette` | Rohpfad der Anfrage | |
|
||||
|
||||
|
||||
#### forwardedRequestHeaders
|
||||
|
||||
@@ -19,7 +19,7 @@ Für Teams, die bereit sind zu skalieren:
|
||||
* Standard-Support
|
||||
|
||||
<Note>
|
||||
Premiumfunktionen (SSO und Berechtigungen auf Zeilenebene) sind im Pro-Plan nicht enthalten.
|
||||
Premiumfunktionen (SSO, Berechtigungen auf Zeilenebene und KI-Nutzungsdaten) sind im Pro-Tarif nicht enthalten.
|
||||
</Note>
|
||||
|
||||
### Organisation (Cloud)
|
||||
@@ -27,7 +27,7 @@ Premiumfunktionen (SSO und Berechtigungen auf Zeilenebene) sind im Pro-Plan nich
|
||||
Für größere Teams mit erweiterten Anforderungen:
|
||||
|
||||
* Alles aus Pro
|
||||
* **Premiumfunktionen**: SSO-Integration und Berechtigungen auf Zeilenebene
|
||||
* **Premiumfunktionen**: SSO-Integration, Berechtigungen auf Zeilenebene und KI-Nutzungsdaten
|
||||
* Vorrangiger Support
|
||||
|
||||
## Selbstgehostete Pläne
|
||||
@@ -45,7 +45,7 @@ Hosten Sie Twenty auf Ihrer eigenen Infrastruktur kostenlos:
|
||||
Für Teams, die beim Selbsthosting Premiumfunktionen benötigen:
|
||||
|
||||
* Alle Pro-Funktionen
|
||||
* **Premiumfunktionen**: SSO-Integration und Berechtigungen auf Zeilenebene
|
||||
* **Premiumfunktionen**: SSO-Integration, Berechtigungen auf Zeilenebene und KI-Nutzungsdaten
|
||||
* Support durch das Twenty-Team
|
||||
* Keine Verpflichtung, benutzerdefinierten Code vor der Weitergabe als Open Source zu veröffentlichen
|
||||
|
||||
@@ -55,6 +55,7 @@ Premiumfunktionen sind nur in den Organisation-Plänen (Cloud oder Selbstgehoste
|
||||
|
||||
* **SSO-Integration**: Single Sign-On mit Ihrem Identitätsanbieter
|
||||
* **Berechtigungen auf Zeilenebene**: Feingranulare Zugriffskontrolle auf Datensatzebene
|
||||
* **KI-Nutzungsdaten**: Verfolgen Sie den KI-Verbrauch in Ihrem Arbeitsbereich
|
||||
|
||||
## Pläne wechseln
|
||||
|
||||
@@ -77,3 +78,15 @@ Wenden Sie sich an den Support, um Ihren Plan herabzustufen.
|
||||
### Zur monatlichen Abrechnung wechseln
|
||||
|
||||
Wenden Sie sich an den Support, um wieder zur monatlichen Abrechnung zu wechseln.
|
||||
|
||||
## Enterprise-Schlüssel für Organization (Self-Hosted) abrufen
|
||||
|
||||
Um den Tarif Organization (Self-Hosted) zu verwenden, müssen Sie einen Enterprise-Schlüssel abrufen:
|
||||
|
||||
1. Gehen Sie zu **Einstellungen → Admin-Panel → Enterprise**
|
||||
|
||||
<img src="/images/user-guide/billing/enterprise-key.png" alt="Enterprise-Schlüssel" />
|
||||
|
||||
2. Klicken Sie auf **Enterprise-Schlüssel abrufen**
|
||||
3. Wenn Sie zu Stripe weitergeleitet werden, geben Sie Ihre Zahlungsdaten ein und bestätigen Sie
|
||||
4. Wenn Ihr Enterprise-Schlüssel angezeigt wird, fügen Sie ihn auf der Seite Enterprise-Einstellungen ein und aktivieren Sie die Organization-Lizenz
|
||||
|
||||
@@ -16,6 +16,11 @@ Wenn Sie selbst hosten möchten und die Premium-Funktionen (SSO und Berechtigung
|
||||
Premium-Funktionen sind nur in den Organization-Tarifen (Cloud oder Self-Hosted) verfügbar:
|
||||
* **SSO-Integration**: Single Sign-On mit Ihrem Identitätsanbieter
|
||||
* **Berechtigungen auf Zeilenebene**: feingranulare Zugriffskontrolle auf Datensatzebene
|
||||
* **KI-Nutzungsdaten**: Verfolgen Sie den KI-Verbrauch in Ihrem Arbeitsbereich
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Sind der Organisationsplan in der Cloud und der Organisationsplan bei selbst gehosteter Bereitstellung gleich?">
|
||||
Sie bieten dieselben Premium-Funktionen. Ein Cloud-Abonnement kann jedoch nicht für selbst gehostete Bereitstellungen verwendet werden. Für selbst gehostete Bereitstellungen ist ein Enterprise-Schlüssel erforderlich.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Bieten Sie kostenlose Plätze für Nur-Ansicht-Benutzer an?">
|
||||
|
||||
+34
-39
@@ -53,38 +53,45 @@ Erstellen Sie zunächst das Zwischenobjekt, das die Verknüpfungen speichert.
|
||||
1. Gehen Sie zu **Einstellungen → Datenmodell**
|
||||
2. Klicken Sie auf **+ Neues Objekt**
|
||||
3. Benennen Sie es aussagekräftig (z. B. "Projektzuweisung", "Teammitglied", "Produktbestellung")
|
||||
4. Klicken Sie auf **Speichern**
|
||||
4. Schalten Sie "Erstellen eines Namensfelds überspringen" ein
|
||||
|
||||
<img src="/images/user-guide/fields/new-pivot-object.png" alt="Neues Verknüpfungsobjekt" />
|
||||
|
||||
5. Klicken Sie auf **Speichern**
|
||||
|
||||
<Tip>
|
||||
**Namenskonvention**: Verwenden Sie einen Namen, der die Beziehung beschreibt, z. B. "Projektzuweisung" oder "Teammitgliedschaft". Das macht das Datenmodell leichter verständlich.
|
||||
</Tip>
|
||||
|
||||
## Schritt 2: Beziehungen vom Verknüpfungsobjekt erstellen
|
||||
## Schritt 2: Beziehungen zwischen Objekten und dem Verknüpfungsobjekt erstellen
|
||||
|
||||
Fügen Sie vom Verknüpfungsobjekt aus Beziehungsfelder zu beiden Objekten hinzu, die Sie verbinden möchten.
|
||||
Fügen Sie für jedes Ihrer beiden Objekte Beziehungsfelder zum Verknüpfungsobjekt hinzu.
|
||||
|
||||
### Erste Beziehung (Verknüpfung → Objekt A)
|
||||
### Erste Beziehung (Objekt A → Verknüpfung)
|
||||
|
||||
1. Wählen Sie Ihr Verknüpfungsobjekt unter **Einstellungen → Datenmodell** aus
|
||||
2. Klicken Sie auf **+ Feld hinzufügen**
|
||||
3. Wählen Sie **Relation** als Feldtyp
|
||||
4. Wählen Sie das erste Objekt aus (z. B. "Personen")
|
||||
5. Legen Sie den Beziehungstyp auf **Viele-zu-Eins** fest (viele Zuweisungen können mit einer Person verknüpft werden)
|
||||
6. Benennen Sie die Felder:
|
||||
* Feld auf der Verknüpfung: z. B. "Person"
|
||||
* Feld bei Personen: z. B. "Projektzuweisungen"
|
||||
7. Klicken Sie auf **Speichern**
|
||||
|
||||
### Zweite Beziehung (Verknüpfung → Objekt B)
|
||||
|
||||
1. Bleiben Sie im Verknüpfungsobjekt und klicken Sie auf **+ Feld hinzufügen**
|
||||
2. Wählen Sie **Relation** als Feldtyp
|
||||
3. Wählen Sie das zweite Objekt aus (z. B. "Projekte")
|
||||
4. Legen Sie den Beziehungstyp auf **Viele-zu-Eins** fest
|
||||
1. Wählen Sie Ihr erstes Objekt unter **Einstellungen → Datenmodell** aus
|
||||
2. Klicken Sie auf **+ Beziehung hinzufügen**
|
||||
3. Wählen Sie das Verknüpfungsobjekt aus (z. B. "Projektzuweisungen")
|
||||
4. Legen Sie den Beziehungstyp auf **Eins-zu-Viele** fest (eine Person kann mit vielen Zuweisungen verknüpft werden)
|
||||
5. Benennen Sie die Felder:
|
||||
* Feld bei Personen: z. B. "Projektzuweisungen"
|
||||
* Feld auf der Verknüpfung: z. B. "Person"
|
||||
6. Klicken Sie auf **Speichern**
|
||||
|
||||
### Zweite Beziehung (Objekt B → Verknüpfung)
|
||||
|
||||
1. Wählen Sie Ihr zweites Objekt unter **Einstellungen → Datenmodell** aus
|
||||
2. Klicken Sie auf **+ Beziehung hinzufügen**
|
||||
3. Wählen Sie das Verknüpfungsobjekt aus (z. B. "Projektzuweisungen")
|
||||
4. Legen Sie den Beziehungstyp auf **Eins-zu-Viele** fest (ein Projekt kann mit vielen Zuweisungen verknüpft werden)
|
||||
5. Aktivieren Sie **"Dies ist eine Beziehung zu einem Verknüpfungsobjekt"**
|
||||
|
||||
<img src="/images/user-guide/fields/junction-relation-toggle.png" style={{width:'100%'}} />
|
||||
|
||||
6. Benennen Sie die Felder:
|
||||
* Feld auf der Verknüpfung: z. B. "Projekt"
|
||||
* Feld bei Projekten: z. B. "Teammitglieder"
|
||||
6. Klicken Sie auf **Speichern**
|
||||
7. Klicken Sie auf **Speichern**
|
||||
|
||||
## Schritt 3: Anzeige der Verknüpfungsbeziehung konfigurieren
|
||||
|
||||
@@ -98,18 +105,6 @@ Konfigurieren Sie nun die Quellobjekte so, dass verknüpfte Datensätze direkt a
|
||||
6. Wählen Sie die **Zielbeziehung** aus (z. B. "Projekt" — das Feld an der Verknüpfung, das auf die andere Seite zeigt)
|
||||
7. Klicken Sie auf **Speichern**
|
||||
|
||||
{/* TODO: Add image
|
||||
<img src="/images/user-guide/fields/junction-relation-toggle.png" style={{width:'100%'}}/>
|
||||
*/}
|
||||
|
||||
Wiederholen Sie dies für das andere Objekt:
|
||||
|
||||
1. Wählen Sie "Projekte" im Datenmodell aus
|
||||
2. Bearbeiten Sie das Beziehungsfeld "Teammitglieder"
|
||||
3. Aktivieren Sie den Verknüpfungsschalter
|
||||
4. Wählen Sie "Person" als Zielbeziehung aus
|
||||
5. Speichern
|
||||
|
||||
## Ergebnis
|
||||
|
||||
Nach der Konfiguration:
|
||||
@@ -130,15 +125,15 @@ Hier ist eine vollständige Schritt-für-Schritt-Anleitung:
|
||||
|
||||
### Beziehungen hinzufügen
|
||||
|
||||
1. **Projektzuweisung → Personen**
|
||||
* Typ: Viele-zu-Eins
|
||||
* Feld bei Zuweisung: "Person"
|
||||
1. **Personen → Projektzuweisung**
|
||||
* Typ: Eins-zu-Viele
|
||||
* Feld bei Personen: "Projektzuweisungen"
|
||||
* Feld bei Zuweisung: "Person"
|
||||
|
||||
2. **Projektzuweisung → Projekte**
|
||||
* Typ: Viele-zu-Eins
|
||||
* Feld bei Zuweisung: "Projekt"
|
||||
2. **Projekte → Projektzuweisung**
|
||||
* Typ: Eins-zu-Viele
|
||||
* Feld bei Projekten: "Teammitglieder"
|
||||
* Feld bei Zuweisung: "Projekt"
|
||||
|
||||
### Verknüpfungsanzeige konfigurieren
|
||||
|
||||
|
||||
@@ -30,3 +30,9 @@ Fügen Sie Links zu externen Tools direkt in der Seitenleiste hinzu. Nützlich,
|
||||
## Befehlsmenü
|
||||
|
||||
Drücken Sie `Cmd+K` (oder `Ctrl+K`), um das Befehlsmenü zu öffnen — eine Suchleiste für den Schnellzugriff, mit der Sie zu jedem Datensatz, jeder Ansicht oder Aktion springen können, ohne durch die Seitenleiste zu navigieren.
|
||||
|
||||
## Anpassung der Seitenleiste
|
||||
|
||||
Um die Seitenleiste anzupassen, bewegen Sie den Mauszeiger über den Abschnitt "Arbeitsbereich" in der Seitenleiste und klicken Sie auf das Schraubenschlüssel-Symbol.
|
||||
|
||||
<img src="/images/user-guide/layout/navigation-edit-icon.png" alt="Symbol zum Bearbeiten der Navigation" />
|
||||
|
||||
@@ -3,6 +3,8 @@ title: Datensatzseiten
|
||||
description: Passen Sie das Layout einzelner Datensatz-Detailseiten mit Tabs und Widgets an.
|
||||
---
|
||||
|
||||
## Übersicht
|
||||
|
||||
Wenn Sie in Twenty einen Datensatz öffnen, besteht die Detailseite aus **Tabs** und **Widgets**. Beide lassen sich je Objekttyp vollständig anpassen.
|
||||
|
||||
## Registerkarten
|
||||
@@ -38,12 +40,20 @@ Widgets sind die Bausteine in jedem Tab. Zu den verfügbaren Widget-Typen gehör
|
||||
|
||||
1. Öffnen Sie einen beliebigen Datensatz
|
||||
2. Drücken Sie `Cmd+K` und suchen Sie nach "Layout der Datensatzseite bearbeiten"
|
||||
|
||||
oder
|
||||
|
||||
1. Gehen Sie zu Einstellungen > Datenmodell > Objekt Ihrer Wahl > Layout
|
||||
|
||||
2. Klicken Sie für dieses Objekt auf die Schaltfläche "Datensatzseite anpassen"
|
||||
|
||||
3. Sie befinden sich jetzt im Anpassungsmodus:
|
||||
* **Widgets hinzufügen** aus der Widget-Auswahl
|
||||
* **Widgets ziehen**, um sie im Raster neu zu positionieren
|
||||
* **Widgets in der Größe ändern**, indem Sie ihre Ränder ziehen
|
||||
* **Felder konfigurieren**, die in jedem Widget angezeigt werden
|
||||
* **Tabs verwalten** — hinzufügen, entfernen, umbenennen, neu anordnen
|
||||
|
||||
4. Speichern Sie Ihre Änderungen — sie gelten für alle Datensätze dieses Objekttyps
|
||||
|
||||
## Feldsichtbarkeit
|
||||
|
||||
@@ -94,15 +94,16 @@ const handler = async (event: RoutePayload) => {
|
||||
|
||||
Il tipo `RoutePayload` ha la seguente struttura:
|
||||
|
||||
| Proprietà | Tipo | Descrizione | Esempio |
|
||||
| ---------------------------- | ------------------------------------------------------- | --------------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
||||
| `headers` | `Record\<string, string \| undefined>` | Intestazioni HTTP (solo quelle elencate in `forwardedRequestHeaders`) | vedi la sezione sotto |
|
||||
| `queryStringParameters` | `Record\<string, string \| undefined>` | Parametri della query string (valori multipli uniti da virgole) | `/users?ids=1&ids=2&ids=3&name=Alice` -> `{ ids: '1,2,3', name: 'Alice' }` |
|
||||
| `pathParameters` | `Record\<string, string \| undefined>` | Parametri di percorso estratti dal pattern della route | `/users/:id`, `/users/123` -> `{ id: '123' }` |
|
||||
| `body` | `object \| null` | Corpo della richiesta analizzato (JSON) | `{ id: 1 }` -> `{ id: 1 }` |
|
||||
| `isBase64Encoded` | `boolean` | Indica se il corpo è codificato in base64 | |
|
||||
| `requestContext.http.method` | `string` | Metodo HTTP (GET, POST, PUT, PATCH, DELETE) | |
|
||||
| `requestContext.http.path` | `string` | Percorso della richiesta non elaborato | |
|
||||
| Proprietà | Tipo | Descrizione | Esempio |
|
||||
| ---------------------------- | ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
||||
| `headers` | `Record\<string, string \| undefined>` | Intestazioni HTTP (solo quelle elencate in `forwardedRequestHeaders`) | vedi la sezione sotto |
|
||||
| `queryStringParameters` | `Record\<string, string \| undefined>` | Parametri della query string (valori multipli uniti da virgole) | `/users?ids=1&ids=2&ids=3&name=Alice` -> `{ ids: '1,2,3', name: 'Alice' }` |
|
||||
| `pathParameters` | `Record\<string, string \| undefined>` | Parametri di percorso estratti dal pattern della route | `/users/:id`, `/users/123` -> `{ id: '123' }` |
|
||||
| `body` | `object \| null` | Corpo della richiesta analizzato (JSON) | `{ id: 1 }` -> `{ id: 1 }` |
|
||||
| `rawBody` | `string \| undefined` | Original UTF-8 request body, before JSON parsing. Useful for verifying HMAC-style webhook signatures (e.g. GitHub's `X-Hub-Signature-256`, Stripe). `undefined` when the runtime did not preserve it. | |
|
||||
| `isBase64Encoded` | `boolean` | Indica se il corpo è codificato in base64 | |
|
||||
| `requestContext.http.method` | `string` | Metodo HTTP (GET, POST, PUT, PATCH, DELETE) | |
|
||||
| `requestContext.http.path` | `string` | Percorso della richiesta non elaborato | |
|
||||
|
||||
|
||||
#### forwardedRequestHeaders
|
||||
|
||||
@@ -19,7 +19,7 @@ Per i team pronti a scalare:
|
||||
* Supporto standard
|
||||
|
||||
<Note>
|
||||
Le funzionalità premium (SSO e autorizzazioni a livello di riga) non sono incluse nel piano Pro.
|
||||
Premium features (SSO, row-level permissions and AI usage data) are not included in the Pro plan.
|
||||
</Note>
|
||||
|
||||
### Organizzazione (Cloud)
|
||||
@@ -27,7 +27,7 @@ Le funzionalità premium (SSO e autorizzazioni a livello di riga) non sono inclu
|
||||
Per i team più numerosi con esigenze avanzate:
|
||||
|
||||
* Tutto ciò che è incluso in Pro
|
||||
* **Funzionalità premium**: integrazione SSO e autorizzazioni a livello di riga
|
||||
* **Premium features**: SSO integration, row-level permissions and AI usage data
|
||||
* Supporto prioritario
|
||||
|
||||
## Piani self‑hosted
|
||||
@@ -45,7 +45,7 @@ Esegui Twenty sulla tua infrastruttura senza costi:
|
||||
Per i team che necessitano di funzionalità premium con il self‑hosting:
|
||||
|
||||
* Tutte le funzionalità di Pro
|
||||
* **Funzionalità premium**: integrazione SSO e autorizzazioni a livello di riga
|
||||
* **Premium features**: SSO integration, row-level permissions and AI usage data
|
||||
* Supporto del team di Twenty
|
||||
* Nessun requisito di pubblicare il codice personalizzato come open source prima della distribuzione
|
||||
|
||||
@@ -55,6 +55,7 @@ Le funzionalità premium sono disponibili solo nei piani Organizzazione (Cloud o
|
||||
|
||||
* **Integrazione SSO**: Single Sign‑On con il tuo provider di identità
|
||||
* **Autorizzazioni a livello di riga**: controllo degli accessi granulare a livello di record
|
||||
* **AI usage data**: Track AI consumption across the workspace
|
||||
|
||||
## Cambio piano
|
||||
|
||||
@@ -77,3 +78,15 @@ Contatta il supporto per eseguire il downgrade del tuo piano.
|
||||
### Passa alla fatturazione mensile
|
||||
|
||||
Contatta il supporto per tornare alla fatturazione mensile.
|
||||
|
||||
## Obtain an Enterprise Key for Organization (Self-Hosted)
|
||||
|
||||
To use the Organization (Self-Hosted) plan, you need to obtain an Enterprise key:
|
||||
|
||||
1. Go to **Settings → Admin Panel → Enterprise**
|
||||
|
||||
<img src="/images/user-guide/billing/enterprise-key.png" alt="Enterprise key" />
|
||||
|
||||
2. Click **Get Enterprise Key**
|
||||
3. When you are redirected to Stripe, enter your payment details and confirm
|
||||
4. When your Enterprise key is displayed, paste it into the Enterprise settings page and activate the Organization license
|
||||
|
||||
@@ -16,6 +16,11 @@ Se vuoi effettuare il self-hosting e hai bisogno delle funzionalità Premium (SS
|
||||
Le funzionalità Premium sono disponibili solo nei piani Organization (Cloud o Self-Hosted):
|
||||
* **Integrazione SSO**: Single Sign-On con il tuo provider di identità
|
||||
* **Autorizzazioni a livello di riga**: controllo degli accessi granulare a livello di record
|
||||
* **Dati di utilizzo dell'IA**: Tieni traccia del consumo dell'IA nel tuo spazio di lavoro
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Il piano Organization su cloud e il piano Organization in modalità self-hosted sono la stessa cosa?">
|
||||
Offrono le stesse funzionalità Premium. Tuttavia, un abbonamento cloud non può essere utilizzato per distribuzioni self-hosted. La modalità self-hosted richiede una chiave Enterprise.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Offrite posti gratuiti per utenti solo visualizzazione?">
|
||||
|
||||
+34
-39
@@ -53,38 +53,45 @@ Per prima cosa, crea l'oggetto intermedio che conterrà i collegamenti.
|
||||
1. Vai a **Impostazioni → Modello dati**
|
||||
2. Fai clic su **+ Nuovo oggetto**
|
||||
3. Assegnagli un nome descrittivo (ad es., "Assegnazione al progetto", "Membro del team", "Ordine del prodotto")
|
||||
4. Clicca su **Salva**
|
||||
4. Attiva l'opzione "Salta la creazione di un campo Nome"
|
||||
|
||||
<img src="/images/user-guide/fields/new-pivot-object.png" alt="Nuovo oggetto pivot" />
|
||||
|
||||
5. Clicca su **Salva**
|
||||
|
||||
<Tip>
|
||||
**Convenzione di denominazione**: Usa un nome che descriva la relazione, come "Assegnazione al progetto" o "Appartenenza al team". Questo rende il modello di dati più facile da comprendere.
|
||||
</Tip>
|
||||
|
||||
## Passaggio 2: Crea le relazioni dall'oggetto di giunzione
|
||||
## Passaggio 2: Crea relazioni tra gli oggetti e l'oggetto di giunzione
|
||||
|
||||
Aggiungi campi di relazione dall'oggetto di giunzione a entrambi gli oggetti che desideri collegare.
|
||||
Aggiungi campi di relazione da ciascuno dei due oggetti all'oggetto di giunzione.
|
||||
|
||||
### Prima relazione (Giunzione → Oggetto A)
|
||||
### Prima relazione (Oggetto A → Oggetto di giunzione)
|
||||
|
||||
1. Seleziona il tuo oggetto di giunzione in **Impostazioni → Modello dati**
|
||||
2. Fai clic su **+ Aggiungi campo**
|
||||
3. Scegli **Relazione** come tipo di campo
|
||||
4. Seleziona il primo oggetto (ad es., "Persone")
|
||||
5. Imposta il tipo di relazione su **Molti-a-uno** (molte assegnazioni possono collegarsi a una persona)
|
||||
6. Assegna un nome ai campi:
|
||||
* Campo sull'oggetto di giunzione: ad es., "Persona"
|
||||
* Campo su Persone: ad es., "Assegnazioni ai progetti"
|
||||
7. Clicca su **Salva**
|
||||
|
||||
### Seconda relazione (Giunzione → Oggetto B)
|
||||
|
||||
1. Sempre sull'oggetto di giunzione, fai clic su **+ Aggiungi campo**
|
||||
2. Scegli **Relazione** come tipo di campo
|
||||
3. Seleziona il secondo oggetto (ad es., "Progetti")
|
||||
4. Imposta il tipo di relazione su **Molti-a-uno**
|
||||
1. Seleziona il tuo primo oggetto in **Impostazioni → Modello dati**
|
||||
2. Fai clic su **+ Aggiungi relazione**
|
||||
3. Seleziona l'oggetto di giunzione (ad es., "Assegnazioni al progetto")
|
||||
4. Imposta il tipo di relazione su **Uno-a-molti** (una persona può collegarsi a molte assegnazioni)
|
||||
5. Assegna un nome ai campi:
|
||||
* Campo su Persone: ad es., "Assegnazioni ai progetti"
|
||||
* Campo sull'oggetto di giunzione: ad es., "Persona"
|
||||
6. Clicca su **Salva**
|
||||
|
||||
### Seconda relazione (Oggetto B → Oggetto di giunzione)
|
||||
|
||||
1. Seleziona il tuo secondo oggetto in **Impostazioni → Modello dati**
|
||||
2. Fai clic su **+ Aggiungi relazione**
|
||||
3. Seleziona l'oggetto di giunzione (ad es., "Assegnazioni al progetto")
|
||||
4. Imposta il tipo di relazione su **Uno-a-molti** (un progetto può collegarsi a molte assegnazioni)
|
||||
5. Abilita **"Questa è una relazione con un oggetto di giunzione"**
|
||||
|
||||
<img src="/images/user-guide/fields/junction-relation-toggle.png" style={{width:'100%'}} />
|
||||
|
||||
6. Assegna un nome ai campi:
|
||||
* Campo sull'oggetto di giunzione: ad es., "Progetto"
|
||||
* Campo su Progetti: ad es., "Membri del team"
|
||||
6. Clicca su **Salva**
|
||||
7. Clicca su **Salva**
|
||||
|
||||
## Passaggio 3: Configura la visualizzazione della relazione di giunzione
|
||||
|
||||
@@ -98,18 +105,6 @@ Ora configura gli oggetti sorgente per visualizzare direttamente i record colleg
|
||||
6. Seleziona la **Relazione di destinazione** (ad es., "Progetto" — il campo sull'oggetto di giunzione che punta all'altro lato)
|
||||
7. Clicca su **Salva**
|
||||
|
||||
{/* TODO: Add image
|
||||
<img src="/images/user-guide/fields/junction-relation-toggle.png" style={{width:'100%'}}/>
|
||||
*/}
|
||||
|
||||
Ripeti per l'altro oggetto:
|
||||
|
||||
1. Seleziona "Progetti" in Modello dati
|
||||
2. Modifica il campo di relazione "Membri del team"
|
||||
3. Abilita l'interruttore di giunzione
|
||||
4. Seleziona "Persona" come relazione di destinazione
|
||||
5. Salva
|
||||
|
||||
## Risultato
|
||||
|
||||
Dopo la configurazione:
|
||||
@@ -130,15 +125,15 @@ Ecco una procedura completa:
|
||||
|
||||
### Aggiungi relazioni
|
||||
|
||||
1. **Assegnazione al progetto → Persone**
|
||||
* Tipo: Molti-a-uno
|
||||
* Campo su Assegnazione: "Persona"
|
||||
1. **Persone → Assegnazione al progetto**
|
||||
* Tipo: Uno-a-molti
|
||||
* Campo su Persone: "Assegnazioni ai progetti"
|
||||
* Campo su Assegnazione: "Persona"
|
||||
|
||||
2. **Assegnazione al progetto → Progetti**
|
||||
* Tipo: Molti-a-uno
|
||||
* Campo su Assegnazione: "Progetto"
|
||||
2. **Progetti → Assegnazione al progetto**
|
||||
* Tipo: Uno-a-molti
|
||||
* Campo su Progetti: "Membri del team"
|
||||
* Campo su Assegnazione: "Progetto"
|
||||
|
||||
### Configura la visualizzazione della giunzione
|
||||
|
||||
|
||||
@@ -30,3 +30,9 @@ Aggiungi collegamenti a strumenti esterni direttamente nella barra laterale. Uti
|
||||
## Menu Comandi
|
||||
|
||||
Premi `Cmd+K` (o `Ctrl+K`) per aprire il menu comandi — una barra di ricerca ad accesso rapido per passare a qualsiasi record, vista o azione senza usare la barra laterale.
|
||||
|
||||
## Personalizzare la barra laterale
|
||||
|
||||
Per personalizzare la barra laterale, passa il mouse sulla sezione "Workspace" nella barra laterale e fai clic sull'icona a forma di chiave inglese.
|
||||
|
||||
<img src="/images/user-guide/layout/navigation-edit-icon.png" alt="Icona di modifica della navigazione" />
|
||||
|
||||
@@ -3,6 +3,8 @@ title: Pagine dei record
|
||||
description: Personalizza il layout delle singole pagine di dettaglio dei record con schede e widget.
|
||||
---
|
||||
|
||||
## Panoramica
|
||||
|
||||
Quando apri un record in Twenty, la pagina di dettaglio è composta da **schede** e **widget**. Entrambi sono completamente personalizzabili per ciascun tipo di oggetto.
|
||||
|
||||
## Schede
|
||||
@@ -38,12 +40,20 @@ I widget sono gli elementi costitutivi all'interno di ogni scheda. Tipi di widge
|
||||
|
||||
1. Apri un record qualsiasi
|
||||
2. Premi `Cmd+K` e cerca "Modifica il layout della pagina del record"
|
||||
|
||||
o
|
||||
|
||||
1. Vai a Impostazioni > Modello dati > oggetto di tua scelta > Layout
|
||||
|
||||
2. Fai clic sul pulsante "Personalizza pagina del record" per quell'oggetto
|
||||
|
||||
3. Ora sei in modalità di personalizzazione:
|
||||
* **Aggiungi widget** dal selettore di widget
|
||||
* **Trascina i widget** per riposizionarli sulla griglia
|
||||
* **Ridimensiona i widget** trascinando i bordi
|
||||
* **Configura i campi** mostrati all'interno di ciascun widget
|
||||
* **Gestisci le schede** — aggiungi, rimuovi, rinomina, riordina
|
||||
|
||||
4. Salva le modifiche — si applicano a tutti i record di quel tipo di oggetto
|
||||
|
||||
## Visibilità dei campi
|
||||
|
||||
@@ -94,15 +94,16 @@ const handler = async (event: RoutePayload) => {
|
||||
|
||||
O tipo `RoutePayload` tem a seguinte estrutura:
|
||||
|
||||
| Propriedade | Tipo | Descrição | Exemplo |
|
||||
| ---------------------------- | ------------------------------------------------------- | ---------------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
||||
| `headers` | `Record\<string, string \| undefined>` | Cabeçalhos HTTP (apenas aqueles listados em `forwardedRequestHeaders`) | veja a seção abaixo |
|
||||
| `queryStringParameters` | `Record\<string, string \| undefined>` | Parâmetros de query string (valores múltiplos unidos por vírgulas) | `/users?ids=1&ids=2&ids=3&name=Alice` -> `{ ids: '1,2,3', name: 'Alice' }` |
|
||||
| `pathParameters` | `Record\<string, string \| undefined>` | Parâmetros de caminho extraídos do padrão de rota | `/users/:id`, `/users/123` -> `{ id: '123' }` |
|
||||
| `body` | `object \| null` | Corpo da requisição analisado (JSON) | `{ id: 1 }` -> `{ id: 1 }` |
|
||||
| `isBase64Encoded` | `boolean` | Se o corpo está codificado em base64 | |
|
||||
| `requestContext.http.method` | `string` | Método HTTP (GET, POST, PUT, PATCH, DELETE) | |
|
||||
| `requestContext.http.path` | `string` | Caminho bruto da requisição | |
|
||||
| Propriedade | Tipo | Descrição | Exemplo |
|
||||
| ---------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
||||
| `headers` | `Record\<string, string \| undefined>` | Cabeçalhos HTTP (apenas aqueles listados em `forwardedRequestHeaders`) | veja a seção abaixo |
|
||||
| `queryStringParameters` | `Record\<string, string \| undefined>` | Parâmetros de query string (valores múltiplos unidos por vírgulas) | `/users?ids=1&ids=2&ids=3&name=Alice` -> `{ ids: '1,2,3', name: 'Alice' }` |
|
||||
| `pathParameters` | `Record\<string, string \| undefined>` | Parâmetros de caminho extraídos do padrão de rota | `/users/:id`, `/users/123` -> `{ id: '123' }` |
|
||||
| `body` | `object \| null` | Corpo da requisição analisado (JSON) | `{ id: 1 }` -> `{ id: 1 }` |
|
||||
| `rawBody` | `string \| undefined` | Corpo da solicitação UTF-8 original, antes da análise de JSON. Útil para verificar assinaturas de webhook no estilo HMAC (por exemplo, `X-Hub-Signature-256` do GitHub, Stripe). `undefined` quando o ambiente de execução não o preservou. | |
|
||||
| `isBase64Encoded` | `boolean` | Se o corpo está codificado em base64 | |
|
||||
| `requestContext.http.method` | `string` | Método HTTP (GET, POST, PUT, PATCH, DELETE) | |
|
||||
| `requestContext.http.path` | `string` | Caminho bruto da requisição | |
|
||||
|
||||
|
||||
#### forwardedRequestHeaders
|
||||
|
||||
@@ -19,7 +19,7 @@ Para equipes prontas para escalar:
|
||||
* Suporte padrão
|
||||
|
||||
<Note>
|
||||
Recursos premium (SSO e permissões em nível de linha) não estão incluídos no plano Pro.
|
||||
Os recursos Premium (SSO, permissões em nível de linha e dados de uso de IA) não estão incluídos no plano Pro.
|
||||
</Note>
|
||||
|
||||
### Organização (Nuvem)
|
||||
@@ -27,7 +27,7 @@ Recursos premium (SSO e permissões em nível de linha) não estão incluídos n
|
||||
Para equipes maiores com necessidades avançadas:
|
||||
|
||||
* Tudo do Pro
|
||||
* **Recursos premium**: integração SSO e permissões em nível de linha
|
||||
* **Recursos Premium**: integração com SSO, permissões em nível de linha e dados de uso de IA
|
||||
* Suporte prioritário
|
||||
|
||||
## Planos auto-hospedados
|
||||
@@ -45,7 +45,7 @@ Hospede o Twenty na sua própria infraestrutura sem custo:
|
||||
Para equipes que precisam de recursos premium enquanto se auto-hospedam:
|
||||
|
||||
* Todos os recursos do Pro
|
||||
* **Recursos premium**: integração SSO e permissões em nível de linha
|
||||
* **Recursos Premium**: integração com SSO, permissões em nível de linha e dados de uso de IA
|
||||
* Suporte da equipe Twenty
|
||||
* Sem necessidade de publicar código personalizado como código aberto antes de distribuir
|
||||
|
||||
@@ -55,6 +55,7 @@ Os recursos premium estão disponíveis apenas nos planos Organização (Nuvem o
|
||||
|
||||
* **Integração SSO**: Single Sign-On com seu provedor de identidade
|
||||
* **Permissões em nível de linha**: controle de acesso granular no nível de registro
|
||||
* **Dados de uso de IA**: Acompanhe o consumo de IA em todo o espaço de trabalho
|
||||
|
||||
## Mudança de planos
|
||||
|
||||
@@ -77,3 +78,15 @@ Entre em contato com o suporte para fazer downgrade do seu plano.
|
||||
### Mudar para faturamento mensal
|
||||
|
||||
Entre em contato com o suporte para voltar ao faturamento mensal.
|
||||
|
||||
## Obtenha uma chave Enterprise para Organization (Self-Hosted)
|
||||
|
||||
Para usar o plano Organization (Self-Hosted), você precisa obter uma chave Enterprise:
|
||||
|
||||
1. Vá para **Configurações → Painel de Administração → Enterprise**
|
||||
|
||||
<img src="/images/user-guide/billing/enterprise-key.png" alt="Chave Enterprise" />
|
||||
|
||||
2. Clique em **Obter chave Enterprise**
|
||||
3. Quando você for redirecionado ao Stripe, insira seus dados de pagamento e confirme
|
||||
4. Quando sua chave Enterprise for exibida, cole-a na página de configurações do Enterprise e ative a licença do Organization
|
||||
|
||||
@@ -16,6 +16,11 @@ Se você quiser hospedar por conta própria e precisar dos recursos Premium (SSO
|
||||
Os recursos Premium estão disponíveis apenas nos planos Organization (Cloud ou Self-Hosted):
|
||||
* **Integração de SSO**: Single Sign-On com seu provedor de identidade
|
||||
* **Permissões em nível de linha**: Controle de acesso granular no nível de registro
|
||||
* **Dados de uso de IA**: Acompanhe o consumo de IA em todo o espaço de trabalho
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="O plano Organization na nuvem e o plano Organization em ambiente autohospedado são iguais?">
|
||||
Ambos oferecem os mesmos recursos Premium. No entanto, uma assinatura na nuvem não pode ser usada para implantações autohospedadas. O ambiente autohospedado requer uma chave Enterprise.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Você oferece assentos gratuitos para usuários apenas visualizadores?">
|
||||
|
||||
+34
-39
@@ -53,38 +53,45 @@ Primeiro, crie o objeto intermediário que manterá as conexões.
|
||||
1. Vá a **Definições → Modelo de Dados**
|
||||
2. Clique em **+ Novo objeto**
|
||||
3. Dê um nome descritivo (por exemplo, "Atribuição de Projeto", "Membro da Equipe", "Pedido de Produto")
|
||||
4. Clique em **Salvar**
|
||||
4. Ative a opção "Ignorar a criação de um campo Nome"
|
||||
|
||||
<img src="/images/user-guide/fields/new-pivot-object.png" alt="Novo objeto pivô" />
|
||||
|
||||
5. Clique em **Salvar**
|
||||
|
||||
<Tip>
|
||||
**Convenção de nomenclatura**: Use um nome que descreva a relação, como "Atribuição de Projeto" ou "Participação na Equipe". Isso torna o modelo de dados mais fácil de entender.
|
||||
</Tip>
|
||||
|
||||
## Etapa 2: Criar Relações a partir do Objeto de Junção
|
||||
## Etapa 2: Crie relações entre os objetos e o objeto de junção
|
||||
|
||||
Adicione campos de relação do objeto de junção para ambos os objetos que deseja conectar.
|
||||
Adicione campos de relação de cada um dos seus dois objetos ao objeto de junção.
|
||||
|
||||
### Primeira Relação (Junção → Objeto A)
|
||||
### Primeira Relação (Objeto A → Junção)
|
||||
|
||||
1. Selecione seu objeto de junção em **Settings → Data Model**
|
||||
2. Clique em **+ Adicionar campo**
|
||||
3. Escolha **Relação** como o tipo de campo
|
||||
4. Selecione o primeiro objeto (por exemplo, "Pessoas")
|
||||
5. Defina o tipo de relação como **Muitos-para-um** (muitas atribuições podem se vincular a uma pessoa)
|
||||
6. Nomeie os campos:
|
||||
* Campo na junção: por exemplo, "Pessoa"
|
||||
* Campo em Pessoas: por exemplo, "Atribuições de Projeto"
|
||||
7. Clique em **Salvar**
|
||||
|
||||
### Segunda Relação (Junção → Objeto B)
|
||||
|
||||
1. Ainda no objeto de junção, clique em **+ Add Field**
|
||||
2. Escolha **Relação** como o tipo de campo
|
||||
3. Selecione o segundo objeto (por exemplo, "Projetos")
|
||||
4. Defina o tipo de relação como **Muitos-para-um**
|
||||
1. Selecione seu primeiro objeto em **Settings → Data Model**
|
||||
2. Clique em **+ Adicionar relação**
|
||||
3. Selecione o objeto de junção (por exemplo, "Atribuições de Projeto")
|
||||
4. Defina o tipo de relação como **Um-para-muitos** (uma pessoa pode se vincular a muitas atribuições)
|
||||
5. Nomeie os campos:
|
||||
* Campo em Pessoas: por exemplo, "Atribuições de Projeto"
|
||||
* Campo na junção: por exemplo, "Pessoa"
|
||||
6. Clique em **Salvar**
|
||||
|
||||
### Segunda Relação (Objeto B → Junção)
|
||||
|
||||
1. Selecione seu segundo objeto em **Settings → Data Model**
|
||||
2. Clique em **+ Adicionar relação**
|
||||
3. Selecione o objeto de junção (por exemplo, "Atribuições de Projeto")
|
||||
4. Defina o tipo de relação como **Um-para-muitos** (um projeto pode se vincular a muitas atribuições)
|
||||
5. Ative **"Esta é uma relação com um objeto de junção"**
|
||||
|
||||
<img src="/images/user-guide/fields/junction-relation-toggle.png" style={{width:'100%'}} />
|
||||
|
||||
6. Nomeie os campos:
|
||||
* Campo na junção: por exemplo, "Projeto"
|
||||
* Campo em Projetos: por exemplo, "Membros da Equipe"
|
||||
6. Clique em **Salvar**
|
||||
7. Clique em **Salvar**
|
||||
|
||||
## Etapa 3: Configurar a Exibição da Relação de Junção
|
||||
|
||||
@@ -98,18 +105,6 @@ Agora configure os objetos de origem para exibir diretamente os registros vincul
|
||||
6. Selecione a **Relação de destino** (por exemplo, "Projeto" — o campo na junção que aponta para o outro lado)
|
||||
7. Clique em **Salvar**
|
||||
|
||||
{/* TODO: Add image
|
||||
<img src="/images/user-guide/fields/junction-relation-toggle.png" style={{width:'100%'}}/>
|
||||
*/}
|
||||
|
||||
Repita para o outro objeto:
|
||||
|
||||
1. Selecione "Projetos" em Data Model
|
||||
2. Edite o campo de relação "Membros da Equipe"
|
||||
3. Ative o alternador de junção
|
||||
4. Selecione "Pessoa" como a relação de destino
|
||||
5. Salvar
|
||||
|
||||
## Resultado
|
||||
|
||||
Após a configuração:
|
||||
@@ -130,15 +125,15 @@ Aqui está um passo a passo completo:
|
||||
|
||||
### Adicionar Relações
|
||||
|
||||
1. **Atribuição de Projeto → Pessoas**
|
||||
* Tipo: Muitos-para-um
|
||||
* Campo em Atribuição: "Pessoa"
|
||||
1. **Pessoas → Atribuição de Projeto**
|
||||
* Tipo: Um-para-muitos
|
||||
* Campo em Pessoas: "Atribuições de Projeto"
|
||||
* Campo em Atribuição: "Pessoa"
|
||||
|
||||
2. **Atribuição de Projeto → Projetos**
|
||||
* Tipo: Muitos-para-um
|
||||
* Campo em Atribuição: "Projeto"
|
||||
2. **Projetos → Atribuição de Projeto**
|
||||
* Tipo: Um-para-muitos
|
||||
* Campo em Projetos: "Membros da Equipe"
|
||||
* Campo em Atribuição: "Projeto"
|
||||
|
||||
### Configurar Exibição de Junção
|
||||
|
||||
|
||||
@@ -30,3 +30,9 @@ Adicione links para ferramentas externas diretamente na barra lateral. Útil par
|
||||
## Menu de Comandos
|
||||
|
||||
Pressione `Cmd+K` (ou `Ctrl+K`) para abrir o menu de comandos — uma barra de pesquisa de acesso rápido para ir a qualquer registro, visualização ou ação sem navegar pela barra lateral.
|
||||
|
||||
## Personalizando a barra lateral
|
||||
|
||||
Para personalizar a barra lateral, passe o cursor sobre a seção "Workspace" na barra lateral e clique no ícone de chave inglesa.
|
||||
|
||||
<img src="/images/user-guide/layout/navigation-edit-icon.png" alt="Ícone de edição da navegação" />
|
||||
|
||||
@@ -3,6 +3,8 @@ title: Páginas de Registos
|
||||
description: Personalize o layout das páginas de detalhe de registos individuais com abas e widgets.
|
||||
---
|
||||
|
||||
## Visão Geral
|
||||
|
||||
Ao abrir um registo no Twenty, a página de detalhe é composta por **abas** e **widgets**. Ambos são totalmente personalizáveis por tipo de objeto.
|
||||
|
||||
## Abas
|
||||
@@ -38,12 +40,20 @@ Os widgets são os componentes básicos dentro de cada aba. Tipos de widget disp
|
||||
|
||||
1. Abra qualquer registro
|
||||
2. Pressione `Cmd+K` e pesquise por "Edit record page layout"
|
||||
|
||||
ou
|
||||
|
||||
1. Vá para Configurações > Modelo de dados > objeto de sua escolha > Layout
|
||||
|
||||
2. Clique no botão "Personalizar página de registro" para esse objeto
|
||||
|
||||
3. Agora você está no modo de personalização:
|
||||
* **Adicionar widgets** no seletor de widgets
|
||||
* **Arraste widgets** para reposicioná-los na grade
|
||||
* **Redimensione os widgets** arrastando suas bordas
|
||||
* **Configure campos** exibidos em cada widget
|
||||
* **Gerencie abas** — adicione, remova, renomeie, reordene
|
||||
|
||||
4. Salve suas alterações — elas se aplicam a todos os registros desse tipo de objeto
|
||||
|
||||
## Visibilidade de campos
|
||||
|
||||
@@ -94,15 +94,16 @@ const handler = async (event: RoutePayload) => {
|
||||
|
||||
Тип `RoutePayload` имеет следующую структуру:
|
||||
|
||||
| Свойство | Тип | Описание | Пример |
|
||||
| ---------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
||||
| `headers` | `Record\<string, string \| undefined>` | HTTP-заголовки (только перечисленные в `forwardedRequestHeaders`) | см. раздел ниже |
|
||||
| `queryStringParameters` | `Record\<string, string \| undefined>` | Параметры строки запроса (несколько значений объединяются запятыми) | `/users?ids=1&ids=2&ids=3&name=Alice` -> `{ ids: '1,2,3', name: 'Alice' }` |
|
||||
| `pathParameters` | `Record\<string, string \| undefined>` | Параметры пути, извлечённые из шаблона маршрута | `/users/:id`, `/users/123` -> `{ id: '123' }` |
|
||||
| `body` | `object \| null` | Разобранное тело запроса (JSON) | `{ id: 1 }` -> `{ id: 1 }` |
|
||||
| `isBase64Encoded` | `boolean` | Является ли тело закодированным в base64 | |
|
||||
| `requestContext.http.method` | `string` | Метод HTTP (GET, POST, PUT, PATCH, DELETE) | |
|
||||
| `requestContext.http.path` | `string` | Необработанный путь запроса | |
|
||||
| Свойство | Тип | Описание | Пример |
|
||||
| ---------------------------- | ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
||||
| `headers` | `Record\<string, string \| undefined>` | HTTP-заголовки (только перечисленные в `forwardedRequestHeaders`) | см. раздел ниже |
|
||||
| `queryStringParameters` | `Record\<string, string \| undefined>` | Параметры строки запроса (несколько значений объединяются запятыми) | `/users?ids=1&ids=2&ids=3&name=Alice` -> `{ ids: '1,2,3', name: 'Alice' }` |
|
||||
| `pathParameters` | `Record\<string, string \| undefined>` | Параметры пути, извлечённые из шаблона маршрута | `/users/:id`, `/users/123` -> `{ id: '123' }` |
|
||||
| `body` | `object \| null` | Разобранное тело запроса (JSON) | `{ id: 1 }` -> `{ id: 1 }` |
|
||||
| `rawBody` | `string \| undefined` | Исходное тело запроса в кодировке UTF-8, до разбора JSON. Полезно для проверки подписей вебхуков в стиле HMAC (например, `X-Hub-Signature-256` от GitHub, Stripe). `undefined`, если среда выполнения не сохранила его. | |
|
||||
| `isBase64Encoded` | `boolean` | Является ли тело закодированным в base64 | |
|
||||
| `requestContext.http.method` | `string` | Метод HTTP (GET, POST, PUT, PATCH, DELETE) | |
|
||||
| `requestContext.http.path` | `string` | Необработанный путь запроса | |
|
||||
|
||||
|
||||
#### forwardedRequestHeaders
|
||||
|
||||
@@ -19,7 +19,7 @@ Twenty предлагает гибкие тарифы для команд люб
|
||||
* Стандартная поддержка
|
||||
|
||||
<Note>
|
||||
Премиальные функции (SSO и разрешения на уровне записей) не входят в план Pro.
|
||||
Премиальные функции (SSO, разрешения на уровне строк и данные об использовании ИИ) не включены в тариф Pro.
|
||||
</Note>
|
||||
|
||||
### Организация (облако)
|
||||
@@ -27,7 +27,7 @@ Twenty предлагает гибкие тарифы для команд люб
|
||||
Для крупных команд с расширенными потребностями:
|
||||
|
||||
* Все, что есть в Pro
|
||||
* **Премиальные функции**: интеграция с SSO и разрешения на уровне записей
|
||||
* **Премиальные функции**: интеграция SSO, разрешения на уровне строк и данные об использовании ИИ
|
||||
* Приоритетная поддержка
|
||||
|
||||
## Планы для самостоятельного размещения
|
||||
@@ -45,7 +45,7 @@ Twenty предлагает гибкие тарифы для команд люб
|
||||
Для команд, которым нужны премиальные функции при самостоятельном размещении:
|
||||
|
||||
* Все возможности Pro
|
||||
* **Премиальные функции**: интеграция с SSO и разрешения на уровне записей
|
||||
* **Премиальные функции**: интеграция SSO, разрешения на уровне строк и данные об использовании ИИ
|
||||
* Поддержка от команды Twenty
|
||||
* Не требуется публиковать пользовательский код с открытым исходным кодом перед распространением
|
||||
|
||||
@@ -55,6 +55,7 @@ Twenty предлагает гибкие тарифы для команд люб
|
||||
|
||||
* **Интеграция с SSO**: единый вход через вашего поставщика идентификации
|
||||
* **Разрешения на уровне записей**: тонкая настройка управления доступом на уровне записей
|
||||
* **Данные об использовании ИИ**: Отслеживайте потребление ИИ в рабочем пространстве
|
||||
|
||||
## Переключение планов
|
||||
|
||||
@@ -77,3 +78,15 @@ Twenty предлагает гибкие тарифы для команд люб
|
||||
### Переход на ежемесячную оплату
|
||||
|
||||
Свяжитесь со службой поддержки, чтобы вернуться на ежемесячную оплату.
|
||||
|
||||
## Получите ключ Enterprise для организации (самостоятельный хостинг)
|
||||
|
||||
Чтобы использовать тариф Organization (Self-Hosted), необходимо получить ключ Enterprise:
|
||||
|
||||
1. Перейдите в **Настройки → Панель администратора → Enterprise**
|
||||
|
||||
<img src="/images/user-guide/billing/enterprise-key.png" alt="Ключ Enterprise" />
|
||||
|
||||
2. Нажмите **Получить ключ Enterprise**
|
||||
3. Когда вы будете перенаправлены на Stripe, введите платёжные данные и подтвердите
|
||||
4. Когда ваш ключ Enterprise будет отображён, вставьте его на странице настроек Enterprise и активируйте лицензию Organization
|
||||
|
||||
@@ -16,6 +16,11 @@ description: Часто задаваемые вопросы о тарифах и
|
||||
Премиум-функции доступны только в планах Organization (облако или Self-Hosted):
|
||||
* **Интеграция с SSO**: единый вход с вашим провайдером идентификации
|
||||
* **Разрешения на уровне записей**: детализированное управление доступом на уровне записей
|
||||
* **Данные об использовании ИИ**: Отслеживайте потребление ИИ в рабочем пространстве
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Одинаков ли тариф Organization в облаке и в самостоятельно размещаемой версии?">
|
||||
Они предлагают одинаковые премиум-функции. Однако облачную подписку нельзя использовать для развертываний на собственном хостинге. Для самостоятельно размещаемой версии требуется ключ Enterprise.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Предлагаете ли вы бесплатные места для пользователей с правами только просмотра?">
|
||||
@@ -27,7 +32,7 @@ description: Часто задаваемые вопросы о тарифах и
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Где я могу переключить свою подписку на план Pro?">
|
||||
Пожалуйста, свяжитесь с нашей командой напрямую через Поддержку, в данный момент нет простого способа сделать это через пользовательский интерфейс.
|
||||
Пожалуйста, свяжитесь с нашей командой напрямую через раздел «Поддержка», в данный момент нет простого способа сделать это через пользовательский интерфейс.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Где я могу переключить свою подписку на годовой период?">
|
||||
|
||||
+34
-39
@@ -53,38 +53,45 @@ People ←→ Project Assignments ←→ Projects
|
||||
1. Перейдите в **Настройки → Модель данных**
|
||||
2. Нажмите **+ Новый объект**
|
||||
3. Дайте ему понятное имя (например, "Project Assignment", "Team Member", "Product Order")
|
||||
4. Нажмите **Сохранить**
|
||||
4. Включите переключатель «Пропустить создание поля „Имя“»
|
||||
|
||||
<img src="/images/user-guide/fields/new-pivot-object.png" alt="Новый объект-связка" />
|
||||
|
||||
5. Нажмите **Сохранить**
|
||||
|
||||
<Tip>
|
||||
**Рекомендации по именованию**: Используйте название, описывающее связь, например "Project Assignment" или "Team Membership". Так модель данных становится более понятной.
|
||||
</Tip>
|
||||
|
||||
## Шаг 2: Создайте связи из объекта-связки
|
||||
## Шаг 2: Создайте связи между объектами и объектом-связкой
|
||||
|
||||
Добавьте поля связи из объекта-связки к обоим объектам, которые вы хотите соединить.
|
||||
Добавьте поля связи из каждого из двух объектов в объект-связку.
|
||||
|
||||
### Первая связь (Объект-связка → Объект A)
|
||||
### Первая связь (Объект A → Объект-связка)
|
||||
|
||||
1. Выберите ваш объект-связку в **Настройки → Модель данных**
|
||||
2. Нажмите **+ Добавить поле**
|
||||
3. Выберите тип поля **Связь**
|
||||
4. Выберите первый объект (например, "Люди")
|
||||
5. Установите тип связи **Многие-к-одному** (много назначений могут ссылаться на одного человека)
|
||||
6. Назовите поля:
|
||||
* Поле на объекте-связке: например, "Person"
|
||||
* Поле в объекте Люди: например, "Project Assignments"
|
||||
7. Нажмите **Сохранить**
|
||||
|
||||
### Вторая связь (Объект-связка → Объект B)
|
||||
|
||||
1. Оставаясь на объекте-связке, нажмите **+ Добавить поле**
|
||||
2. Выберите тип поля **Связь**
|
||||
3. Выберите второй объект (например, "Проекты")
|
||||
4. Установите тип связи **Многие-к-одному**
|
||||
1. Выберите ваш первый объект в **Настройках → Модель данных**
|
||||
2. Нажмите **+ Добавить связь**
|
||||
3. Выберите объект-связку (например, "Назначения по проектам")
|
||||
4. Установите тип связи **Один-ко-многим** (один человек может быть связан со многими назначениями)
|
||||
5. Назовите поля:
|
||||
* Поле в объекте Люди: например, "Project Assignments"
|
||||
* Поле на объекте-связке: например, "Person"
|
||||
6. Нажмите **Сохранить**
|
||||
|
||||
### Вторая связь (Объект B → Объект-связка)
|
||||
|
||||
1. Выберите ваш второй объект в **Настройках → Модель данных**
|
||||
2. Нажмите **+ Добавить связь**
|
||||
3. Выберите объект-связку (например, "Назначения по проектам")
|
||||
4. Установите тип связи **Один-ко-многим** (один проект может быть связан со многими назначениями)
|
||||
5. Включите **"Это связь с объектом-связкой"**
|
||||
|
||||
<img src="/images/user-guide/fields/junction-relation-toggle.png" style={{width:'100%'}} />
|
||||
|
||||
6. Назовите поля:
|
||||
* Поле на объекте-связке: например, "Project"
|
||||
* Поле в объекте Проекты: например, "Team Members"
|
||||
6. Нажмите **Сохранить**
|
||||
7. Нажмите **Сохранить**
|
||||
|
||||
## Шаг 3: Настройте отображение связи через объект-связку
|
||||
|
||||
@@ -98,18 +105,6 @@ People ←→ Project Assignments ←→ Projects
|
||||
6. Выберите **Целевую связь** (например, "Project" — поле на объекте-связке, указывающее на другую сторону)
|
||||
7. Нажмите **Сохранить**
|
||||
|
||||
{/* TODO: Add image
|
||||
<img src="/images/user-guide/fields/junction-relation-toggle.png" style={{width:'100%'}}/>
|
||||
*/}
|
||||
|
||||
Повторите для другого объекта:
|
||||
|
||||
1. Выберите "Проекты" в Модели данных
|
||||
2. Отредактируйте поле связи "Team Members"
|
||||
3. Включите переключатель объекта-связки
|
||||
4. Выберите "Person" как целевую связь
|
||||
5. Сохранить
|
||||
|
||||
## Результат
|
||||
|
||||
После настройки:
|
||||
@@ -130,15 +125,15 @@ People ←→ Project Assignments ←→ Projects
|
||||
|
||||
### Добавьте связи
|
||||
|
||||
1. **Project Assignment → Люди**
|
||||
* Тип: Многие-к-одному
|
||||
* Поле в объекте Assignment: "Person"
|
||||
1. **Люди → Назначение на проект**
|
||||
* Тип: Один-ко-многим
|
||||
* Поле в объекте Люди: "Project Assignments"
|
||||
* Поле в объекте Assignment: "Person"
|
||||
|
||||
2. **Project Assignment → Проекты**
|
||||
* Тип: Многие-к-одному
|
||||
* Поле в объекте Assignment: "Project"
|
||||
2. **Проекты → Назначение на проект**
|
||||
* Тип: Один-ко-многим
|
||||
* Поле в объекте Проекты: "Team Members"
|
||||
* Поле в объекте Assignment: "Project"
|
||||
|
||||
### Настройте отображение объекта-связки
|
||||
|
||||
|
||||
@@ -30,3 +30,9 @@ description: Настройте левую боковую панель под т
|
||||
## Меню команд
|
||||
|
||||
Нажмите `Cmd+K` (или `Ctrl+K`), чтобы открыть меню команд — строку быстрого поиска для перехода к любой записи, представлению или действию, не используя боковую панель.
|
||||
|
||||
## Настройка боковой панели
|
||||
|
||||
Чтобы настроить боковую панель, наведите курсор на раздел "Workspace" на боковой панели и нажмите значок гаечного ключа.
|
||||
|
||||
<img src="/images/user-guide/layout/navigation-edit-icon.png" alt="Значок редактирования навигации" />
|
||||
|
||||
@@ -3,6 +3,8 @@ title: Страницы записей
|
||||
description: Настройте макет отдельных страниц сведений о записях с вкладками и виджетами.
|
||||
---
|
||||
|
||||
## Обзор
|
||||
|
||||
Когда вы открываете запись в Twenty, страница сведений состоит из **вкладок** и **виджетов**. Оба полностью настраиваются для каждого типа объекта.
|
||||
|
||||
## Вкладки
|
||||
@@ -38,12 +40,20 @@ description: Настройте макет отдельных страниц с
|
||||
|
||||
1. Откройте любую запись
|
||||
2. Нажмите `Cmd+K` и найдите "Изменить макет страницы записи"
|
||||
|
||||
или
|
||||
|
||||
1. Перейдите в Настройки > Модель данных > объект по вашему выбору > Макет
|
||||
|
||||
2. Нажмите кнопку "Настроить страницу записи" для этого объекта
|
||||
|
||||
3. Теперь вы в режиме настройки:
|
||||
* **Добавляйте виджеты** из списка виджетов
|
||||
* **Перетаскивайте виджеты**, чтобы изменить их положение на сетке
|
||||
* **Изменяйте размер виджетов**, перетаскивая их границы
|
||||
* **Настраивайте поля**, отображаемые в каждом виджете
|
||||
* **Управляйте вкладками** — добавляйте, удаляйте, переименовывайте, меняйте порядок
|
||||
|
||||
4. Сохраните изменения — они применятся ко всем записям этого типа объекта
|
||||
|
||||
## Видимость полей
|
||||
|
||||
@@ -95,15 +95,16 @@ const handler = async (event: RoutePayload) => {
|
||||
|
||||
`RoutePayload` türünün yapısı şu şekildedir:
|
||||
|
||||
| Özellik | Tür | Açıklama | Örnek |
|
||||
| ---------------------------- | ------------------------------------------------------- | -------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
||||
| `headers` | `Record\<string, string \| undefined>` | HTTP başlıkları (`forwardedRequestHeaders` içinde listelenenlerle sınırlı) | aşağıdaki bölüme bakın |
|
||||
| `queryStringParameters` | `Record\<string, string \| undefined>` | Sorgu dizesi parametreleri (birden çok değer virgülle birleştirilir) | `/users?ids=1&ids=2&ids=3&name=Alice` -> `{ ids: '1,2,3', name: 'Alice' }` |
|
||||
| `pathParameters` | `Record\<string, string \| undefined>` | Rota deseninden çıkarılan yol parametreleri | `/users/:id`, `/users/123` -> `{ id: '123' }` |
|
||||
| `body` | `object \| null` | Ayrıştırılmış istek gövdesi (JSON) | `{ id: 1 }` -> `{ id: 1 }` |
|
||||
| `isBase64Encoded` | `boolean` | Gövdenin base64 ile kodlanıp kodlanmadığı | |
|
||||
| `requestContext.http.method` | `string` | HTTP yöntemi (GET, POST, PUT, PATCH, DELETE) | |
|
||||
| `requestContext.http.path` | `string` | Ham istek yolu | |
|
||||
| Özellik | Tür | Açıklama | Örnek |
|
||||
| ---------------------------- | ------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
||||
| `headers` | `Record\<string, string \| undefined>` | HTTP başlıkları (`forwardedRequestHeaders` içinde listelenenlerle sınırlı) | aşağıdaki bölüme bakın |
|
||||
| `queryStringParameters` | `Record\<string, string \| undefined>` | Sorgu dizesi parametreleri (birden çok değer virgülle birleştirilir) | `/users?ids=1&ids=2&ids=3&name=Alice` -> `{ ids: '1,2,3', name: 'Alice' }` |
|
||||
| `pathParameters` | `Record\<string, string \| undefined>` | Rota deseninden çıkarılan yol parametreleri | `/users/:id`, `/users/123` -> `{ id: '123' }` |
|
||||
| `body` | `object \| null` | Ayrıştırılmış istek gövdesi (JSON) | `{ id: 1 }` -> `{ id: 1 }` |
|
||||
| `rawBody` | `string \| undefined` | JSON ayrıştırılmadan önceki özgün UTF-8 istek gövdesi. HMAC tarzı webhook imzalarını doğrulamak için kullanışlıdır (ör. GitHub'ın `X-Hub-Signature-256`, Stripe). Çalışma zamanı onu korumadığında `undefined` olur. | |
|
||||
| `isBase64Encoded` | `boolean` | Gövdenin base64 ile kodlanıp kodlanmadığı | |
|
||||
| `requestContext.http.method` | `string` | HTTP yöntemi (GET, POST, PUT, PATCH, DELETE) | |
|
||||
| `requestContext.http.path` | `string` | Ham istek yolu | |
|
||||
|
||||
|
||||
#### forwardedRequestHeaders
|
||||
|
||||
@@ -19,7 +19,7 @@ Büyümeye hazır ekipler için:
|
||||
* Standart destek
|
||||
|
||||
<Note>
|
||||
Premium özellikler (SSO ve satır düzeyi izinler) Pro planına dahil değildir.
|
||||
Premium özellikler (SSO, satır düzeyi izinler ve Yapay Zeka kullanım verileri) Pro plana dahil değildir.
|
||||
</Note>
|
||||
|
||||
### Kuruluş (Bulut)
|
||||
@@ -27,7 +27,7 @@ Premium özellikler (SSO ve satır düzeyi izinler) Pro planına dahil değildir
|
||||
Gelişmiş ihtiyaçları olan daha büyük ekipler için:
|
||||
|
||||
* Pro'daki her şey
|
||||
* **Premium özellikler**: SSO entegrasyonu ve satır düzeyi izinler
|
||||
* **Premium özellikler**: SSO entegrasyonu, satır düzeyi izinler ve Yapay Zeka kullanım verileri
|
||||
* Öncelikli destek
|
||||
|
||||
## Kendi Kendine Barındırılan Planlar
|
||||
@@ -45,7 +45,7 @@ Twenty'yi kendi altyapınızda hiçbir ücret ödemeden barındırın:
|
||||
Kendi kendine barındırma yaparken premium özelliklere ihtiyaç duyan ekipler için:
|
||||
|
||||
* Tüm Pro özellikleri
|
||||
* **Premium özellikler**: SSO entegrasyonu ve satır düzeyi izinler
|
||||
* **Premium özellikler**: SSO entegrasyonu, satır düzeyi izinler ve Yapay Zeka kullanım verileri
|
||||
* Twenty ekibinden destek
|
||||
* Dağıtmadan önce özel kodu açık kaynak olarak yayınlama zorunluluğu yoktur.
|
||||
|
||||
@@ -55,6 +55,7 @@ Premium özellikler yalnızca Kuruluş planlarında (Bulut veya Kendi Kendine Ba
|
||||
|
||||
* **SSO entegrasyonu**: Kimlik sağlayıcınızla Tek Oturum Açma
|
||||
* **Satır düzeyi izinler**: Kayıt düzeyinde ayrıntılı erişim denetimi
|
||||
* **Yapay Zeka kullanım verileri**: Çalışma alanı genelinde Yapay Zeka tüketimini takip edin
|
||||
|
||||
## Planlar Arasında Geçiş
|
||||
|
||||
@@ -77,3 +78,15 @@ Planınızı düşürmek için destek ekibiyle iletişime geçin.
|
||||
### Aylığa Geçiş Yap
|
||||
|
||||
Aylık faturalamaya geri dönmek için destek ekibiyle iletişime geçin.
|
||||
|
||||
## Organizasyon (Kendi Sunucunuzda Barındırılan) için Kurumsal Anahtar edinin
|
||||
|
||||
Organizasyon (Kendi Sunucunuzda Barındırılan) planını kullanmak için bir Kurumsal Anahtar edinmeniz gerekir:
|
||||
|
||||
1. **Ayarlar → Yönetici Paneli → Kurumsal** bölümüne gidin
|
||||
|
||||
<img src="/images/user-guide/billing/enterprise-key.png" alt="Kurumsal Anahtar" />
|
||||
|
||||
2. **Kurumsal Anahtar Alın**'ı tıklayın
|
||||
3. Stripe'a yönlendirildiğinizde ödeme bilgilerinizi girin ve onaylayın
|
||||
4. Kurumsal anahtarınız görüntülendiğinde, bunu Kurumsal ayarlar sayfasına yapıştırın ve Organizasyon lisansını etkinleştirin
|
||||
|
||||
@@ -16,6 +16,11 @@ Kendiniz barındırmak istiyor ve Premium özelliklere (SSO ve satır düzeyi iz
|
||||
Premium özellikler yalnızca Kuruluş planlarında (Bulut veya Kendi Barındırmalı) kullanılabilir:
|
||||
* **SSO entegrasyonu**: Kimlik sağlayıcınızla Tek Oturum Açma
|
||||
* **Satır düzeyi izinler**: Kayıt düzeyinde ayrıntılı erişim denetimi
|
||||
* **Yapay Zeka kullanım verileri**: Çalışma alanı genelinde Yapay Zeka tüketimini takip edin
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Buluttaki Organization planı ile kendi barındırmalı ortamdaki Organization planı aynı mı?">
|
||||
İkisi de aynı Premium özellikleri sunar. Ancak bulut aboneliği, kendi barındırmalı dağıtımlarda kullanılamaz. Kendi barındırmalı kurulumlar için bir Enterprise anahtarı gerekir.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Salt görüntüleme kullanıcıları için ücretsiz koltuklar sunuyor musunuz?">
|
||||
|
||||
+34
-39
@@ -53,38 +53,45 @@ Bağlantı ilişkisi anahtarını etkinleştirdiğinizde, Twenty aradaki bağlan
|
||||
1. **Ayarlar → Veri Modeli** bölümüne gidin
|
||||
2. **+ Yeni nesne**'ye tıklayın
|
||||
3. Açıklayıcı bir ad verin (örn. "Project Assignment", "Team Member", "Product Order")
|
||||
4. **Kaydet**'e tıklayın
|
||||
4. "Ad alanı oluşturmayı atla" seçeneğini açın
|
||||
|
||||
<img src="/images/user-guide/fields/new-pivot-object.png" alt="Yeni pivot nesnesi" />
|
||||
|
||||
5. **Kaydet**'e tıklayın
|
||||
|
||||
<Tip>
|
||||
**Adlandırma kuralı**: "Project Assignment" veya "Team Membership" gibi ilişkiyi tanımlayan bir ad kullanın. Bu, veri modelinin anlaşılmasını kolaylaştırır.
|
||||
</Tip>
|
||||
|
||||
## Adım 2: Bağlantı Nesnesinden İlişkiler Oluşturun
|
||||
## Adım 2: Nesneler ile Bağlantı nesnesi arasında ilişkiler oluşturun
|
||||
|
||||
Bağlamak istediğiniz her iki nesneye de bağlantı nesnesinden ilişki alanları ekleyin.
|
||||
İki nesnenizin her birinden bağlantı nesnesine ilişki alanları ekleyin.
|
||||
|
||||
### İlk İlişki (Bağlantı → Nesne A)
|
||||
### İlk İlişki (Nesne A → Bağlantı)
|
||||
|
||||
1. **Ayarlar → Veri Modeli**'nde bağlantı nesnenizi seçin
|
||||
2. **+ Alan Ekle**'ye tıklayın
|
||||
3. Alan türü olarak **İlişki**'yi seçin
|
||||
4. İlk nesneyi seçin (örn. "People")
|
||||
5. İlişki türünü **Çoktan-Bire** olarak ayarlayın (birçok atama bir kişiye bağlanabilir)
|
||||
6. Alanları adlandırın:
|
||||
* Bağlantı üzerindeki alan: örn. "Person"
|
||||
* People üzerindeki alan: örn. "Project Assignments"
|
||||
7. **Kaydet**'e tıklayın
|
||||
|
||||
### İkinci İlişki (Bağlantı → Nesne B)
|
||||
|
||||
1. Hâlâ bağlantı nesnesindeyken, **+ Add Field**'e tıklayın
|
||||
2. Alan türü olarak **İlişki**'yi seçin
|
||||
3. İkinci nesneyi seçin (örn. "Projects")
|
||||
4. İlişki türünü **Çoktan-Bire** olarak ayarlayın
|
||||
1. İlk nesnenizi **Ayarlar → Veri Modeli**'nde seçin
|
||||
2. **+ İlişki Ekle**'ye tıklayın
|
||||
3. Bağlantı nesnesini seçin (örn. "Project Assignments")
|
||||
4. İlişki türünü **Birden-Çoğa** olarak ayarlayın (bir kişi birçok atamaya bağlanabilir)
|
||||
5. Alanları adlandırın:
|
||||
* People üzerindeki alan: örn. "Project Assignments"
|
||||
* Bağlantı üzerindeki alan: örn. "Person"
|
||||
6. **Kaydet**'e tıklayın
|
||||
|
||||
### İkinci İlişki (Nesne B → Bağlantı)
|
||||
|
||||
1. İkinci nesnenizi **Ayarlar → Veri Modeli**'nde seçin
|
||||
2. **+ İlişki Ekle**'ye tıklayın
|
||||
3. Bağlantı nesnesini seçin (örn. "Project Assignments")
|
||||
4. İlişki türünü **Birden-Çoğa** olarak ayarlayın (bir proje birçok atamaya bağlanabilir)
|
||||
5. **"Bu, bir bağlantı nesnesine kurulan bir ilişkidir"** seçeneğini etkinleştirin
|
||||
|
||||
<img src="/images/user-guide/fields/junction-relation-toggle.png" style={{width:'100%'}} />
|
||||
|
||||
6. Alanları adlandırın:
|
||||
* Bağlantı üzerindeki alan: örn. "Project"
|
||||
* Projects üzerindeki alan: örn. "Team Members"
|
||||
6. **Kaydet**'e tıklayın
|
||||
7. **Kaydet**'e tıklayın
|
||||
|
||||
## Adım 3: Bağlantı İlişkisi Görüntüsünü Yapılandırın
|
||||
|
||||
@@ -98,18 +105,6 @@ Bağlamak istediğiniz her iki nesneye de bağlantı nesnesinden ilişki alanlar
|
||||
6. **Hedef ilişki**yi seçin (örn. "Project" — bağlantı üzerindeki, diğer tarafı işaret eden alan)
|
||||
7. **Kaydet**'e tıklayın
|
||||
|
||||
{/* TODO: Add image
|
||||
<img src="/images/user-guide/fields/junction-relation-toggle.png" style={{width:'100%'}}/>
|
||||
*/}
|
||||
|
||||
Diğer nesne için tekrarlayın:
|
||||
|
||||
1. Veri Modeli'nde "Projects"i seçin
|
||||
2. "Team Members" ilişki alanını düzenleyin
|
||||
3. Bağlantı anahtarını etkinleştirin
|
||||
4. Hedef ilişki olarak "Person"ı seçin
|
||||
5. Kaydet
|
||||
|
||||
## Sonuç
|
||||
|
||||
Yapılandırmadan sonra:
|
||||
@@ -130,15 +125,15 @@ Bağlantı nesnesi hâlâ mevcuttur ve bağlantıları saklar, ancak kullanıcı
|
||||
|
||||
### İlişkiler Ekleyin
|
||||
|
||||
1. **Project Assignment → People**
|
||||
* Tür: Çoktan-Bire
|
||||
* Assignment üzerindeki alan: "Person"
|
||||
1. **People → Project Assignment**
|
||||
* Tür: Birden-Çoğa
|
||||
* People üzerindeki alan: "Project Assignments"
|
||||
* Assignment üzerindeki alan: "Person"
|
||||
|
||||
2. **Project Assignment → Projects**
|
||||
* Tür: Çoktan-Bire
|
||||
* Assignment üzerindeki alan: "Project"
|
||||
2. **Projects → Project Assignment**
|
||||
* Tür: Birden-Çoğa
|
||||
* Projects üzerindeki alan: "Team Members"
|
||||
* Assignment üzerindeki alan: "Project"
|
||||
|
||||
### Bağlantı Görüntüsünü Yapılandırın
|
||||
|
||||
|
||||
@@ -30,3 +30,9 @@ Harici araçlara yönelik bağlantıları doğrudan kenar çubuğuna ekleyin. Wi
|
||||
## Komut Menüsü
|
||||
|
||||
Komut menüsünü açmak için `Cmd+K` (veya `Ctrl+K`) tuşlarına basın — kenar çubuğunda gezinmeden herhangi bir kayda, görünüme veya eyleme atlamak için hızlı erişim sunan bir arama çubuğu.
|
||||
|
||||
## Kenar Çubuğunu Özelleştirme
|
||||
|
||||
Kenar çubuğunu özelleştirmek için kenar çubuğundaki "Workspace" bölümünün üzerine gelin ve anahtar simgesine tıklayın.
|
||||
|
||||
<img src="/images/user-guide/layout/navigation-edit-icon.png" alt="Gezinti düzenleme simgesi" />
|
||||
|
||||
@@ -3,6 +3,8 @@ title: Kayıt Sayfaları
|
||||
description: Her bir kayıt ayrıntı sayfasının düzenini sekmeler ve widget'larla özelleştirin.
|
||||
---
|
||||
|
||||
## Genel Bakış
|
||||
|
||||
Twenty'de bir kaydı açtığınızda, ayrıntı sayfası **sekmeler** ve **widget'lar** içerir. Her ikisi de her nesne türü bazında tamamen özelleştirilebilir.
|
||||
|
||||
## Sekmeler
|
||||
@@ -38,12 +40,20 @@ Widget'lar, her sekmenin içindeki yapı taşlarıdır. Kullanılabilir widget t
|
||||
|
||||
1. Herhangi bir kaydı açın
|
||||
2. `Cmd+K` tuşlarına basın ve "Kayıt sayfası yerleşimini düzenle" ifadesini arayın
|
||||
|
||||
veya
|
||||
|
||||
1. Ayarlar > Veri modeli > seçtiğiniz nesne > Düzen'e gidin
|
||||
|
||||
2. O nesne için "Kayıt sayfasını özelleştir" düğmesine tıklayın
|
||||
|
||||
3. Artık özelleştirme modundasınız:
|
||||
* **Widget ekleyin** widget seçicisinden
|
||||
* **Widget'ları sürükleyin** ve ızgara üzerinde yeniden konumlandırın
|
||||
* **Widget'ları yeniden boyutlandırın** kenarlarını sürükleyerek
|
||||
* **Alanları yapılandırın** — her bir widget içinde gösterilen
|
||||
* **Sekmeleri yönetin** — ekleyin, kaldırın, yeniden adlandırın, yeniden sıralayın
|
||||
|
||||
4. Değişikliklerinizi kaydedin — bu değişiklikler o nesne türündeki tüm kayıtlara uygulanır
|
||||
|
||||
## Alan görünürlüğü
|
||||
|
||||
@@ -95,15 +95,16 @@ const handler = async (event: RoutePayload) => {
|
||||
|
||||
`RoutePayload` 类型具有以下结构:
|
||||
|
||||
| 属性 | 类型 | 描述 | 示例 |
|
||||
| ---------------------------- | ------------------------------------------------------- | --------------------------------------------- | -------------------------------------------------------------------------- |
|
||||
| `headers` | `Record\<string, string \| undefined>` | HTTP 请求头(仅限 `forwardedRequestHeaders` 中列出的那些) | 见下文 |
|
||||
| `queryStringParameters` | `Record\<string, string \| undefined>` | 查询字符串参数(多个值以逗号连接) | `/users?ids=1&ids=2&ids=3&name=Alice` -> `{ ids: '1,2,3', name: 'Alice' }` |
|
||||
| `pathParameters` | `Record\<string, string \| undefined>` | 从路由模式中提取的路径参数 | `/users/:id`,`/users/123` -> `{ id: '123' }` |
|
||||
| `body` | `object \| null` | 已解析的请求体(JSON) | `{ id: 1 }` -> `{ id: 1 }` |
|
||||
| `isBase64Encoded` | `boolean` | 请求体是否为 base64 编码 | |
|
||||
| `requestContext.http.method` | `string` | HTTP 方法(GET、POST、PUT、PATCH、DELETE) | |
|
||||
| `requestContext.http.path` | `string` | 原始请求路径 | |
|
||||
| 属性 | 类型 | 描述 | 示例 |
|
||||
| ---------------------------- | ------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- |
|
||||
| `headers` | `Record\<string, string \| undefined>` | HTTP 请求头(仅限 `forwardedRequestHeaders` 中列出的那些) | 见下文 |
|
||||
| `queryStringParameters` | `Record\<string, string \| undefined>` | 查询字符串参数(多个值以逗号连接) | `/users?ids=1&ids=2&ids=3&name=Alice` -> `{ ids: '1,2,3', name: 'Alice' }` |
|
||||
| `pathParameters` | `Record\<string, string \| undefined>` | 从路由模式中提取的路径参数 | `/users/:id`,`/users/123` -> `{ id: '123' }` |
|
||||
| `body` | `object \| null` | 已解析的请求体(JSON) | `{ id: 1 }` -> `{ id: 1 }` |
|
||||
| `rawBody` | `string \| undefined` | 在 JSON 解析之前的原始 UTF-8 请求体。 用于验证 HMAC 风格的 Webhook 签名(例如 GitHub 的 `X-Hub-Signature-256`、Stripe)。 当运行时未保留它时为 `undefined`。 | |
|
||||
| `isBase64Encoded` | `boolean` | 请求体是否为 base64 编码 | |
|
||||
| `requestContext.http.method` | `string` | HTTP 方法(GET、POST、PUT、PATCH、DELETE) | |
|
||||
| `requestContext.http.path` | `string` | 原始请求路径 | |
|
||||
|
||||
|
||||
#### forwardedRequestHeaders
|
||||
|
||||
@@ -19,7 +19,7 @@ description: 了解 Twenty 的定价方案以及如何在它们之间切换。
|
||||
* 标准支持
|
||||
|
||||
<Note>
|
||||
Pro 计划不包含高级功能(SSO 和行级权限)。
|
||||
Pro 方案不包含高级功能(SSO、行级权限和 AI 使用数据)。
|
||||
</Note>
|
||||
|
||||
### 组织计划(云端)
|
||||
@@ -27,7 +27,7 @@ Pro 计划不包含高级功能(SSO 和行级权限)。
|
||||
适用于具有高级需求的大型团队:
|
||||
|
||||
* 包含 Pro 的全部内容
|
||||
* **高级功能**:SSO 集成和行级权限
|
||||
* **高级功能**:SSO 集成、行级权限和 AI 使用数据
|
||||
* 优先支持
|
||||
|
||||
## 自托管方案
|
||||
@@ -45,7 +45,7 @@ Pro 计划不包含高级功能(SSO 和行级权限)。
|
||||
适用于在自托管同时需要高级功能的团队:
|
||||
|
||||
* 所有 Pro 功能
|
||||
* **高级功能**:SSO 集成和行级权限
|
||||
* **高级功能**:SSO 集成、行级权限和 AI 使用数据
|
||||
* Twenty 团队支持
|
||||
* 分发前无需将自定义代码开源
|
||||
|
||||
@@ -55,6 +55,7 @@ Pro 计划不包含高级功能(SSO 和行级权限)。
|
||||
|
||||
* **SSO 集成**:与您的身份提供商进行单点登录
|
||||
* **行级权限**:在记录级别进行细粒度访问控制
|
||||
* **AI 使用数据**:在整个工作区跟踪 AI 消耗
|
||||
|
||||
## 切换计划
|
||||
|
||||
@@ -77,3 +78,15 @@ Pro 计划不包含高级功能(SSO 和行级权限)。
|
||||
### 切换为按月计费
|
||||
|
||||
联系支持以切换回按月计费。
|
||||
|
||||
## 为 Organization (Self-Hosted) 获取企业密钥
|
||||
|
||||
要使用 Organization (Self-Hosted) 方案,您需要获取企业密钥:
|
||||
|
||||
1. 转到 **设置 → 管理员面板 → 企业版**
|
||||
|
||||
<img src="/images/user-guide/billing/enterprise-key.png" alt="企业密钥" />
|
||||
|
||||
2. 单击 **获取企业密钥**
|
||||
3. 当您被重定向到 Stripe 时,输入您的付款信息并确认
|
||||
4. 当显示出您的企业密钥时,将其粘贴到企业版设置页面并激活 Organization 许可证
|
||||
|
||||
@@ -16,6 +16,11 @@ description: 关于 Twenty 定价和账单的常见问题。
|
||||
高级功能仅适用于 Organization 计划(云端或自托管):
|
||||
* **SSO 集成**:与您的身份提供商进行单点登录
|
||||
* **行级权限**:在记录级别进行细粒度的访问控制
|
||||
* **AI 使用数据**:在整个工作区跟踪 AI 消耗
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="云端的 Organization 计划与自托管的 Organization 计划是否相同?">
|
||||
它们提供相同的高级功能。 但是,云端订阅不能用于自托管部署。 自托管需要 Enterprise 密钥。
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="你们是否为只读用户提供免费席位?">
|
||||
|
||||
+34
-39
@@ -53,38 +53,45 @@ People ←→ Project Assignments ←→ Projects
|
||||
1. 进入 **设置 → 数据模型**
|
||||
2. 点击 **+ 新建对象**
|
||||
3. 使用描述性名称(例如,"Project Assignment"、"Team Member"、"Product Order")
|
||||
4. 单击 **保存**
|
||||
4. 将“跳过创建名称字段”切换为开启
|
||||
|
||||
<img src="/images/user-guide/fields/new-pivot-object.png" alt="新建连接对象" />
|
||||
|
||||
5. 单击 **保存**
|
||||
|
||||
<Tip>
|
||||
**命名约定**:使用能描述关系的名称,例如 "Project Assignment" 或 "Team Membership"。 这会让数据模型更易理解。
|
||||
</Tip>
|
||||
|
||||
## 步骤 2:从连接对象创建关系
|
||||
## 第 2 步:在对象与连接对象之间创建关系
|
||||
|
||||
从连接对象向您要连接的两个对象添加关系字段。
|
||||
从您的两个对象分别向连接对象添加关系字段。
|
||||
|
||||
### 第一条关系(连接对象 → 对象 A)
|
||||
### 第一条关系(对象 A → 连接对象)
|
||||
|
||||
1. 在 **Settings → Data Model** 中选择您的连接对象
|
||||
2. 点击 **+ 添加字段**
|
||||
3. 将字段类型选择为 **Relation**
|
||||
4. 选择第一个对象(例如,"People")
|
||||
5. 将关系类型设置为 **Many-to-One**(多个分配可关联到一个人)
|
||||
6. 为这些字段命名:
|
||||
* 连接对象上的字段:例如,"Person"
|
||||
* People 上的字段:例如,"Project Assignments"
|
||||
7. 单击 **保存**
|
||||
|
||||
### 第二条关系(连接对象 → 对象 B)
|
||||
|
||||
1. 仍在连接对象中,点击 **+ Add Field**
|
||||
2. 将字段类型选择为 **Relation**
|
||||
3. 选择第二个对象(例如,"Projects")
|
||||
4. 将关系类型设置为 **Many-to-One**
|
||||
1. 在 **Settings → Data Model** 中选择您的第一个对象
|
||||
2. 单击 **+ 添加关系**
|
||||
3. 选择连接对象(例如,"Project Assignments")
|
||||
4. 将关系类型设置为 **One-To-Many**(一个人可以关联到多个分配)
|
||||
5. 为这些字段命名:
|
||||
* People 上的字段:例如,"Project Assignments"
|
||||
* 连接对象上的字段:例如,"Person"
|
||||
6. 单击 **保存**
|
||||
|
||||
### 第二条关系(对象 B → 连接对象)
|
||||
|
||||
1. 在 **Settings → Data Model** 中选择您的第二个对象
|
||||
2. 单击 **+ 添加关系**
|
||||
3. 选择连接对象(例如,"Project Assignments")
|
||||
4. 将关系类型设置为 **One-To-Many**(一个项目可以关联到多个分配)
|
||||
5. 启用 **"This is a relation to a Junction Object"**
|
||||
|
||||
<img src="/images/user-guide/fields/junction-relation-toggle.png" style={{width:'100%'}} />
|
||||
|
||||
6. 为这些字段命名:
|
||||
* 连接对象上的字段:例如,"Project"
|
||||
* Projects 上的字段:例如,"Team Members"
|
||||
6. 单击 **保存**
|
||||
7. 单击 **保存**
|
||||
|
||||
## 步骤 3:配置连接关系的显示方式
|
||||
|
||||
@@ -98,18 +105,6 @@ People ←→ Project Assignments ←→ Projects
|
||||
6. 选择 **Target relation**(例如,"Project" —— 连接对象上指向另一侧的字段)
|
||||
7. 单击 **保存**
|
||||
|
||||
{/* TODO: Add image
|
||||
<img src="/images/user-guide/fields/junction-relation-toggle.png" style={{width:'100%'}}/>
|
||||
*/}
|
||||
|
||||
对另一侧对象重复上述操作:
|
||||
|
||||
1. 在 Data Model 中选择 "Projects"
|
||||
2. 编辑 "Team Members" 关系字段
|
||||
3. 启用连接关系开关
|
||||
4. 将目标关系选择为 "Person"
|
||||
5. 保存
|
||||
|
||||
## 结果
|
||||
|
||||
配置完成后:
|
||||
@@ -130,15 +125,15 @@ People ←→ Project Assignments ←→ Projects
|
||||
|
||||
### 添加关系
|
||||
|
||||
1. **Project Assignment → People**
|
||||
* 类型:Many-to-One
|
||||
* Assignment 上的字段:"Person"
|
||||
1. **People → Project Assignment**
|
||||
* 类型:One-to-Many
|
||||
* People 上的字段:"Project Assignments"
|
||||
* Assignment 上的字段:"Person"
|
||||
|
||||
2. **Project Assignment → Projects**
|
||||
* 类型:Many-to-One
|
||||
* Assignment 上的字段:"Project"
|
||||
2. **Projects → Project Assignment**
|
||||
* 类型:One-to-Many
|
||||
* Projects 上的字段:"Team Members"
|
||||
* Assignment 上的字段:"Project"
|
||||
|
||||
### 配置连接关系显示
|
||||
|
||||
|
||||
@@ -30,3 +30,9 @@ description: 自定义左侧边栏,使其符合您团队的工作方式。
|
||||
## 命令菜单
|
||||
|
||||
按下`Cmd+K`(或`Ctrl+K`)打开命令菜单——一个快速访问的搜索栏,无需通过侧边栏即可跳转到任何记录、视图或操作。
|
||||
|
||||
## 自定义侧边栏
|
||||
|
||||
要自定义侧边栏,请将鼠标悬停在侧边栏中的"工作区"部分,然后单击扳手图标。
|
||||
|
||||
<img src="/images/user-guide/layout/navigation-edit-icon.png" alt="导航编辑图标" />
|
||||
|
||||
@@ -3,6 +3,8 @@ title: 记录页面
|
||||
description: 使用选项卡和小部件自定义单个记录详情页的布局。
|
||||
---
|
||||
|
||||
## 概览
|
||||
|
||||
当你在 Twenty 中打开一条记录时,详情页由**选项卡**和**小部件**组成。 两者都可按对象类型完全自定义。
|
||||
|
||||
## 选项卡
|
||||
@@ -38,12 +40,20 @@ description: 使用选项卡和小部件自定义单个记录详情页的布局
|
||||
|
||||
1. 打开任意记录
|
||||
2. 按下 `Cmd+K`,搜索“编辑记录页面布局”
|
||||
|
||||
或
|
||||
|
||||
1. 前往 设置 > 数据模型 > 所选对象 > 布局
|
||||
|
||||
2. 单击该对象的“自定义记录页面”按钮
|
||||
|
||||
3. 你现在处于自定义模式:
|
||||
* 从小部件选择器中**添加小部件**
|
||||
* **拖动小部件**,在网格上重新定位它们
|
||||
* **调整小部件大小**,通过拖动其边缘
|
||||
* **配置字段**,设置每个小部件内显示的字段
|
||||
* **管理选项卡** — 添加、删除、重命名、重新排序
|
||||
|
||||
4. 保存你的更改—它们将应用于该对象类型的所有记录
|
||||
|
||||
## 字段可见性
|
||||
|
||||
@@ -17,13 +17,13 @@ For teams ready to scale:
|
||||
- Standard support
|
||||
|
||||
<Note>
|
||||
Premium features (SSO and row-level permissions) are not included in the Pro plan.
|
||||
Premium features (SSO, row-level permissions and AI usage data) are not included in the Pro plan.
|
||||
</Note>
|
||||
|
||||
### Organization (Cloud)
|
||||
For larger teams with advanced needs:
|
||||
- Everything in Pro
|
||||
- **Premium features**: SSO integration and row-level permissions
|
||||
- **Premium features**: SSO integration, row-level permissions and AI usage data
|
||||
- Priority support
|
||||
|
||||
## Self-Hosted Plans
|
||||
@@ -37,7 +37,7 @@ Host Twenty on your own infrastructure at no cost:
|
||||
### Organization (Self-Hosted)
|
||||
For teams who need premium features while self-hosting:
|
||||
- All Pro features
|
||||
- **Premium features**: SSO integration and row-level permissions
|
||||
- **Premium features**: SSO integration, row-level permissions and AI usage data
|
||||
- Twenty team support
|
||||
- No requirement to publish custom code as open-source before distributing
|
||||
|
||||
@@ -46,6 +46,7 @@ For teams who need premium features while self-hosting:
|
||||
Premium features are only available on the Organization plans (Cloud or Self-Hosted):
|
||||
- **SSO integration**: Single Sign-On with your identity provider
|
||||
- **Row-level permissions**: Fine-grained access control at the record level
|
||||
- **AI usage data**: Track AI consumption across the workspace
|
||||
|
||||
## Switching Plans
|
||||
|
||||
@@ -65,3 +66,15 @@ Contact support to downgrade your plan.
|
||||
### Switch to Monthly Billing
|
||||
Contact support to switch back to monthly billing.
|
||||
|
||||
## Obtain an Enterprise Key for Organization (Self-Hosted)
|
||||
|
||||
To use the Organization (Self-Hosted) plan, you need to obtain an Enterprise key:
|
||||
|
||||
1. Go to **Settings → Admin Panel → Enterprise**
|
||||
|
||||
<img src="/images/user-guide/billing/enterprise-key.png" alt="Enterprise key" />
|
||||
|
||||
2. Click **Get Enterprise Key**
|
||||
3. When you are redirected to Stripe, enter your payment details and confirm
|
||||
4. When your Enterprise key is displayed, paste it into the Enterprise settings page and activate the Organization license
|
||||
|
||||
|
||||
@@ -16,6 +16,11 @@ If you want to self-host and need the Premium features (SSO and row-level permis
|
||||
Premium features are only available on the Organization plans (Cloud or Self-Hosted):
|
||||
- **SSO integration**: Single Sign-On with your identity provider
|
||||
- **Row-level permissions**: Fine-grained access control at the record level
|
||||
- **AI usage data**: Track AI consumption across the workspace
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Is Organization plan on cloud and Organization plan on self-hosted the same?">
|
||||
They offer the same premium features. However, a cloud subscription cannot be used for self-hosted deployments. Self-hosted requires an Enterprise key.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Do you offer free seats for view-only users?">
|
||||
|
||||
+34
-39
@@ -52,38 +52,45 @@ First, create the intermediate object that will hold the connections.
|
||||
1. Go to **Settings → Data Model**
|
||||
2. Click **+ New object**
|
||||
3. Name it descriptively (e.g., "Project Assignment", "Team Member", "Product Order")
|
||||
4. Click **Save**
|
||||
4. Toggle "Skip creating a Name field" on
|
||||
|
||||
<img src="/images/user-guide/fields/new-pivot-object.png" alt="New pivot object" />
|
||||
|
||||
5. Click **Save**
|
||||
|
||||
<Tip>
|
||||
**Naming convention**: Use a name that describes the relationship, like "Project Assignment" or "Team Membership". This makes the data model easier to understand.
|
||||
</Tip>
|
||||
|
||||
## Step 2: Create Relations from the Junction Object
|
||||
## Step 2: Create Relations Between Objects and the Junction
|
||||
|
||||
Add relation fields from the junction object to both objects you want to connect.
|
||||
Add relation fields from each of your two objects to the junction object.
|
||||
|
||||
### First Relation (Junction → Object A)
|
||||
### First Relation (Object A → Junction)
|
||||
|
||||
1. Select your junction object in **Settings → Data Model**
|
||||
2. Click **+ Add Field**
|
||||
3. Choose **Relation** as the field type
|
||||
4. Select the first object (e.g., "People")
|
||||
5. Set the relation type to **Many-to-One** (many assignments can link to one person)
|
||||
6. Name the fields:
|
||||
- Field on junction: e.g., "Person"
|
||||
- Field on People: e.g., "Project Assignments"
|
||||
7. Click **Save**
|
||||
|
||||
### Second Relation (Junction → Object B)
|
||||
|
||||
1. Still on the junction object, click **+ Add Field**
|
||||
2. Choose **Relation** as the field type
|
||||
3. Select the second object (e.g., "Projects")
|
||||
4. Set the relation type to **Many-to-One**
|
||||
1. Select your first object in **Settings → Data Model**
|
||||
2. Click **+ Add Relation**
|
||||
3. Select the junction object (e.g., "Project Assignments")
|
||||
4. Set the relation type to **One-To-Many** (one person can link to many assignments)
|
||||
5. Name the fields:
|
||||
- Field on People: e.g., "Project Assignments"
|
||||
- Field on junction: e.g., "Person"
|
||||
6. Click **Save**
|
||||
|
||||
### Second Relation (Object B → Junction)
|
||||
|
||||
1. Select your second object in **Settings → Data Model**
|
||||
2. Click **+ Add Relation**
|
||||
3. Select the junction object (e.g., "Project Assignments")
|
||||
4. Set the relation type to **One-To-Many** (one project can link to many assignments)
|
||||
5. Enable **"This is a relation to a Junction Object"**
|
||||
|
||||
<img src="/images/user-guide/fields/junction-relation-toggle.png" style={{width:'100%'}}/>
|
||||
|
||||
6. Name the fields:
|
||||
- Field on junction: e.g., "Project"
|
||||
- Field on Projects: e.g., "Team Members"
|
||||
6. Click **Save**
|
||||
7. Click **Save**
|
||||
|
||||
## Step 3: Configure the Junction Relation Display
|
||||
|
||||
@@ -97,18 +104,6 @@ Now configure the source objects to display linked records directly, skipping th
|
||||
6. Select the **Target relation** (e.g., "Project" — the field on the junction that points to the other side)
|
||||
7. Click **Save**
|
||||
|
||||
|
||||
{/* TODO: Add image
|
||||
<img src="/images/user-guide/fields/junction-relation-toggle.png" style={{width:'100%'}}/>
|
||||
*/}
|
||||
|
||||
Repeat for the other object:
|
||||
1. Select "Projects" in Data Model
|
||||
2. Edit the "Team Members" relation field
|
||||
3. Enable the junction toggle
|
||||
4. Select "Person" as the target relation
|
||||
5. Save
|
||||
|
||||
## Result
|
||||
|
||||
After configuration:
|
||||
@@ -127,15 +122,15 @@ Here's a complete walkthrough:
|
||||
- Description: "Links people to projects they work on"
|
||||
|
||||
### Add Relations
|
||||
1. **Project Assignment → People**
|
||||
- Type: Many-to-One
|
||||
- Field on Assignment: "Person"
|
||||
1. **People → Project Assignment**
|
||||
- Type: One-to-Many
|
||||
- Field on People: "Project Assignments"
|
||||
- Field on Assignment: "Person"
|
||||
|
||||
2. **Project Assignment → Projects**
|
||||
- Type: Many-to-One
|
||||
- Field on Assignment: "Project"
|
||||
2. **Projects → Project Assignment**
|
||||
- Type: One-to-Many
|
||||
- Field on Projects: "Team Members"
|
||||
- Field on Assignment: "Project"
|
||||
|
||||
### Configure Junction Display
|
||||
1. On **People** object:
|
||||
|
||||
@@ -30,3 +30,9 @@ Add links to external tools directly in the sidebar. Useful for linking to your
|
||||
## Command menu
|
||||
|
||||
Press `Cmd+K` (or `Ctrl+K`) to open the command menu — a quick-access search bar for jumping to any record, view, or action without navigating the sidebar.
|
||||
|
||||
## Customizing the sidebar
|
||||
|
||||
To customize the sidebar, hover over the "Workspace" section in the sidebar and click the wrench icon.
|
||||
|
||||
<img src="/images/user-guide/layout/navigation-edit-icon.png" alt="Navigation edit icon" />
|
||||
@@ -3,6 +3,8 @@ title: Record Pages
|
||||
description: Customize the layout of individual record detail pages with tabs and widgets.
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
When you open a record in Twenty, the detail page is composed of **tabs** and **widgets**. Both are fully customizable per object type.
|
||||
|
||||
## Tabs
|
||||
@@ -37,6 +39,12 @@ Widgets are the building blocks inside each tab. Available widget types include:
|
||||
|
||||
1. Open any record
|
||||
2. Press `Cmd+K` and search for "Edit record page layout"
|
||||
|
||||
or
|
||||
|
||||
1. Go to Settings > Data model > object of your choice > Layout
|
||||
2. Click the "Customize record page" button for that object
|
||||
|
||||
3. You're now in customization mode:
|
||||
- **Add widgets** from the widget picker
|
||||
- **Drag widgets** to reposition them on the grid
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { setupI18n, type I18n, type Messages } from '@lingui/core';
|
||||
import { type Messages } from '@lingui/core';
|
||||
import { createI18nInstanceFactory } from 'twenty-shared/i18n';
|
||||
import { type APP_LOCALES } from 'twenty-shared/translations';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { messages as afMessages } from '@/locales/generated/af-ZA';
|
||||
import { messages as arMessages } from '@/locales/generated/ar-SA';
|
||||
import { messages as caMessages } from '@/locales/generated/ca-ES';
|
||||
@@ -67,20 +67,4 @@ const messages: Record<keyof typeof APP_LOCALES, Messages> = {
|
||||
'zh-TW': zhHantMessages,
|
||||
};
|
||||
|
||||
const i18nInstancesMap: Partial<Record<keyof typeof APP_LOCALES, I18n>> = {};
|
||||
|
||||
export const createI18nInstance = (locale: keyof typeof APP_LOCALES): I18n => {
|
||||
if (isDefined(i18nInstancesMap[locale])) {
|
||||
return i18nInstancesMap[locale];
|
||||
}
|
||||
|
||||
const i18nInstance = setupI18n();
|
||||
const localeMessages = messages[locale] ?? messages.en;
|
||||
|
||||
i18nInstance.load(locale, localeMessages);
|
||||
i18nInstance.activate(locale);
|
||||
|
||||
i18nInstancesMap[locale] = i18nInstance;
|
||||
|
||||
return i18nInstance;
|
||||
};
|
||||
export const createI18nInstance = createI18nInstanceFactory(messages);
|
||||
|
||||
@@ -10,6 +10,10 @@ export type SerializedEventData = {
|
||||
pageY?: number;
|
||||
screenX?: number;
|
||||
screenY?: number;
|
||||
offsetX?: number;
|
||||
offsetY?: number;
|
||||
movementX?: number;
|
||||
movementY?: number;
|
||||
button?: number;
|
||||
buttons?: number;
|
||||
key?: string;
|
||||
|
||||
@@ -81,6 +81,12 @@ const serializeEvent = (event: unknown): SerializedEventData => {
|
||||
if ('pageY' in domEvent) serialized.pageY = domEvent.pageY as number;
|
||||
if ('screenX' in domEvent) serialized.screenX = domEvent.screenX as number;
|
||||
if ('screenY' in domEvent) serialized.screenY = domEvent.screenY as number;
|
||||
if ('offsetX' in domEvent) serialized.offsetX = domEvent.offsetX as number;
|
||||
if ('offsetY' in domEvent) serialized.offsetY = domEvent.offsetY as number;
|
||||
if ('movementX' in domEvent)
|
||||
serialized.movementX = domEvent.movementX as number;
|
||||
if ('movementY' in domEvent)
|
||||
serialized.movementY = domEvent.movementY as number;
|
||||
if ('button' in domEvent) serialized.button = domEvent.button as number;
|
||||
if ('buttons' in domEvent) serialized.buttons = domEvent.buttons as number;
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "NODE_ENV=production NODE_OPTIONS=--max-old-space-size=8192 npx vite build && sh ./scripts/inject-runtime-env.sh",
|
||||
"build:sourcemaps": "NODE_ENV=production VITE_BUILD_SOURCEMAP=true NODE_OPTIONS=--max-old-space-size=8192 npx vite build && sh ./scripts/inject-runtime-env.sh",
|
||||
"build": "NODE_ENV=production NODE_OPTIONS=--max-old-space-size=8192 npx vite build",
|
||||
"build:sourcemaps": "NODE_ENV=production VITE_BUILD_SOURCEMAP=true NODE_OPTIONS=--max-old-space-size=8192 npx vite build",
|
||||
"start:prod": "NODE_ENV=production npx serve -s build",
|
||||
"tsup": "npx tsup"
|
||||
},
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ -z "$REACT_APP_SERVER_BASE_URL" ]; then
|
||||
echo "Error: REACT_APP_SERVER_BASE_URL is not set."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Injecting runtime environment variables into index.html..."
|
||||
|
||||
CONFIG_BLOCK=$(cat << EOF
|
||||
|
||||
@@ -18,6 +18,4 @@ const getDefaultUrl = () => {
|
||||
};
|
||||
|
||||
export const REACT_APP_SERVER_BASE_URL =
|
||||
window._env_?.REACT_APP_SERVER_BASE_URL ||
|
||||
process.env.REACT_APP_SERVER_BASE_URL ||
|
||||
getDefaultUrl();
|
||||
window._env_?.REACT_APP_SERVER_BASE_URL || getDefaultUrl();
|
||||
|
||||
@@ -83,19 +83,21 @@ export enum AdminPanelHealthServiceStatus {
|
||||
|
||||
export type AdminPanelRecentUser = {
|
||||
__typename?: 'AdminPanelRecentUser';
|
||||
avatarUrl?: Maybe<Scalars['String']>;
|
||||
createdAt: Scalars['DateTime'];
|
||||
email: Scalars['String'];
|
||||
firstName?: Maybe<Scalars['String']>;
|
||||
id: Scalars['UUID'];
|
||||
lastName?: Maybe<Scalars['String']>;
|
||||
workspaceId?: Maybe<Scalars['UUID']>;
|
||||
workspaceLogo?: Maybe<Scalars['String']>;
|
||||
workspaceName?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type AdminPanelTopWorkspace = {
|
||||
__typename?: 'AdminPanelTopWorkspace';
|
||||
id: Scalars['UUID'];
|
||||
logo?: Maybe<Scalars['String']>;
|
||||
logoUrl?: Maybe<Scalars['String']>;
|
||||
name: Scalars['String'];
|
||||
subdomain: Scalars['String'];
|
||||
totalUsers: Scalars['Int'];
|
||||
@@ -666,6 +668,7 @@ export type UsageBreakdownItem = {
|
||||
|
||||
export type UserInfo = {
|
||||
__typename?: 'UserInfo';
|
||||
avatarUrl?: Maybe<Scalars['String']>;
|
||||
createdAt: Scalars['DateTime'];
|
||||
email: Scalars['String'];
|
||||
firstName?: Maybe<Scalars['String']>;
|
||||
@@ -829,7 +832,7 @@ export type GetModelsDevSuggestionsQuery = { __typename?: 'Query', getModelsDevS
|
||||
export type FindAllApplicationRegistrationsQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type FindAllApplicationRegistrationsQuery = { __typename?: 'Query', findAllApplicationRegistrations: Array<{ __typename?: 'ApplicationRegistration', id: string, universalIdentifier: string, name: string, oAuthClientId: string, oAuthRedirectUris: Array<string>, oAuthScopes: Array<string>, sourceType: ApplicationRegistrationSourceType, sourcePackage?: string | null, latestAvailableVersion?: string | null, isListed: boolean, isFeatured: boolean, isPreInstalled: boolean, ownerWorkspaceId?: string | null, createdAt: string, updatedAt: string }> };
|
||||
export type FindAllApplicationRegistrationsQuery = { __typename?: 'Query', findAllApplicationRegistrations: Array<{ __typename?: 'ApplicationRegistration', id: string, universalIdentifier: string, name: string, logoUrl?: string | null, oAuthClientId: string, oAuthRedirectUris: Array<string>, oAuthScopes: Array<string>, sourceType: ApplicationRegistrationSourceType, sourcePackage?: string | null, latestAvailableVersion?: string | null, isListed: boolean, isFeatured: boolean, isPreInstalled: boolean, ownerWorkspaceId?: string | null, createdAt: string, updatedAt: string }> };
|
||||
|
||||
export type CreateDatabaseConfigVariableMutationVariables = Exact<{
|
||||
key: Scalars['String'];
|
||||
@@ -882,21 +885,21 @@ export type AdminPanelRecentUsersQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type AdminPanelRecentUsersQuery = { __typename?: 'Query', adminPanelRecentUsers: Array<{ __typename?: 'AdminPanelRecentUser', id: string, email: string, firstName?: string | null, lastName?: string | null, createdAt: string, workspaceName?: string | null, workspaceId?: string | null }> };
|
||||
export type AdminPanelRecentUsersQuery = { __typename?: 'Query', adminPanelRecentUsers: Array<{ __typename?: 'AdminPanelRecentUser', id: string, email: string, firstName?: string | null, lastName?: string | null, avatarUrl?: string | null, createdAt: string, workspaceName?: string | null, workspaceId?: string | null, workspaceLogo?: string | null }> };
|
||||
|
||||
export type AdminPanelTopWorkspacesQueryVariables = Exact<{
|
||||
searchTerm?: InputMaybe<Scalars['String']>;
|
||||
}>;
|
||||
|
||||
|
||||
export type AdminPanelTopWorkspacesQuery = { __typename?: 'Query', adminPanelTopWorkspaces: Array<{ __typename?: 'AdminPanelTopWorkspace', id: string, name: string, totalUsers: number, subdomain: string, logo?: string | null }> };
|
||||
export type AdminPanelTopWorkspacesQuery = { __typename?: 'Query', adminPanelTopWorkspaces: Array<{ __typename?: 'AdminPanelTopWorkspace', id: string, logoUrl?: string | null, name: string, totalUsers: number, subdomain: string }> };
|
||||
|
||||
export type FindOneAdminApplicationRegistrationQueryVariables = Exact<{
|
||||
id: Scalars['String'];
|
||||
}>;
|
||||
|
||||
|
||||
export type FindOneAdminApplicationRegistrationQuery = { __typename?: 'Query', findOneAdminApplicationRegistration: { __typename?: 'ApplicationRegistration', id: string, universalIdentifier: string, name: string, oAuthClientId: string, oAuthRedirectUris: Array<string>, oAuthScopes: Array<string>, sourceType: ApplicationRegistrationSourceType, sourcePackage?: string | null, latestAvailableVersion?: string | null, isListed: boolean, isFeatured: boolean, isPreInstalled: boolean, ownerWorkspaceId?: string | null, createdAt: string, updatedAt: string } };
|
||||
export type FindOneAdminApplicationRegistrationQuery = { __typename?: 'Query', findOneAdminApplicationRegistration: { __typename?: 'ApplicationRegistration', id: string, universalIdentifier: string, name: string, logoUrl?: string | null, oAuthClientId: string, oAuthRedirectUris: Array<string>, oAuthScopes: Array<string>, sourceType: ApplicationRegistrationSourceType, sourcePackage?: string | null, latestAvailableVersion?: string | null, isListed: boolean, isFeatured: boolean, isPreInstalled: boolean, ownerWorkspaceId?: string | null, createdAt: string, updatedAt: string } };
|
||||
|
||||
export type GetAdminChatThreadMessagesQueryVariables = Exact<{
|
||||
threadId: Scalars['UUID'];
|
||||
@@ -936,7 +939,7 @@ export type WorkspaceLookupAdminPanelQueryVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type WorkspaceLookupAdminPanelQuery = { __typename?: 'Query', workspaceLookupAdminPanel: { __typename?: 'UserLookup', user: { __typename?: 'UserInfo', id: string, email: string, firstName?: string | null, lastName?: string | null, createdAt: string }, workspaces: Array<{ __typename?: 'WorkspaceInfo', id: string, name: string, allowImpersonation: boolean, logo?: string | null, totalUsers: number, activationStatus: WorkspaceActivationStatus, createdAt: string, workspaceUrls: { __typename?: 'WorkspaceUrls', customUrl?: string | null, subdomainUrl: string }, users: Array<{ __typename?: 'UserInfo', id: string, email: string, firstName?: string | null, lastName?: string | null }>, featureFlags: Array<{ __typename?: 'FeatureFlag', key: FeatureFlagKey, value: boolean }> }> } };
|
||||
export type WorkspaceLookupAdminPanelQuery = { __typename?: 'Query', workspaceLookupAdminPanel: { __typename?: 'UserLookup', user: { __typename?: 'UserInfo', id: string, email: string, firstName?: string | null, lastName?: string | null, createdAt: string }, workspaces: Array<{ __typename?: 'WorkspaceInfo', id: string, name: string, allowImpersonation: boolean, logo?: string | null, totalUsers: number, activationStatus: WorkspaceActivationStatus, createdAt: string, workspaceUrls: { __typename?: 'WorkspaceUrls', customUrl?: string | null, subdomainUrl: string }, users: Array<{ __typename?: 'UserInfo', id: string, email: string, firstName?: string | null, lastName?: string | null, avatarUrl?: string | null }>, featureFlags: Array<{ __typename?: 'FeatureFlag', key: FeatureFlagKey, value: boolean }> }> } };
|
||||
|
||||
export type DeleteJobsMutationVariables = Exact<{
|
||||
queueName: Scalars['String'];
|
||||
@@ -1003,10 +1006,10 @@ export type GetMaintenanceModeQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
export type GetMaintenanceModeQuery = { __typename?: 'Query', getMaintenanceMode?: { __typename?: 'MaintenanceMode', startAt: string, endAt: string, link?: string | null } | null };
|
||||
|
||||
export type ApplicationRegistrationFragmentFragment = { __typename?: 'ApplicationRegistration', id: string, universalIdentifier: string, name: string, oAuthClientId: string, oAuthRedirectUris: Array<string>, oAuthScopes: Array<string>, sourceType: ApplicationRegistrationSourceType, sourcePackage?: string | null, latestAvailableVersion?: string | null, isListed: boolean, isFeatured: boolean, isPreInstalled: boolean, ownerWorkspaceId?: string | null, createdAt: string, updatedAt: string };
|
||||
export type ApplicationRegistrationFragmentFragment = { __typename?: 'ApplicationRegistration', id: string, universalIdentifier: string, name: string, logoUrl?: string | null, oAuthClientId: string, oAuthRedirectUris: Array<string>, oAuthScopes: Array<string>, sourceType: ApplicationRegistrationSourceType, sourcePackage?: string | null, latestAvailableVersion?: string | null, isListed: boolean, isFeatured: boolean, isPreInstalled: boolean, ownerWorkspaceId?: string | null, createdAt: string, updatedAt: string };
|
||||
|
||||
export const UserInfoFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"UserInfoFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"UserInfo"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]} as unknown as DocumentNode<UserInfoFragmentFragment, unknown>;
|
||||
export const ApplicationRegistrationFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ApplicationRegistrationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ApplicationRegistration"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"universalIdentifier"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthClientId"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthRedirectUris"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthScopes"}},{"kind":"Field","name":{"kind":"Name","value":"sourceType"}},{"kind":"Field","name":{"kind":"Name","value":"sourcePackage"}},{"kind":"Field","name":{"kind":"Name","value":"latestAvailableVersion"}},{"kind":"Field","name":{"kind":"Name","value":"isListed"}},{"kind":"Field","name":{"kind":"Name","value":"isFeatured"}},{"kind":"Field","name":{"kind":"Name","value":"isPreInstalled"}},{"kind":"Field","name":{"kind":"Name","value":"ownerWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<ApplicationRegistrationFragmentFragment, unknown>;
|
||||
export const ApplicationRegistrationFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ApplicationRegistrationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ApplicationRegistration"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"universalIdentifier"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"logoUrl"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthClientId"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthRedirectUris"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthScopes"}},{"kind":"Field","name":{"kind":"Name","value":"sourceType"}},{"kind":"Field","name":{"kind":"Name","value":"sourcePackage"}},{"kind":"Field","name":{"kind":"Name","value":"latestAvailableVersion"}},{"kind":"Field","name":{"kind":"Name","value":"isListed"}},{"kind":"Field","name":{"kind":"Name","value":"isFeatured"}},{"kind":"Field","name":{"kind":"Name","value":"isPreInstalled"}},{"kind":"Field","name":{"kind":"Name","value":"ownerWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<ApplicationRegistrationFragmentFragment, unknown>;
|
||||
export const AddAiProviderDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"AddAiProvider"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"providerName"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"providerConfig"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"addAiProvider"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"providerName"},"value":{"kind":"Variable","name":{"kind":"Name","value":"providerName"}}},{"kind":"Argument","name":{"kind":"Name","value":"providerConfig"},"value":{"kind":"Variable","name":{"kind":"Name","value":"providerConfig"}}}]}]}}]} as unknown as DocumentNode<AddAiProviderMutation, AddAiProviderMutationVariables>;
|
||||
export const AddModelToProviderDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"AddModelToProvider"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"providerName"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"modelConfig"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"addModelToProvider"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"providerName"},"value":{"kind":"Variable","name":{"kind":"Name","value":"providerName"}}},{"kind":"Argument","name":{"kind":"Name","value":"modelConfig"},"value":{"kind":"Variable","name":{"kind":"Name","value":"modelConfig"}}}]}]}}]} as unknown as DocumentNode<AddModelToProviderMutation, AddModelToProviderMutationVariables>;
|
||||
export const RemoveAiProviderDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RemoveAiProvider"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"providerName"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"removeAiProvider"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"providerName"},"value":{"kind":"Variable","name":{"kind":"Name","value":"providerName"}}}]}]}}]} as unknown as DocumentNode<RemoveAiProviderMutation, RemoveAiProviderMutationVariables>;
|
||||
@@ -1021,22 +1024,22 @@ export const GetAdminAiUsageByWorkspaceDocument = {"kind":"Document","definition
|
||||
export const GetAiProvidersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetAiProviders"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getAiProviders"}}]}}]} as unknown as DocumentNode<GetAiProvidersQuery, GetAiProvidersQueryVariables>;
|
||||
export const GetModelsDevProvidersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetModelsDevProviders"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getModelsDevProviders"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"modelCount"}},{"kind":"Field","name":{"kind":"Name","value":"npm"}}]}}]}}]} as unknown as DocumentNode<GetModelsDevProvidersQuery, GetModelsDevProvidersQueryVariables>;
|
||||
export const GetModelsDevSuggestionsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetModelsDevSuggestions"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"providerType"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getModelsDevSuggestions"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"providerType"},"value":{"kind":"Variable","name":{"kind":"Name","value":"providerType"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"modelId"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"inputCostPerMillionTokens"}},{"kind":"Field","name":{"kind":"Name","value":"outputCostPerMillionTokens"}},{"kind":"Field","name":{"kind":"Name","value":"cachedInputCostPerMillionTokens"}},{"kind":"Field","name":{"kind":"Name","value":"cacheCreationCostPerMillionTokens"}},{"kind":"Field","name":{"kind":"Name","value":"contextWindowTokens"}},{"kind":"Field","name":{"kind":"Name","value":"maxOutputTokens"}},{"kind":"Field","name":{"kind":"Name","value":"modalities"}},{"kind":"Field","name":{"kind":"Name","value":"supportsReasoning"}}]}}]}}]} as unknown as DocumentNode<GetModelsDevSuggestionsQuery, GetModelsDevSuggestionsQueryVariables>;
|
||||
export const FindAllApplicationRegistrationsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FindAllApplicationRegistrations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findAllApplicationRegistrations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ApplicationRegistrationFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ApplicationRegistrationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ApplicationRegistration"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"universalIdentifier"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthClientId"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthRedirectUris"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthScopes"}},{"kind":"Field","name":{"kind":"Name","value":"sourceType"}},{"kind":"Field","name":{"kind":"Name","value":"sourcePackage"}},{"kind":"Field","name":{"kind":"Name","value":"latestAvailableVersion"}},{"kind":"Field","name":{"kind":"Name","value":"isListed"}},{"kind":"Field","name":{"kind":"Name","value":"isFeatured"}},{"kind":"Field","name":{"kind":"Name","value":"isPreInstalled"}},{"kind":"Field","name":{"kind":"Name","value":"ownerWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<FindAllApplicationRegistrationsQuery, FindAllApplicationRegistrationsQueryVariables>;
|
||||
export const FindAllApplicationRegistrationsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FindAllApplicationRegistrations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findAllApplicationRegistrations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ApplicationRegistrationFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ApplicationRegistrationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ApplicationRegistration"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"universalIdentifier"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"logoUrl"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthClientId"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthRedirectUris"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthScopes"}},{"kind":"Field","name":{"kind":"Name","value":"sourceType"}},{"kind":"Field","name":{"kind":"Name","value":"sourcePackage"}},{"kind":"Field","name":{"kind":"Name","value":"latestAvailableVersion"}},{"kind":"Field","name":{"kind":"Name","value":"isListed"}},{"kind":"Field","name":{"kind":"Name","value":"isFeatured"}},{"kind":"Field","name":{"kind":"Name","value":"isPreInstalled"}},{"kind":"Field","name":{"kind":"Name","value":"ownerWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<FindAllApplicationRegistrationsQuery, FindAllApplicationRegistrationsQueryVariables>;
|
||||
export const CreateDatabaseConfigVariableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateDatabaseConfigVariable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"key"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"value"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createDatabaseConfigVariable"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}},{"kind":"Argument","name":{"kind":"Name","value":"value"},"value":{"kind":"Variable","name":{"kind":"Name","value":"value"}}}]}]}}]} as unknown as DocumentNode<CreateDatabaseConfigVariableMutation, CreateDatabaseConfigVariableMutationVariables>;
|
||||
export const DeleteDatabaseConfigVariableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteDatabaseConfigVariable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"key"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteDatabaseConfigVariable"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}]}]}}]} as unknown as DocumentNode<DeleteDatabaseConfigVariableMutation, DeleteDatabaseConfigVariableMutationVariables>;
|
||||
export const UpdateDatabaseConfigVariableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateDatabaseConfigVariable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"key"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"value"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateDatabaseConfigVariable"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}},{"kind":"Argument","name":{"kind":"Name","value":"value"},"value":{"kind":"Variable","name":{"kind":"Name","value":"value"}}}]}]}}]} as unknown as DocumentNode<UpdateDatabaseConfigVariableMutation, UpdateDatabaseConfigVariableMutationVariables>;
|
||||
export const GetConfigVariablesGroupedDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetConfigVariablesGrouped"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getConfigVariablesGrouped"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"groups"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"isHiddenOnLoad"}},{"kind":"Field","name":{"kind":"Name","value":"variables"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"isSensitive"}},{"kind":"Field","name":{"kind":"Name","value":"isEnvOnly"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"options"}},{"kind":"Field","name":{"kind":"Name","value":"source"}}]}}]}}]}}]}}]} as unknown as DocumentNode<GetConfigVariablesGroupedQuery, GetConfigVariablesGroupedQueryVariables>;
|
||||
export const GetDatabaseConfigVariableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetDatabaseConfigVariable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"key"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getDatabaseConfigVariable"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"isSensitive"}},{"kind":"Field","name":{"kind":"Name","value":"isEnvOnly"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"options"}},{"kind":"Field","name":{"kind":"Name","value":"source"}}]}}]}}]} as unknown as DocumentNode<GetDatabaseConfigVariableQuery, GetDatabaseConfigVariableQueryVariables>;
|
||||
export const UpdateWorkspaceFeatureFlagDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateWorkspaceFeatureFlag"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"featureFlag"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"value"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateWorkspaceFeatureFlag"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"workspaceId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}}},{"kind":"Argument","name":{"kind":"Name","value":"featureFlag"},"value":{"kind":"Variable","name":{"kind":"Name","value":"featureFlag"}}},{"kind":"Argument","name":{"kind":"Name","value":"value"},"value":{"kind":"Variable","name":{"kind":"Name","value":"value"}}}]}]}}]} as unknown as DocumentNode<UpdateWorkspaceFeatureFlagMutation, UpdateWorkspaceFeatureFlagMutationVariables>;
|
||||
export const AdminPanelRecentUsersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AdminPanelRecentUsers"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"searchTerm"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"adminPanelRecentUsers"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"searchTerm"},"value":{"kind":"Variable","name":{"kind":"Name","value":"searchTerm"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceName"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceId"}}]}}]}}]} as unknown as DocumentNode<AdminPanelRecentUsersQuery, AdminPanelRecentUsersQueryVariables>;
|
||||
export const AdminPanelTopWorkspacesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AdminPanelTopWorkspaces"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"searchTerm"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"adminPanelTopWorkspaces"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"searchTerm"},"value":{"kind":"Variable","name":{"kind":"Name","value":"searchTerm"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"totalUsers"}},{"kind":"Field","name":{"kind":"Name","value":"subdomain"}},{"kind":"Field","name":{"kind":"Name","value":"logo"}}]}}]}}]} as unknown as DocumentNode<AdminPanelTopWorkspacesQuery, AdminPanelTopWorkspacesQueryVariables>;
|
||||
export const FindOneAdminApplicationRegistrationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FindOneAdminApplicationRegistration"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findOneAdminApplicationRegistration"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ApplicationRegistrationFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ApplicationRegistrationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ApplicationRegistration"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"universalIdentifier"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthClientId"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthRedirectUris"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthScopes"}},{"kind":"Field","name":{"kind":"Name","value":"sourceType"}},{"kind":"Field","name":{"kind":"Name","value":"sourcePackage"}},{"kind":"Field","name":{"kind":"Name","value":"latestAvailableVersion"}},{"kind":"Field","name":{"kind":"Name","value":"isListed"}},{"kind":"Field","name":{"kind":"Name","value":"isFeatured"}},{"kind":"Field","name":{"kind":"Name","value":"isPreInstalled"}},{"kind":"Field","name":{"kind":"Name","value":"ownerWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<FindOneAdminApplicationRegistrationQuery, FindOneAdminApplicationRegistrationQueryVariables>;
|
||||
export const AdminPanelRecentUsersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AdminPanelRecentUsers"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"searchTerm"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"adminPanelRecentUsers"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"searchTerm"},"value":{"kind":"Variable","name":{"kind":"Name","value":"searchTerm"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceName"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceLogo"}}]}}]}}]} as unknown as DocumentNode<AdminPanelRecentUsersQuery, AdminPanelRecentUsersQueryVariables>;
|
||||
export const AdminPanelTopWorkspacesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"AdminPanelTopWorkspaces"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"searchTerm"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"adminPanelTopWorkspaces"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"searchTerm"},"value":{"kind":"Variable","name":{"kind":"Name","value":"searchTerm"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"logoUrl"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"totalUsers"}},{"kind":"Field","name":{"kind":"Name","value":"subdomain"}}]}}]}}]} as unknown as DocumentNode<AdminPanelTopWorkspacesQuery, AdminPanelTopWorkspacesQueryVariables>;
|
||||
export const FindOneAdminApplicationRegistrationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FindOneAdminApplicationRegistration"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findOneAdminApplicationRegistration"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ApplicationRegistrationFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ApplicationRegistrationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ApplicationRegistration"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"universalIdentifier"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"logoUrl"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthClientId"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthRedirectUris"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthScopes"}},{"kind":"Field","name":{"kind":"Name","value":"sourceType"}},{"kind":"Field","name":{"kind":"Name","value":"sourcePackage"}},{"kind":"Field","name":{"kind":"Name","value":"latestAvailableVersion"}},{"kind":"Field","name":{"kind":"Name","value":"isListed"}},{"kind":"Field","name":{"kind":"Name","value":"isFeatured"}},{"kind":"Field","name":{"kind":"Name","value":"isPreInstalled"}},{"kind":"Field","name":{"kind":"Name","value":"ownerWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<FindOneAdminApplicationRegistrationQuery, FindOneAdminApplicationRegistrationQueryVariables>;
|
||||
export const GetAdminChatThreadMessagesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetAdminChatThreadMessages"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"threadId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getAdminChatThreadMessages"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"threadId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"threadId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"thread"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"totalInputTokens"}},{"kind":"Field","name":{"kind":"Name","value":"totalOutputTokens"}},{"kind":"Field","name":{"kind":"Name","value":"conversationSize"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}},{"kind":"Field","name":{"kind":"Name","value":"messages"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"parts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"textContent"}},{"kind":"Field","name":{"kind":"Name","value":"toolName"}}]}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]}}]}}]} as unknown as DocumentNode<GetAdminChatThreadMessagesQuery, GetAdminChatThreadMessagesQueryVariables>;
|
||||
export const GetAdminWorkspaceChatThreadsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetAdminWorkspaceChatThreads"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getAdminWorkspaceChatThreads"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"workspaceId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"totalInputTokens"}},{"kind":"Field","name":{"kind":"Name","value":"totalOutputTokens"}},{"kind":"Field","name":{"kind":"Name","value":"conversationSize"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]} as unknown as DocumentNode<GetAdminWorkspaceChatThreadsQuery, GetAdminWorkspaceChatThreadsQueryVariables>;
|
||||
export const GetVersionInfoDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetVersionInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"versionInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currentVersion"}},{"kind":"Field","name":{"kind":"Name","value":"latestVersion"}}]}}]}}]} as unknown as DocumentNode<GetVersionInfoQuery, GetVersionInfoQueryVariables>;
|
||||
export const WorkspaceBillingAdminPanelDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"WorkspaceBillingAdminPanel"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspaceBillingAdminPanel"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"workspaceId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"stripeCustomerId"}},{"kind":"Field","name":{"kind":"Name","value":"creditBalance"}},{"kind":"Field","name":{"kind":"Name","value":"subscription"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"stripeSubscriptionId"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"interval"}},{"kind":"Field","name":{"kind":"Name","value":"currency"}},{"kind":"Field","name":{"kind":"Name","value":"planKey"}},{"kind":"Field","name":{"kind":"Name","value":"currentPeriodStart"}},{"kind":"Field","name":{"kind":"Name","value":"currentPeriodEnd"}},{"kind":"Field","name":{"kind":"Name","value":"trialStart"}},{"kind":"Field","name":{"kind":"Name","value":"trialEnd"}},{"kind":"Field","name":{"kind":"Name","value":"cancelAt"}},{"kind":"Field","name":{"kind":"Name","value":"canceledAt"}},{"kind":"Field","name":{"kind":"Name","value":"cancelAtPeriodEnd"}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"productName"}},{"kind":"Field","name":{"kind":"Name","value":"productKey"}},{"kind":"Field","name":{"kind":"Name","value":"stripePriceId"}},{"kind":"Field","name":{"kind":"Name","value":"quantity"}},{"kind":"Field","name":{"kind":"Name","value":"unitAmount"}},{"kind":"Field","name":{"kind":"Name","value":"includedCredits"}}]}}]}}]}}]}}]} as unknown as DocumentNode<WorkspaceBillingAdminPanelQuery, WorkspaceBillingAdminPanelQueryVariables>;
|
||||
export const UserLookupAdminPanelDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"UserLookupAdminPanel"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"userIdentifier"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"userLookupAdminPanel"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"userIdentifier"},"value":{"kind":"Variable","name":{"kind":"Name","value":"userIdentifier"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"UserInfoFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"workspaces"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"logo"}},{"kind":"Field","name":{"kind":"Name","value":"totalUsers"}},{"kind":"Field","name":{"kind":"Name","value":"activationStatus"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"allowImpersonation"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceUrls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"customUrl"}},{"kind":"Field","name":{"kind":"Name","value":"subdomainUrl"}}]}},{"kind":"Field","name":{"kind":"Name","value":"users"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}}]}},{"kind":"Field","name":{"kind":"Name","value":"featureFlags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"UserInfoFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"UserInfo"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]} as unknown as DocumentNode<UserLookupAdminPanelQuery, UserLookupAdminPanelQueryVariables>;
|
||||
export const WorkspaceLookupAdminPanelDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"WorkspaceLookupAdminPanel"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspaceLookupAdminPanel"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"workspaceId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"UserInfoFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"workspaces"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"allowImpersonation"}},{"kind":"Field","name":{"kind":"Name","value":"logo"}},{"kind":"Field","name":{"kind":"Name","value":"totalUsers"}},{"kind":"Field","name":{"kind":"Name","value":"activationStatus"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceUrls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"customUrl"}},{"kind":"Field","name":{"kind":"Name","value":"subdomainUrl"}}]}},{"kind":"Field","name":{"kind":"Name","value":"users"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}}]}},{"kind":"Field","name":{"kind":"Name","value":"featureFlags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"UserInfoFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"UserInfo"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]} as unknown as DocumentNode<WorkspaceLookupAdminPanelQuery, WorkspaceLookupAdminPanelQueryVariables>;
|
||||
export const WorkspaceLookupAdminPanelDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"WorkspaceLookupAdminPanel"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"workspaceLookupAdminPanel"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"workspaceId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"workspaceId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"user"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"UserInfoFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"workspaces"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"allowImpersonation"}},{"kind":"Field","name":{"kind":"Name","value":"logo"}},{"kind":"Field","name":{"kind":"Name","value":"totalUsers"}},{"kind":"Field","name":{"kind":"Name","value":"activationStatus"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"workspaceUrls"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"customUrl"}},{"kind":"Field","name":{"kind":"Name","value":"subdomainUrl"}}]}},{"kind":"Field","name":{"kind":"Name","value":"users"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"avatarUrl"}}]}},{"kind":"Field","name":{"kind":"Name","value":"featureFlags"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"UserInfoFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"UserInfo"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"email"}},{"kind":"Field","name":{"kind":"Name","value":"firstName"}},{"kind":"Field","name":{"kind":"Name","value":"lastName"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]} as unknown as DocumentNode<WorkspaceLookupAdminPanelQuery, WorkspaceLookupAdminPanelQueryVariables>;
|
||||
export const DeleteJobsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteJobs"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"queueName"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"jobIds"}},"type":{"kind":"NonNullType","type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteJobs"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"queueName"},"value":{"kind":"Variable","name":{"kind":"Name","value":"queueName"}}},{"kind":"Argument","name":{"kind":"Name","value":"jobIds"},"value":{"kind":"Variable","name":{"kind":"Name","value":"jobIds"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deletedCount"}},{"kind":"Field","name":{"kind":"Name","value":"results"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"jobId"}},{"kind":"Field","name":{"kind":"Name","value":"success"}},{"kind":"Field","name":{"kind":"Name","value":"error"}}]}}]}}]}}]} as unknown as DocumentNode<DeleteJobsMutation, DeleteJobsMutationVariables>;
|
||||
export const RetryJobsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RetryJobs"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"queueName"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"jobIds"}},"type":{"kind":"NonNullType","type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"retryJobs"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"queueName"},"value":{"kind":"Variable","name":{"kind":"Name","value":"queueName"}}},{"kind":"Argument","name":{"kind":"Name","value":"jobIds"},"value":{"kind":"Variable","name":{"kind":"Name","value":"jobIds"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"retriedCount"}},{"kind":"Field","name":{"kind":"Name","value":"results"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"jobId"}},{"kind":"Field","name":{"kind":"Name","value":"success"}},{"kind":"Field","name":{"kind":"Name","value":"error"}}]}}]}}]}}]} as unknown as DocumentNode<RetryJobsMutation, RetryJobsMutationVariables>;
|
||||
export const GetIndicatorHealthStatusDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetIndicatorHealthStatus"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"indicatorId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"HealthIndicatorId"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getIndicatorHealthStatus"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"indicatorId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"indicatorId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"errorMessage"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"queues"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"queueName"}},{"kind":"Field","name":{"kind":"Name","value":"status"}}]}}]}}]}}]} as unknown as DocumentNode<GetIndicatorHealthStatusQuery, GetIndicatorHealthStatusQueryVariables>;
|
||||
|
||||
@@ -6825,7 +6825,7 @@ export type MyMessageFoldersQueryVariables = Exact<{
|
||||
|
||||
export type MyMessageFoldersQuery = { __typename?: 'Query', myMessageFolders: Array<{ __typename?: 'MessageFolder', id: string, name?: string | null, isSynced: boolean, isSentFolder: boolean, parentFolderId?: string | null, externalId?: string | null, messageChannelId: string, createdAt: string, updatedAt: string }> };
|
||||
|
||||
export type ApplicationRegistrationFragmentFragment = { __typename?: 'ApplicationRegistration', id: string, universalIdentifier: string, name: string, oAuthClientId: string, oAuthRedirectUris: Array<string>, oAuthScopes: Array<string>, sourceType: ApplicationRegistrationSourceType, sourcePackage?: string | null, latestAvailableVersion?: string | null, isListed: boolean, isFeatured: boolean, isPreInstalled: boolean, ownerWorkspaceId?: string | null, createdAt: string, updatedAt: string };
|
||||
export type ApplicationRegistrationFragmentFragment = { __typename?: 'ApplicationRegistration', id: string, universalIdentifier: string, name: string, logoUrl?: string | null, oAuthClientId: string, oAuthRedirectUris: Array<string>, oAuthScopes: Array<string>, sourceType: ApplicationRegistrationSourceType, sourcePackage?: string | null, latestAvailableVersion?: string | null, isListed: boolean, isFeatured: boolean, isPreInstalled: boolean, ownerWorkspaceId?: string | null, createdAt: string, updatedAt: string };
|
||||
|
||||
export type DeleteApplicationRegistrationMutationVariables = Exact<{
|
||||
id: Scalars['String'];
|
||||
@@ -6854,7 +6854,7 @@ export type UpdateApplicationRegistrationMutationVariables = Exact<{
|
||||
}>;
|
||||
|
||||
|
||||
export type UpdateApplicationRegistrationMutation = { __typename?: 'Mutation', updateApplicationRegistration: { __typename?: 'ApplicationRegistration', id: string, universalIdentifier: string, name: string, oAuthClientId: string, oAuthRedirectUris: Array<string>, oAuthScopes: Array<string>, sourceType: ApplicationRegistrationSourceType, sourcePackage?: string | null, latestAvailableVersion?: string | null, isListed: boolean, isFeatured: boolean, isPreInstalled: boolean, ownerWorkspaceId?: string | null, createdAt: string, updatedAt: string } };
|
||||
export type UpdateApplicationRegistrationMutation = { __typename?: 'Mutation', updateApplicationRegistration: { __typename?: 'ApplicationRegistration', id: string, universalIdentifier: string, name: string, logoUrl?: string | null, oAuthClientId: string, oAuthRedirectUris: Array<string>, oAuthScopes: Array<string>, sourceType: ApplicationRegistrationSourceType, sourcePackage?: string | null, latestAvailableVersion?: string | null, isListed: boolean, isFeatured: boolean, isPreInstalled: boolean, ownerWorkspaceId?: string | null, createdAt: string, updatedAt: string } };
|
||||
|
||||
export type UpdateApplicationRegistrationVariableMutationVariables = Exact<{
|
||||
input: UpdateApplicationRegistrationVariableInput;
|
||||
@@ -6887,14 +6887,14 @@ export type FindApplicationRegistrationVariablesQuery = { __typename?: 'Query',
|
||||
export type FindManyApplicationRegistrationsQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type FindManyApplicationRegistrationsQuery = { __typename?: 'Query', findManyApplicationRegistrations: Array<{ __typename?: 'ApplicationRegistration', id: string, universalIdentifier: string, name: string, oAuthClientId: string, oAuthRedirectUris: Array<string>, oAuthScopes: Array<string>, sourceType: ApplicationRegistrationSourceType, sourcePackage?: string | null, latestAvailableVersion?: string | null, isListed: boolean, isFeatured: boolean, isPreInstalled: boolean, ownerWorkspaceId?: string | null, createdAt: string, updatedAt: string }> };
|
||||
export type FindManyApplicationRegistrationsQuery = { __typename?: 'Query', findManyApplicationRegistrations: Array<{ __typename?: 'ApplicationRegistration', id: string, universalIdentifier: string, name: string, logoUrl?: string | null, oAuthClientId: string, oAuthRedirectUris: Array<string>, oAuthScopes: Array<string>, sourceType: ApplicationRegistrationSourceType, sourcePackage?: string | null, latestAvailableVersion?: string | null, isListed: boolean, isFeatured: boolean, isPreInstalled: boolean, ownerWorkspaceId?: string | null, createdAt: string, updatedAt: string }> };
|
||||
|
||||
export type FindOneApplicationRegistrationQueryVariables = Exact<{
|
||||
id: Scalars['String'];
|
||||
}>;
|
||||
|
||||
|
||||
export type FindOneApplicationRegistrationQuery = { __typename?: 'Query', findOneApplicationRegistration: { __typename?: 'ApplicationRegistration', id: string, universalIdentifier: string, name: string, oAuthClientId: string, oAuthRedirectUris: Array<string>, oAuthScopes: Array<string>, sourceType: ApplicationRegistrationSourceType, sourcePackage?: string | null, latestAvailableVersion?: string | null, isListed: boolean, isFeatured: boolean, isPreInstalled: boolean, ownerWorkspaceId?: string | null, createdAt: string, updatedAt: string } };
|
||||
export type FindOneApplicationRegistrationQuery = { __typename?: 'Query', findOneApplicationRegistration: { __typename?: 'ApplicationRegistration', id: string, universalIdentifier: string, name: string, logoUrl?: string | null, oAuthClientId: string, oAuthRedirectUris: Array<string>, oAuthScopes: Array<string>, sourceType: ApplicationRegistrationSourceType, sourcePackage?: string | null, latestAvailableVersion?: string | null, isListed: boolean, isFeatured: boolean, isPreInstalled: boolean, ownerWorkspaceId?: string | null, createdAt: string, updatedAt: string } };
|
||||
|
||||
export type UninstallApplicationMutationVariables = Exact<{
|
||||
universalIdentifier: Scalars['String'];
|
||||
@@ -7788,7 +7788,7 @@ export const MarketplaceAppFieldsFragmentDoc = {"kind":"Document","definitions":
|
||||
export const NavigationMenuItemFieldsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NavigationMenuItemFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NavigationMenuItem"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"userWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"targetRecordId"}},{"kind":"Field","name":{"kind":"Name","value":"targetObjectMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"viewId"}},{"kind":"Field","name":{"kind":"Name","value":"folderId"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"link"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"color"}},{"kind":"Field","name":{"kind":"Name","value":"pageLayoutId"}},{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"applicationId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<NavigationMenuItemFieldsFragment, unknown>;
|
||||
export const NavigationMenuItemQueryFieldsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NavigationMenuItemQueryFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NavigationMenuItem"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"NavigationMenuItemFields"}},{"kind":"Field","name":{"kind":"Name","value":"targetRecordIdentifier"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"labelIdentifier"}},{"kind":"Field","name":{"kind":"Name","value":"imageIdentifier"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"NavigationMenuItemFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"NavigationMenuItem"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"userWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"targetRecordId"}},{"kind":"Field","name":{"kind":"Name","value":"targetObjectMetadataId"}},{"kind":"Field","name":{"kind":"Name","value":"viewId"}},{"kind":"Field","name":{"kind":"Name","value":"folderId"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"link"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"color"}},{"kind":"Field","name":{"kind":"Name","value":"pageLayoutId"}},{"kind":"Field","name":{"kind":"Name","value":"position"}},{"kind":"Field","name":{"kind":"Name","value":"applicationId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<NavigationMenuItemQueryFieldsFragment, unknown>;
|
||||
export const PublicConnectionParamsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"PublicConnectionParams"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"PublicConnectionParametersOutput"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"host"}},{"kind":"Field","name":{"kind":"Name","value":"port"}},{"kind":"Field","name":{"kind":"Name","value":"secure"}},{"kind":"Field","name":{"kind":"Name","value":"username"}}]}}]} as unknown as DocumentNode<PublicConnectionParamsFragment, unknown>;
|
||||
export const ApplicationRegistrationFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ApplicationRegistrationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ApplicationRegistration"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"universalIdentifier"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthClientId"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthRedirectUris"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthScopes"}},{"kind":"Field","name":{"kind":"Name","value":"sourceType"}},{"kind":"Field","name":{"kind":"Name","value":"sourcePackage"}},{"kind":"Field","name":{"kind":"Name","value":"latestAvailableVersion"}},{"kind":"Field","name":{"kind":"Name","value":"isListed"}},{"kind":"Field","name":{"kind":"Name","value":"isFeatured"}},{"kind":"Field","name":{"kind":"Name","value":"isPreInstalled"}},{"kind":"Field","name":{"kind":"Name","value":"ownerWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<ApplicationRegistrationFragmentFragment, unknown>;
|
||||
export const ApplicationRegistrationFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ApplicationRegistrationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ApplicationRegistration"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"universalIdentifier"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"logoUrl"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthClientId"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthRedirectUris"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthScopes"}},{"kind":"Field","name":{"kind":"Name","value":"sourceType"}},{"kind":"Field","name":{"kind":"Name","value":"sourcePackage"}},{"kind":"Field","name":{"kind":"Name","value":"latestAvailableVersion"}},{"kind":"Field","name":{"kind":"Name","value":"isListed"}},{"kind":"Field","name":{"kind":"Name","value":"isFeatured"}},{"kind":"Field","name":{"kind":"Name","value":"isPreInstalled"}},{"kind":"Field","name":{"kind":"Name","value":"ownerWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<ApplicationRegistrationFragmentFragment, unknown>;
|
||||
export const BillingPriceLicensedFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BillingPriceLicensedFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"BillingPriceLicensed"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"stripePriceId"}},{"kind":"Field","name":{"kind":"Name","value":"unitAmount"}},{"kind":"Field","name":{"kind":"Name","value":"recurringInterval"}},{"kind":"Field","name":{"kind":"Name","value":"priceUsageType"}}]}}]} as unknown as DocumentNode<BillingPriceLicensedFragmentFragment, unknown>;
|
||||
export const BillingPriceMeteredFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BillingPriceMeteredFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"BillingPriceMetered"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"priceUsageType"}},{"kind":"Field","name":{"kind":"Name","value":"recurringInterval"}},{"kind":"Field","name":{"kind":"Name","value":"stripePriceId"}},{"kind":"Field","name":{"kind":"Name","value":"tiers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"flatAmount"}},{"kind":"Field","name":{"kind":"Name","value":"unitAmount"}},{"kind":"Field","name":{"kind":"Name","value":"upTo"}}]}}]}}]} as unknown as DocumentNode<BillingPriceMeteredFragmentFragment, unknown>;
|
||||
export const ApiKeyFragmentFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ApiKeyFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ApiKey"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"expiresAt"}},{"kind":"Field","name":{"kind":"Name","value":"revokedAt"}},{"kind":"Field","name":{"kind":"Name","value":"role"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}}]} as unknown as DocumentNode<ApiKeyFragmentFragment, unknown>;
|
||||
@@ -7940,13 +7940,13 @@ export const MyMessageFoldersDocument = {"kind":"Document","definitions":[{"kind
|
||||
export const DeleteApplicationRegistrationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteApplicationRegistration"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deleteApplicationRegistration"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}]}]}}]} as unknown as DocumentNode<DeleteApplicationRegistrationMutation, DeleteApplicationRegistrationMutationVariables>;
|
||||
export const RotateApplicationRegistrationClientSecretDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"RotateApplicationRegistrationClientSecret"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"rotateApplicationRegistrationClientSecret"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"clientSecret"}}]}}]}}]} as unknown as DocumentNode<RotateApplicationRegistrationClientSecretMutation, RotateApplicationRegistrationClientSecretMutationVariables>;
|
||||
export const TransferApplicationRegistrationOwnershipDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"TransferApplicationRegistrationOwnership"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"applicationRegistrationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"targetWorkspaceSubdomain"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"transferApplicationRegistrationOwnership"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"applicationRegistrationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"applicationRegistrationId"}}},{"kind":"Argument","name":{"kind":"Name","value":"targetWorkspaceSubdomain"},"value":{"kind":"Variable","name":{"kind":"Name","value":"targetWorkspaceSubdomain"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}}]}}]}}]} as unknown as DocumentNode<TransferApplicationRegistrationOwnershipMutation, TransferApplicationRegistrationOwnershipMutationVariables>;
|
||||
export const UpdateApplicationRegistrationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateApplicationRegistration"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UpdateApplicationRegistrationInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateApplicationRegistration"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ApplicationRegistrationFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ApplicationRegistrationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ApplicationRegistration"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"universalIdentifier"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthClientId"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthRedirectUris"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthScopes"}},{"kind":"Field","name":{"kind":"Name","value":"sourceType"}},{"kind":"Field","name":{"kind":"Name","value":"sourcePackage"}},{"kind":"Field","name":{"kind":"Name","value":"latestAvailableVersion"}},{"kind":"Field","name":{"kind":"Name","value":"isListed"}},{"kind":"Field","name":{"kind":"Name","value":"isFeatured"}},{"kind":"Field","name":{"kind":"Name","value":"isPreInstalled"}},{"kind":"Field","name":{"kind":"Name","value":"ownerWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<UpdateApplicationRegistrationMutation, UpdateApplicationRegistrationMutationVariables>;
|
||||
export const UpdateApplicationRegistrationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateApplicationRegistration"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UpdateApplicationRegistrationInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateApplicationRegistration"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ApplicationRegistrationFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ApplicationRegistrationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ApplicationRegistration"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"universalIdentifier"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"logoUrl"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthClientId"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthRedirectUris"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthScopes"}},{"kind":"Field","name":{"kind":"Name","value":"sourceType"}},{"kind":"Field","name":{"kind":"Name","value":"sourcePackage"}},{"kind":"Field","name":{"kind":"Name","value":"latestAvailableVersion"}},{"kind":"Field","name":{"kind":"Name","value":"isListed"}},{"kind":"Field","name":{"kind":"Name","value":"isFeatured"}},{"kind":"Field","name":{"kind":"Name","value":"isPreInstalled"}},{"kind":"Field","name":{"kind":"Name","value":"ownerWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<UpdateApplicationRegistrationMutation, UpdateApplicationRegistrationMutationVariables>;
|
||||
export const UpdateApplicationRegistrationVariableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateApplicationRegistrationVariable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UpdateApplicationRegistrationVariableInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateApplicationRegistrationVariable"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"isSecret"}},{"kind":"Field","name":{"kind":"Name","value":"isRequired"}},{"kind":"Field","name":{"kind":"Name","value":"isFilled"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]} as unknown as DocumentNode<UpdateApplicationRegistrationVariableMutation, UpdateApplicationRegistrationVariableMutationVariables>;
|
||||
export const ApplicationRegistrationTarballUrlDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"ApplicationRegistrationTarballUrl"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"applicationRegistrationTarballUrl"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}]}]}}]} as unknown as DocumentNode<ApplicationRegistrationTarballUrlQuery, ApplicationRegistrationTarballUrlQueryVariables>;
|
||||
export const FindApplicationRegistrationStatsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FindApplicationRegistrationStats"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findApplicationRegistrationStats"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeInstalls"}},{"kind":"Field","name":{"kind":"Name","value":"mostInstalledVersion"}},{"kind":"Field","name":{"kind":"Name","value":"versionDistribution"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"version"}},{"kind":"Field","name":{"kind":"Name","value":"count"}}]}}]}}]}}]} as unknown as DocumentNode<FindApplicationRegistrationStatsQuery, FindApplicationRegistrationStatsQueryVariables>;
|
||||
export const FindApplicationRegistrationVariablesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FindApplicationRegistrationVariables"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"applicationRegistrationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findApplicationRegistrationVariables"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"applicationRegistrationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"applicationRegistrationId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"isSecret"}},{"kind":"Field","name":{"kind":"Name","value":"isRequired"}},{"kind":"Field","name":{"kind":"Name","value":"isFilled"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]} as unknown as DocumentNode<FindApplicationRegistrationVariablesQuery, FindApplicationRegistrationVariablesQueryVariables>;
|
||||
export const FindManyApplicationRegistrationsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FindManyApplicationRegistrations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findManyApplicationRegistrations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ApplicationRegistrationFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ApplicationRegistrationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ApplicationRegistration"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"universalIdentifier"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthClientId"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthRedirectUris"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthScopes"}},{"kind":"Field","name":{"kind":"Name","value":"sourceType"}},{"kind":"Field","name":{"kind":"Name","value":"sourcePackage"}},{"kind":"Field","name":{"kind":"Name","value":"latestAvailableVersion"}},{"kind":"Field","name":{"kind":"Name","value":"isListed"}},{"kind":"Field","name":{"kind":"Name","value":"isFeatured"}},{"kind":"Field","name":{"kind":"Name","value":"isPreInstalled"}},{"kind":"Field","name":{"kind":"Name","value":"ownerWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<FindManyApplicationRegistrationsQuery, FindManyApplicationRegistrationsQueryVariables>;
|
||||
export const FindOneApplicationRegistrationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FindOneApplicationRegistration"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findOneApplicationRegistration"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ApplicationRegistrationFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ApplicationRegistrationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ApplicationRegistration"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"universalIdentifier"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthClientId"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthRedirectUris"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthScopes"}},{"kind":"Field","name":{"kind":"Name","value":"sourceType"}},{"kind":"Field","name":{"kind":"Name","value":"sourcePackage"}},{"kind":"Field","name":{"kind":"Name","value":"latestAvailableVersion"}},{"kind":"Field","name":{"kind":"Name","value":"isListed"}},{"kind":"Field","name":{"kind":"Name","value":"isFeatured"}},{"kind":"Field","name":{"kind":"Name","value":"isPreInstalled"}},{"kind":"Field","name":{"kind":"Name","value":"ownerWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<FindOneApplicationRegistrationQuery, FindOneApplicationRegistrationQueryVariables>;
|
||||
export const FindManyApplicationRegistrationsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FindManyApplicationRegistrations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findManyApplicationRegistrations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ApplicationRegistrationFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ApplicationRegistrationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ApplicationRegistration"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"universalIdentifier"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"logoUrl"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthClientId"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthRedirectUris"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthScopes"}},{"kind":"Field","name":{"kind":"Name","value":"sourceType"}},{"kind":"Field","name":{"kind":"Name","value":"sourcePackage"}},{"kind":"Field","name":{"kind":"Name","value":"latestAvailableVersion"}},{"kind":"Field","name":{"kind":"Name","value":"isListed"}},{"kind":"Field","name":{"kind":"Name","value":"isFeatured"}},{"kind":"Field","name":{"kind":"Name","value":"isPreInstalled"}},{"kind":"Field","name":{"kind":"Name","value":"ownerWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<FindManyApplicationRegistrationsQuery, FindManyApplicationRegistrationsQueryVariables>;
|
||||
export const FindOneApplicationRegistrationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FindOneApplicationRegistration"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findOneApplicationRegistration"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ApplicationRegistrationFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ApplicationRegistrationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ApplicationRegistration"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"universalIdentifier"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"logoUrl"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthClientId"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthRedirectUris"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthScopes"}},{"kind":"Field","name":{"kind":"Name","value":"sourceType"}},{"kind":"Field","name":{"kind":"Name","value":"sourcePackage"}},{"kind":"Field","name":{"kind":"Name","value":"latestAvailableVersion"}},{"kind":"Field","name":{"kind":"Name","value":"isListed"}},{"kind":"Field","name":{"kind":"Name","value":"isFeatured"}},{"kind":"Field","name":{"kind":"Name","value":"isPreInstalled"}},{"kind":"Field","name":{"kind":"Name","value":"ownerWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<FindOneApplicationRegistrationQuery, FindOneApplicationRegistrationQueryVariables>;
|
||||
export const UninstallApplicationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UninstallApplication"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"universalIdentifier"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"uninstallApplication"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"universalIdentifier"},"value":{"kind":"Variable","name":{"kind":"Name","value":"universalIdentifier"}}}]}]}}]} as unknown as DocumentNode<UninstallApplicationMutation, UninstallApplicationMutationVariables>;
|
||||
export const UpdateOneApplicationVariableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateOneApplicationVariable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"key"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"value"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"applicationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateOneApplicationVariable"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"key"},"value":{"kind":"Variable","name":{"kind":"Name","value":"key"}}},{"kind":"Argument","name":{"kind":"Name","value":"value"},"value":{"kind":"Variable","name":{"kind":"Name","value":"value"}}},{"kind":"Argument","name":{"kind":"Name","value":"applicationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"applicationId"}}}]}]}}]} as unknown as DocumentNode<UpdateOneApplicationVariableMutation, UpdateOneApplicationVariableMutationVariables>;
|
||||
export const CancelSwitchBillingIntervalDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CancelSwitchBillingInterval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"cancelSwitchBillingInterval"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currentBillingSubscription"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CurrentBillingSubscriptionFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"billingSubscriptions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BillingSubscriptionFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhaseItemFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhaseItem"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"price"}},{"kind":"Field","name":{"kind":"Name","value":"quantity"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhaseFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhase"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start_date"}},{"kind":"Field","name":{"kind":"Name","value":"end_date"}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhaseItemFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CurrentBillingSubscriptionFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"BillingSubscription"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"interval"}},{"kind":"Field","name":{"kind":"Name","value":"metadata"}},{"kind":"Field","name":{"kind":"Name","value":"currentPeriodEnd"}},{"kind":"Field","name":{"kind":"Name","value":"phases"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhaseFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"billingSubscriptionItems"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"hasReachedCurrentPeriodCap"}},{"kind":"Field","name":{"kind":"Name","value":"quantity"}},{"kind":"Field","name":{"kind":"Name","value":"stripePriceId"}},{"kind":"Field","name":{"kind":"Name","value":"billingProduct"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"images"}},{"kind":"Field","name":{"kind":"Name","value":"metadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"productKey"}},{"kind":"Field","name":{"kind":"Name","value":"planKey"}},{"kind":"Field","name":{"kind":"Name","value":"priceUsageBased"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BillingSubscriptionFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"BillingSubscription"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"metadata"}},{"kind":"Field","name":{"kind":"Name","value":"phases"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhaseFragment"}}]}}]}}]} as unknown as DocumentNode<CancelSwitchBillingIntervalMutation, CancelSwitchBillingIntervalMutationVariables>;
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import { useApplicationAvatarColors } from '@/applications/hooks/useApplicationAvatarColors';
|
||||
import { Avatar, OverflowingTextWithTooltip } from 'twenty-ui/display';
|
||||
|
||||
type ApplicationDisplayData = {
|
||||
id?: string | null;
|
||||
name?: string | null;
|
||||
universalIdentifier?: string | null;
|
||||
logoUrl?: string | null;
|
||||
applicationRegistration?: {
|
||||
logoUrl?: string | null;
|
||||
} | null;
|
||||
};
|
||||
|
||||
type ApplicationDisplayProps = {
|
||||
application: ApplicationDisplayData;
|
||||
};
|
||||
|
||||
export const ApplicationDisplay = ({
|
||||
application,
|
||||
}: ApplicationDisplayProps) => {
|
||||
const colors = useApplicationAvatarColors(application);
|
||||
const name = application.name ?? '';
|
||||
const logoUrl =
|
||||
application.logoUrl ?? application.applicationRegistration?.logoUrl;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Avatar
|
||||
type="app"
|
||||
size="md"
|
||||
avatarUrl={logoUrl ?? undefined}
|
||||
placeholder={name}
|
||||
placeholderColorSeed={application.universalIdentifier ?? name}
|
||||
color={colors?.color}
|
||||
backgroundColor={colors?.backgroundColor}
|
||||
borderColor={colors?.borderColor}
|
||||
/>
|
||||
<OverflowingTextWithTooltip text={name} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
+15
-1
@@ -1,5 +1,4 @@
|
||||
import { useExitLayoutCustomizationMode } from '@/layout-customization/hooks/useExitLayoutCustomizationMode';
|
||||
import { type DraftPageLayout } from '@/page-layout/types/DraftPageLayout';
|
||||
import { activeCustomizationPageLayoutIdsState } from '@/layout-customization/states/activeCustomizationPageLayoutIdsState';
|
||||
import { fieldsWidgetEditorModeDraftComponentState } from '@/page-layout/states/fieldsWidgetEditorModeDraftComponentState';
|
||||
import { fieldsWidgetEditorModePersistedComponentState } from '@/page-layout/states/fieldsWidgetEditorModePersistedComponentState';
|
||||
@@ -10,6 +9,9 @@ import { fieldsWidgetUngroupedFieldsPersistedComponentState } from '@/page-layou
|
||||
import { pageLayoutCurrentLayoutsComponentState } from '@/page-layout/states/pageLayoutCurrentLayoutsComponentState';
|
||||
import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState';
|
||||
import { pageLayoutPersistedComponentState } from '@/page-layout/states/pageLayoutPersistedComponentState';
|
||||
import { recordTableWidgetViewDraftComponentState } from '@/page-layout/states/recordTableWidgetViewDraftComponentState';
|
||||
import { recordTableWidgetViewPersistedComponentState } from '@/page-layout/states/recordTableWidgetViewPersistedComponentState';
|
||||
import { type DraftPageLayout } from '@/page-layout/types/DraftPageLayout';
|
||||
import { convertPageLayoutToTabLayouts } from '@/page-layout/utils/convertPageLayoutToTabLayouts';
|
||||
import { useStore } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
@@ -90,6 +92,18 @@ export const useCancelLayoutCustomization = () => {
|
||||
}),
|
||||
fieldsWidgetEditorModePersisted,
|
||||
);
|
||||
|
||||
const recordTableWidgetViewPersisted = store.get(
|
||||
recordTableWidgetViewPersistedComponentState.atomFamily({
|
||||
instanceId: pageLayoutId,
|
||||
}),
|
||||
);
|
||||
store.set(
|
||||
recordTableWidgetViewDraftComponentState.atomFamily({
|
||||
instanceId: pageLayoutId,
|
||||
}),
|
||||
recordTableWidgetViewPersisted,
|
||||
);
|
||||
}
|
||||
|
||||
exitLayoutCustomizationMode();
|
||||
|
||||
+23
-1
@@ -1,6 +1,5 @@
|
||||
import { useCommandMenuItemsDraftState } from '@/command-menu-item/hooks/useCommandMenuItemsDraftState';
|
||||
import { activeCustomizationPageLayoutIdsState } from '@/layout-customization/states/activeCustomizationPageLayoutIdsState';
|
||||
import { type DraftPageLayout } from '@/page-layout/types/DraftPageLayout';
|
||||
import { useNavigationMenuItemsDraftState } from '@/navigation-menu-item/edit/hooks/useNavigationMenuItemsDraftState';
|
||||
import { fieldsWidgetGroupsDraftComponentState } from '@/page-layout/states/fieldsWidgetGroupsDraftComponentState';
|
||||
import { fieldsWidgetGroupsPersistedComponentState } from '@/page-layout/states/fieldsWidgetGroupsPersistedComponentState';
|
||||
@@ -8,6 +7,9 @@ import { fieldsWidgetUngroupedFieldsDraftComponentState } from '@/page-layout/st
|
||||
import { fieldsWidgetUngroupedFieldsPersistedComponentState } from '@/page-layout/states/fieldsWidgetUngroupedFieldsPersistedComponentState';
|
||||
import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState';
|
||||
import { pageLayoutPersistedComponentState } from '@/page-layout/states/pageLayoutPersistedComponentState';
|
||||
import { recordTableWidgetViewDraftComponentState } from '@/page-layout/states/recordTableWidgetViewDraftComponentState';
|
||||
import { recordTableWidgetViewPersistedComponentState } from '@/page-layout/states/recordTableWidgetViewPersistedComponentState';
|
||||
import { type DraftPageLayout } from '@/page-layout/types/DraftPageLayout';
|
||||
import { atom, useAtomValue } from 'jotai';
|
||||
import { useMemo } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
@@ -86,6 +88,26 @@ export const useIsLayoutCustomizationDirty = () => {
|
||||
if (!isDeeplyEqual(ungroupedFieldsDraft, ungroupedFieldsPersisted)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const recordTableWidgetViewDraft = get(
|
||||
recordTableWidgetViewDraftComponentState.atomFamily({
|
||||
instanceId: pageLayoutId,
|
||||
}),
|
||||
);
|
||||
const recordTableWidgetViewPersisted = get(
|
||||
recordTableWidgetViewPersistedComponentState.atomFamily({
|
||||
instanceId: pageLayoutId,
|
||||
}),
|
||||
);
|
||||
|
||||
if (
|
||||
!isDeeplyEqual(
|
||||
recordTableWidgetViewDraft,
|
||||
recordTableWidgetViewPersisted,
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
+5
@@ -7,6 +7,7 @@ import { navigationMenuItemsSelector } from '@/navigation-menu-item/common/state
|
||||
import { filterWorkspaceNavigationMenuItems } from '@/navigation-menu-item/common/utils/filterWorkspaceNavigationMenuItems';
|
||||
import { useSaveNavigationMenuItemsDraft } from '@/navigation-menu-item/edit/hooks/useSaveNavigationMenuItemsDraft';
|
||||
import { useCreatePendingFieldsWidgetViews } from '@/page-layout/hooks/useCreatePendingFieldsWidgetViews';
|
||||
import { useCreatePendingRecordTableWidgetViews } from '@/page-layout/hooks/useCreatePendingRecordTableWidgetViews';
|
||||
import { useSavePageLayoutWidgetsData } from '@/page-layout/hooks/useSavePageLayoutWidgetsData';
|
||||
import { useUpdatePageLayoutWithTabsAndWidgets } from '@/page-layout/hooks/useUpdatePageLayoutWithTabsAndWidgets';
|
||||
import { pageLayoutCurrentLayoutsComponentState } from '@/page-layout/states/pageLayoutCurrentLayoutsComponentState';
|
||||
@@ -42,6 +43,8 @@ export const useSaveLayoutCustomization = () => {
|
||||
useUpdatePageLayoutWithTabsAndWidgets();
|
||||
const { createPendingFieldsWidgetViews } =
|
||||
useCreatePendingFieldsWidgetViews();
|
||||
const { createPendingRecordTableWidgetViews } =
|
||||
useCreatePendingRecordTableWidgetViews();
|
||||
const { exitLayoutCustomizationMode } = useExitLayoutCustomizationMode();
|
||||
const { savePageLayoutWidgetsData } = useSavePageLayoutWidgetsData();
|
||||
|
||||
@@ -113,6 +116,7 @@ export const useSaveLayoutCustomization = () => {
|
||||
);
|
||||
|
||||
await createPendingFieldsWidgetViews(pageLayoutId);
|
||||
await createPendingRecordTableWidgetViews(pageLayoutId);
|
||||
|
||||
if (isPageLayoutStructureDirty) {
|
||||
const updateInput = convertPageLayoutDraftToUpdateInput(draft, {
|
||||
@@ -185,6 +189,7 @@ export const useSaveLayoutCustomization = () => {
|
||||
saveCommandMenuItemsDraft,
|
||||
isCommandMenuItemsDirty,
|
||||
createPendingFieldsWidgetViews,
|
||||
createPendingRecordTableWidgetViews,
|
||||
updatePageLayoutWithTabsAndWidgets,
|
||||
savePageLayoutWidgetsData,
|
||||
exitLayoutCustomizationMode,
|
||||
|
||||
@@ -2,18 +2,27 @@ import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
|
||||
import { NavigationDrawerAiChatContent } from '@/ai/components/NavigationDrawerAiChatContent';
|
||||
import { MainNavigationDrawerNavigationContent } from '@/navigation/components/MainNavigationDrawerNavigationContent';
|
||||
import { MainNavigationDrawerTabsRow } from '@/navigation/components/MainNavigationDrawerTabsRow';
|
||||
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
|
||||
import { NavigationDrawer } from '@/ui/navigation/navigation-drawer/components/NavigationDrawer';
|
||||
import { NavigationDrawerFixedContent } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerFixedContent';
|
||||
import { NavigationDrawerScrollableContent } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerScrollableContent';
|
||||
import { navigationDrawerActiveTabState } from '@/ui/navigation/states/navigationDrawerActiveTabState';
|
||||
import { NAVIGATION_DRAWER_TABS } from '@/ui/navigation/states/navigationDrawerTabs';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { PermissionFlagType } from '~/generated-metadata/graphql';
|
||||
|
||||
export const MainNavigationDrawer = ({ className }: { className?: string }) => {
|
||||
const navigationDrawerActiveTab = useAtomStateValue(
|
||||
navigationDrawerActiveTabState,
|
||||
);
|
||||
const currentWorkspace = useAtomStateValue(currentWorkspaceState);
|
||||
const hasAiSettingsPermission = useHasPermissionFlag(
|
||||
PermissionFlagType.AI_SETTINGS,
|
||||
);
|
||||
|
||||
const showAiChatContent =
|
||||
hasAiSettingsPermission &&
|
||||
navigationDrawerActiveTab === NAVIGATION_DRAWER_TABS.AI_CHAT_HISTORY;
|
||||
|
||||
return (
|
||||
<NavigationDrawer
|
||||
@@ -25,8 +34,7 @@ export const MainNavigationDrawer = ({ className }: { className?: string }) => {
|
||||
</NavigationDrawerFixedContent>
|
||||
|
||||
<NavigationDrawerScrollableContent>
|
||||
{navigationDrawerActiveTab ===
|
||||
NAVIGATION_DRAWER_TABS.AI_CHAT_HISTORY ? (
|
||||
{showAiChatContent ? (
|
||||
<NavigationDrawerAiChatContent />
|
||||
) : (
|
||||
<MainNavigationDrawerNavigationContent />
|
||||
|
||||
+9
@@ -12,6 +12,7 @@ import { useIsMobile } from 'twenty-ui/utilities';
|
||||
import { useContext } from 'react';
|
||||
|
||||
import { useSwitchToNewAiChat } from '@/ai/hooks/useSwitchToNewAiChat';
|
||||
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
|
||||
import { NavigationDrawerAnimatedCollapseWrapper } from '@/ui/navigation/navigation-drawer/components/NavigationDrawerAnimatedCollapseWrapper';
|
||||
import { isNavigationDrawerExpandedState } from '@/ui/navigation/states/isNavigationDrawerExpanded';
|
||||
import { navigationDrawerActiveTabState } from '@/ui/navigation/states/navigationDrawerActiveTabState';
|
||||
@@ -22,6 +23,7 @@ import {
|
||||
import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState';
|
||||
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
|
||||
import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
|
||||
import { PermissionFlagType } from '~/generated-metadata/graphql';
|
||||
|
||||
const StyledRow = styled.div<{ isExpanded: boolean }>`
|
||||
align-items: center;
|
||||
@@ -142,9 +144,16 @@ export const MainNavigationDrawerTabsRow = () => {
|
||||
const setIsNavigationDrawerExpanded = useSetAtomState(
|
||||
isNavigationDrawerExpandedState,
|
||||
);
|
||||
const hasAiSettingsPermission = useHasPermissionFlag(
|
||||
PermissionFlagType.AI_SETTINGS,
|
||||
);
|
||||
|
||||
const isExpanded = isNavigationDrawerExpanded || isMobile;
|
||||
|
||||
if (!hasAiSettingsPermission) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const handleTabClick = (tab: NavigationDrawerActiveTab) => () => {
|
||||
setNavigationDrawerActiveTab(tab);
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@ import { useDefaultHomePagePath } from '@/navigation/hooks/useDefaultHomePagePat
|
||||
import { useIsSettingsPage } from '@/navigation/hooks/useIsSettingsPage';
|
||||
import { currentMobileNavigationDrawerState } from '@/navigation/states/currentMobileNavigationDrawerState';
|
||||
import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems';
|
||||
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
|
||||
import { useOpenRecordsSearchPageInSidePanel } from '@/side-panel/hooks/useOpenRecordsSearchPageInSidePanel';
|
||||
import { useSidePanelMenu } from '@/side-panel/hooks/useSidePanelMenu';
|
||||
import { isSidePanelOpenedState } from '@/side-panel/states/isSidePanelOpenedState';
|
||||
@@ -20,6 +21,7 @@ import {
|
||||
IconSearch,
|
||||
} from 'twenty-ui/display';
|
||||
import { NavigationBar } from 'twenty-ui/navigation';
|
||||
import { PermissionFlagType } from '~/generated-metadata/graphql';
|
||||
|
||||
type NavigationBarItemName = 'main' | 'search' | 'newAiChat';
|
||||
|
||||
@@ -37,6 +39,9 @@ export const MobileNavigationBar = () => {
|
||||
const { switchToNewChat } = useSwitchToNewAiChat();
|
||||
const { alphaSortedActiveNonSystemObjectMetadataItems } =
|
||||
useFilteredObjectMetadataItems();
|
||||
const hasAiSettingsPermission = useHasPermissionFlag(
|
||||
PermissionFlagType.AI_SETTINGS,
|
||||
);
|
||||
|
||||
const setContextStoreCurrentObjectMetadataItemId = useSetAtomComponentState(
|
||||
contextStoreCurrentObjectMetadataItemIdComponentState,
|
||||
@@ -89,15 +94,19 @@ export const MobileNavigationBar = () => {
|
||||
openRecordsSearchPage();
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'newAiChat' as const,
|
||||
Icon: IconMessageCirclePlus,
|
||||
onClick: () => {
|
||||
setIsNavigationDrawerExpanded(false);
|
||||
closeSidePanelMenu();
|
||||
switchToNewChat();
|
||||
},
|
||||
},
|
||||
...(hasAiSettingsPermission
|
||||
? [
|
||||
{
|
||||
name: 'newAiChat' as const,
|
||||
Icon: IconMessageCirclePlus,
|
||||
onClick: () => {
|
||||
setIsNavigationDrawerExpanded(false);
|
||||
closeSidePanelMenu();
|
||||
switchToNewChat();
|
||||
},
|
||||
},
|
||||
]
|
||||
: []),
|
||||
];
|
||||
|
||||
return <NavigationBar activeItemName={activeItemName} items={items} />;
|
||||
|
||||
+1
@@ -98,6 +98,7 @@ export const RecordTableWidgetProvider = ({
|
||||
>
|
||||
<RecordTableWidgetViewLoadEffect
|
||||
viewId={viewId}
|
||||
widgetId={widgetId}
|
||||
objectMetadataItem={objectMetadataItem}
|
||||
/>
|
||||
{children}
|
||||
|
||||
+27
-9
@@ -1,6 +1,10 @@
|
||||
import { type EnrichedObjectMetadataItem } from '@/object-metadata/types/EnrichedObjectMetadataItem';
|
||||
import { useLoadRecordIndexStates } from '@/object-record/record-index/hooks/useLoadRecordIndexStates';
|
||||
import { lastLoadedRecordTableWidgetViewIdComponentState } from '@/object-record/record-table-widget/states/lastLoadedRecordTableWidgetViewIdComponentState';
|
||||
import { useIsPageLayoutInEditMode } from '@/page-layout/hooks/useIsPageLayoutInEditMode';
|
||||
import { recordTableWidgetViewDraftByWidgetIdComponentFamilySelector } from '@/page-layout/states/selectors/recordTableWidgetViewDraftByWidgetIdComponentFamilySelector';
|
||||
import { constructViewFromRecordTableWidgetViewSnapshot } from '@/page-layout/widgets/record-table/utils/constructViewFromRecordTableWidgetViewSnapshot';
|
||||
import { useAtomComponentFamilySelectorValue } from '@/ui/utilities/state/jotai/hooks/useAtomComponentFamilySelectorValue';
|
||||
import { useAtomComponentState } from '@/ui/utilities/state/jotai/hooks/useAtomComponentState';
|
||||
import { useAtomFamilySelectorValue } from '@/ui/utilities/state/jotai/hooks/useAtomFamilySelectorValue';
|
||||
import { viewFromViewIdFamilySelector } from '@/views/states/selectors/viewFromViewIdFamilySelector';
|
||||
@@ -9,11 +13,13 @@ import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
type RecordTableWidgetViewLoadEffectProps = {
|
||||
viewId: string;
|
||||
widgetId: string;
|
||||
objectMetadataItem: EnrichedObjectMetadataItem;
|
||||
};
|
||||
|
||||
export const RecordTableWidgetViewLoadEffect = ({
|
||||
viewId,
|
||||
widgetId,
|
||||
objectMetadataItem,
|
||||
}: RecordTableWidgetViewLoadEffectProps) => {
|
||||
const { loadRecordIndexStates } = useLoadRecordIndexStates();
|
||||
@@ -23,18 +29,30 @@ export const RecordTableWidgetViewLoadEffect = ({
|
||||
setLastLoadedRecordTableWidgetViewId,
|
||||
] = useAtomComponentState(lastLoadedRecordTableWidgetViewIdComponentState);
|
||||
|
||||
const viewFromViewId = useAtomFamilySelectorValue(
|
||||
viewFromViewIdFamilySelector,
|
||||
{
|
||||
viewId,
|
||||
},
|
||||
const isPageLayoutInEditMode = useIsPageLayoutInEditMode();
|
||||
|
||||
const draftSnapshot = useAtomComponentFamilySelectorValue(
|
||||
recordTableWidgetViewDraftByWidgetIdComponentFamilySelector,
|
||||
{ widgetId },
|
||||
);
|
||||
|
||||
const viewFromDraft =
|
||||
isPageLayoutInEditMode && isDefined(draftSnapshot)
|
||||
? constructViewFromRecordTableWidgetViewSnapshot(draftSnapshot)
|
||||
: undefined;
|
||||
|
||||
const viewFromSelector = useAtomFamilySelectorValue(
|
||||
viewFromViewIdFamilySelector,
|
||||
{ viewId },
|
||||
);
|
||||
|
||||
const currentView = viewFromDraft ?? viewFromSelector;
|
||||
|
||||
const viewHasFields =
|
||||
isDefined(viewFromViewId) && viewFromViewId.viewFields.length > 0;
|
||||
isDefined(currentView) && currentView.viewFields.length > 0;
|
||||
|
||||
useEffect(() => {
|
||||
if (!isDefined(viewFromViewId)) {
|
||||
if (!isDefined(currentView)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -50,7 +68,7 @@ export const RecordTableWidgetViewLoadEffect = ({
|
||||
return;
|
||||
}
|
||||
|
||||
loadRecordIndexStates(viewFromViewId, objectMetadataItem);
|
||||
loadRecordIndexStates(currentView, objectMetadataItem);
|
||||
|
||||
setLastLoadedRecordTableWidgetViewId({
|
||||
viewId,
|
||||
@@ -60,7 +78,7 @@ export const RecordTableWidgetViewLoadEffect = ({
|
||||
viewId,
|
||||
lastLoadedRecordTableWidgetViewId,
|
||||
setLastLoadedRecordTableWidgetViewId,
|
||||
viewFromViewId,
|
||||
currentView,
|
||||
viewHasFields,
|
||||
objectMetadataItem,
|
||||
loadRecordIndexStates,
|
||||
|
||||
+3
-3
@@ -9,10 +9,10 @@ import {
|
||||
} from './PageLayoutTestWrapper';
|
||||
|
||||
jest.mock(
|
||||
'@/page-layout/widgets/record-table/hooks/useDeleteViewForRecordTableWidget',
|
||||
'@/page-layout/widgets/record-table/hooks/useRemoveDraftViewForRecordTableWidget',
|
||||
() => ({
|
||||
useDeleteViewForRecordTableWidget: () => ({
|
||||
deleteViewForRecordTableWidget: jest.fn(),
|
||||
useRemoveDraftViewForRecordTableWidget: () => ({
|
||||
removeDraftViewForRecordTableWidget: jest.fn(),
|
||||
}),
|
||||
}),
|
||||
);
|
||||
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
import { pageLayoutDraftComponentState } from '@/page-layout/states/pageLayoutDraftComponentState';
|
||||
import { pageLayoutPersistedComponentState } from '@/page-layout/states/pageLayoutPersistedComponentState';
|
||||
import { recordTableWidgetViewDraftComponentState } from '@/page-layout/states/recordTableWidgetViewDraftComponentState';
|
||||
import { recordTableWidgetViewPersistedComponentState } from '@/page-layout/states/recordTableWidgetViewPersistedComponentState';
|
||||
import { getWidgetConfigurationViewId } from '@/page-layout/utils/getWidgetConfigurationViewId';
|
||||
import { usePerformViewAPIPersist } from '@/views/hooks/internal/usePerformViewAPIPersist';
|
||||
import { usePerformViewFieldAPIPersist } from '@/views/hooks/internal/usePerformViewFieldAPIPersist';
|
||||
import { useStore } from 'jotai';
|
||||
import { useCallback } from 'react';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { WidgetType } from '~/generated-metadata/graphql';
|
||||
|
||||
export const useCreatePendingRecordTableWidgetViews = () => {
|
||||
const { performViewAPICreate, performViewAPIDestroy } =
|
||||
usePerformViewAPIPersist();
|
||||
const { performViewFieldAPICreate } = usePerformViewFieldAPIPersist();
|
||||
const store = useStore();
|
||||
|
||||
const createPendingRecordTableWidgetViews = useCallback(
|
||||
async (pageLayoutId: string) => {
|
||||
const draft = store.get(
|
||||
pageLayoutDraftComponentState.atomFamily({
|
||||
instanceId: pageLayoutId,
|
||||
}),
|
||||
);
|
||||
const persisted = store.get(
|
||||
pageLayoutPersistedComponentState.atomFamily({
|
||||
instanceId: pageLayoutId,
|
||||
}),
|
||||
);
|
||||
|
||||
const recordTableWidgetViewDraft = store.get(
|
||||
recordTableWidgetViewDraftComponentState.atomFamily({
|
||||
instanceId: pageLayoutId,
|
||||
}),
|
||||
);
|
||||
|
||||
const persistedRecordTableWidgets = new Map(
|
||||
(persisted?.tabs ?? [])
|
||||
.flatMap((tab) => tab.widgets)
|
||||
.filter((widget) => widget.type === WidgetType.RECORD_TABLE)
|
||||
.map((widget) => [
|
||||
widget.id,
|
||||
getWidgetConfigurationViewId(widget.configuration),
|
||||
]),
|
||||
);
|
||||
|
||||
const draftRecordTableWidgets = draft.tabs
|
||||
.flatMap((tab) => tab.widgets)
|
||||
.filter((widget) => widget.type === WidgetType.RECORD_TABLE);
|
||||
|
||||
const draftWidgetIds = new Set(
|
||||
draftRecordTableWidgets.map((widget) => widget.id),
|
||||
);
|
||||
|
||||
for (const widget of draftRecordTableWidgets) {
|
||||
const viewId = getWidgetConfigurationViewId(widget.configuration);
|
||||
|
||||
if (!isDefined(viewId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const persistedViewId = persistedRecordTableWidgets.get(widget.id);
|
||||
|
||||
if (persistedViewId === viewId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isDefined(persistedViewId)) {
|
||||
await performViewAPIDestroy({ id: persistedViewId });
|
||||
}
|
||||
|
||||
const widgetViewDraft = recordTableWidgetViewDraft[widget.id];
|
||||
|
||||
if (!isDefined(widgetViewDraft)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const { view } = widgetViewDraft;
|
||||
|
||||
const result = await performViewAPICreate(
|
||||
{
|
||||
input: {
|
||||
id: view.id,
|
||||
name: view.name,
|
||||
icon: view.icon,
|
||||
objectMetadataId: view.objectMetadataId,
|
||||
type: view.type,
|
||||
isCompact: view.isCompact,
|
||||
position: view.position,
|
||||
openRecordIn: view.openRecordIn,
|
||||
visibility: view.visibility,
|
||||
shouldHideEmptyGroups: view.shouldHideEmptyGroups,
|
||||
},
|
||||
},
|
||||
view.objectMetadataId,
|
||||
);
|
||||
|
||||
if (result.status === 'failed') {
|
||||
throw new Error(
|
||||
`Failed to create view for RECORD_TABLE widget ${widget.id}`,
|
||||
);
|
||||
}
|
||||
|
||||
const viewFieldInputs = widgetViewDraft.viewFields.map((field) => ({
|
||||
id: field.id,
|
||||
viewId: field.viewId,
|
||||
fieldMetadataId: field.fieldMetadataId,
|
||||
position: field.position,
|
||||
size: field.size,
|
||||
isVisible: field.isVisible,
|
||||
}));
|
||||
|
||||
if (viewFieldInputs.length > 0) {
|
||||
await performViewFieldAPICreate({ inputs: viewFieldInputs });
|
||||
}
|
||||
}
|
||||
|
||||
for (const [widgetId, viewId] of persistedRecordTableWidgets) {
|
||||
if (!draftWidgetIds.has(widgetId) && isDefined(viewId)) {
|
||||
await performViewAPIDestroy({ id: viewId });
|
||||
}
|
||||
}
|
||||
|
||||
store.set(
|
||||
recordTableWidgetViewPersistedComponentState.atomFamily({
|
||||
instanceId: pageLayoutId,
|
||||
}),
|
||||
recordTableWidgetViewDraft,
|
||||
);
|
||||
},
|
||||
[
|
||||
performViewAPICreate,
|
||||
performViewAPIDestroy,
|
||||
performViewFieldAPICreate,
|
||||
store,
|
||||
],
|
||||
);
|
||||
|
||||
return { createPendingRecordTableWidgetViews };
|
||||
};
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useCreatePendingFieldsWidgetViews } from '@/page-layout/hooks/useCreatePendingFieldsWidgetViews';
|
||||
import { useCreatePendingRecordTableWidgetViews } from '@/page-layout/hooks/useCreatePendingRecordTableWidgetViews';
|
||||
import { useUpdatePageLayoutWithTabsAndWidgets } from '@/page-layout/hooks/useUpdatePageLayoutWithTabsAndWidgets';
|
||||
import { PageLayoutComponentInstanceContext } from '@/page-layout/states/contexts/PageLayoutComponentInstanceContext';
|
||||
import { pageLayoutCurrentLayoutsComponentState } from '@/page-layout/states/pageLayoutCurrentLayoutsComponentState';
|
||||
@@ -45,6 +46,9 @@ export const useSavePageLayout = (pageLayoutIdFromProps: string) => {
|
||||
const { createPendingFieldsWidgetViews } =
|
||||
useCreatePendingFieldsWidgetViews();
|
||||
|
||||
const { createPendingRecordTableWidgetViews } =
|
||||
useCreatePendingRecordTableWidgetViews();
|
||||
|
||||
const featureFlags = useFeatureFlagsMap();
|
||||
const isRecordPageLayoutEditingEnabled =
|
||||
featureFlags[FeatureFlagKey.IS_RECORD_PAGE_LAYOUT_EDITING_ENABLED];
|
||||
@@ -52,6 +56,7 @@ export const useSavePageLayout = (pageLayoutIdFromProps: string) => {
|
||||
|
||||
const savePageLayout = useCallback(async () => {
|
||||
await createPendingFieldsWidgetViews(pageLayoutId);
|
||||
await createPendingRecordTableWidgetViews(pageLayoutId);
|
||||
|
||||
const pageLayoutDraft = store.get(pageLayoutDraftCallbackState);
|
||||
const updateInput = convertPageLayoutDraftToUpdateInput(pageLayoutDraft, {
|
||||
@@ -91,6 +96,7 @@ export const useSavePageLayout = (pageLayoutIdFromProps: string) => {
|
||||
return result;
|
||||
}, [
|
||||
createPendingFieldsWidgetViews,
|
||||
createPendingRecordTableWidgetViews,
|
||||
isRecordPageLayoutEditingEnabled,
|
||||
pageLayoutCurrentLayoutsCallbackState,
|
||||
pageLayoutDraftCallbackState,
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import { type RecordTableWidgetViewSnapshot } from '@/page-layout/widgets/record-table/types/RecordTableWidgetViewSnapshot';
|
||||
import { createAtomComponentState } from '@/ui/utilities/state/jotai/utils/createAtomComponentState';
|
||||
|
||||
import { PageLayoutComponentInstanceContext } from './contexts/PageLayoutComponentInstanceContext';
|
||||
|
||||
export const recordTableWidgetViewDraftComponentState =
|
||||
createAtomComponentState<Record<string, RecordTableWidgetViewSnapshot>>({
|
||||
key: 'recordTableWidgetViewDraftComponentState',
|
||||
defaultValue: {},
|
||||
componentInstanceContext: PageLayoutComponentInstanceContext,
|
||||
});
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import { type RecordTableWidgetViewSnapshot } from '@/page-layout/widgets/record-table/types/RecordTableWidgetViewSnapshot';
|
||||
import { createAtomComponentState } from '@/ui/utilities/state/jotai/utils/createAtomComponentState';
|
||||
|
||||
import { PageLayoutComponentInstanceContext } from './contexts/PageLayoutComponentInstanceContext';
|
||||
|
||||
export const recordTableWidgetViewPersistedComponentState =
|
||||
createAtomComponentState<Record<string, RecordTableWidgetViewSnapshot>>({
|
||||
key: 'recordTableWidgetViewPersistedComponentState',
|
||||
defaultValue: {},
|
||||
componentInstanceContext: PageLayoutComponentInstanceContext,
|
||||
});
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
import { recordTableWidgetViewDraftComponentState } from '@/page-layout/states/recordTableWidgetViewDraftComponentState';
|
||||
import { type RecordTableWidgetViewSnapshot } from '@/page-layout/widgets/record-table/types/RecordTableWidgetViewSnapshot';
|
||||
import { createAtomComponentFamilySelector } from '@/ui/utilities/state/jotai/utils/createAtomComponentFamilySelector';
|
||||
|
||||
import { PageLayoutComponentInstanceContext } from '../contexts/PageLayoutComponentInstanceContext';
|
||||
|
||||
export const recordTableWidgetViewDraftByWidgetIdComponentFamilySelector =
|
||||
createAtomComponentFamilySelector<
|
||||
RecordTableWidgetViewSnapshot | undefined,
|
||||
{ widgetId: string }
|
||||
>({
|
||||
key: 'recordTableWidgetViewDraftByWidgetIdComponentFamilySelector',
|
||||
componentInstanceContext: PageLayoutComponentInstanceContext,
|
||||
get:
|
||||
({ instanceId, familyKey }) =>
|
||||
({ get }) => {
|
||||
const draftMap = get(recordTableWidgetViewDraftComponentState, {
|
||||
instanceId,
|
||||
});
|
||||
|
||||
return draftMap[familyKey.widgetId];
|
||||
},
|
||||
});
|
||||
+281
@@ -0,0 +1,281 @@
|
||||
import { type FlatViewField } from '@/metadata-store/types/FlatViewField';
|
||||
import { type FlatViewFieldGroup } from '@/metadata-store/types/FlatViewFieldGroup';
|
||||
import { type FieldMetadataItem } from '@/object-metadata/types/FieldMetadataItem';
|
||||
import { buildFieldsWidgetGroupsFromFlatViewData } from '@/page-layout/utils/buildFieldsWidgetGroupsFromFlatViewData';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
|
||||
const createFieldMetadata = (
|
||||
overrides: Partial<FieldMetadataItem> & { id: string },
|
||||
): FieldMetadataItem =>
|
||||
({
|
||||
name: 'field',
|
||||
label: 'Field',
|
||||
type: FieldMetadataType.TEXT,
|
||||
isActive: true,
|
||||
isSystem: false,
|
||||
...overrides,
|
||||
}) as FieldMetadataItem;
|
||||
|
||||
const createFlatViewField = (
|
||||
overrides: Partial<FlatViewField> & {
|
||||
id: string;
|
||||
fieldMetadataId: string;
|
||||
viewId: string;
|
||||
},
|
||||
): FlatViewField =>
|
||||
({
|
||||
position: 0,
|
||||
isVisible: true,
|
||||
isActive: true,
|
||||
...overrides,
|
||||
}) as FlatViewField;
|
||||
|
||||
const createFlatViewFieldGroup = (
|
||||
overrides: Partial<FlatViewFieldGroup> & { id: string },
|
||||
): FlatViewFieldGroup =>
|
||||
({
|
||||
name: 'Group',
|
||||
position: 0,
|
||||
isVisible: true,
|
||||
...overrides,
|
||||
}) as FlatViewFieldGroup;
|
||||
|
||||
describe('buildFieldsWidgetGroupsFromFlatViewData', () => {
|
||||
const fm1 = createFieldMetadata({ id: 'fm-1', name: 'name', label: 'Name' });
|
||||
const fm2 = createFieldMetadata({
|
||||
id: 'fm-2',
|
||||
name: 'email',
|
||||
label: 'Email',
|
||||
});
|
||||
const fm3 = createFieldMetadata({
|
||||
id: 'fm-3',
|
||||
name: 'phone',
|
||||
label: 'Phone',
|
||||
});
|
||||
|
||||
describe('ungrouped mode', () => {
|
||||
it('should return ungrouped fields sorted by position when no groups exist', () => {
|
||||
const flatViewFields = [
|
||||
createFlatViewField({
|
||||
id: 'vf-2',
|
||||
fieldMetadataId: 'fm-2',
|
||||
viewId: 'v1',
|
||||
position: 1,
|
||||
}),
|
||||
createFlatViewField({
|
||||
id: 'vf-1',
|
||||
fieldMetadataId: 'fm-1',
|
||||
viewId: 'v1',
|
||||
position: 0,
|
||||
}),
|
||||
];
|
||||
|
||||
const result = buildFieldsWidgetGroupsFromFlatViewData({
|
||||
flatViewFieldGroups: [],
|
||||
flatViewFields,
|
||||
fieldMetadataItems: [fm1, fm2],
|
||||
});
|
||||
|
||||
expect(result.editorMode).toBe('ungrouped');
|
||||
expect(result.groups).toEqual([]);
|
||||
expect(result.ungroupedFields).toHaveLength(2);
|
||||
expect(result.ungroupedFields[0].fieldMetadataItem.id).toBe('fm-1');
|
||||
expect(result.ungroupedFields[1].fieldMetadataItem.id).toBe('fm-2');
|
||||
});
|
||||
|
||||
it('should assign sequential globalIndex based on sorted position', () => {
|
||||
const flatViewFields = [
|
||||
createFlatViewField({
|
||||
id: 'vf-1',
|
||||
fieldMetadataId: 'fm-1',
|
||||
viewId: 'v1',
|
||||
position: 5,
|
||||
}),
|
||||
createFlatViewField({
|
||||
id: 'vf-2',
|
||||
fieldMetadataId: 'fm-2',
|
||||
viewId: 'v1',
|
||||
position: 2,
|
||||
}),
|
||||
];
|
||||
|
||||
const result = buildFieldsWidgetGroupsFromFlatViewData({
|
||||
flatViewFieldGroups: [],
|
||||
flatViewFields,
|
||||
fieldMetadataItems: [fm1, fm2],
|
||||
});
|
||||
|
||||
expect(result.ungroupedFields[0].globalIndex).toBe(0);
|
||||
expect(result.ungroupedFields[0].fieldMetadataItem.id).toBe('fm-2');
|
||||
expect(result.ungroupedFields[1].globalIndex).toBe(1);
|
||||
expect(result.ungroupedFields[1].fieldMetadataItem.id).toBe('fm-1');
|
||||
});
|
||||
|
||||
it('should skip fields whose fieldMetadataId has no matching metadata', () => {
|
||||
const flatViewFields = [
|
||||
createFlatViewField({
|
||||
id: 'vf-1',
|
||||
fieldMetadataId: 'fm-1',
|
||||
viewId: 'v1',
|
||||
position: 0,
|
||||
}),
|
||||
createFlatViewField({
|
||||
id: 'vf-orphan',
|
||||
fieldMetadataId: 'fm-nonexistent',
|
||||
viewId: 'v1',
|
||||
position: 1,
|
||||
}),
|
||||
];
|
||||
|
||||
const result = buildFieldsWidgetGroupsFromFlatViewData({
|
||||
flatViewFieldGroups: [],
|
||||
flatViewFields,
|
||||
fieldMetadataItems: [fm1],
|
||||
});
|
||||
|
||||
expect(result.ungroupedFields).toHaveLength(1);
|
||||
expect(result.ungroupedFields[0].fieldMetadataItem.id).toBe('fm-1');
|
||||
});
|
||||
|
||||
it('should return empty ungroupedFields when there are no view fields', () => {
|
||||
const result = buildFieldsWidgetGroupsFromFlatViewData({
|
||||
flatViewFieldGroups: [],
|
||||
flatViewFields: [],
|
||||
fieldMetadataItems: [fm1],
|
||||
});
|
||||
|
||||
expect(result.editorMode).toBe('ungrouped');
|
||||
expect(result.ungroupedFields).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('grouped mode', () => {
|
||||
it('should return grouped fields when groups exist', () => {
|
||||
const group1 = createFlatViewFieldGroup({
|
||||
id: 'g1',
|
||||
name: 'General',
|
||||
position: 0,
|
||||
});
|
||||
const group2 = createFlatViewFieldGroup({
|
||||
id: 'g2',
|
||||
name: 'Details',
|
||||
position: 1,
|
||||
});
|
||||
|
||||
const flatViewFields = [
|
||||
createFlatViewField({
|
||||
id: 'vf-1',
|
||||
fieldMetadataId: 'fm-1',
|
||||
viewId: 'v1',
|
||||
position: 0,
|
||||
viewFieldGroupId: 'g1',
|
||||
}),
|
||||
createFlatViewField({
|
||||
id: 'vf-2',
|
||||
fieldMetadataId: 'fm-2',
|
||||
viewId: 'v1',
|
||||
position: 0,
|
||||
viewFieldGroupId: 'g2',
|
||||
}),
|
||||
];
|
||||
|
||||
const result = buildFieldsWidgetGroupsFromFlatViewData({
|
||||
flatViewFieldGroups: [group1, group2],
|
||||
flatViewFields,
|
||||
fieldMetadataItems: [fm1, fm2],
|
||||
});
|
||||
|
||||
expect(result.editorMode).toBe('grouped');
|
||||
expect(result.ungroupedFields).toEqual([]);
|
||||
expect(result.groups).toHaveLength(2);
|
||||
expect(result.groups[0].name).toBe('General');
|
||||
expect(result.groups[0].fields).toHaveLength(1);
|
||||
expect(result.groups[0].fields[0].fieldMetadataItem.id).toBe('fm-1');
|
||||
expect(result.groups[1].name).toBe('Details');
|
||||
expect(result.groups[1].fields[0].fieldMetadataItem.id).toBe('fm-2');
|
||||
});
|
||||
|
||||
it('should sort fields within each group by position', () => {
|
||||
const group = createFlatViewFieldGroup({ id: 'g1', name: 'All' });
|
||||
|
||||
const flatViewFields = [
|
||||
createFlatViewField({
|
||||
id: 'vf-3',
|
||||
fieldMetadataId: 'fm-3',
|
||||
viewId: 'v1',
|
||||
position: 2,
|
||||
viewFieldGroupId: 'g1',
|
||||
}),
|
||||
createFlatViewField({
|
||||
id: 'vf-1',
|
||||
fieldMetadataId: 'fm-1',
|
||||
viewId: 'v1',
|
||||
position: 0,
|
||||
viewFieldGroupId: 'g1',
|
||||
}),
|
||||
createFlatViewField({
|
||||
id: 'vf-2',
|
||||
fieldMetadataId: 'fm-2',
|
||||
viewId: 'v1',
|
||||
position: 1,
|
||||
viewFieldGroupId: 'g1',
|
||||
}),
|
||||
];
|
||||
|
||||
const result = buildFieldsWidgetGroupsFromFlatViewData({
|
||||
flatViewFieldGroups: [group],
|
||||
flatViewFields,
|
||||
fieldMetadataItems: [fm1, fm2, fm3],
|
||||
});
|
||||
|
||||
expect(
|
||||
result.groups[0].fields.map((f) => f.fieldMetadataItem.id),
|
||||
).toEqual(['fm-1', 'fm-2', 'fm-3']);
|
||||
});
|
||||
|
||||
it('should skip fields with missing metadata in grouped mode', () => {
|
||||
const group = createFlatViewFieldGroup({ id: 'g1', name: 'All' });
|
||||
|
||||
const flatViewFields = [
|
||||
createFlatViewField({
|
||||
id: 'vf-1',
|
||||
fieldMetadataId: 'fm-1',
|
||||
viewId: 'v1',
|
||||
position: 0,
|
||||
viewFieldGroupId: 'g1',
|
||||
}),
|
||||
createFlatViewField({
|
||||
id: 'vf-orphan',
|
||||
fieldMetadataId: 'fm-nonexistent',
|
||||
viewId: 'v1',
|
||||
position: 1,
|
||||
viewFieldGroupId: 'g1',
|
||||
}),
|
||||
];
|
||||
|
||||
const result = buildFieldsWidgetGroupsFromFlatViewData({
|
||||
flatViewFieldGroups: [group],
|
||||
flatViewFields,
|
||||
fieldMetadataItems: [fm1],
|
||||
});
|
||||
|
||||
expect(result.groups[0].fields).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('should preserve group visibility in the output', () => {
|
||||
const group = createFlatViewFieldGroup({
|
||||
id: 'g1',
|
||||
name: 'Hidden Group',
|
||||
isVisible: false,
|
||||
});
|
||||
|
||||
const result = buildFieldsWidgetGroupsFromFlatViewData({
|
||||
flatViewFieldGroups: [group],
|
||||
flatViewFields: [],
|
||||
fieldMetadataItems: [],
|
||||
});
|
||||
|
||||
expect(result.groups[0].isVisible).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
+14
-7
@@ -1,6 +1,7 @@
|
||||
import { useObjectMetadataItemById } from '@/object-metadata/hooks/useObjectMetadataItemById';
|
||||
import { RecordTableWidget } from '@/object-record/record-table-widget/components/RecordTableWidget';
|
||||
import { RecordTableWidgetProvider } from '@/object-record/record-table-widget/components/RecordTableWidgetProvider';
|
||||
import { RecordTableWidgetViewDraftInitEffect } from '@/page-layout/widgets/record-table/components/RecordTableWidgetViewDraftInitEffect';
|
||||
|
||||
type RecordTableWidgetRendererContentProps = {
|
||||
objectMetadataId: string;
|
||||
@@ -18,12 +19,18 @@ export const RecordTableWidgetRendererContent = ({
|
||||
});
|
||||
|
||||
return (
|
||||
<RecordTableWidgetProvider
|
||||
objectNameSingular={objectMetadataItem.nameSingular}
|
||||
viewId={viewId}
|
||||
widgetId={widgetId}
|
||||
>
|
||||
<RecordTableWidget />
|
||||
</RecordTableWidgetProvider>
|
||||
<>
|
||||
<RecordTableWidgetViewDraftInitEffect
|
||||
widgetId={widgetId}
|
||||
viewId={viewId}
|
||||
/>
|
||||
<RecordTableWidgetProvider
|
||||
objectNameSingular={objectMetadataItem.nameSingular}
|
||||
viewId={viewId}
|
||||
widgetId={widgetId}
|
||||
>
|
||||
<RecordTableWidget />
|
||||
</RecordTableWidgetProvider>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user