From 2eb1d03c201a1be30d9f583d07092bcdf774ac9f Mon Sep 17 00:00:00 2001 From: sriram veeraghanta Date: Fri, 21 Mar 2025 01:51:50 +0530 Subject: [PATCH 001/146] fix: transpile and optimize package imports --- web/next.config.js | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/web/next.config.js b/web/next.config.js index 672d9151b..8422342b6 100644 --- a/web/next.config.js +++ b/web/next.config.js @@ -18,7 +18,39 @@ const nextConfig = { images: { unoptimized: true, }, - transpilePackages: ["@plane/i18n", "@plane/propel"], + experimental: { + optimizePackageImports: [ + "lucide-react", + "date-fns", + "@headlessui/react", + "@nivo/core", + "@nivo/bar", + "@nivo/line", + "@nivo/pie", + "@nivo/calendar", + "@nivo/scatterplot", + "react-color", + "react-day-picker", + "react-dropzone", + "react-hook-form", + "lodash", + "clsx", + "tailwind-merge", + ], + }, + transpilePackages: [ + "@plane/constants", + "@plane/editor", + "@plane/hooks", + "@plane/i18n", + "@plane/logger", + "@plane/propel", + "@plane/services", + "@plane/shared-state", + "@plane/types", + "@plane/ui", + "@plane/utils", + ], async redirects() { return [ { From 6bafdb6dd8d1a8c1286d0746bd664d09dd2db9db Mon Sep 17 00:00:00 2001 From: Vipin Chaudhary Date: Mon, 24 Mar 2025 12:32:11 +0530 Subject: [PATCH 002/146] [PE-298] Fix: Copy markdown to clipboard (#6675) * fix: markdown for mentions fixed * fix: copying text in mentions * fix: refactored the component to use the same function * chore: renamed funcion name * add the new copy extension * init working fix * remove useless code * improve readibility * update node import * better smaller logic * remove log * add open close end handler * update readabliity * handle tables * handle triple click in cell * triple tap select current line * handle block and list * lists fixed * handle all possible cases of copy in table * update the min elements * handle multi types in table * handle table seletion cases * handle whole table handler * feat: all case converd * update markdown handling code * update return statement * handle using group block * handle param * handle multple cell in table * handle using recursion * add types * fix code rabbit suggestions * fix root node bug * update recursion with loop * update transform copied to false * refactor clipboard extension: remove options and integrate MarkdownClipboard into core extensions * fix: header and code handler * fix: store hooks fixed * fix: mention id --------- Co-authored-by: Palanikannan M --- .../editor/src/core/extensions/clipboard.ts | 89 +++++++++++++++++++ .../editor/src/core/extensions/extensions.tsx | 4 +- packages/editor/src/core/extensions/index.ts | 1 + .../extensions/mentions/extension-config.ts | 24 ++++- .../core/extensions/mentions/extension.tsx | 3 +- .../core/extensions/read-only-extensions.tsx | 4 +- .../extensions/table/table/table-controls.ts | 16 ++++ packages/editor/src/core/types/mention.ts | 3 +- .../editor/lite-text-read-only-editor.tsx | 41 +++++---- .../components/editor/rich-text-editor.tsx | 7 +- .../editor/rich-text-read-only-editor.tsx | 41 +++++---- .../lite-text-editor/lite-text-editor.tsx | 5 ++ .../lite-text-read-only-editor.tsx | 6 ++ .../rich-text-editor/rich-text-editor.tsx | 5 ++ .../rich-text-read-only-editor.tsx | 6 ++ .../components/pages/editor/editor-body.tsx | 5 +- web/core/components/pages/version/editor.tsx | 5 ++ 17 files changed, 225 insertions(+), 40 deletions(-) create mode 100644 packages/editor/src/core/extensions/clipboard.ts diff --git a/packages/editor/src/core/extensions/clipboard.ts b/packages/editor/src/core/extensions/clipboard.ts new file mode 100644 index 000000000..252f0a113 --- /dev/null +++ b/packages/editor/src/core/extensions/clipboard.ts @@ -0,0 +1,89 @@ +import { Extension } from "@tiptap/core"; +import { Fragment, Node } from "@tiptap/pm/model"; +import { Plugin, PluginKey } from "@tiptap/pm/state"; + +export const MarkdownClipboard = Extension.create({ + name: "markdownClipboard", + + addProseMirrorPlugins() { + return [ + new Plugin({ + key: new PluginKey("markdownClipboard"), + props: { + clipboardTextSerializer: (slice) => { + const markdownSerializer = this.editor.storage.markdown.serializer; + const isTableRow = slice.content.firstChild?.type?.name === "tableRow"; + const nodeSelect = slice.openStart === 0 && slice.openEnd === 0; + + if (nodeSelect) { + return markdownSerializer.serialize(slice.content); + } + + const processTableContent = (tableNode: Node | Fragment) => { + let result = ""; + tableNode.content?.forEach?.((tableRowNode: Node | Fragment) => { + tableRowNode.content?.forEach?.((cell: Node) => { + const cellContent = cell.content ? markdownSerializer.serialize(cell.content) : ""; + result += cellContent + "\n"; + }); + }); + return result; + }; + + if (isTableRow) { + const rowsCount = slice.content?.childCount || 0; + const cellsCount = slice.content?.firstChild?.content?.childCount || 0; + if (rowsCount === 1 || cellsCount === 1) { + return processTableContent(slice.content); + } else { + return markdownSerializer.serialize(slice.content); + } + } + + const traverseToParentOfLeaf = ( + node: Node | null, + parent: Fragment | Node, + depth: number + ): Node | Fragment => { + let currentNode = node; + let currentParent = parent; + let currentDepth = depth; + + while (currentNode && currentDepth > 1 && currentNode.content?.firstChild) { + if (currentNode.content?.childCount > 1) { + if (currentNode.content.firstChild?.type?.name === "listItem") { + return currentParent; + } else { + return currentNode.content; + } + } + + currentParent = currentNode; + currentNode = currentNode.content?.firstChild || null; + currentDepth--; + } + + return currentParent; + }; + + if (slice.content.childCount > 1) { + return markdownSerializer.serialize(slice.content); + } else { + const targetNode = traverseToParentOfLeaf(slice.content.firstChild, slice.content, slice.openStart); + + let currentNode = targetNode; + while (currentNode && currentNode.content && currentNode.childCount === 1 && currentNode.firstChild) { + currentNode = currentNode.firstChild; + } + if (currentNode instanceof Node && currentNode.isText) { + return currentNode.text; + } + + return markdownSerializer.serialize(targetNode); + } + }, + }, + }), + ]; + }, +}); diff --git a/packages/editor/src/core/extensions/extensions.tsx b/packages/editor/src/core/extensions/extensions.tsx index 8b9290d62..002dce945 100644 --- a/packages/editor/src/core/extensions/extensions.tsx +++ b/packages/editor/src/core/extensions/extensions.tsx @@ -29,6 +29,7 @@ import { TableCell, TableHeader, TableRow, + MarkdownClipboard, } from "@/extensions"; // helpers import { isValidHttpUrl } from "@/helpers/common"; @@ -130,10 +131,11 @@ export const CoreEditorExtensions = (args: TArguments): Extensions => { CustomCodeInlineExtension, Markdown.configure({ html: true, - transformCopiedText: true, + transformCopiedText: false, transformPastedText: true, breaks: true, }), + MarkdownClipboard, Table, TableHeader, TableCell, diff --git a/packages/editor/src/core/extensions/index.ts b/packages/editor/src/core/extensions/index.ts index d1fa0ce6d..e98607585 100644 --- a/packages/editor/src/core/extensions/index.ts +++ b/packages/editor/src/core/extensions/index.ts @@ -23,3 +23,4 @@ export * from "./quote"; export * from "./read-only-extensions"; export * from "./side-menu"; export * from "./text-align"; +export * from "./clipboard"; diff --git a/packages/editor/src/core/extensions/mentions/extension-config.ts b/packages/editor/src/core/extensions/mentions/extension-config.ts index 827137a1d..cf192507f 100644 --- a/packages/editor/src/core/extensions/mentions/extension-config.ts +++ b/packages/editor/src/core/extensions/mentions/extension-config.ts @@ -1,12 +1,15 @@ import { mergeAttributes } from "@tiptap/core"; import Mention, { MentionOptions } from "@tiptap/extension-mention"; +import { MarkdownSerializerState } from "@tiptap/pm/markdown"; +import { Node as NodeType } from "@tiptap/pm/model"; // types import { TMentionHandler } from "@/types"; // local types -import { EMentionComponentAttributeNames } from "./types"; +import { EMentionComponentAttributeNames, TMentionComponentAttributes } from "./types"; export type TMentionExtensionOptions = MentionOptions & { renderComponent: TMentionHandler["renderComponent"]; + getMentionedEntityDetails: TMentionHandler["getMentionedEntityDetails"]; }; export const CustomMentionExtensionConfig = Mention.extend({ @@ -40,9 +43,26 @@ export const CustomMentionExtensionConfig = Mention.extend { - const { searchCallback, renderComponent } = props; + const { searchCallback, renderComponent, getMentionedEntityDetails } = props; return CustomMentionExtensionConfig.extend({ addOptions(this) { return { ...this.parent?.(), renderComponent, + getMentionedEntityDetails, }; }, diff --git a/packages/editor/src/core/extensions/read-only-extensions.tsx b/packages/editor/src/core/extensions/read-only-extensions.tsx index b949fe6b7..6f09cb683 100644 --- a/packages/editor/src/core/extensions/read-only-extensions.tsx +++ b/packages/editor/src/core/extensions/read-only-extensions.tsx @@ -24,6 +24,7 @@ import { CustomTextAlignExtension, CustomCalloutReadOnlyExtension, CustomColorExtension, + MarkdownClipboard, } from "@/extensions"; // helpers import { isValidHttpUrl } from "@/helpers/common"; @@ -114,8 +115,9 @@ export const CoreReadOnlyEditorExtensions = (props: Props): Extensions => { CustomCodeInlineExtension, Markdown.configure({ html: true, - transformCopiedText: true, + transformCopiedText: false, }), + MarkdownClipboard, Table, TableHeader, TableCell, diff --git a/packages/editor/src/core/extensions/table/table/table-controls.ts b/packages/editor/src/core/extensions/table/table/table-controls.ts index bd5f8f589..052922579 100644 --- a/packages/editor/src/core/extensions/table/table/table-controls.ts +++ b/packages/editor/src/core/extensions/table/table/table-controls.ts @@ -16,6 +16,22 @@ export function tableControls() { }, }, props: { + handleTripleClickOn(view, pos, node, nodePos, event, direct) { + if (node.type.name === 'tableCell') { + event.preventDefault(); + const $pos = view.state.doc.resolve(pos); + const line = $pos.parent; + const linePos = $pos.start(); + const start = linePos; + const end = linePos + line.nodeSize - 1; + const tr = view.state.tr.setSelection( + TextSelection.create(view.state.doc, start, end) + ); + view.dispatch(tr); + return true; + } + return false; + }, handleDOMEvents: { mousemove: (view, event) => { const pluginState = key.getState(view.state); diff --git a/packages/editor/src/core/types/mention.ts b/packages/editor/src/core/types/mention.ts index 20f1ec0dc..b7a65f8b4 100644 --- a/packages/editor/src/core/types/mention.ts +++ b/packages/editor/src/core/types/mention.ts @@ -1,5 +1,5 @@ // plane types -import { TSearchEntities } from "@plane/types"; +import { IUserLite, TSearchEntities } from "@plane/types"; export type TMentionSuggestion = { entity_identifier: string; @@ -20,6 +20,7 @@ export type TMentionComponentProps = Pick React.ReactNode; + getMentionedEntityDetails?: (entity_identifier: string) => { display_name: string } | undefined; }; export type TMentionHandler = TReadOnlyMentionHandler & { diff --git a/space/core/components/editor/lite-text-read-only-editor.tsx b/space/core/components/editor/lite-text-read-only-editor.tsx index 5c8785e90..acb5cf14d 100644 --- a/space/core/components/editor/lite-text-read-only-editor.tsx +++ b/space/core/components/editor/lite-text-read-only-editor.tsx @@ -7,6 +7,8 @@ import { EditorMentionsRoot } from "@/components/editor"; // helpers import { cn } from "@/helpers/common.helper"; import { getReadOnlyEditorFileHandlers } from "@/helpers/editor.helper"; +// store hooks +import { useMember } from "@/hooks/store"; type LiteTextReadOnlyEditorWrapperProps = MakeOptional< Omit, @@ -17,22 +19,29 @@ type LiteTextReadOnlyEditorWrapperProps = MakeOptional< }; export const LiteTextReadOnlyEditor = React.forwardRef( - ({ anchor, workspaceId, disabledExtensions, ...props }, ref) => ( - , - }} - {...props} - // overriding the customClassName to add relative class passed - containerClassName={cn(props.containerClassName, "relative p-2")} - /> - ) + ({ anchor, workspaceId, disabledExtensions, ...props }, ref) => { + const { getMemberById } = useMember(); + + return ( + , + getMentionedEntityDetails: (id: string) => ({ + display_name: getMemberById(id)?.member__display_name ?? "", + }), + }} + {...props} + // overriding the customClassName to add relative class passed + containerClassName={cn(props.containerClassName, "relative p-2")} + /> + ); + } ); LiteTextReadOnlyEditor.displayName = "LiteTextReadOnlyEditor"; diff --git a/space/core/components/editor/rich-text-editor.tsx b/space/core/components/editor/rich-text-editor.tsx index 682036f2a..8bf98c230 100644 --- a/space/core/components/editor/rich-text-editor.tsx +++ b/space/core/components/editor/rich-text-editor.tsx @@ -6,6 +6,8 @@ import { MakeOptional } from "@plane/types"; import { EditorMentionsRoot } from "@/components/editor"; // helpers import { getEditorFileHandlers } from "@/helpers/editor.helper"; +// store hooks +import { useMember } from "@/hooks/store"; interface RichTextEditorWrapperProps extends MakeOptional, "disabledExtensions"> { @@ -16,11 +18,14 @@ interface RichTextEditorWrapperProps export const RichTextEditor = forwardRef((props, ref) => { const { anchor, containerClassName, uploadFile, workspaceId, disabledExtensions, ...rest } = props; - + const { getMemberById } = useMember(); return ( , + getMentionedEntityDetails: (id: string) => ({ + display_name: getMemberById(id)?.member__display_name ?? "", + }), }} ref={ref} disabledExtensions={disabledExtensions ?? []} diff --git a/space/core/components/editor/rich-text-read-only-editor.tsx b/space/core/components/editor/rich-text-read-only-editor.tsx index b989e1e41..f2d386629 100644 --- a/space/core/components/editor/rich-text-read-only-editor.tsx +++ b/space/core/components/editor/rich-text-read-only-editor.tsx @@ -7,6 +7,8 @@ import { EditorMentionsRoot } from "@/components/editor"; // helpers import { cn } from "@/helpers/common.helper"; import { getReadOnlyEditorFileHandlers } from "@/helpers/editor.helper"; +// store hooks +import { useMember } from "@/hooks/store"; type RichTextReadOnlyEditorWrapperProps = MakeOptional< Omit, @@ -17,22 +19,29 @@ type RichTextReadOnlyEditorWrapperProps = MakeOptional< }; export const RichTextReadOnlyEditor = React.forwardRef( - ({ anchor, workspaceId, disabledExtensions, ...props }, ref) => ( - , - }} - {...props} - // overriding the customClassName to add relative class passed - containerClassName={cn("relative p-0 border-none", props.containerClassName)} - /> - ) + ({ anchor, workspaceId, disabledExtensions, ...props }, ref) => { + const { getMemberById } = useMember(); + + return ( + , + getMentionedEntityDetails: (id: string) => ({ + display_name: getMemberById(id)?.member__display_name ?? "", + }), + }} + {...props} + // overriding the customClassName to add relative class passed + containerClassName={cn("relative p-0 border-none", props.containerClassName)} + /> + ); + } ); RichTextReadOnlyEditor.displayName = "RichTextReadOnlyEditor"; diff --git a/web/core/components/editor/lite-text-editor/lite-text-editor.tsx b/web/core/components/editor/lite-text-editor/lite-text-editor.tsx index b06d39c85..714b773a4 100644 --- a/web/core/components/editor/lite-text-editor/lite-text-editor.tsx +++ b/web/core/components/editor/lite-text-editor/lite-text-editor.tsx @@ -13,6 +13,8 @@ import { cn } from "@/helpers/common.helper"; import { isCommentEmpty } from "@/helpers/string.helper"; // hooks import { useEditorConfig, useEditorMention } from "@/hooks/editor"; +// store hooks +import { useMember } from "@/hooks/store"; // plane web hooks import { useEditorFlagging } from "@/plane-web/hooks/use-editor-flagging"; // plane web services @@ -57,6 +59,8 @@ export const LiteTextEditor = React.forwardRef @@ -97,6 +101,7 @@ export const LiteTextEditor = React.forwardRef , + getMentionedEntityDetails: (id: string) => ({ display_name: getUserDetails(id)?.display_name ?? "" }), }} placeholder={placeholder} containerClassName={cn(containerClassName, "relative")} diff --git a/web/core/components/editor/lite-text-editor/lite-text-read-only-editor.tsx b/web/core/components/editor/lite-text-editor/lite-text-read-only-editor.tsx index 0763a49f9..a8747538e 100644 --- a/web/core/components/editor/lite-text-editor/lite-text-read-only-editor.tsx +++ b/web/core/components/editor/lite-text-editor/lite-text-read-only-editor.tsx @@ -8,6 +8,8 @@ import { EditorMentionsRoot } from "@/components/editor"; import { cn } from "@/helpers/common.helper"; // hooks import { useEditorConfig } from "@/hooks/editor"; +// store hooks +import { useMember } from "@/hooks/store"; // plane web hooks import { useEditorFlagging } from "@/plane-web/hooks/use-editor-flagging"; @@ -22,6 +24,9 @@ type LiteTextReadOnlyEditorWrapperProps = MakeOptional< export const LiteTextReadOnlyEditor = React.forwardRef( ({ workspaceId, workspaceSlug, projectId, disabledExtensions: additionalDisabledExtensions, ...props }, ref) => { + // store hooks + const { getUserDetails } = useMember(); + // editor flaggings const { liteTextEditor: disabledExtensions } = useEditorFlagging(workspaceSlug?.toString()); // editor config @@ -38,6 +43,7 @@ export const LiteTextReadOnlyEditor = React.forwardRef , + getMentionedEntityDetails: (id: string) => ({ display_name: getUserDetails(id)?.display_name ?? "" }), }} {...props} // overriding the containerClassName to add relative class passed diff --git a/web/core/components/editor/rich-text-editor/rich-text-editor.tsx b/web/core/components/editor/rich-text-editor/rich-text-editor.tsx index b18fc1859..ea27ec45d 100644 --- a/web/core/components/editor/rich-text-editor/rich-text-editor.tsx +++ b/web/core/components/editor/rich-text-editor/rich-text-editor.tsx @@ -8,6 +8,8 @@ import { EditorMentionsRoot } from "@/components/editor"; import { cn } from "@/helpers/common.helper"; // hooks import { useEditorConfig, useEditorMention } from "@/hooks/editor"; +// store hooks +import { useMember } from "@/hooks/store"; // plane web hooks import { useEditorFlagging } from "@/plane-web/hooks/use-editor-flagging"; @@ -31,6 +33,8 @@ export const RichTextEditor = forwardRef , + getMentionedEntityDetails: (id: string) => ({ display_name: getUserDetails(id)?.display_name ?? "" }), }} {...rest} containerClassName={cn("relative pl-3 pb-3", containerClassName)} diff --git a/web/core/components/editor/rich-text-editor/rich-text-read-only-editor.tsx b/web/core/components/editor/rich-text-editor/rich-text-read-only-editor.tsx index 31ce65159..50eb65e78 100644 --- a/web/core/components/editor/rich-text-editor/rich-text-read-only-editor.tsx +++ b/web/core/components/editor/rich-text-editor/rich-text-read-only-editor.tsx @@ -8,6 +8,8 @@ import { EditorMentionsRoot } from "@/components/editor"; import { cn } from "@/helpers/common.helper"; // hooks import { useEditorConfig } from "@/hooks/editor"; +// store hooks +import { useMember } from "@/hooks/store"; // plane web hooks import { useEditorFlagging } from "@/plane-web/hooks/use-editor-flagging"; @@ -22,6 +24,9 @@ type RichTextReadOnlyEditorWrapperProps = MakeOptional< export const RichTextReadOnlyEditor = React.forwardRef( ({ workspaceId, workspaceSlug, projectId, disabledExtensions: additionalDisabledExtensions, ...props }, ref) => { + // store hooks + const { getUserDetails } = useMember(); + // editor flaggings const { richTextEditor: disabledExtensions } = useEditorFlagging(workspaceSlug?.toString()); // editor config @@ -38,6 +43,7 @@ export const RichTextReadOnlyEditor = React.forwardRef , + getMentionedEntityDetails: (id: string) => ({ display_name: getUserDetails(id)?.display_name ?? "" }), }} {...props} // overriding the containerClassName to add relative class passed diff --git a/web/core/components/pages/editor/editor-body.tsx b/web/core/components/pages/editor/editor-body.tsx index 72533c3dc..aba274aff 100644 --- a/web/core/components/pages/editor/editor-body.tsx +++ b/web/core/components/pages/editor/editor-body.tsx @@ -22,7 +22,7 @@ import { cn, LIVE_BASE_PATH, LIVE_BASE_URL } from "@/helpers/common.helper"; import { generateRandomColor } from "@/helpers/string.helper"; // hooks import { useEditorMention } from "@/hooks/editor"; -import { useUser, useWorkspace } from "@/hooks/store"; +import { useUser, useWorkspace, useMember } from "@/hooks/store"; import { usePageFilters } from "@/hooks/use-page-filters"; // plane web components import { EditorAIMenu } from "@/plane-web/components/pages"; @@ -68,6 +68,8 @@ export const PageEditorBody: React.FC = observer((props) => { // store hooks const { data: currentUser } = useUser(); const { getWorkspaceBySlug } = useWorkspace(); + const { getUserDetails } = useMember(); + // derived values const { id: pageId, name: pageTitle, isContentEditable, updateTitle } = page; const workspaceId = getWorkspaceBySlug(workspaceSlug)?.id ?? ""; @@ -192,6 +194,7 @@ export const PageEditorBody: React.FC = observer((props) => { return res; }, renderComponent: (props) => , + getMentionedEntityDetails: (id: string) => ({ display_name: getUserDetails(id)?.display_name ?? "" }), }} embedHandler={{ issue: issueEmbedProps, diff --git a/web/core/components/pages/version/editor.tsx b/web/core/components/pages/version/editor.tsx index d20123290..c067c5d9e 100644 --- a/web/core/components/pages/version/editor.tsx +++ b/web/core/components/pages/version/editor.tsx @@ -12,6 +12,8 @@ import { EditorMentionsRoot } from "@/components/editor"; import { useEditorConfig } from "@/hooks/editor"; import { useWorkspace } from "@/hooks/store"; import { usePageFilters } from "@/hooks/use-page-filters"; +// store hooks +import { useMember } from "@/hooks/store"; // plane web hooks import { useEditorFlagging } from "@/plane-web/hooks/use-editor-flagging"; import { useIssueEmbed } from "@/plane-web/hooks/use-issue-embed"; @@ -25,6 +27,8 @@ export type TVersionEditorProps = { export const PagesVersionEditor: React.FC = observer((props) => { const { activeVersion, currentVersionDescription, isCurrentVersionActive, versionDetails } = props; + // store hooks + const { getUserDetails } = useMember(); // params const { workspaceSlug, projectId } = useParams(); // store hooks @@ -108,6 +112,7 @@ export const PagesVersionEditor: React.FC = observer((props })} mentionHandler={{ renderComponent: (props) => , + getMentionedEntityDetails: (id: string) => ({ display_name: getUserDetails(id)?.display_name ?? "" }), }} embedHandler={{ issue: { From ef42ce04a4485726b81c8fc1d4a434a4701fc960 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Mar 2025 12:48:05 +0530 Subject: [PATCH 003/146] chore(deps): bump gunicorn (#6793) Bumps the pip group with 1 update in the /apiserver/requirements directory: [gunicorn](https://github.com/benoitc/gunicorn). Updates `gunicorn` from 22.0.0 to 23.0.0 - [Release notes](https://github.com/benoitc/gunicorn/releases) - [Commits](https://github.com/benoitc/gunicorn/compare/22.0.0...23.0.0) --- updated-dependencies: - dependency-name: gunicorn dependency-type: direct:production dependency-group: pip ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- apiserver/requirements/production.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apiserver/requirements/production.txt b/apiserver/requirements/production.txt index ed763c0df..f09c60806 100644 --- a/apiserver/requirements/production.txt +++ b/apiserver/requirements/production.txt @@ -1,3 +1,3 @@ -r base.txt # server -gunicorn==22.0.0 +gunicorn==23.0.0 From 75a9b71edbe5aa171a16cb292e94db9dac0da0f2 Mon Sep 17 00:00:00 2001 From: Dheeraj Kumar Ketireddy Date: Mon, 24 Mar 2025 12:51:44 +0530 Subject: [PATCH 004/146] [WEB-3513] fix: return cycle start and end dates in project's timezone --- apiserver/plane/api/serializers/cycle.py | 9 +++++++++ apiserver/plane/api/views/cycle.py | 22 +++++++++++++++------- apiserver/plane/app/views/cycle/base.py | 21 +++++++++++++++------ 3 files changed, 39 insertions(+), 13 deletions(-) diff --git a/apiserver/plane/api/serializers/cycle.py b/apiserver/plane/api/serializers/cycle.py index ea3c4eb3d..c828195d2 100644 --- a/apiserver/plane/api/serializers/cycle.py +++ b/apiserver/plane/api/serializers/cycle.py @@ -1,4 +1,5 @@ # Third party imports +import pytz from rest_framework import serializers # Module imports @@ -18,6 +19,14 @@ class CycleSerializer(BaseSerializer): completed_estimates = serializers.FloatField(read_only=True) started_estimates = serializers.FloatField(read_only=True) + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + project = self.context.get("project") + if project and project.timezone: + project_timezone = pytz.timezone(project.timezone) + self.fields["start_date"].timezone = project_timezone + self.fields["end_date"].timezone = project_timezone + def validate(self, data): if ( data.get("start_date", None) is not None diff --git a/apiserver/plane/api/views/cycle.py b/apiserver/plane/api/views/cycle.py index 3665e3b0f..e0f44f984 100644 --- a/apiserver/plane/api/views/cycle.py +++ b/apiserver/plane/api/views/cycle.py @@ -137,10 +137,12 @@ class CycleAPIEndpoint(BaseAPIView): ) def get(self, request, slug, project_id, pk=None): + project = Project.objects.get(workspace__slug=slug, pk=project_id) if pk: queryset = self.get_queryset().filter(archived_at__isnull=True).get(pk=pk) data = CycleSerializer( - queryset, fields=self.fields, expand=self.expand + queryset, fields=self.fields, + expand=self.expand, context={"project": project} ).data return Response(data, status=status.HTTP_200_OK) queryset = self.get_queryset().filter(archived_at__isnull=True) @@ -152,7 +154,8 @@ class CycleAPIEndpoint(BaseAPIView): start_date__lte=timezone.now(), end_date__gte=timezone.now() ) data = CycleSerializer( - queryset, many=True, fields=self.fields, expand=self.expand + queryset, many=True, fields=self.fields, + expand=self.expand, context={"project": project} ).data return Response(data, status=status.HTTP_200_OK) @@ -163,7 +166,8 @@ class CycleAPIEndpoint(BaseAPIView): request=request, queryset=(queryset), on_results=lambda cycles: CycleSerializer( - cycles, many=True, fields=self.fields, expand=self.expand + cycles, many=True, fields=self.fields, + expand=self.expand, context={"project": project} ).data, ) @@ -174,7 +178,8 @@ class CycleAPIEndpoint(BaseAPIView): request=request, queryset=(queryset), on_results=lambda cycles: CycleSerializer( - cycles, many=True, fields=self.fields, expand=self.expand + cycles, many=True, fields=self.fields, + expand=self.expand, context={"project": project} ).data, ) @@ -185,7 +190,8 @@ class CycleAPIEndpoint(BaseAPIView): request=request, queryset=(queryset), on_results=lambda cycles: CycleSerializer( - cycles, many=True, fields=self.fields, expand=self.expand + cycles, many=True, fields=self.fields, + expand=self.expand, context={"project": project} ).data, ) @@ -198,14 +204,16 @@ class CycleAPIEndpoint(BaseAPIView): request=request, queryset=(queryset), on_results=lambda cycles: CycleSerializer( - cycles, many=True, fields=self.fields, expand=self.expand + cycles, many=True, fields=self.fields, + expand=self.expand, context={"project": project} ).data, ) return self.paginate( request=request, queryset=(queryset), on_results=lambda cycles: CycleSerializer( - cycles, many=True, fields=self.fields, expand=self.expand + cycles, many=True, fields=self.fields, + expand=self.expand, context={"project": project} ).data, ) diff --git a/apiserver/plane/app/views/cycle/base.py b/apiserver/plane/app/views/cycle/base.py index 84a161619..45b6f94d8 100644 --- a/apiserver/plane/app/views/cycle/base.py +++ b/apiserver/plane/app/views/cycle/base.py @@ -268,7 +268,7 @@ class CycleViewSet(BaseViewSet): ) datetime_fields = ["start_date", "end_date"] data = user_timezone_converter( - data, datetime_fields, request.user.user_timezone + data, datetime_fields, project_timezone ) return Response(data, status=status.HTTP_200_OK) @@ -318,9 +318,13 @@ class CycleViewSet(BaseViewSet): .first() ) + # Fetch the project timezone + project = Project.objects.get(id=self.kwargs.get("project_id")) + project_timezone = project.timezone + datetime_fields = ["start_date", "end_date"] cycle = user_timezone_converter( - cycle, datetime_fields, request.user.user_timezone + cycle, datetime_fields, project_timezone ) # Send the model activity @@ -407,9 +411,13 @@ class CycleViewSet(BaseViewSet): "created_by", ).first() + # Fetch the project timezone + project = Project.objects.get(id=self.kwargs.get("project_id")) + project_timezone = project.timezone + datetime_fields = ["start_date", "end_date"] cycle = user_timezone_converter( - cycle, datetime_fields, request.user.user_timezone + cycle, datetime_fields, project_timezone ) # Send the model activity @@ -480,10 +488,11 @@ class CycleViewSet(BaseViewSet): ) queryset = queryset.first() + # Fetch the project timezone + project = Project.objects.get(id=self.kwargs.get("project_id")) + project_timezone = project.timezone datetime_fields = ["start_date", "end_date"] - data = user_timezone_converter( - data, datetime_fields, request.user.user_timezone - ) + data = user_timezone_converter(data, datetime_fields, project_timezone) recent_visited_task.delay( slug=slug, From cbe248591e79e483baa7a99fb9acd41640c235a9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Mar 2025 12:52:16 +0530 Subject: [PATCH 005/146] chore(deps): bump next in the npm_and_yarn group across 1 directory (#6796) Bumps the npm_and_yarn group with 1 update in the / directory: [next](https://github.com/vercel/next.js). Updates `next` from 14.2.24 to 14.2.25 - [Release notes](https://github.com/vercel/next.js/releases) - [Changelog](https://github.com/vercel/next.js/blob/canary/release.js) - [Commits](https://github.com/vercel/next.js/compare/v14.2.24...v14.2.25) --- updated-dependencies: - dependency-name: next dependency-type: direct:production dependency-group: npm_and_yarn ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- admin/package.json | 2 +- space/package.json | 2 +- web/package.json | 2 +- yarn.lock | 116 ++++++++++++++++++++++----------------------- 4 files changed, 61 insertions(+), 61 deletions(-) diff --git a/admin/package.json b/admin/package.json index 5f3fd5e45..f6c83e06b 100644 --- a/admin/package.json +++ b/admin/package.json @@ -30,7 +30,7 @@ "lucide-react": "^0.469.0", "mobx": "^6.12.0", "mobx-react": "^9.1.1", - "next": "^14.2.20", + "next": "^14.2.25", "next-themes": "^0.2.1", "postcss": "^8.4.38", "react": "^18.3.1", diff --git a/space/package.json b/space/package.json index 8be06a5a8..c18238111 100644 --- a/space/package.json +++ b/space/package.json @@ -37,7 +37,7 @@ "mobx": "^6.10.0", "mobx-react": "^9.1.1", "mobx-utils": "^6.0.8", - "next": "^14.2.20", + "next": "^14.2.25", "next-themes": "^0.2.1", "nprogress": "^0.2.0", "react": "^18.3.1", diff --git a/web/package.json b/web/package.json index eb01bbd4a..ee31d3572 100644 --- a/web/package.json +++ b/web/package.json @@ -51,7 +51,7 @@ "mobx": "^6.10.0", "mobx-react": "^9.1.1", "mobx-utils": "^6.0.8", - "next": "^14.2.20", + "next": "^14.2.25", "next-themes": "^0.2.1", "nprogress": "^0.2.0", "posthog-js": "^1.131.3", diff --git a/yarn.lock b/yarn.lock index 37c885e34..783bb901e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -259,7 +259,7 @@ "@babel/helpers@7.26.10", "@babel/helpers@^7.26.7": version "7.26.10" - resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.10.tgz#6baea3cd62ec2d0c1068778d63cb1314f6637384" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.26.10.tgz#6baea3cd62ec2d0c1068778d63cb1314f6637384" integrity sha512-UPYc3SauzZ3JGgj87GgZ89JVdC5dj0AoetR5Bw6wj4niittNyFh6+eOGonYvJ1ao6B8lEa3Q3klS7ADZ53bc5g== dependencies: "@babel/template" "^7.26.9" @@ -854,7 +854,7 @@ "@babel/runtime@7.26.10", "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.13", "@babel/runtime@^7.23.9", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7": version "7.26.10" - resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.10.tgz#a07b4d8fa27af131a633d7b3524db803eb4764c2" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.10.tgz#a07b4d8fa27af131a633d7b3524db803eb4764c2" integrity sha512-2WJMeRQPHKSPemqk/awGrAiuFfzBmOIPXKizAsVhWH9YJqLZ0H+HS4c8loHGgW6utJ3E/ejXQUsiGaQy2NZ9Fw== dependencies: regenerator-runtime "^0.14.0" @@ -1613,10 +1613,10 @@ prop-types "^15.8.1" react-is "^19.0.0" -"@next/env@14.2.24": - version "14.2.24" - resolved "https://registry.npmjs.org/@next/env/-/env-14.2.24.tgz#49274c9ccbbb9d314d4a414a4ff2717756105ebc" - integrity sha512-LAm0Is2KHTNT6IT16lxT+suD0u+VVfYNQqM+EJTKuFRRuY2z+zj01kueWXPCxbMBDt0B5vONYzabHGUNbZYAhA== +"@next/env@14.2.25": + version "14.2.25" + resolved "https://registry.yarnpkg.com/@next/env/-/env-14.2.25.tgz#936d10b967e103e49a4bcea1e97292d5605278dd" + integrity sha512-JnzQ2cExDeG7FxJwqAksZ3aqVJrHjFwZQAEJ9gQZSoEhIow7SNoKZzju/AwQ+PLIR4NY8V0rhcVozx/2izDO0w== "@next/eslint-plugin-next@14.2.24": version "14.2.24" @@ -1625,50 +1625,50 @@ dependencies: glob "10.3.10" -"@next/swc-darwin-arm64@14.2.24": - version "14.2.24" - resolved "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.24.tgz#95a4be350a03c136ae1b61969748ff810ffc63eb" - integrity sha512-7Tdi13aojnAZGpapVU6meVSpNzgrFwZ8joDcNS8cJVNuP3zqqrLqeory9Xec5TJZR/stsGJdfwo8KeyloT3+rQ== +"@next/swc-darwin-arm64@14.2.25": + version "14.2.25" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.25.tgz#7bcccfda0c0ff045c45fbe34c491b7368e373e3d" + integrity sha512-09clWInF1YRd6le00vt750s3m7SEYNehz9C4PUcSu3bAdCTpjIV4aTYQZ25Ehrr83VR1rZeqtKUPWSI7GfuKZQ== -"@next/swc-darwin-x64@14.2.24": - version "14.2.24" - resolved "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.24.tgz#5fdfa185040924c0533c4005a21a8e5985ffbd9c" - integrity sha512-lXR2WQqUtu69l5JMdTwSvQUkdqAhEWOqJEYUQ21QczQsAlNOW2kWZCucA6b3EXmPbcvmHB1kSZDua/713d52xg== +"@next/swc-darwin-x64@14.2.25": + version "14.2.25" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.25.tgz#b489e209d7b405260b73f69a38186ed150fb7a08" + integrity sha512-V+iYM/QR+aYeJl3/FWWU/7Ix4b07ovsQ5IbkwgUK29pTHmq+5UxeDr7/dphvtXEq5pLB/PucfcBNh9KZ8vWbug== -"@next/swc-linux-arm64-gnu@14.2.24": - version "14.2.24" - resolved "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.24.tgz#7242d382d2e301d385591b4250ebf608b3a555d3" - integrity sha512-nxvJgWOpSNmzidYvvGDfXwxkijb6hL9+cjZx1PVG6urr2h2jUqBALkKjT7kpfurRWicK6hFOvarmaWsINT1hnA== +"@next/swc-linux-arm64-gnu@14.2.25": + version "14.2.25" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.25.tgz#ba064fabfdce0190d9859493d8232fffa84ef2e2" + integrity sha512-LFnV2899PJZAIEHQ4IMmZIgL0FBieh5keMnriMY1cK7ompR+JUd24xeTtKkcaw8QmxmEdhoE5Mu9dPSuDBgtTg== -"@next/swc-linux-arm64-musl@14.2.24": - version "14.2.24" - resolved "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.24.tgz#9a67b28e6fd6f0078929f0ef5256549b51b0320d" - integrity sha512-PaBgOPhqa4Abxa3y/P92F3kklNPsiFjcjldQGT7kFmiY5nuFn8ClBEoX8GIpqU1ODP2y8P6hio6vTomx2Vy0UQ== +"@next/swc-linux-arm64-musl@14.2.25": + version "14.2.25" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.25.tgz#bf0018267e4e0fbfa1524750321f8cae855144a3" + integrity sha512-QC5y5PPTmtqFExcKWKYgUNkHeHE/z3lUsu83di488nyP0ZzQ3Yse2G6TCxz6nNsQwgAx1BehAJTZez+UQxzLfw== -"@next/swc-linux-x64-gnu@14.2.24": - version "14.2.24" - resolved "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.24.tgz#012d801b44e179912d7136c74d25de8a7da42084" - integrity sha512-vEbyadiRI7GOr94hd2AB15LFVgcJZQWu7Cdi9cWjCMeCiUsHWA0U5BkGPuoYRnTxTn0HacuMb9NeAmStfBCLoQ== +"@next/swc-linux-x64-gnu@14.2.25": + version "14.2.25" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.25.tgz#64f5a6016a7148297ee80542e0fd788418a32472" + integrity sha512-y6/ML4b9eQ2D/56wqatTJN5/JR8/xdObU2Fb1RBidnrr450HLCKr6IJZbPqbv7NXmje61UyxjF5kvSajvjye5w== -"@next/swc-linux-x64-musl@14.2.24": - version "14.2.24" - resolved "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.24.tgz#97408c53510c6960094bc6c743670c6e72bfa41c" - integrity sha512-df0FC9ptaYsd8nQCINCzFtDWtko8PNRTAU0/+d7hy47E0oC17tI54U/0NdGk7l/76jz1J377dvRjmt6IUdkpzQ== +"@next/swc-linux-x64-musl@14.2.25": + version "14.2.25" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.25.tgz#58dc636d7c55828478159546f7b95ab1e902301c" + integrity sha512-sPX0TSXHGUOZFvv96GoBXpB3w4emMqKeMgemrSxI7A6l55VBJp/RKYLwZIB9JxSqYPApqiREaIIap+wWq0RU8w== -"@next/swc-win32-arm64-msvc@14.2.24": - version "14.2.24" - resolved "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.24.tgz#4252ea2bcc5ae62ebff16dd9320741b4f88ec368" - integrity sha512-ZEntbLjeYAJ286eAqbxpZHhDFYpYjArotQ+/TW9j7UROh0DUmX7wYDGtsTPpfCV8V+UoqHBPU7q9D4nDNH014Q== +"@next/swc-win32-arm64-msvc@14.2.25": + version "14.2.25" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.25.tgz#93562d447c799bded1e89c1a62d5195a2a8c6c0d" + integrity sha512-ReO9S5hkA1DU2cFCsGoOEp7WJkhFzNbU/3VUF6XxNGUCQChyug6hZdYL/istQgfT/GWE6PNIg9cm784OI4ddxQ== -"@next/swc-win32-ia32-msvc@14.2.24": - version "14.2.24" - resolved "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.24.tgz#fa15ae451617ce820517714cf2e98b56c18960d7" - integrity sha512-9KuS+XUXM3T6v7leeWU0erpJ6NsFIwiTFD5nzNg8J5uo/DMIPvCp3L1Ao5HjbHX0gkWPB1VrKoo/Il4F0cGK2Q== +"@next/swc-win32-ia32-msvc@14.2.25": + version "14.2.25" + resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.25.tgz#ad85a33466be1f41d083211ea21adc0d2c6e6554" + integrity sha512-DZ/gc0o9neuCDyD5IumyTGHVun2dCox5TfPQI/BJTYwpSNYM3CZDI4i6TOdjeq1JMo+Ug4kPSMuZdwsycwFbAw== -"@next/swc-win32-x64-msvc@14.2.24": - version "14.2.24" - resolved "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.24.tgz#0f7002e8c8b1f310a48fdc829cfda77ffcabf489" - integrity sha512-cXcJ2+x0fXQ2CntaE00d7uUH+u1Bfp/E0HsNQH79YiLaZE5Rbm7dZzyAYccn3uICM7mw+DxoMqEfGXZtF4Fgaw== +"@next/swc-win32-x64-msvc@14.2.25": + version "14.2.25" + resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.25.tgz#3969c66609e683ec63a6a9f320a855f7be686a08" + integrity sha512-KSznmS6eFjQ9RJ1nEc66kJvtGIL1iZMYmGEXsZPh2YtnLtqrgdVvKXJY2ScjjoFnG6nGLyPFR0UiEvDwVah4Tw== "@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.3": version "2.1.8-no-fsevents.3" @@ -6608,7 +6608,7 @@ esbuild-register@^3.5.0: esbuild@0.25.0, "esbuild@^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0", esbuild@^0.25.0: version "0.25.0" - resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz#0de1787a77206c5a79eeb634a623d39b5006ce92" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.25.0.tgz#0de1787a77206c5a79eeb634a623d39b5006ce92" integrity sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw== optionalDependencies: "@esbuild/aix-ppc64" "0.25.0" @@ -9116,7 +9116,7 @@ mz@^2.7.0: nanoid@3.3.8, nanoid@^3.3.6, nanoid@^3.3.8: version "3.3.8" - resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz#b1be3030bee36aaff18bacb375e5cce521684baf" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.8.tgz#b1be3030bee36aaff18bacb375e5cce521684baf" integrity sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w== napi-build-utils@^2.0.0: @@ -9154,12 +9154,12 @@ next-themes@^0.2.1: resolved "https://registry.npmjs.org/next-themes/-/next-themes-0.2.1.tgz#0c9f128e847979daf6c67f70b38e6b6567856e45" integrity sha512-B+AKNfYNIzh0vqQQKqQItTS8evEouKD7H5Hj3kmuPERwddR2TxvDSFZuTj6T7Jfn1oyeUyJMydPl1Bkxkh0W7A== -next@^14.2.20: - version "14.2.24" - resolved "https://registry.npmjs.org/next/-/next-14.2.24.tgz#02294330af05705aca19b9aebcfe10ac61271d16" - integrity sha512-En8VEexSJ0Py2FfVnRRh8gtERwDRaJGNvsvad47ShkC2Yi8AXQPXEA2vKoDJlGFSj5WE5SyF21zNi4M5gyi+SQ== +next@^14.2.25: + version "14.2.25" + resolved "https://registry.yarnpkg.com/next/-/next-14.2.25.tgz#0657551fde6a97f697cf9870e9ccbdaa465c6008" + integrity sha512-N5M7xMc4wSb4IkPvEV5X2BRRXUmhVHNyaXwEM86+voXthSZz8ZiRyQW4p9mwAoAPIm6OzuVZtn7idgEJeAJN3Q== dependencies: - "@next/env" "14.2.24" + "@next/env" "14.2.25" "@swc/helpers" "0.5.5" busboy "1.6.0" caniuse-lite "^1.0.30001579" @@ -9167,15 +9167,15 @@ next@^14.2.20: postcss "8.4.31" styled-jsx "5.1.1" optionalDependencies: - "@next/swc-darwin-arm64" "14.2.24" - "@next/swc-darwin-x64" "14.2.24" - "@next/swc-linux-arm64-gnu" "14.2.24" - "@next/swc-linux-arm64-musl" "14.2.24" - "@next/swc-linux-x64-gnu" "14.2.24" - "@next/swc-linux-x64-musl" "14.2.24" - "@next/swc-win32-arm64-msvc" "14.2.24" - "@next/swc-win32-ia32-msvc" "14.2.24" - "@next/swc-win32-x64-msvc" "14.2.24" + "@next/swc-darwin-arm64" "14.2.25" + "@next/swc-darwin-x64" "14.2.25" + "@next/swc-linux-arm64-gnu" "14.2.25" + "@next/swc-linux-arm64-musl" "14.2.25" + "@next/swc-linux-x64-gnu" "14.2.25" + "@next/swc-linux-x64-musl" "14.2.25" + "@next/swc-win32-arm64-msvc" "14.2.25" + "@next/swc-win32-ia32-msvc" "14.2.25" + "@next/swc-win32-x64-msvc" "14.2.25" no-case@^3.0.4: version "3.0.4" From 4032aa62c5bc020a931a575d35eeb38ddbeecb9a Mon Sep 17 00:00:00 2001 From: Akshita Goyal <36129505+gakshita@users.noreply.github.com> Date: Mon, 24 Mar 2025 12:52:57 +0530 Subject: [PATCH 006/146] [WEB-3551] fix: role improvements (#6763) * Return Cycle start and end dates in project's timezone * fix: role improvements * chore: role updates * chore: update role endpoint to update workspace admin permissions * fix: conditions * chore: update member role for workspace members * chore: update workspace permission role * fix: currentAdmin permissions --------- Co-authored-by: Dheeraj Kumar Ketireddy Co-authored-by: pablohashescobar --- apiserver/plane/app/views/project/member.py | 30 ++++----- apiserver/plane/app/views/workspace/member.py | 7 ++- packages/constants/src/workspace.ts | 8 ++- .../settings/(with-sidebar)/members/page.tsx | 4 +- .../settings/(with-sidebar)/layout.tsx | 18 ++++-- web/ce/constants/project/settings/tabs.ts | 2 +- .../project/settings/member-columns.tsx | 61 +++++++++++-------- .../workspace/sidebar/dropdown-item.tsx | 10 +-- web/core/store/member/project-member.store.ts | 15 ++++- 9 files changed, 94 insertions(+), 61 deletions(-) diff --git a/apiserver/plane/app/views/project/member.py b/apiserver/plane/app/views/project/member.py index 55d2d4a58..7b910509c 100644 --- a/apiserver/plane/app/views/project/member.py +++ b/apiserver/plane/app/views/project/member.py @@ -10,11 +10,7 @@ from plane.app.serializers import ( ProjectMemberRoleSerializer, ) -from plane.app.permissions import ( - ProjectMemberPermission, - ProjectLitePermission, - WorkspaceUserPermission, -) +from plane.app.permissions import WorkspaceUserPermission from plane.db.models import Project, ProjectMember, IssueUserProperty, WorkspaceMember from plane.bgtasks.project_add_user_email_task import project_add_user_email @@ -26,14 +22,6 @@ class ProjectMemberViewSet(BaseViewSet): serializer_class = ProjectMemberAdminSerializer model = ProjectMember - def get_permissions(self): - if self.action == "leave": - self.permission_classes = [ProjectLitePermission] - else: - self.permission_classes = [ProjectMemberPermission] - - return super(ProjectMemberViewSet, self).get_permissions() - search_fields = ["member__display_name", "member__first_name"] def get_queryset(self): @@ -187,12 +175,20 @@ class ProjectMemberViewSet(BaseViewSet): ) return Response(serializer.data, status=status.HTTP_200_OK) - @allow_permission([ROLE.ADMIN]) + @allow_permission([ROLE.ADMIN, ROLE.MEMBER, ROLE.GUEST]) def partial_update(self, request, slug, project_id, pk): project_member = ProjectMember.objects.get( pk=pk, workspace__slug=slug, project_id=project_id, is_active=True ) - if request.user.id == project_member.member_id: + + # Fetch the workspace role of the project member + workspace_role = WorkspaceMember.objects.get( + workspace__slug=slug, member=project_member.member, is_active=True + ).role + is_workspace_admin = workspace_role == ROLE.ADMIN.value + + # Check if the user is not editing their own role if they are not an admin + if request.user.id == project_member.member_id and not is_workspace_admin: return Response( {"error": "You cannot update your own role"}, status=status.HTTP_400_BAD_REQUEST, @@ -205,9 +201,6 @@ class ProjectMemberViewSet(BaseViewSet): is_active=True, ) - workspace_role = WorkspaceMember.objects.get( - workspace__slug=slug, member=project_member.member, is_active=True - ).role if workspace_role in [5] and int( request.data.get("role", project_member.role) ) in [15, 20]: @@ -222,6 +215,7 @@ class ProjectMemberViewSet(BaseViewSet): "role" in request.data and int(request.data.get("role", project_member.role)) > requested_project_member.role + and not is_workspace_admin ): return Response( {"error": "You cannot update a role that is higher than your own role"}, diff --git a/apiserver/plane/app/views/workspace/member.py b/apiserver/plane/app/views/workspace/member.py index 9541f9980..5dde2f78c 100644 --- a/apiserver/plane/app/views/workspace/member.py +++ b/apiserver/plane/app/views/workspace/member.py @@ -68,10 +68,11 @@ class WorkSpaceMemberViewSet(BaseViewSet): status=status.HTTP_400_BAD_REQUEST, ) - if workspace_member.role > int(request.data.get("role")): - _ = ProjectMember.objects.filter( + # If a user is moved to a guest role he can't have any other role in projects + if "role" in request.data and int(request.data.get("role")) == 5: + ProjectMember.objects.filter( workspace__slug=slug, member_id=workspace_member.member_id - ).update(role=int(request.data.get("role"))) + ).update(role=5) serializer = WorkSpaceMemberSerializer( workspace_member, data=request.data, partial=True diff --git a/packages/constants/src/workspace.ts b/packages/constants/src/workspace.ts index 06c9fb659..c1c60f392 100644 --- a/packages/constants/src/workspace.ts +++ b/packages/constants/src/workspace.ts @@ -83,14 +83,14 @@ export const WORKSPACE_SETTINGS = { key: "general", i18n_label: "workspace_settings.settings.general.title", href: `/settings`, - access: [EUserWorkspaceRoles.ADMIN], + access: [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER], highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/`, }, members: { key: "members", i18n_label: "workspace_settings.settings.members.title", href: `/settings/members`, - access: [EUserWorkspaceRoles.ADMIN], + access: [EUserWorkspaceRoles.ADMIN, EUserWorkspaceRoles.MEMBER], highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/members/`, }, "billing-and-plans": { @@ -123,6 +123,10 @@ export const WORKSPACE_SETTINGS = { }, }; +export const WORKSPACE_SETTINGS_ACCESS = Object.fromEntries( + Object.entries(WORKSPACE_SETTINGS).map(([_, { href, access }]) => [href, access]) +); + export const WORKSPACE_SETTINGS_LINKS: { key: string; i18n_label: string; diff --git a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/settings/(with-sidebar)/members/page.tsx b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/settings/(with-sidebar)/members/page.tsx index 565e18754..9deaef126 100644 --- a/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/settings/(with-sidebar)/members/page.tsx +++ b/web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/settings/(with-sidebar)/members/page.tsx @@ -15,10 +15,12 @@ const MembersSettingsPage = observer(() => { const { workspaceUserInfo, allowPermissions } = useUserPermissions(); // derived values const pageTitle = currentProjectDetails?.name ? `${currentProjectDetails?.name} - Members` : undefined; - const canPerformProjectMemberActions = allowPermissions( + const isProjectMemberOrAdmin = allowPermissions( [EUserPermissions.ADMIN, EUserPermissions.MEMBER], EUserPermissionsLevel.PROJECT ); + const isWorkspaceAdmin = allowPermissions([EUserPermissions.ADMIN], EUserPermissionsLevel.WORKSPACE); + const canPerformProjectMemberActions = isProjectMemberOrAdmin || isWorkspaceAdmin; if (workspaceUserInfo && !canPerformProjectMemberActions) { return ; diff --git a/web/app/[workspaceSlug]/(projects)/settings/(with-sidebar)/layout.tsx b/web/app/[workspaceSlug]/(projects)/settings/(with-sidebar)/layout.tsx index 6dfe44ed6..24f81d39d 100644 --- a/web/app/[workspaceSlug]/(projects)/settings/(with-sidebar)/layout.tsx +++ b/web/app/[workspaceSlug]/(projects)/settings/(with-sidebar)/layout.tsx @@ -3,7 +3,8 @@ import { FC, ReactNode } from "react"; import { observer } from "mobx-react"; // components -import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants"; +import { useParams, usePathname } from "next/navigation"; +import { EUserWorkspaceRoles, WORKSPACE_SETTINGS_ACCESS } from "@plane/constants"; import { NotAuthorizedView } from "@/components/auth-screens"; import { AppHeader } from "@/components/core"; // hooks @@ -21,17 +22,26 @@ export interface IWorkspaceSettingLayout { const WorkspaceSettingLayout: FC = observer((props) => { const { children } = props; - const { workspaceUserInfo, allowPermissions } = useUserPermissions(); + const { workspaceUserInfo } = useUserPermissions(); + const pathname = usePathname(); + const { workspaceSlug } = useParams(); // derived values - const isWorkspaceAdmin = allowPermissions([EUserPermissions.ADMIN], EUserPermissionsLevel.WORKSPACE); + const userWorkspaceRole = workspaceUserInfo?.[workspaceSlug.toString()]?.role; + const isAuthorized = + pathname && + workspaceSlug && + userWorkspaceRole && + WORKSPACE_SETTINGS_ACCESS[pathname.replace(`/${workspaceSlug}`, "").slice(0, -1)]?.includes( + userWorkspaceRole as EUserWorkspaceRoles + ); return ( <> } />
- {workspaceUserInfo && !isWorkspaceAdmin ? ( + {workspaceUserInfo && !isAuthorized ? ( ) : ( <> diff --git a/web/ce/constants/project/settings/tabs.ts b/web/ce/constants/project/settings/tabs.ts index 50bff1115..15869c186 100644 --- a/web/ce/constants/project/settings/tabs.ts +++ b/web/ce/constants/project/settings/tabs.ts @@ -18,7 +18,7 @@ export const PROJECT_SETTINGS = { key: "members", i18n_label: "members", href: `/settings/members`, - access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER], + access: [EUserPermissions.ADMIN, EUserPermissions.MEMBER, EUserPermissions.GUEST], highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/members/`, Icon: SettingIcon, }, diff --git a/web/core/components/project/settings/member-columns.tsx b/web/core/components/project/settings/member-columns.tsx index f3b6ec956..d9af617ea 100644 --- a/web/core/components/project/settings/member-columns.tsx +++ b/web/core/components/project/settings/member-columns.tsx @@ -13,7 +13,7 @@ import { CustomSelect, PopoverMenu, TOAST_TYPE, setToast } from "@plane/ui"; // helpers import { getFileURL } from "@/helpers/file.helper"; // hooks -import { useMember, useUser } from "@/hooks/store"; +import { useMember, useUser, useUserPermissions } from "@/hooks/store"; export interface RowData { member: IWorkspaceMember; @@ -91,7 +91,7 @@ export const NameColumn: React.FC = (props) => { }; export const AccountTypeColumn: React.FC = observer((props) => { - const { rowData, currentProjectRole, projectId, workspaceSlug } = props; + const { rowData, projectId, workspaceSlug } = props; // form info const { control, @@ -99,48 +99,56 @@ export const AccountTypeColumn: React.FC = observer((props) => } = useForm(); // store hooks const { - project: { updateMember, getProjectMemberDetails }, + project: { updateMember }, workspace: { getWorkspaceMemberDetails }, } = useMember(); const { data: currentUser } = useUser(); + const { projectUserInfo } = useUserPermissions(); // derived values const isCurrentUser = currentUser?.id === rowData.member.id; - const isProjectAdminOrGuest = [EUserPermissions.ADMIN, EUserPermissions.GUEST].includes(rowData.role); - const isWorkspaceMember = [EUserPermissions.MEMBER].includes( + const isRowDataWorkspaceAdmin = [EUserPermissions.ADMIN].includes( Number(getWorkspaceMemberDetails(rowData.member.id)?.role) ?? EUserPermissions.GUEST ); - const isCurrentUserProjectMember = currentUser - ? getProjectMemberDetails(currentUser.id, projectId)?.role === EUserPermissions.MEMBER + const isCurrentUserWorkspaceAdmin = currentUser + ? [EUserPermissions.ADMIN].includes( + Number(getWorkspaceMemberDetails(currentUser.id)?.role) ?? EUserPermissions.GUEST + ) : false; - const isRoleNonEditable = - isCurrentUser || (isProjectAdminOrGuest && !isWorkspaceMember) || isCurrentUserProjectMember; + const currentProjectRole = projectUserInfo?.[workspaceSlug.toString()]?.[projectId.toString()] + ?.role as unknown as EUserPermissions; + const isCurrentUserProjectAdmin = currentProjectRole + ? ![EUserPermissions.MEMBER, EUserPermissions.GUEST].includes(Number(currentProjectRole) ?? EUserPermissions.GUEST) + : false; + + // logic + // Workspace admin can change his own role + // Project admin can change any role except his own and workspace admin's role + const isRoleEditable = + (isCurrentUserWorkspaceAdmin && isCurrentUser) || + (isCurrentUserProjectAdmin && !isRowDataWorkspaceAdmin && !isCurrentUser); const checkCurrentOptionWorkspaceRole = (value: string) => { const currentMemberWorkspaceRole = getWorkspaceMemberDetails(value)?.role as EUserPermissions | undefined; if (!value || !currentMemberWorkspaceRole) return ROLE; - const isGuestOROwner = [EUserPermissions.ADMIN, EUserPermissions.GUEST].includes(currentMemberWorkspaceRole); + const isGuest = [EUserPermissions.GUEST].includes(currentMemberWorkspaceRole); return Object.fromEntries( - Object.entries(ROLE).filter(([key]) => !isGuestOROwner || [currentMemberWorkspaceRole].includes(parseInt(key))) + Object.entries(ROLE).filter(([key]) => !isGuest || parseInt(key) === EUserPermissions.GUEST) ); }; return ( <> - {isRoleNonEditable ? ( -
- {ROLE[rowData.role]} -
- ) : ( + {isRoleEditable ? ( ( + render={() => ( { if (!workspaceSlug) return; @@ -168,17 +176,18 @@ export const AccountTypeColumn: React.FC = observer((props) => optionsClassName="w-full" input > - {Object.entries(checkCurrentOptionWorkspaceRole(rowData.member.id)).map(([key, label]) => { - if (parseInt(key) > (currentProjectRole ?? EUserPermissions.GUEST)) return null; - return ( - - {label} - - ); - })} + {Object.entries(checkCurrentOptionWorkspaceRole(rowData.member.id)).map(([key, label]) => ( + + {label} + + ))} )} /> + ) : ( +
+ {ROLE[rowData.role]} +
)} ); diff --git a/web/core/components/workspace/sidebar/dropdown-item.tsx b/web/core/components/workspace/sidebar/dropdown-item.tsx index 2259f95d2..9eef151d1 100644 --- a/web/core/components/workspace/sidebar/dropdown-item.tsx +++ b/web/core/components/workspace/sidebar/dropdown-item.tsx @@ -86,8 +86,8 @@ const SidebarDropdownItem = observer((props: TProps) => {
{workspace.id === activeWorkspace?.id && ( <> - {workspace?.role === EUserPermissions.ADMIN && ( -
+
+ {[EUserPermissions.ADMIN, EUserPermissions.MEMBER].includes(workspace?.role) && ( { {t("settings")} + )} + {[EUserPermissions.ADMIN].includes(workspace?.role) && ( { {t("project_settings.members.invite_members.title")} -
- )} + )} +
)} diff --git a/web/core/store/member/project-member.store.ts b/web/core/store/member/project-member.store.ts index 5c67f61b1..e97e5ab32 100644 --- a/web/core/store/member/project-member.store.ts +++ b/web/core/store/member/project-member.store.ts @@ -69,6 +69,7 @@ export class ProjectMemberStore implements IProjectMemberStore { userStore: IUserStore; memberRoot: IMemberRootStore; projectRoot: IProjectStore; + rootStore: CoreRootStore; // services projectMemberService; @@ -86,6 +87,7 @@ export class ProjectMemberStore implements IProjectMemberStore { }); // root store + this.rootStore = _rootStore; this.routerStore = _rootStore.router; this.userStore = _rootStore.user; this.memberRoot = _memberRoot; @@ -199,10 +201,13 @@ export class ProjectMemberStore implements IProjectMemberStore { const memberDetails = this.getProjectMemberDetails(userId, projectId); if (!memberDetails) throw new Error("Member not found"); // original data to revert back in case of error - const originalProjectMemberData = this.projectMemberMap?.[projectId]?.[userId]; + const originalProjectMemberData = this.projectMemberMap?.[projectId]?.[userId]?.role; + const isCurrentUser = this.rootStore.user.data?.id === userId; try { runInAction(() => { set(this.projectMemberMap, [projectId, userId, "role"], data.role); + if (isCurrentUser) + set(this.rootStore.user.permission.projectUserInfo, [workspaceSlug, projectId, "role"], data.role); }); const response = await this.projectMemberService.updateProjectMember( workspaceSlug, @@ -214,7 +219,13 @@ export class ProjectMemberStore implements IProjectMemberStore { } catch (error) { // revert back to original members in case of error runInAction(() => { - set(this.projectMemberMap, [projectId, userId], originalProjectMemberData); + set(this.projectMemberMap, [projectId, userId, "role"], originalProjectMemberData); + if (isCurrentUser) + set( + this.rootStore.user.permission.projectUserInfo, + [workspaceSlug, projectId, "role"], + originalProjectMemberData + ); }); throw error; } From f720a9afb2c45636ce35b276b8d9afdcec2d250f Mon Sep 17 00:00:00 2001 From: Samuel Torres Date: Mon, 24 Mar 2025 00:25:20 -0700 Subject: [PATCH 007/146] feat: validate github organization during OAuth login (#6700) * feat: add GITHUB_ORGANIZATION_ID support for GitHub OAuth integration * fix: remove debug print statements from InstanceConfigurationEndpoint --- admin/app/authentication/github/form.tsx | 15 ++++++++++ .../plane/authentication/adapter/error.py | 2 ++ .../authentication/provider/oauth/github.py | 29 ++++++++++++++++++- .../management/commands/configure_instance.py | 6 ++++ 4 files changed, 51 insertions(+), 1 deletion(-) diff --git a/admin/app/authentication/github/form.tsx b/admin/app/authentication/github/form.tsx index 4842675cd..91795ea70 100644 --- a/admin/app/authentication/github/form.tsx +++ b/admin/app/authentication/github/form.tsx @@ -43,6 +43,7 @@ export const InstanceGithubConfigForm: FC = (props) => { defaultValues: { GITHUB_CLIENT_ID: config["GITHUB_CLIENT_ID"], GITHUB_CLIENT_SECRET: config["GITHUB_CLIENT_SECRET"], + GITHUB_ORGANIZATION_ID: config["GITHUB_ORGANIZATION_ID"], }, }); @@ -93,6 +94,19 @@ export const InstanceGithubConfigForm: FC = (props) => { error: Boolean(errors.GITHUB_CLIENT_SECRET), required: true, }, + { + key: "GITHUB_ORGANIZATION_ID", + type: "text", + label: "Organization ID", + description: ( + <> + The organization github ID. + + ), + placeholder: "123456789", + error: Boolean(errors.GITHUB_ORGANIZATION_ID), + required: false, + }, ]; const GITHUB_SERVICE_FIELD: TCopyField[] = [ @@ -150,6 +164,7 @@ export const InstanceGithubConfigForm: FC = (props) => { reset({ GITHUB_CLIENT_ID: response.find((item) => item.key === "GITHUB_CLIENT_ID")?.value, GITHUB_CLIENT_SECRET: response.find((item) => item.key === "GITHUB_CLIENT_SECRET")?.value, + GITHUB_ORGANIZATION_ID: response.find((item) => item.key === "GITHUB_ORGANIZATION_ID")?.value, }); }) .catch((err) => console.error(err)); diff --git a/apiserver/plane/authentication/adapter/error.py b/apiserver/plane/authentication/adapter/error.py index 63fafffbe..dcbe039fb 100644 --- a/apiserver/plane/authentication/adapter/error.py +++ b/apiserver/plane/authentication/adapter/error.py @@ -36,10 +36,12 @@ AUTHENTICATION_ERROR_CODES = { "OAUTH_NOT_CONFIGURED": 5104, "GOOGLE_NOT_CONFIGURED": 5105, "GITHUB_NOT_CONFIGURED": 5110, + "GITHUB_USER_NOT_IN_ORG": 5122, "GITLAB_NOT_CONFIGURED": 5111, "GOOGLE_OAUTH_PROVIDER_ERROR": 5115, "GITHUB_OAUTH_PROVIDER_ERROR": 5120, "GITLAB_OAUTH_PROVIDER_ERROR": 5121, + # Reset Password "INVALID_PASSWORD_TOKEN": 5125, "EXPIRED_PASSWORD_TOKEN": 5130, diff --git a/apiserver/plane/authentication/provider/oauth/github.py b/apiserver/plane/authentication/provider/oauth/github.py index 1808aa515..4a7808c8a 100644 --- a/apiserver/plane/authentication/provider/oauth/github.py +++ b/apiserver/plane/authentication/provider/oauth/github.py @@ -18,11 +18,16 @@ from plane.authentication.adapter.error import ( class GitHubOAuthProvider(OauthAdapter): token_url = "https://github.com/login/oauth/access_token" userinfo_url = "https://api.github.com/user" + org_membership_url = f"https://api.github.com/orgs" + provider = "github" scope = "read:user user:email" + organization_scope = "read:org" + + def __init__(self, request, code=None, state=None, callback=None): - GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET = get_configuration_value( + GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET, GITHUB_ORGANIZATION_ID = get_configuration_value( [ { "key": "GITHUB_CLIENT_ID", @@ -32,6 +37,10 @@ class GitHubOAuthProvider(OauthAdapter): "key": "GITHUB_CLIENT_SECRET", "default": os.environ.get("GITHUB_CLIENT_SECRET"), }, + { + "key": "GITHUB_ORGANIZATION_ID", + "default": os.environ.get("GITHUB_ORGANIZATION_ID"), + }, ] ) @@ -43,6 +52,10 @@ class GitHubOAuthProvider(OauthAdapter): client_id = GITHUB_CLIENT_ID client_secret = GITHUB_CLIENT_SECRET + self.organization_id = GITHUB_ORGANIZATION_ID + + if self.organization_id: + self.scope += f" {self.organization_scope}" redirect_uri = f"""{"https" if request.is_secure() else "http"}://{request.get_host()}/auth/github/callback/""" url_params = { @@ -113,12 +126,26 @@ class GitHubOAuthProvider(OauthAdapter): error_message="GITHUB_OAUTH_PROVIDER_ERROR", ) + def is_user_in_organization(self, github_username): + headers = {"Authorization": f"Bearer {self.token_data.get('access_token')}"} + response = requests.get(f"{self.org_membership_url}/{self.organization_id}/memberships/{github_username}", headers=headers) + return response.status_code == 200 # 200 means the user is a member + def set_user_data(self): user_info_response = self.get_user_response() headers = { "Authorization": f"Bearer {self.token_data.get('access_token')}", "Accept": "application/json", } + + if self.organization_id: + if not self.is_user_in_organization(user_info_response.get("login")): + raise AuthenticationException( + error_code=AUTHENTICATION_ERROR_CODES["GITHUB_USER_NOT_IN_ORG"], + error_message="GITHUB_USER_NOT_IN_ORG", + ) + + email = self.__get_email(headers=headers) super().set_user_data( { diff --git a/apiserver/plane/license/management/commands/configure_instance.py b/apiserver/plane/license/management/commands/configure_instance.py index 8458df5df..ce6bbf7a0 100644 --- a/apiserver/plane/license/management/commands/configure_instance.py +++ b/apiserver/plane/license/management/commands/configure_instance.py @@ -71,6 +71,12 @@ class Command(BaseCommand): "category": "GITHUB", "is_encrypted": True, }, + { + "key": "GITHUB_ORGANIZATION_ID", + "value": os.environ.get("GITHUB_ORGANIZATION_ID"), + "category": "GITHUB", + "is_encrypted": False, + }, { "key": "GITLAB_HOST", "value": os.environ.get("GITLAB_HOST"), From 962923ff4f6d3cebe387213986b636fad2969e63 Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Mon, 24 Mar 2025 13:40:07 +0530 Subject: [PATCH 008/146] fix: admin build (#6798) --- packages/types/src/instance/auth.d.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/types/src/instance/auth.d.ts b/packages/types/src/instance/auth.d.ts index d71cfa0bb..31d3a2582 100644 --- a/packages/types/src/instance/auth.d.ts +++ b/packages/types/src/instance/auth.d.ts @@ -21,7 +21,8 @@ export type TInstanceGoogleAuthenticationConfigurationKeys = export type TInstanceGithubAuthenticationConfigurationKeys = | "GITHUB_CLIENT_ID" - | "GITHUB_CLIENT_SECRET"; + | "GITHUB_CLIENT_SECRET" + | "GITHUB_ORGANIZATION_ID"; export type TInstanceGitlabAuthenticationConfigurationKeys = | "GITLAB_HOST" From 0d069bf46e25def4dc89d42b2a23c773a883ba50 Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Mon, 24 Mar 2025 13:41:02 +0530 Subject: [PATCH 009/146] [RANTS-65] fix: undefined work item sequence in bulk delete work item modal (#6797) --- .../core/modals/bulk-delete-issues-modal-item.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/web/core/components/core/modals/bulk-delete-issues-modal-item.tsx b/web/core/components/core/modals/bulk-delete-issues-modal-item.tsx index 6fb44d11a..e0c4be23e 100644 --- a/web/core/components/core/modals/bulk-delete-issues-modal-item.tsx +++ b/web/core/components/core/modals/bulk-delete-issues-modal-item.tsx @@ -34,7 +34,13 @@ export const BulkDeleteIssuesModalItem: React.FC = observer((props: Props backgroundColor: color, }} /> - + {issue.name} From ab3eadf76709e6b19d827c420d12542880754baa Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Mon, 24 Mar 2025 18:13:49 +0530 Subject: [PATCH 010/146] [WEB-3614] fix: cmd-k item focus state (#6800) --- web/styles/command-pallette.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/styles/command-pallette.css b/web/styles/command-pallette.css index 133b5299f..bd3685e76 100644 --- a/web/styles/command-pallette.css +++ b/web/styles/command-pallette.css @@ -30,7 +30,7 @@ background-color: rgba(var(--color-background-100)); } -[cmdk-item]:hover { +[cmdk-item]:focus { background-color: rgba(var(--color-background-80)); } @@ -45,7 +45,7 @@ background-color: transparent; } -[cmdk-item][aria-disabled="true"]:hover, -[cmdk-item][data-disabled="true"]:hover { +[cmdk-item][aria-disabled="true"]:focus, +[cmdk-item][data-disabled="true"]:focus { background-color: rgba(var(--color-background-80), 0.7); } From d37d21092161592427bcb3f3dbf4d0e0bbc65ff3 Mon Sep 17 00:00:00 2001 From: Akshita Goyal <36129505+gakshita@users.noreply.github.com> Date: Mon, 24 Mar 2025 18:15:43 +0530 Subject: [PATCH 011/146] [WEB-3677] fix: settings dynamic pages permissions (#6804) * fix: settings dynamic pages permissions * fix: refactor --- .../(projects)/settings/(with-sidebar)/layout.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/app/[workspaceSlug]/(projects)/settings/(with-sidebar)/layout.tsx b/web/app/[workspaceSlug]/(projects)/settings/(with-sidebar)/layout.tsx index 24f81d39d..e51106bfe 100644 --- a/web/app/[workspaceSlug]/(projects)/settings/(with-sidebar)/layout.tsx +++ b/web/app/[workspaceSlug]/(projects)/settings/(with-sidebar)/layout.tsx @@ -24,7 +24,7 @@ const WorkspaceSettingLayout: FC = observer((props) => const { workspaceUserInfo } = useUserPermissions(); const pathname = usePathname(); - const { workspaceSlug } = useParams(); + const [workspaceSlug, suffix, route] = pathname.replace(/^\/|\/$/g, "").split("/"); // Regex removes leading and trailing slashes // derived values const userWorkspaceRole = workspaceUserInfo?.[workspaceSlug.toString()]?.role; @@ -32,7 +32,7 @@ const WorkspaceSettingLayout: FC = observer((props) => pathname && workspaceSlug && userWorkspaceRole && - WORKSPACE_SETTINGS_ACCESS[pathname.replace(`/${workspaceSlug}`, "").slice(0, -1)]?.includes( + WORKSPACE_SETTINGS_ACCESS[route ? `/${suffix}/${route}` : `/${suffix}`]?.includes( userWorkspaceRole as EUserWorkspaceRoles ); From 50e0cb7ffdf5b6c225f25954a5a084b850632066 Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com> Date: Mon, 24 Mar 2025 18:21:12 +0530 Subject: [PATCH 012/146] [RANTS-75] chore: update profile sidebar icons and copy for consistency (#6808) --- web/app/profile/sidebar.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/web/app/profile/sidebar.tsx b/web/app/profile/sidebar.tsx index 07fd746c6..59e3daa48 100644 --- a/web/app/profile/sidebar.tsx +++ b/web/app/profile/sidebar.tsx @@ -9,13 +9,13 @@ import { ChevronLeft, LogOut, MoveLeft, - Plus, - UserPlus, Activity, Bell, CircleUser, KeyRound, Settings2, + CirclePlus, + Mails, } from "lucide-react"; // plane imports import { PROFILE_ACTION_LINKS } from "@plane/constants"; @@ -35,14 +35,14 @@ import { usePlatformOS } from "@/hooks/use-platform-os"; const WORKSPACE_ACTION_LINKS = [ { key: "create_workspace", - Icon: Plus, - label: "Create workspace", + Icon: CirclePlus, + i18n_label: "create_workspace", href: "/create-workspace", }, { key: "invitations", - Icon: UserPlus, - label: "Invitations", + Icon: Mails, + i18n_label: "workspace_invites", href: "/invitations", }, ]; @@ -243,8 +243,8 @@ export const ProfileLayoutSidebar = observer(() => { sidebarCollapsed ? "justify-center" : "" }`} > - {} - {!sidebarCollapsed && t(link.key)} + {} + {!sidebarCollapsed && t(link.i18n_label)} From fe04e5a292b269dc0f1f066a6ceef5ad48d2bdb0 Mon Sep 17 00:00:00 2001 From: Bavisetti Narayan <72156168+NarayanBavisetti@users.noreply.github.com> Date: Mon, 24 Mar 2025 18:23:09 +0530 Subject: [PATCH 013/146] [WEB-3658] fix: remove cycles and modules when issues are bulk deleted (#6807) --- apiserver/plane/app/views/issue/base.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apiserver/plane/app/views/issue/base.py b/apiserver/plane/app/views/issue/base.py index 79ffe35d8..71e794fec 100644 --- a/apiserver/plane/app/views/issue/base.py +++ b/apiserver/plane/app/views/issue/base.py @@ -45,6 +45,7 @@ from plane.db.models import ( ProjectMember, CycleIssue, UserRecentVisit, + ModuleIssue, ) from plane.utils.grouper import ( issue_group_values, @@ -738,6 +739,13 @@ class BulkDeleteIssuesEndpoint(BaseAPIView): total_issues = len(issues) + # First, delete all related cycle issues + CycleIssue.objects.filter(issue_id__in=issue_ids).delete() + + # Then, delete all related module issues + ModuleIssue.objects.filter(issue_id__in=issue_ids).delete() + + # Finally, delete the issues themselves issues.delete() return Response( From ef108839c4614d72bfa1ccb1faa43483237571f0 Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com> Date: Mon, 24 Mar 2025 18:24:10 +0530 Subject: [PATCH 014/146] [RANTS-57] chore: replace target date with due date in work item filters dropdown (#6806) --- .../filters/header/filters/{target-date.tsx => due-date.tsx} | 4 ++-- .../filters/header/filters/filters-selection.tsx | 4 ++-- .../issues/issue-layouts/filters/header/filters/index.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) rename web/core/components/issues/issue-layouts/filters/header/filters/{target-date.tsx => due-date.tsx} (93%) diff --git a/web/core/components/issues/issue-layouts/filters/header/filters/target-date.tsx b/web/core/components/issues/issue-layouts/filters/header/filters/due-date.tsx similarity index 93% rename from web/core/components/issues/issue-layouts/filters/header/filters/target-date.tsx rename to web/core/components/issues/issue-layouts/filters/header/filters/due-date.tsx index bfd677681..8f3dfa58d 100644 --- a/web/core/components/issues/issue-layouts/filters/header/filters/target-date.tsx +++ b/web/core/components/issues/issue-layouts/filters/header/filters/due-date.tsx @@ -12,7 +12,7 @@ type Props = { searchQuery: string; }; -export const FilterTargetDate: React.FC = observer((props) => { +export const FilterDueDate: React.FC = observer((props) => { const { appliedFilters, handleUpdate, searchQuery } = props; const [previewEnabled, setPreviewEnabled] = useState(true); @@ -46,7 +46,7 @@ export const FilterTargetDate: React.FC = observer((props) => { /> )} 0 ? ` (${appliedFiltersCount})` : ""}`} + title={`Due date${appliedFiltersCount > 0 ? ` (${appliedFiltersCount})` : ""}`} isPreviewEnabled={previewEnabled} handleIsPreviewEnabled={() => setPreviewEnabled(!previewEnabled)} /> diff --git a/web/core/components/issues/issue-layouts/filters/header/filters/filters-selection.tsx b/web/core/components/issues/issue-layouts/filters/header/filters/filters-selection.tsx index 7791efc16..28e29ab62 100644 --- a/web/core/components/issues/issue-layouts/filters/header/filters/filters-selection.tsx +++ b/web/core/components/issues/issue-layouts/filters/header/filters/filters-selection.tsx @@ -18,13 +18,13 @@ import { FilterAssignees, FilterMentions, FilterCreatedBy, + FilterDueDate, FilterLabels, FilterPriority, FilterProjects, FilterStartDate, FilterState, FilterStateGroup, - FilterTargetDate, FilterCycle, FilterModule, FilterIssueGrouping, @@ -276,7 +276,7 @@ export const FilterSelection: React.FC = observer((props) => { {/* target_date */} {isFilterEnabled("target_date") && (
- handleFiltersUpdate("target_date", val)} searchQuery={filtersSearchQuery} diff --git a/web/core/components/issues/issue-layouts/filters/header/filters/index.ts b/web/core/components/issues/issue-layouts/filters/header/filters/index.ts index ab5756bf4..f4de8a278 100644 --- a/web/core/components/issues/issue-layouts/filters/header/filters/index.ts +++ b/web/core/components/issues/issue-layouts/filters/header/filters/index.ts @@ -1,6 +1,7 @@ export * from "./assignee"; export * from "./mentions"; export * from "./created-by"; +export * from "./due-date"; export * from "./filters-selection"; export * from "./labels"; export * from "./priority"; @@ -10,4 +11,3 @@ export * from "./state-group"; export * from "./state"; export * from "./cycle"; export * from "./module"; -export * from "./target-date"; From 983e0fa081eae4e6e2ff5108a59f55d01954db4e Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Mon, 24 Mar 2025 18:30:31 +0530 Subject: [PATCH 015/146] [WEB-3438] fix: transfer completed cycle issue modal (#6802) --- web/core/components/cycles/transfer-issues-modal.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/core/components/cycles/transfer-issues-modal.tsx b/web/core/components/cycles/transfer-issues-modal.tsx index 6259a2bca..33a94bb2e 100644 --- a/web/core/components/cycles/transfer-issues-modal.tsx +++ b/web/core/components/cycles/transfer-issues-modal.tsx @@ -149,10 +149,10 @@ export const TransferIssuesModal: React.FC = observer((props) => { }} > -
- {cycleDetails?.name} +
+ {cycleDetails?.name} {cycleDetails.status && ( - + {cycleDetails.status.toLocaleLowerCase()} )} From e8718a84fea24d8e65f1f22be498f33311a4ca31 Mon Sep 17 00:00:00 2001 From: Vamsi Krishna <46787868+vamsikrishnamathala@users.noreply.github.com> Date: Mon, 24 Mar 2025 18:33:22 +0530 Subject: [PATCH 016/146] chore: issue detail refactor (#6803) --- .../issues/issue-detail-widgets/additional-widgets.tsx | 10 ++++++++++ web/ce/components/issues/issue-detail-widgets/index.ts | 1 + web/ce/store/issue/helpers/base-issue-store.ts | 4 ++++ .../issue-detail-widget-collapsibles.tsx | 8 ++++++++ web/core/components/issues/issue-detail/sidebar.tsx | 1 - 5 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 web/ce/components/issues/issue-detail-widgets/additional-widgets.tsx create mode 100644 web/ce/components/issues/issue-detail-widgets/index.ts create mode 100644 web/ce/store/issue/helpers/base-issue-store.ts diff --git a/web/ce/components/issues/issue-detail-widgets/additional-widgets.tsx b/web/ce/components/issues/issue-detail-widgets/additional-widgets.tsx new file mode 100644 index 000000000..04288603a --- /dev/null +++ b/web/ce/components/issues/issue-detail-widgets/additional-widgets.tsx @@ -0,0 +1,10 @@ +import { FC } from "react"; + +export type TWorkItemAdditionalWidgets = { + workspaceSlug: string; + projectId: string; + workItemId: string; + disabled: boolean; +}; + +export const WorkItemAdditionalWidgets: FC = (props) => <>; diff --git a/web/ce/components/issues/issue-detail-widgets/index.ts b/web/ce/components/issues/issue-detail-widgets/index.ts new file mode 100644 index 000000000..a972c5053 --- /dev/null +++ b/web/ce/components/issues/issue-detail-widgets/index.ts @@ -0,0 +1 @@ +export * from "./additional-widgets"; diff --git a/web/ce/store/issue/helpers/base-issue-store.ts b/web/ce/store/issue/helpers/base-issue-store.ts new file mode 100644 index 000000000..b75a4916a --- /dev/null +++ b/web/ce/store/issue/helpers/base-issue-store.ts @@ -0,0 +1,4 @@ +import { TIssue } from "@plane/types"; +import { getIssueIds } from "@/store/issue/helpers/base-issues-utils"; + +export const workItemSortWithOrderByExtended = (array: TIssue[], key?: string) => getIssueIds(array); diff --git a/web/core/components/issues/issue-detail-widgets/issue-detail-widget-collapsibles.tsx b/web/core/components/issues/issue-detail-widgets/issue-detail-widget-collapsibles.tsx index 26ec7b6bf..1f3d148dc 100644 --- a/web/core/components/issues/issue-detail-widgets/issue-detail-widget-collapsibles.tsx +++ b/web/core/components/issues/issue-detail-widgets/issue-detail-widget-collapsibles.tsx @@ -11,6 +11,7 @@ import { // hooks import { useIssueDetail } from "@/hooks/store"; // Plane-web +import { WorkItemAdditionalWidgets } from "@/plane-web/components/issues/issue-detail-widgets"; import { useTimeLineRelationOptions } from "@/plane-web/components/relations"; type Props = { @@ -68,6 +69,13 @@ export const IssueDetailWidgetCollapsibles: FC = observer((props) => { disabled={disabled} /> )} + +
); }); diff --git a/web/core/components/issues/issue-detail/sidebar.tsx b/web/core/components/issues/issue-detail/sidebar.tsx index d132b4e77..8e7bf151b 100644 --- a/web/core/components/issues/issue-detail/sidebar.tsx +++ b/web/core/components/issues/issue-detail/sidebar.tsx @@ -299,7 +299,6 @@ export const IssueDetailsSidebar: React.FC = observer((props) => { projectId={projectId} workspaceSlug={workspaceSlug} isEditable={isEditable} - isPeekView />
From 0ec206b75df5edf44f65d625eeb93d63494981c0 Mon Sep 17 00:00:00 2001 From: sriram veeraghanta Date: Mon, 24 Mar 2025 18:55:59 +0530 Subject: [PATCH 017/146] fix: transpile packages update on space and admin apps --- admin/next.config.js | 13 +++++++++++++ space/next.config.js | 15 +++++++++++++++ web/next.config.js | 1 + 3 files changed, 29 insertions(+) diff --git a/admin/next.config.js b/admin/next.config.js index 2109cec69..421f645e8 100644 --- a/admin/next.config.js +++ b/admin/next.config.js @@ -9,6 +9,19 @@ const nextConfig = { unoptimized: true, }, basePath: process.env.NEXT_PUBLIC_ADMIN_BASE_PATH || "", + transpilePackages: [ + "@plane/constants", + "@plane/editor", + "@plane/hooks", + "@plane/i18n", + "@plane/logger", + "@plane/propel", + "@plane/services", + "@plane/shared-state", + "@plane/types", + "@plane/ui", + "@plane/utils", + ], }; module.exports = nextConfig; diff --git a/space/next.config.js b/space/next.config.js index 58b6cfa0b..aabd70cb4 100644 --- a/space/next.config.js +++ b/space/next.config.js @@ -1,7 +1,9 @@ // eslint-disable-next-line @typescript-eslint/no-var-requires /* eslint-disable @typescript-eslint/no-var-requires */ /** @type {import('next').NextConfig} */ +// eslint-disable-next-line @typescript-eslint/no-require-imports require("dotenv").config({ path: ".env" }); +// eslint-disable-next-line @typescript-eslint/no-require-imports const { withSentryConfig } = require("@sentry/nextjs"); const nextConfig = { @@ -27,6 +29,19 @@ const nextConfig = { ], unoptimized: true, }, + transpilePackages: [ + "@plane/constants", + "@plane/editor", + "@plane/hooks", + "@plane/i18n", + "@plane/logger", + "@plane/propel", + "@plane/services", + "@plane/shared-state", + "@plane/types", + "@plane/ui", + "@plane/utils", + ], }; const sentryConfig = { diff --git a/web/next.config.js b/web/next.config.js index 8422342b6..7f83ec742 100644 --- a/web/next.config.js +++ b/web/next.config.js @@ -1,5 +1,6 @@ /* eslint-disable @typescript-eslint/no-var-requires */ /** @type {import("next").NextConfig} */ +// eslint-disable-next-line @typescript-eslint/no-require-imports require("dotenv").config({ path: ".env" }); const nextConfig = { From c347dd7dcd65e0128d9e82abacfd707e5d7a883d Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Mon, 24 Mar 2025 19:05:53 +0530 Subject: [PATCH 018/146] [WEB-3614] chore: list layout display filters (#6801) --- packages/constants/src/issue/filter.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/constants/src/issue/filter.ts b/packages/constants/src/issue/filter.ts index 5d1d694b7..687a2bd71 100644 --- a/packages/constants/src/issue/filter.ts +++ b/packages/constants/src/issue/filter.ts @@ -339,6 +339,7 @@ export const ISSUE_DISPLAY_FILTERS_BY_PAGE: TIssueFiltersToDisplayByPageType = { "-updated_at", "start_date", "-priority", + "target_date", ], type: [null, "active", "backlog"], }, From 5cb37a0b9cceb11edd43e6d66627a47b6960d0b4 Mon Sep 17 00:00:00 2001 From: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Date: Mon, 24 Mar 2025 19:06:36 +0530 Subject: [PATCH 019/146] [WEB-3560] fix: table layout issue block and code refactor (#6805) --- .../issue-layouts/spreadsheet/issue-row.tsx | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/web/core/components/issues/issue-layouts/spreadsheet/issue-row.tsx b/web/core/components/issues/issue-layouts/spreadsheet/issue-row.tsx index 0c87dfae5..c60519053 100644 --- a/web/core/components/issues/issue-layouts/spreadsheet/issue-row.tsx +++ b/web/core/components/issues/issue-layouts/spreadsheet/issue-row.tsx @@ -261,19 +261,21 @@ const IssueRowDetails = observer((props: IssueRowDetailsProps) => { handleIssuePeekOverview(issueDetail)} - className={cn( - "group clickable cursor-pointer h-11 w-[28rem] flex items-center text-sm after:absolute border-r-[0.5px] z-10 border-custom-border-200 bg-transparent group-[.selected-issue-row]:bg-custom-primary-100/5 group-[.selected-issue-row]:hover:bg-custom-primary-100/10", - { - "border-b-[0.5px]": !getIsIssuePeeked(issueDetail.id), - "border border-custom-primary-70 hover:border-custom-primary-70": - getIsIssuePeeked(issueDetail.id) && nestingLevel === peekIssue?.nestingLevel, - "shadow-[8px_22px_22px_10px_rgba(0,0,0,0.05)]": isScrolled.current, - } - )} + className="outline-none" disabled={!!issueDetail?.tempId} > - -
+ +
{/* select checkbox */} {projectId && canSelectIssues && ( Date: Mon, 24 Mar 2025 19:57:13 +0530 Subject: [PATCH 020/146] [WEB-3601] chore: content updated (#6811) --- packages/i18n/src/locales/en/core.json | 2 +- space/core/components/account/oauth/oauth-options.tsx | 2 +- web/core/components/account/oauth/oauth-options.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/i18n/src/locales/en/core.json b/packages/i18n/src/locales/en/core.json index 14207c5a8..a17de227e 100644 --- a/packages/i18n/src/locales/en/core.json +++ b/packages/i18n/src/locales/en/core.json @@ -9,7 +9,7 @@ "workspace": "Workspace", "views": "Views", "analytics": "Analytics", - "work_items": "Work Items", + "work_items": "Work items", "cycles": "Cycles", "modules": "Modules", "intake": "Intake", diff --git a/space/core/components/account/oauth/oauth-options.tsx b/space/core/components/account/oauth/oauth-options.tsx index d514f1b68..153516b34 100644 --- a/space/core/components/account/oauth/oauth-options.tsx +++ b/space/core/components/account/oauth/oauth-options.tsx @@ -21,7 +21,7 @@ export const OAuthOptions: React.FC = observer(() => {
)} - {config?.is_github_enabled && } + {config?.is_github_enabled && } {config?.is_gitlab_enabled && }
diff --git a/web/core/components/account/oauth/oauth-options.tsx b/web/core/components/account/oauth/oauth-options.tsx index 10396f239..eb4ec4851 100644 --- a/web/core/components/account/oauth/oauth-options.tsx +++ b/web/core/components/account/oauth/oauth-options.tsx @@ -29,7 +29,7 @@ export const OAuthOptions: React.FC = observer(() => { )} - {config?.is_github_enabled && } + {config?.is_github_enabled && } {config?.is_gitlab_enabled && } From c91972cc0a6b7337513b9c7e563aa4d087d266cd Mon Sep 17 00:00:00 2001 From: sriram veeraghanta Date: Tue, 25 Mar 2025 15:45:31 +0530 Subject: [PATCH 021/146] chore: removing sentry instrumentation --- space/google.d.ts | 11 -------- space/instrumentation.ts | 9 ------- space/next.config.js | 47 +---------------------------------- space/sentry.client.config.ts | 31 ----------------------- space/sentry.edge.config.ts | 17 ------------- space/sentry.properties | 3 --- space/sentry.server.config.ts | 19 -------------- 7 files changed, 1 insertion(+), 136 deletions(-) delete mode 100644 space/google.d.ts delete mode 100644 space/instrumentation.ts delete mode 100644 space/sentry.client.config.ts delete mode 100644 space/sentry.edge.config.ts delete mode 100644 space/sentry.properties delete mode 100644 space/sentry.server.config.ts diff --git a/space/google.d.ts b/space/google.d.ts deleted file mode 100644 index c37c83c94..000000000 --- a/space/google.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -// google.d.ts -interface GsiButtonConfiguration { - type: "standard" | "icon"; - theme?: "outline" | "filled_blue" | "filled_black"; - size?: "large" | "medium" | "small"; - text?: "signin_with" | "signup_with" | "continue_with" | "signup_with"; - shape?: "rectangular" | "pill" | "circle" | "square"; - logo_alignment?: "left" | "center"; - width?: number; - local?: string; -} diff --git a/space/instrumentation.ts b/space/instrumentation.ts deleted file mode 100644 index 7b89a972e..000000000 --- a/space/instrumentation.ts +++ /dev/null @@ -1,9 +0,0 @@ -export async function register() { - if (process.env.NEXT_RUNTIME === 'nodejs') { - await import('./sentry.server.config'); - } - - if (process.env.NEXT_RUNTIME === 'edge') { - await import('./sentry.edge.config'); - } -} diff --git a/space/next.config.js b/space/next.config.js index aabd70cb4..2d3e4e788 100644 --- a/space/next.config.js +++ b/space/next.config.js @@ -1,10 +1,4 @@ -// eslint-disable-next-line @typescript-eslint/no-var-requires -/* eslint-disable @typescript-eslint/no-var-requires */ /** @type {import('next').NextConfig} */ -// eslint-disable-next-line @typescript-eslint/no-require-imports -require("dotenv").config({ path: ".env" }); -// eslint-disable-next-line @typescript-eslint/no-require-imports -const { withSentryConfig } = require("@sentry/nextjs"); const nextConfig = { trailingSlash: true, @@ -44,43 +38,4 @@ const nextConfig = { ], }; -const sentryConfig = { - // For all available options, see: - // https://github.com/getsentry/sentry-webpack-plugin#options - - org: process.env.SENTRY_ORG_ID || "plane-hq", - project: process.env.SENTRY_PROJECT_ID || "plane-space", - authToken: process.env.SENTRY_AUTH_TOKEN, - // Only print logs for uploading source maps in CI - silent: true, - - // For all available options, see: - // https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/ - - // Upload a larger set of source maps for prettier stack traces (increases build time) - widenClientFileUpload: true, - - // Route browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers. - // This can increase your server load as well as your hosting bill. - // Note: Check that the configured route will not match with your Next.js middleware, otherwise reporting of client- - // side errors will fail. - tunnelRoute: "/monitoring", - - // Hides source maps from generated client bundles - hideSourceMaps: true, - - // Automatically tree-shake Sentry logger statements to reduce bundle size - disableLogger: true, - - // Enables automatic instrumentation of Vercel Cron Monitors. (Does not yet work with App Router route handlers.) - // See the following for more information: - // https://docs.sentry.io/product/crons/ - // https://vercel.com/docs/cron-jobs - automaticVercelMonitors: true, -}; - -if (parseInt(process.env.SENTRY_MONITORING_ENABLED || "0", 10)) { - module.exports = withSentryConfig(nextConfig, sentryConfig); -} else { - module.exports = nextConfig; -} +module.exports = nextConfig; diff --git a/space/sentry.client.config.ts b/space/sentry.client.config.ts deleted file mode 100644 index c81030622..000000000 --- a/space/sentry.client.config.ts +++ /dev/null @@ -1,31 +0,0 @@ -// This file configures the initialization of Sentry on the client. -// The config you add here will be used whenever a users loads a page in their browser. -// https://docs.sentry.io/platforms/javascript/guides/nextjs/ - -import * as Sentry from "@sentry/nextjs"; - -Sentry.init({ - dsn: process.env.NEXT_PUBLIC_SENTRY_DSN, - environment: process.env.NEXT_PUBLIC_SENTRY_ENVIRONMENT || "development", - - // Adjust this value in production, or use tracesSampler for greater control - tracesSampleRate: 1, - - // Setting this option to true will print useful information to the console while you're setting up Sentry. - debug: false, - - replaysOnErrorSampleRate: 1.0, - - // This sets the sample rate to be 10%. You may want this to be 100% while - // in development and sample at a lower rate in production - replaysSessionSampleRate: 0.1, - - // You can remove this option if you're not planning to use the Sentry Session Replay feature: - integrations: [ - Sentry.replayIntegration({ - // Additional Replay configuration goes in here, for example: - maskAllText: true, - blockAllMedia: true, - }), - ], -}); diff --git a/space/sentry.edge.config.ts b/space/sentry.edge.config.ts deleted file mode 100644 index 2dbc6e93a..000000000 --- a/space/sentry.edge.config.ts +++ /dev/null @@ -1,17 +0,0 @@ -// This file configures the initialization of Sentry for edge features (middleware, edge routes, and so on). -// The config you add here will be used whenever one of the edge features is loaded. -// Note that this config is unrelated to the Vercel Edge Runtime and is also required when running locally. -// https://docs.sentry.io/platforms/javascript/guides/nextjs/ - -import * as Sentry from "@sentry/nextjs"; - -Sentry.init({ - dsn: process.env.NEXT_PUBLIC_SENTRY_DSN, - environment: process.env.NEXT_PUBLIC_SENTRY_ENVIRONMENT || "development", - - // Adjust this value in production, or use tracesSampler for greater control - tracesSampleRate: 1, - - // Setting this option to true will print useful information to the console while you're setting up Sentry. - debug: false, -}); diff --git a/space/sentry.properties b/space/sentry.properties deleted file mode 100644 index 1741152a3..000000000 --- a/space/sentry.properties +++ /dev/null @@ -1,3 +0,0 @@ -defaults.url=https://sentry.io/ -defaults.org=plane -defaults.project=plane-space diff --git a/space/sentry.server.config.ts b/space/sentry.server.config.ts deleted file mode 100644 index e578f1530..000000000 --- a/space/sentry.server.config.ts +++ /dev/null @@ -1,19 +0,0 @@ -// This file configures the initialization of Sentry on the server. -// The config you add here will be used whenever the server handles a request. -// https://docs.sentry.io/platforms/javascript/guides/nextjs/ - -import * as Sentry from "@sentry/nextjs"; - -Sentry.init({ - dsn: process.env.NEXT_PUBLIC_SENTRY_DSN, - environment: process.env.NEXT_PUBLIC_SENTRY_ENVIRONMENT || "development", - - // Adjust this value in production, or use tracesSampler for greater control - tracesSampleRate: 1, - - // Setting this option to true will print useful information to the console while you're setting up Sentry. - debug: false, - - // Uncomment the line below to enable Spotlight (https://spotlightjs.com) - // spotlight: process.env.NODE_ENV === 'development', -}); From f29867968a28b97b74c247173f9b4ef32f3186a9 Mon Sep 17 00:00:00 2001 From: sriram veeraghanta Date: Tue, 25 Mar 2025 15:54:44 +0530 Subject: [PATCH 022/146] chore: removed sentry instrumentation dependencies --- ENV_SETUP.md | 3 - admin/package.json | 1 - aio/Dockerfile-app | 3 - apiserver/.env.example | 4 - ..._alter_analyticview_created_by_and_more.py | 2 - apiserver/plane/settings/common.py | 23 - apiserver/plane/utils/exception_logger.py | 5 - apiserver/requirements/base.txt | 2 - app.json | 18 +- deploy/selfhost/docker-compose.yml | 2 - deploy/selfhost/variables.env | 2 - live/package.json | 2 - live/src/core/config/sentry-config.ts | 19 - live/src/server.ts | 7 +- live/tsconfig.json | 3 - space/package.json | 1 - turbo.json | 8 +- yarn.lock | 937 +----------------- 18 files changed, 19 insertions(+), 1023 deletions(-) delete mode 100644 live/src/core/config/sentry-config.ts diff --git a/ENV_SETUP.md b/ENV_SETUP.md index cdcf6be37..775d6a55f 100644 --- a/ENV_SETUP.md +++ b/ENV_SETUP.md @@ -43,9 +43,6 @@ NGINX_PORT=80 # Debug value for api server use it as 0 for production use DEBUG=0 CORS_ALLOWED_ORIGINS="http://localhost" -# Error logs -SENTRY_DSN="" -SENTRY_ENVIRONMENT="development" # Database Settings POSTGRES_USER="plane" POSTGRES_PASSWORD="plane" diff --git a/admin/package.json b/admin/package.json index f6c83e06b..2397a6c5d 100644 --- a/admin/package.json +++ b/admin/package.json @@ -21,7 +21,6 @@ "@plane/ui": "*", "@plane/utils": "*", "@plane/services": "*", - "@sentry/nextjs": "^8.54.0", "@tailwindcss/typography": "^0.5.9", "@types/lodash": "^4.17.0", "autoprefixer": "10.4.14", diff --git a/aio/Dockerfile-app b/aio/Dockerfile-app index 54b5269e3..7ffe3f803 100644 --- a/aio/Dockerfile-app +++ b/aio/Dockerfile-app @@ -145,11 +145,8 @@ RUN chmod +x /app/pg-setup.sh # APPLICATION ENVIRONMENT SETTINGS # ***************************************************************************** ENV APP_DOMAIN=localhost - ENV WEB_URL=http://${APP_DOMAIN} ENV DEBUG=0 -ENV SENTRY_DSN= -ENV SENTRY_ENVIRONMENT=production ENV CORS_ALLOWED_ORIGINS=http://${APP_DOMAIN},https://${APP_DOMAIN} # Secret Key ENV SECRET_KEY=60gp0byfz2dvffa45cxl20p1scy9xbpf6d8c5y0geejgkyp1b5 diff --git a/apiserver/.env.example b/apiserver/.env.example index ff3f353c7..b56494c35 100644 --- a/apiserver/.env.example +++ b/apiserver/.env.example @@ -3,10 +3,6 @@ DEBUG=0 CORS_ALLOWED_ORIGINS="http://localhost" -# Error logs -SENTRY_DSN="" -SENTRY_ENVIRONMENT="development" - # Database Settings POSTGRES_USER="plane" POSTGRES_PASSWORD="plane" diff --git a/apiserver/plane/db/migrations/0043_alter_analyticview_created_by_and_more.py b/apiserver/plane/db/migrations/0043_alter_analyticview_created_by_and_more.py index edca91f2c..f7998c4a0 100644 --- a/apiserver/plane/db/migrations/0043_alter_analyticview_created_by_and_more.py +++ b/apiserver/plane/db/migrations/0043_alter_analyticview_created_by_and_more.py @@ -3,7 +3,6 @@ from django.conf import settings from django.db import migrations, models import django.db.models.deletion -from sentry_sdk import capture_exception import uuid @@ -29,7 +28,6 @@ def create_issue_relation(apps, schema_editor): ) except Exception as e: print(e) - capture_exception(e) def update_issue_priority_choice(apps, schema_editor): diff --git a/apiserver/plane/settings/common.py b/apiserver/plane/settings/common.py index 10776f9af..57b11da00 100644 --- a/apiserver/plane/settings/common.py +++ b/apiserver/plane/settings/common.py @@ -7,13 +7,9 @@ from urllib.parse import urlparse # Third party imports import dj_database_url -import sentry_sdk # Django imports from django.core.management.utils import get_random_secret_key -from sentry_sdk.integrations.celery import CeleryIntegration -from sentry_sdk.integrations.django import DjangoIntegration -from sentry_sdk.integrations.redis import RedisIntegration from corsheaders.defaults import default_headers @@ -267,25 +263,6 @@ CELERY_IMPORTS = ( "plane.bgtasks.issue_description_version_sync", ) -# Sentry Settings -# Enable Sentry Settings -if bool(os.environ.get("SENTRY_DSN", False)) and os.environ.get( - "SENTRY_DSN" -).startswith("https://"): - sentry_sdk.init( - dsn=os.environ.get("SENTRY_DSN", ""), - integrations=[ - DjangoIntegration(), - RedisIntegration(), - CeleryIntegration(monitor_beat_tasks=True), - ], - traces_sample_rate=1, - send_default_pii=True, - environment=os.environ.get("SENTRY_ENVIRONMENT", "development"), - profiles_sample_rate=float(os.environ.get("SENTRY_PROFILE_SAMPLE_RATE", 0)), - ) - - FILE_SIZE_LIMIT = int(os.environ.get("FILE_SIZE_LIMIT", 5242880)) # Unsplash Access key diff --git a/apiserver/plane/utils/exception_logger.py b/apiserver/plane/utils/exception_logger.py index f802f286b..e261c7384 100644 --- a/apiserver/plane/utils/exception_logger.py +++ b/apiserver/plane/utils/exception_logger.py @@ -5,9 +5,6 @@ import traceback # Django imports from django.conf import settings -# Third party imports -from sentry_sdk import capture_exception - def log_exception(e): # Log the error @@ -18,6 +15,4 @@ def log_exception(e): # Print the traceback if in debug mode print(traceback.format_exc()) - # Capture in sentry if configured - capture_exception(e) return diff --git a/apiserver/requirements/base.txt b/apiserver/requirements/base.txt index ff220984d..a3d660408 100644 --- a/apiserver/requirements/base.txt +++ b/apiserver/requirements/base.txt @@ -26,8 +26,6 @@ faker==25.0.0 django-filter==24.2 # json model jsonmodels==2.7.0 -# sentry -sentry-sdk==2.8.0 # storage django-storages==1.14.2 # user management diff --git a/app.json b/app.json index 600b524d2..6b1ab7528 100644 --- a/app.json +++ b/app.json @@ -6,16 +6,8 @@ "website": "https://plane.so/", "success_url": "/", "stack": "heroku-22", - "keywords": [ - "plane", - "project management", - "django", - "next" - ], - "addons": [ - "heroku-postgresql:mini", - "heroku-redis:mini" - ], + "keywords": ["plane", "project management", "django", "next"], + "addons": ["heroku-postgresql:mini", "heroku-redis:mini"], "buildpacks": [ { "url": "https://github.com/heroku/heroku-buildpack-python.git" @@ -61,10 +53,6 @@ "description": "AWS Bucket Name to use for S3", "value": "" }, - "SENTRY_DSN": { - "description": "", - "value": "" - }, "WEB_URL": { "description": "Web URL for Plane this will be used for redirections in the emails", "value": "" @@ -82,4 +70,4 @@ "value": "" } } -} \ No newline at end of file +} diff --git a/deploy/selfhost/docker-compose.yml b/deploy/selfhost/docker-compose.yml index 8e6dab531..0d12d529e 100644 --- a/deploy/selfhost/docker-compose.yml +++ b/deploy/selfhost/docker-compose.yml @@ -42,8 +42,6 @@ x-live-env: &live-env x-app-env: &app-env WEB_URL: ${WEB_URL:-http://localhost} DEBUG: ${DEBUG:-0} - SENTRY_DSN: ${SENTRY_DSN} - SENTRY_ENVIRONMENT: ${SENTRY_ENVIRONMENT:-production} CORS_ALLOWED_ORIGINS: ${CORS_ALLOWED_ORIGINS} GUNICORN_WORKERS: 1 USE_MINIO: ${USE_MINIO:-1} diff --git a/deploy/selfhost/variables.env b/deploy/selfhost/variables.env index 9b3d6b99a..118e71d86 100644 --- a/deploy/selfhost/variables.env +++ b/deploy/selfhost/variables.env @@ -12,8 +12,6 @@ LIVE_REPLICAS=1 NGINX_PORT=80 WEB_URL=http://${APP_DOMAIN} DEBUG=0 -SENTRY_DSN= -SENTRY_ENVIRONMENT=production CORS_ALLOWED_ORIGINS=http://${APP_DOMAIN} API_BASE_URL=http://api:8000 diff --git a/live/package.json b/live/package.json index cd05ed0c0..02bff5477 100644 --- a/live/package.json +++ b/live/package.json @@ -23,8 +23,6 @@ "@plane/constants": "*", "@plane/editor": "*", "@plane/types": "*", - "@sentry/node": "^9.0.1", - "@sentry/profiling-node": "^8.28.0", "@tiptap/core": "2.10.4", "@tiptap/html": "2.11.0", "axios": "^1.8.3", diff --git a/live/src/core/config/sentry-config.ts b/live/src/core/config/sentry-config.ts deleted file mode 100644 index f879763ec..000000000 --- a/live/src/core/config/sentry-config.ts +++ /dev/null @@ -1,19 +0,0 @@ -import * as Sentry from "@sentry/node"; -import { nodeProfilingIntegration } from "@sentry/profiling-node"; - -// Ensure to call this before importing any other modules! -Sentry.init({ - dsn: process.env.LIVE_SENTRY_DSN, - environment: process.env.LIVE_SENTRY_ENVIRONMENT || "development", - - integrations: [ - // Add our Profiling integration - nodeProfilingIntegration(), - ], - // Add Tracing by setting tracesSampleRate - // We recommend adjusting this value in production - tracesSampleRate: Number(process.env.LIVE_SENTRY_TRACES_SAMPLE_RATE) || 0.5, - // Set sampling rate for profiling - // This is relative to tracesSampleRate - profilesSampleRate: 1.0, -}); diff --git a/live/src/server.ts b/live/src/server.ts index 93f56bdb5..6a47ef791 100644 --- a/live/src/server.ts +++ b/live/src/server.ts @@ -1,11 +1,8 @@ -import * as Sentry from "@sentry/node"; import compression from "compression"; import cors from "cors"; import expressWs from "express-ws"; import express from "express"; import helmet from "helmet"; -// config -import "@/core/config/sentry-config.js"; // hocuspocus server import { getHocusPocusServer } from "@/core/hocuspocus-server.js"; // helpers @@ -15,7 +12,7 @@ import { errorHandler } from "@/core/helpers/error-handler.js"; // types import { TConvertDocumentRequestBody } from "@/core/types/common.js"; -const app = express(); +const app: any = express(); expressWs(app); app.set("port", process.env.PORT || 3000); @@ -92,8 +89,6 @@ app.use((_req, res) => { res.status(404).send("Not Found"); }); -Sentry.setupExpressErrorHandler(app); - app.use(errorHandler); const liveServer = app.listen(app.get("port"), () => { diff --git a/live/tsconfig.json b/live/tsconfig.json index 54de4c245..622dc2232 100644 --- a/live/tsconfig.json +++ b/live/tsconfig.json @@ -16,9 +16,6 @@ "skipLibCheck": true, "sourceMap": true, "inlineSources": true, - // Set `sourceRoot` to "/" to strip the build path prefix - // from generated source code references. - // This improves issue grouping in Sentry. "sourceRoot": "/" }, "include": ["src/**/*.ts", "tsup.config.ts"], diff --git a/space/package.json b/space/package.json index c18238111..b487269a7 100644 --- a/space/package.json +++ b/space/package.json @@ -25,7 +25,6 @@ "@plane/types": "*", "@plane/ui": "*", "@plane/services": "*", - "@sentry/nextjs": "^8.54.0", "axios": "^1.8.3", "clsx": "^2.0.0", "date-fns": "^4.1.0", diff --git a/turbo.json b/turbo.json index 1113926ce..65f289b9c 100644 --- a/turbo.json +++ b/turbo.json @@ -18,13 +18,7 @@ "NEXT_PUBLIC_POSTHOG_KEY", "NEXT_PUBLIC_POSTHOG_HOST", "NEXT_PUBLIC_POSTHOG_DEBUG", - "NEXT_PUBLIC_SUPPORT_EMAIL", - "SENTRY_AUTH_TOKEN", - "SENTRY_ORG_ID", - "SENTRY_PROJECT_ID", - "NEXT_PUBLIC_SENTRY_ENVIRONMENT", - "NEXT_PUBLIC_SENTRY_DSN", - "SENTRY_MONITORING_ENABLED" + "NEXT_PUBLIC_SUPPORT_EMAIL" ], "tasks": { "build": { diff --git a/yarn.lock b/yarn.lock index 783bb901e..e2f842081 100644 --- a/yarn.lock +++ b/yarn.lock @@ -86,7 +86,7 @@ resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz#821c1d35641c355284d4a870b8a4a7b0c141e367" integrity sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ== -"@babel/core@^7.18.5", "@babel/core@^7.18.9", "@babel/core@^7.25.2": +"@babel/core@^7.18.9", "@babel/core@^7.25.2": version "7.26.8" resolved "https://registry.npmjs.org/@babel/core/-/core-7.26.8.tgz#7742f11c75acea6b08a8e24c5c0c8c89e89bf53e" integrity sha512-l+lkXCHS6tQEc5oUpK28xBOZ6+HwaH7YwoYQbLFiYb4nS2/l1tKnZEtEWkD0GuiYdvArf9qBS0XlQGXzPMsNqQ== @@ -1502,7 +1502,7 @@ "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.25" -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15", "@jridgewell/sourcemap-codec@^1.5.0": +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0": version "1.5.0" resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== @@ -1896,332 +1896,6 @@ resolved "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz#3dc35ba0f1e66b403c00b39344f870298ebb1c8e" integrity sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA== -"@opentelemetry/api-logs@0.53.0": - version "0.53.0" - resolved "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.53.0.tgz#c478cbd8120ec2547b64edfa03a552cfe42170be" - integrity sha512-8HArjKx+RaAI8uEIgcORbZIPklyh1YLjPSBus8hjRmvLi6DeFzgOcdZ7KwPabKj8mXF8dX0hyfAyGfycz0DbFw== - dependencies: - "@opentelemetry/api" "^1.0.0" - -"@opentelemetry/api-logs@0.56.0": - version "0.56.0" - resolved "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.56.0.tgz#68f8c51ca905c260b610c8a3c67d3f9fa3d59a45" - integrity sha512-Wr39+94UNNG3Ei9nv3pHd4AJ63gq5nSemMRpCd8fPwDL9rN3vK26lzxfH27mw16XzOSO+TpyQwBAMaLxaPWG0g== - dependencies: - "@opentelemetry/api" "^1.3.0" - -"@opentelemetry/api-logs@0.57.1": - version "0.57.1" - resolved "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.57.1.tgz#97ebd714f0b1fcdf896e85c465ae5c5b22747425" - integrity sha512-I4PHczeujhQAQv6ZBzqHYEUiggZL4IdSMixtVD3EYqbdrjujE7kRfI5QohjlPoJm8BvenoW5YaTMWRrbpot6tg== - dependencies: - "@opentelemetry/api" "^1.3.0" - -"@opentelemetry/api@^1.0.0", "@opentelemetry/api@^1.3.0", "@opentelemetry/api@^1.8", "@opentelemetry/api@^1.9.0": - version "1.9.0" - resolved "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz#d03eba68273dc0f7509e2a3d5cba21eae10379fe" - integrity sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg== - -"@opentelemetry/context-async-hooks@^1.30.1": - version "1.30.1" - resolved "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-1.30.1.tgz#4f76280691a742597fd0bf682982126857622948" - integrity sha512-s5vvxXPVdjqS3kTLKMeBMvop9hbWkwzBpu+mUO2M7sZtlkyDJGwFe33wRKnbaYDo8ExRVBIIdwIGrqpxHuKttA== - -"@opentelemetry/core@1.30.1", "@opentelemetry/core@^1.1.0", "@opentelemetry/core@^1.26.0", "@opentelemetry/core@^1.30.1", "@opentelemetry/core@^1.8.0": - version "1.30.1" - resolved "https://registry.npmjs.org/@opentelemetry/core/-/core-1.30.1.tgz#a0b468bb396358df801881709ea38299fc30ab27" - integrity sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ== - dependencies: - "@opentelemetry/semantic-conventions" "1.28.0" - -"@opentelemetry/instrumentation-amqplib@^0.46.0": - version "0.46.0" - resolved "https://registry.npmjs.org/@opentelemetry/instrumentation-amqplib/-/instrumentation-amqplib-0.46.0.tgz#8b0c61213034780a79c16216c62eee0ce1457ddf" - integrity sha512-04VHHV1KIN/c1wLWwzmLI02d/welgscBJ4BuDqrHaxd+ZIdlVXK9UYQsYf3JwSeF52z/4YoSzr8bfdVBSWoMAg== - dependencies: - "@opentelemetry/core" "^1.8.0" - "@opentelemetry/instrumentation" "^0.57.0" - "@opentelemetry/semantic-conventions" "^1.27.0" - -"@opentelemetry/instrumentation-connect@0.43.0": - version "0.43.0" - resolved "https://registry.npmjs.org/@opentelemetry/instrumentation-connect/-/instrumentation-connect-0.43.0.tgz#411035f4a8f2e498dbfa7300e545c58586a062e2" - integrity sha512-Q57JGpH6T4dkYHo9tKXONgLtxzsh1ZEW5M9A/OwKrZFyEpLqWgjhcZ3hIuVvDlhb426iDF1f9FPToV/mi5rpeA== - dependencies: - "@opentelemetry/core" "^1.8.0" - "@opentelemetry/instrumentation" "^0.57.0" - "@opentelemetry/semantic-conventions" "^1.27.0" - "@types/connect" "3.4.36" - -"@opentelemetry/instrumentation-dataloader@0.16.0": - version "0.16.0" - resolved "https://registry.npmjs.org/@opentelemetry/instrumentation-dataloader/-/instrumentation-dataloader-0.16.0.tgz#913345c335f67bf8e17a9b38c227dba741fe488b" - integrity sha512-88+qCHZC02up8PwKHk0UQKLLqGGURzS3hFQBZC7PnGwReuoKjHXS1o29H58S+QkXJpkTr2GACbx8j6mUoGjNPA== - dependencies: - "@opentelemetry/instrumentation" "^0.57.0" - -"@opentelemetry/instrumentation-express@0.47.0": - version "0.47.0" - resolved "https://registry.npmjs.org/@opentelemetry/instrumentation-express/-/instrumentation-express-0.47.0.tgz#f0477db3b1f4b342beb9ecd08edc26c470566724" - integrity sha512-XFWVx6k0XlU8lu6cBlCa29ONtVt6ADEjmxtyAyeF2+rifk8uBJbk1La0yIVfI0DoKURGbaEDTNelaXG9l/lNNQ== - dependencies: - "@opentelemetry/core" "^1.8.0" - "@opentelemetry/instrumentation" "^0.57.0" - "@opentelemetry/semantic-conventions" "^1.27.0" - -"@opentelemetry/instrumentation-fastify@0.44.1": - version "0.44.1" - resolved "https://registry.npmjs.org/@opentelemetry/instrumentation-fastify/-/instrumentation-fastify-0.44.1.tgz#c8080f24a6fbdd14689c619ad7b14fe189b10f28" - integrity sha512-RoVeMGKcNttNfXMSl6W4fsYoCAYP1vi6ZAWIGhBY+o7R9Y0afA7f9JJL0j8LHbyb0P0QhSYk+6O56OwI2k4iRQ== - dependencies: - "@opentelemetry/core" "^1.8.0" - "@opentelemetry/instrumentation" "^0.57.0" - "@opentelemetry/semantic-conventions" "^1.27.0" - -"@opentelemetry/instrumentation-fs@0.19.0": - version "0.19.0" - resolved "https://registry.npmjs.org/@opentelemetry/instrumentation-fs/-/instrumentation-fs-0.19.0.tgz#a44807aea97edc64c597d6a5b5b8637b7ab45057" - integrity sha512-JGwmHhBkRT2G/BYNV1aGI+bBjJu4fJUD/5/Jat0EWZa2ftrLV3YE8z84Fiij/wK32oMZ88eS8DI4ecLGZhpqsQ== - dependencies: - "@opentelemetry/core" "^1.8.0" - "@opentelemetry/instrumentation" "^0.57.0" - -"@opentelemetry/instrumentation-generic-pool@0.43.0": - version "0.43.0" - resolved "https://registry.npmjs.org/@opentelemetry/instrumentation-generic-pool/-/instrumentation-generic-pool-0.43.0.tgz#b1769eb0e30f2abb764a9cbc811aa3d4560ecc24" - integrity sha512-at8GceTtNxD1NfFKGAuwtqM41ot/TpcLh+YsGe4dhf7gvv1HW/ZWdq6nfRtS6UjIvZJOokViqLPJ3GVtZItAnQ== - dependencies: - "@opentelemetry/instrumentation" "^0.57.0" - -"@opentelemetry/instrumentation-graphql@0.47.0": - version "0.47.0" - resolved "https://registry.npmjs.org/@opentelemetry/instrumentation-graphql/-/instrumentation-graphql-0.47.0.tgz#271807e21a6224bd1986a3e9887650f1858ee733" - integrity sha512-Cc8SMf+nLqp0fi8oAnooNEfwZWFnzMiBHCGmDFYqmgjPylyLmi83b+NiTns/rKGwlErpW0AGPt0sMpkbNlzn8w== - dependencies: - "@opentelemetry/instrumentation" "^0.57.0" - -"@opentelemetry/instrumentation-hapi@0.45.1": - version "0.45.1" - resolved "https://registry.npmjs.org/@opentelemetry/instrumentation-hapi/-/instrumentation-hapi-0.45.1.tgz#5edf982549070d95e20152d568279548ad44d662" - integrity sha512-VH6mU3YqAKTePPfUPwfq4/xr049774qWtfTuJqVHoVspCLiT3bW+fCQ1toZxt6cxRPYASoYaBsMA3CWo8B8rcw== - dependencies: - "@opentelemetry/core" "^1.8.0" - "@opentelemetry/instrumentation" "^0.57.0" - "@opentelemetry/semantic-conventions" "^1.27.0" - -"@opentelemetry/instrumentation-http@0.57.1": - version "0.57.1" - resolved "https://registry.npmjs.org/@opentelemetry/instrumentation-http/-/instrumentation-http-0.57.1.tgz#2d8b395df62191475e76fa0eb7bf60079ea886b9" - integrity sha512-ThLmzAQDs7b/tdKI3BV2+yawuF09jF111OFsovqT1Qj3D8vjwKBwhi/rDE5xethwn4tSXtZcJ9hBsVAlWFQZ7g== - dependencies: - "@opentelemetry/core" "1.30.1" - "@opentelemetry/instrumentation" "0.57.1" - "@opentelemetry/semantic-conventions" "1.28.0" - forwarded-parse "2.1.2" - semver "^7.5.2" - -"@opentelemetry/instrumentation-ioredis@0.47.0": - version "0.47.0" - resolved "https://registry.npmjs.org/@opentelemetry/instrumentation-ioredis/-/instrumentation-ioredis-0.47.0.tgz#f83bd133d36d137d2d0b58bfbdfe12ed6fe5ab2f" - integrity sha512-4HqP9IBC8e7pW9p90P3q4ox0XlbLGme65YTrA3UTLvqvo4Z6b0puqZQP203YFu8m9rE/luLfaG7/xrwwqMUpJw== - dependencies: - "@opentelemetry/instrumentation" "^0.57.0" - "@opentelemetry/redis-common" "^0.36.2" - "@opentelemetry/semantic-conventions" "^1.27.0" - -"@opentelemetry/instrumentation-kafkajs@0.7.0": - version "0.7.0" - resolved "https://registry.npmjs.org/@opentelemetry/instrumentation-kafkajs/-/instrumentation-kafkajs-0.7.0.tgz#079b949ec814b42e49d23bb4d4f73735fe460d52" - integrity sha512-LB+3xiNzc034zHfCtgs4ITWhq6Xvdo8bsq7amR058jZlf2aXXDrN9SV4si4z2ya9QX4tz6r4eZJwDkXOp14/AQ== - dependencies: - "@opentelemetry/instrumentation" "^0.57.0" - "@opentelemetry/semantic-conventions" "^1.27.0" - -"@opentelemetry/instrumentation-knex@0.44.0": - version "0.44.0" - resolved "https://registry.npmjs.org/@opentelemetry/instrumentation-knex/-/instrumentation-knex-0.44.0.tgz#af251ed38f06a2f248812c5addf0266697b6149a" - integrity sha512-SlT0+bLA0Lg3VthGje+bSZatlGHw/vwgQywx0R/5u9QC59FddTQSPJeWNw29M6f8ScORMeUOOTwihlQAn4GkJQ== - dependencies: - "@opentelemetry/instrumentation" "^0.57.0" - "@opentelemetry/semantic-conventions" "^1.27.0" - -"@opentelemetry/instrumentation-koa@0.47.0": - version "0.47.0" - resolved "https://registry.npmjs.org/@opentelemetry/instrumentation-koa/-/instrumentation-koa-0.47.0.tgz#a74b35809ba95d0f9db49e8c3f214bde475b095a" - integrity sha512-HFdvqf2+w8sWOuwtEXayGzdZ2vWpCKEQv5F7+2DSA74Te/Cv4rvb2E5So5/lh+ok4/RAIPuvCbCb/SHQFzMmbw== - dependencies: - "@opentelemetry/core" "^1.8.0" - "@opentelemetry/instrumentation" "^0.57.0" - "@opentelemetry/semantic-conventions" "^1.27.0" - -"@opentelemetry/instrumentation-lru-memoizer@0.44.0": - version "0.44.0" - resolved "https://registry.npmjs.org/@opentelemetry/instrumentation-lru-memoizer/-/instrumentation-lru-memoizer-0.44.0.tgz#c22e770d950c165f80c657a9c790c9843baaa65b" - integrity sha512-Tn7emHAlvYDFik3vGU0mdwvWJDwtITtkJ+5eT2cUquct6nIs+H8M47sqMJkCpyPe5QIBJoTOHxmc6mj9lz6zDw== - dependencies: - "@opentelemetry/instrumentation" "^0.57.0" - -"@opentelemetry/instrumentation-mongodb@0.51.0": - version "0.51.0" - resolved "https://registry.npmjs.org/@opentelemetry/instrumentation-mongodb/-/instrumentation-mongodb-0.51.0.tgz#8a323c2fb4cb2c93bf95f1b1c0fcb30952d12a08" - integrity sha512-cMKASxCX4aFxesoj3WK8uoQ0YUrRvnfxaO72QWI2xLu5ZtgX/QvdGBlU3Ehdond5eb74c2s1cqRQUIptBnKz1g== - dependencies: - "@opentelemetry/instrumentation" "^0.57.0" - "@opentelemetry/semantic-conventions" "^1.27.0" - -"@opentelemetry/instrumentation-mongoose@0.46.0": - version "0.46.0" - resolved "https://registry.npmjs.org/@opentelemetry/instrumentation-mongoose/-/instrumentation-mongoose-0.46.0.tgz#c3a5f69e1a5b950b542cf84650fbbd3e31bd681e" - integrity sha512-mtVv6UeaaSaWTeZtLo4cx4P5/ING2obSqfWGItIFSunQBrYROfhuVe7wdIrFUs2RH1tn2YYpAJyMaRe/bnTTIQ== - dependencies: - "@opentelemetry/core" "^1.8.0" - "@opentelemetry/instrumentation" "^0.57.0" - "@opentelemetry/semantic-conventions" "^1.27.0" - -"@opentelemetry/instrumentation-mysql2@0.45.0": - version "0.45.0" - resolved "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql2/-/instrumentation-mysql2-0.45.0.tgz#95501759d470dbc7038670e91205e8ed601ec402" - integrity sha512-qLslv/EPuLj0IXFvcE3b0EqhWI8LKmrgRPIa4gUd8DllbBpqJAvLNJSv3cC6vWwovpbSI3bagNO/3Q2SuXv2xA== - dependencies: - "@opentelemetry/instrumentation" "^0.57.0" - "@opentelemetry/semantic-conventions" "^1.27.0" - "@opentelemetry/sql-common" "^0.40.1" - -"@opentelemetry/instrumentation-mysql@0.45.0": - version "0.45.0" - resolved "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql/-/instrumentation-mysql-0.45.0.tgz#e4df8bc709c0c8b0ff90bbef92fb36e92ebe0d19" - integrity sha512-tWWyymgwYcTwZ4t8/rLDfPYbOTF3oYB8SxnYMtIQ1zEf5uDm90Ku3i6U/vhaMyfHNlIHvDhvJh+qx5Nc4Z3Acg== - dependencies: - "@opentelemetry/instrumentation" "^0.57.0" - "@opentelemetry/semantic-conventions" "^1.27.0" - "@types/mysql" "2.15.26" - -"@opentelemetry/instrumentation-nestjs-core@0.44.0": - version "0.44.0" - resolved "https://registry.npmjs.org/@opentelemetry/instrumentation-nestjs-core/-/instrumentation-nestjs-core-0.44.0.tgz#d2a3631de3bed2b1c0a03afa79c08ae22bef8b6c" - integrity sha512-t16pQ7A4WYu1yyQJZhRKIfUNvl5PAaF2pEteLvgJb/BWdd1oNuU1rOYt4S825kMy+0q4ngiX281Ss9qiwHfxFQ== - dependencies: - "@opentelemetry/instrumentation" "^0.57.0" - "@opentelemetry/semantic-conventions" "^1.27.0" - -"@opentelemetry/instrumentation-pg@0.50.0": - version "0.50.0" - resolved "https://registry.npmjs.org/@opentelemetry/instrumentation-pg/-/instrumentation-pg-0.50.0.tgz#525ecf683c349529539a14f2be47164f4e3eb0f5" - integrity sha512-TtLxDdYZmBhFswm8UIsrDjh/HFBeDXd4BLmE8h2MxirNHewLJ0VS9UUddKKEverb5Sm2qFVjqRjcU+8Iw4FJ3w== - dependencies: - "@opentelemetry/core" "^1.26.0" - "@opentelemetry/instrumentation" "^0.57.0" - "@opentelemetry/semantic-conventions" "1.27.0" - "@opentelemetry/sql-common" "^0.40.1" - "@types/pg" "8.6.1" - "@types/pg-pool" "2.0.6" - -"@opentelemetry/instrumentation-redis-4@0.46.0": - version "0.46.0" - resolved "https://registry.npmjs.org/@opentelemetry/instrumentation-redis-4/-/instrumentation-redis-4-0.46.0.tgz#828704b8134f023730ac508bcf3a38ca4d5d697c" - integrity sha512-aTUWbzbFMFeRODn3720TZO0tsh/49T8H3h8vVnVKJ+yE36AeW38Uj/8zykQ/9nO8Vrtjr5yKuX3uMiG/W8FKNw== - dependencies: - "@opentelemetry/instrumentation" "^0.57.0" - "@opentelemetry/redis-common" "^0.36.2" - "@opentelemetry/semantic-conventions" "^1.27.0" - -"@opentelemetry/instrumentation-tedious@0.18.0": - version "0.18.0" - resolved "https://registry.npmjs.org/@opentelemetry/instrumentation-tedious/-/instrumentation-tedious-0.18.0.tgz#636745423db28e303b4e0289b8f69685cb36f807" - integrity sha512-9zhjDpUDOtD+coeADnYEJQ0IeLVCj7w/hqzIutdp5NqS1VqTAanaEfsEcSypyvYv5DX3YOsTUoF+nr2wDXPETA== - dependencies: - "@opentelemetry/instrumentation" "^0.57.0" - "@opentelemetry/semantic-conventions" "^1.27.0" - "@types/tedious" "^4.0.14" - -"@opentelemetry/instrumentation-undici@0.10.0": - version "0.10.0" - resolved "https://registry.npmjs.org/@opentelemetry/instrumentation-undici/-/instrumentation-undici-0.10.0.tgz#99cba213a6e9d47a82896b6c782c3f2d60e0edb5" - integrity sha512-vm+V255NGw9gaSsPD6CP0oGo8L55BffBc8KnxqsMuc6XiAD1L8SFNzsW0RHhxJFqy9CJaJh+YiJ5EHXuZ5rZBw== - dependencies: - "@opentelemetry/core" "^1.8.0" - "@opentelemetry/instrumentation" "^0.57.0" - -"@opentelemetry/instrumentation@0.57.1", "@opentelemetry/instrumentation@^0.57.0", "@opentelemetry/instrumentation@^0.57.1": - version "0.57.1" - resolved "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.57.1.tgz#5aea772be8783a35d69d643da46582f381ba1810" - integrity sha512-SgHEKXoVxOjc20ZYusPG3Fh+RLIZTSa4x8QtD3NfgAUDyqdFFS9W1F2ZVbZkqDCdyMcQG02Ok4duUGLHJXHgbA== - dependencies: - "@opentelemetry/api-logs" "0.57.1" - "@types/shimmer" "^1.2.0" - import-in-the-middle "^1.8.1" - require-in-the-middle "^7.1.1" - semver "^7.5.2" - shimmer "^1.2.1" - -"@opentelemetry/instrumentation@^0.49 || ^0.50 || ^0.51 || ^0.52.0 || ^0.53.0": - version "0.53.0" - resolved "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.53.0.tgz#e6369e4015eb5112468a4d45d38dcada7dad892d" - integrity sha512-DMwg0hy4wzf7K73JJtl95m/e0boSoWhH07rfvHvYzQtBD3Bmv0Wc1x733vyZBqmFm8OjJD0/pfiUg1W3JjFX0A== - dependencies: - "@opentelemetry/api-logs" "0.53.0" - "@types/shimmer" "^1.2.0" - import-in-the-middle "^1.8.1" - require-in-the-middle "^7.1.1" - semver "^7.5.2" - shimmer "^1.2.1" - -"@opentelemetry/instrumentation@^0.52.0 || ^0.53.0 || ^0.54.0 || ^0.55.0 || ^0.56.0": - version "0.56.0" - resolved "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.56.0.tgz#3330ce16d9235a548efa1019a4a7f01414edd44a" - integrity sha512-2KkGBKE+FPXU1F0zKww+stnlUxUTlBvLCiWdP63Z9sqXYeNI/ziNzsxAp4LAdUcTQmXjw1IWgvm5CAb/BHy99w== - dependencies: - "@opentelemetry/api-logs" "0.56.0" - "@types/shimmer" "^1.2.0" - import-in-the-middle "^1.8.1" - require-in-the-middle "^7.1.1" - semver "^7.5.2" - shimmer "^1.2.1" - -"@opentelemetry/redis-common@^0.36.2": - version "0.36.2" - resolved "https://registry.npmjs.org/@opentelemetry/redis-common/-/redis-common-0.36.2.tgz#906ac8e4d804d4109f3ebd5c224ac988276fdc47" - integrity sha512-faYX1N0gpLhej/6nyp6bgRjzAKXn5GOEMYY7YhciSfCoITAktLUtQ36d24QEWNA1/WA1y6qQunCe0OhHRkVl9g== - -"@opentelemetry/resources@1.30.1", "@opentelemetry/resources@^1.30.1": - version "1.30.1" - resolved "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.30.1.tgz#a4eae17ebd96947fdc7a64f931ca4b71e18ce964" - integrity sha512-5UxZqiAgLYGFjS4s9qm5mBVo433u+dSPUFWVWXmLAD4wB65oMCoXaJP1KJa9DIYYMeHu3z4BZcStG3LC593cWA== - dependencies: - "@opentelemetry/core" "1.30.1" - "@opentelemetry/semantic-conventions" "1.28.0" - -"@opentelemetry/sdk-trace-base@^1.22", "@opentelemetry/sdk-trace-base@^1.30.1": - version "1.30.1" - resolved "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.30.1.tgz#41a42234096dc98e8f454d24551fc80b816feb34" - integrity sha512-jVPgBbH1gCy2Lb7X0AVQ8XAfgg0pJ4nvl8/IiQA6nxOsPvS+0zMJaFSs2ltXe0J6C8dqjcnpyqINDJmU30+uOg== - dependencies: - "@opentelemetry/core" "1.30.1" - "@opentelemetry/resources" "1.30.1" - "@opentelemetry/semantic-conventions" "1.28.0" - -"@opentelemetry/semantic-conventions@1.27.0": - version "1.27.0" - resolved "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.27.0.tgz#1a857dcc95a5ab30122e04417148211e6f945e6c" - integrity sha512-sAay1RrB+ONOem0OZanAR1ZI/k7yDpnOQSQmTMuGImUQb2y8EbSaCJ94FQluM74xoU03vlb2d2U90hZluL6nQg== - -"@opentelemetry/semantic-conventions@1.28.0": - version "1.28.0" - resolved "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.28.0.tgz#337fb2bca0453d0726696e745f50064411f646d6" - integrity sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA== - -"@opentelemetry/semantic-conventions@^1.27.0", "@opentelemetry/semantic-conventions@^1.28.0": - version "1.30.0" - resolved "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.30.0.tgz#3a42c4c475482f2ec87c12aad98832dc0087dc9a" - integrity sha512-4VlGgo32k2EQ2wcCY3vEU28A0O13aOtHz3Xt2/2U5FAh9EfhD6t6DqL5Z6yAnRCntbTFDU4YfbpyzSlHNWycPw== - -"@opentelemetry/sql-common@^0.40.1": - version "0.40.1" - resolved "https://registry.npmjs.org/@opentelemetry/sql-common/-/sql-common-0.40.1.tgz#93fbc48d8017449f5b3c3274f2268a08af2b83b6" - integrity sha512-nSDlnHSqzC3pXn/wZEZVLuAuJ1MYMXPBwtv2qAbCa3847SaHItdE7SzUq/Jtb0KZmh1zfAbNi3AAMjztTT4Ugg== - dependencies: - "@opentelemetry/core" "^1.1.0" - "@pkgjs/parseargs@^0.11.0": version "0.11.0" resolved "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" @@ -2232,22 +1906,6 @@ resolved "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== -"@prisma/instrumentation@5.22.0": - version "5.22.0" - resolved "https://registry.npmjs.org/@prisma/instrumentation/-/instrumentation-5.22.0.tgz#c39941046e9886e17bdb47dbac45946c24d579aa" - integrity sha512-LxccF392NN37ISGxIurUljZSh1YWnphO34V5a0+T7FVQG2u9bhAXRTJpgmQ3483woVhkraQZFF7cbRrpbw/F4Q== - dependencies: - "@opentelemetry/api" "^1.8" - "@opentelemetry/instrumentation" "^0.49 || ^0.50 || ^0.51 || ^0.52.0 || ^0.53.0" - "@opentelemetry/sdk-trace-base" "^1.22" - -"@prisma/instrumentation@6.2.1": - version "6.2.1" - resolved "https://registry.npmjs.org/@prisma/instrumentation/-/instrumentation-6.2.1.tgz#261b885467d36759b7ca01d1b2ca4e1120bda886" - integrity sha512-QrcWRAwNHXX4nHXB+Q94nfm701gPQsR4zkaxYV6qCiENopRi8yYvXt6FNIvxbuwEiWW5Zid6DoWwIsBKJ/5r5w== - dependencies: - "@opentelemetry/instrumentation" "^0.52.0 || ^0.53.0 || ^0.54.0 || ^0.55.0 || ^0.56.0" - "@radix-ui/number@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@radix-ui/number/-/number-1.1.0.tgz#1e95610461a09cdf8bb05c152e76ca1278d5da46" @@ -2578,28 +2236,6 @@ resolved "https://registry.npmjs.org/@remirror/core-constants/-/core-constants-3.0.0.tgz#96fdb89d25c62e7b6a5d08caf0ce5114370e3b8f" integrity sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg== -"@rollup/plugin-commonjs@28.0.1": - version "28.0.1" - resolved "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.1.tgz#e2138e31cc0637676dc3d5cae7739131f7cd565e" - integrity sha512-+tNWdlWKbpB3WgBN7ijjYkq9X5uhjmcvyjEght4NmH5fAU++zfQzAJ6wumLS+dNcvwEZhKx2Z+skY8m7v0wGSA== - dependencies: - "@rollup/pluginutils" "^5.0.1" - commondir "^1.0.1" - estree-walker "^2.0.2" - fdir "^6.2.0" - is-reference "1.2.1" - magic-string "^0.30.3" - picomatch "^4.0.2" - -"@rollup/pluginutils@^5.0.1": - version "5.1.4" - resolved "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.4.tgz#bb94f1f9eaaac944da237767cdfee6c5b2262d4a" - integrity sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ== - dependencies: - "@types/estree" "^1.0.0" - estree-walker "^2.0.2" - picomatch "^4.0.2" - "@rollup/rollup-android-arm-eabi@4.35.0": version "4.35.0" resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.35.0.tgz#e1d7700735f7e8de561ef7d1fa0362082a180c43" @@ -2705,281 +2341,6 @@ resolved "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.10.5.tgz#3a1c12c959010a55c17d46b395ed3047b545c246" integrity sha512-kkKUDVlII2DQiKy7UstOR1ErJP8kUKAQ4oa+SQtM0K+lPdmmjj0YnnxBgtTVYH7mUKtbsxeFC9y0AmK7Yb78/A== -"@sentry-internal/browser-utils@8.54.0": - version "8.54.0" - resolved "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-8.54.0.tgz#2d68c7fa843db867ed98059faf1a750be3eca95a" - integrity sha512-DKWCqb4YQosKn6aD45fhKyzhkdG7N6goGFDeyTaJFREJDFVDXiNDsYZu30nJ6BxMM7uQIaARhPAC5BXfoED3pQ== - dependencies: - "@sentry/core" "8.54.0" - -"@sentry-internal/feedback@8.54.0": - version "8.54.0" - resolved "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-8.54.0.tgz#52c3a63aa5b520eca7acfa1376621e8441984126" - integrity sha512-nQqRacOXoElpE0L0ADxUUII0I3A94niqG9Z4Fmsw6057QvyrV/LvTiMQBop6r5qLjwMqK+T33iR4/NQI5RhsXQ== - dependencies: - "@sentry/core" "8.54.0" - -"@sentry-internal/replay-canvas@8.54.0": - version "8.54.0" - resolved "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-8.54.0.tgz#e57a3893db2bb0ea7ad9dc2a804bb035142fe3ba" - integrity sha512-K/On3OAUBeq/TV2n+1EvObKC+WMV9npVXpVyJqCCyn8HYMm8FUGzuxeajzm0mlW4wDTPCQor6mK9/IgOquUzCw== - dependencies: - "@sentry-internal/replay" "8.54.0" - "@sentry/core" "8.54.0" - -"@sentry-internal/replay@8.54.0": - version "8.54.0" - resolved "https://registry.npmjs.org/@sentry-internal/replay/-/replay-8.54.0.tgz#b92990a51ffbe8d92998ff8188db9e3a6f9d1e18" - integrity sha512-8xuBe06IaYIGJec53wUC12tY2q4z2Z0RPS2s1sLtbA00EvK1YDGuXp96IDD+HB9mnDMrQ/jW5f97g9TvPsPQUg== - dependencies: - "@sentry-internal/browser-utils" "8.54.0" - "@sentry/core" "8.54.0" - -"@sentry/babel-plugin-component-annotate@2.22.7": - version "2.22.7" - resolved "https://registry.npmjs.org/@sentry/babel-plugin-component-annotate/-/babel-plugin-component-annotate-2.22.7.tgz#604c7e33d48528a13477e7af597c4d5fca51b8bd" - integrity sha512-aa7XKgZMVl6l04NY+3X7BP7yvQ/s8scn8KzQfTLrGRarziTlMGrsCOBQtCNWXOPEbtxAIHpZ9dsrAn5EJSivOQ== - -"@sentry/browser@8.54.0": - version "8.54.0" - resolved "https://registry.npmjs.org/@sentry/browser/-/browser-8.54.0.tgz#5487075908aac564892e689e1b6d233fdb314f5b" - integrity sha512-BgUtvxFHin0fS0CmJVKTLXXZcke0Av729IVfi+2fJ4COX8HO7/HAP02RKaSQGmL2HmvWYTfNZ7529AnUtrM4Rg== - dependencies: - "@sentry-internal/browser-utils" "8.54.0" - "@sentry-internal/feedback" "8.54.0" - "@sentry-internal/replay" "8.54.0" - "@sentry-internal/replay-canvas" "8.54.0" - "@sentry/core" "8.54.0" - -"@sentry/bundler-plugin-core@2.22.7": - version "2.22.7" - resolved "https://registry.npmjs.org/@sentry/bundler-plugin-core/-/bundler-plugin-core-2.22.7.tgz#28204a224cd1fef58d157e5beeb2493947a9bc35" - integrity sha512-ouQh5sqcB8vsJ8yTTe0rf+iaUkwmeUlGNFi35IkCFUQlWJ22qS6OfvNjOqFI19e6eGUXks0c/2ieFC4+9wJ+1g== - dependencies: - "@babel/core" "^7.18.5" - "@sentry/babel-plugin-component-annotate" "2.22.7" - "@sentry/cli" "2.39.1" - dotenv "^16.3.1" - find-up "^5.0.0" - glob "^9.3.2" - magic-string "0.30.8" - unplugin "1.0.1" - -"@sentry/cli-darwin@2.39.1": - version "2.39.1" - resolved "https://registry.npmjs.org/@sentry/cli-darwin/-/cli-darwin-2.39.1.tgz#75c338a53834b4cf72f57599f4c72ffb36cf0781" - integrity sha512-kiNGNSAkg46LNGatfNH5tfsmI/kCAaPA62KQuFZloZiemTNzhy9/6NJP8HZ/GxGs8GDMxic6wNrV9CkVEgFLJQ== - -"@sentry/cli-linux-arm64@2.39.1": - version "2.39.1" - resolved "https://registry.npmjs.org/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.39.1.tgz#27db44700c33fcb1e8966257020b43f8494373e6" - integrity sha512-5VbVJDatolDrWOgaffsEM7znjs0cR8bHt9Bq0mStM3tBolgAeSDHE89NgHggfZR+DJ2VWOy4vgCwkObrUD6NQw== - -"@sentry/cli-linux-arm@2.39.1": - version "2.39.1" - resolved "https://registry.npmjs.org/@sentry/cli-linux-arm/-/cli-linux-arm-2.39.1.tgz#451683fa9a5a60b1359d104ec71334ed16f4b63c" - integrity sha512-DkENbxyRxUrfLnJLXTA4s5UL/GoctU5Cm4ER1eB7XN7p9WsamFJd/yf2KpltkjEyiTuplv0yAbdjl1KX3vKmEQ== - -"@sentry/cli-linux-i686@2.39.1": - version "2.39.1" - resolved "https://registry.npmjs.org/@sentry/cli-linux-i686/-/cli-linux-i686-2.39.1.tgz#9965a81f97a94e8b6d1d15589e43fee158e35201" - integrity sha512-pXWVoKXCRrY7N8vc9H7mETiV9ZCz+zSnX65JQCzZxgYrayQPJTc+NPRnZTdYdk5RlAupXaFicBI2GwOCRqVRkg== - -"@sentry/cli-linux-x64@2.39.1": - version "2.39.1" - resolved "https://registry.npmjs.org/@sentry/cli-linux-x64/-/cli-linux-x64-2.39.1.tgz#31fe008b02f92769543dc9919e2a5cbc4cda7889" - integrity sha512-IwayNZy+it7FWG4M9LayyUmG1a/8kT9+/IEm67sT5+7dkMIMcpmHDqL8rWcPojOXuTKaOBBjkVdNMBTXy0mXlA== - -"@sentry/cli-win32-i686@2.39.1": - version "2.39.1" - resolved "https://registry.npmjs.org/@sentry/cli-win32-i686/-/cli-win32-i686-2.39.1.tgz#609e8790c49414011445e397130560c777850b35" - integrity sha512-NglnNoqHSmE+Dz/wHeIVRnV2bLMx7tIn3IQ8vXGO5HWA2f8zYJGktbkLq1Lg23PaQmeZLPGlja3gBQfZYSG10Q== - -"@sentry/cli-win32-x64@2.39.1": - version "2.39.1" - resolved "https://registry.npmjs.org/@sentry/cli-win32-x64/-/cli-win32-x64-2.39.1.tgz#1a874a5570c6d162b35d9d001c96e5389d07d2cb" - integrity sha512-xv0R2CMf/X1Fte3cMWie1NXuHmUyQPDBfCyIt6k6RPFPxAYUgcqgMPznYwVMwWEA1W43PaOkSn3d8ZylsDaETw== - -"@sentry/cli@2.39.1": - version "2.39.1" - resolved "https://registry.npmjs.org/@sentry/cli/-/cli-2.39.1.tgz#916bb5b7567ccf7fdf94ef6cf8a2b9ab78370d29" - integrity sha512-JIb3e9vh0+OmQ0KxmexMXg9oZsR/G7HMwxt5BUIKAXZ9m17Xll4ETXTRnRUBT3sf7EpNGAmlQk1xEmVN9pYZYQ== - dependencies: - https-proxy-agent "^5.0.0" - node-fetch "^2.6.7" - progress "^2.0.3" - proxy-from-env "^1.1.0" - which "^2.0.2" - optionalDependencies: - "@sentry/cli-darwin" "2.39.1" - "@sentry/cli-linux-arm" "2.39.1" - "@sentry/cli-linux-arm64" "2.39.1" - "@sentry/cli-linux-i686" "2.39.1" - "@sentry/cli-linux-x64" "2.39.1" - "@sentry/cli-win32-i686" "2.39.1" - "@sentry/cli-win32-x64" "2.39.1" - -"@sentry/core@8.54.0": - version "8.54.0" - resolved "https://registry.npmjs.org/@sentry/core/-/core-8.54.0.tgz#a2ebec965cadcb6de89e116689feeef79d5862a6" - integrity sha512-03bWf+D1j28unOocY/5FDB6bUHtYlm6m6ollVejhg45ZmK9iPjdtxNWbrLsjT1WRym0Tjzowu+A3p+eebYEv0Q== - -"@sentry/core@9.0.1": - version "9.0.1" - resolved "https://registry.npmjs.org/@sentry/core/-/core-9.0.1.tgz#da0207f7a4f74eb4af4ba26ad4244056968b3e41" - integrity sha512-RQ3B3NfF+BdmQz1c+vj4OBO+kxvxSsYMcmCDxSEZ7YrS/6Er1kMy0fwfxmdZJMdM1LlzXmO0XWF2g1IO9CzKyQ== - -"@sentry/nextjs@^8.54.0": - version "8.54.0" - resolved "https://registry.npmjs.org/@sentry/nextjs/-/nextjs-8.54.0.tgz#53e8c8620de95c7f3ac848b21a3e5021a11ba57d" - integrity sha512-TiNrT98+3AdeX/CMM8uhx0yOt/ITkx8EOJ8d1FjiRZdrR/UcY1dpq1S/m3h3T2NkwTQ9Os1A/GpDJz7LHPoL/w== - dependencies: - "@opentelemetry/api" "^1.9.0" - "@opentelemetry/semantic-conventions" "^1.28.0" - "@rollup/plugin-commonjs" "28.0.1" - "@sentry-internal/browser-utils" "8.54.0" - "@sentry/core" "8.54.0" - "@sentry/node" "8.54.0" - "@sentry/opentelemetry" "8.54.0" - "@sentry/react" "8.54.0" - "@sentry/vercel-edge" "8.54.0" - "@sentry/webpack-plugin" "2.22.7" - chalk "3.0.0" - resolve "1.22.8" - rollup "3.29.5" - stacktrace-parser "^0.1.10" - -"@sentry/node@8.54.0": - version "8.54.0" - resolved "https://registry.npmjs.org/@sentry/node/-/node-8.54.0.tgz#4ba175e320c36263f75a88670f4a5507754cf8f0" - integrity sha512-z9ak481OtCw3V4l55ke/9FOiorF2J/niO1J1gvGefXpgFucpw0M3qqEFjB5cpg9HoZM8Y1WtA1OFusfTAnvcXg== - dependencies: - "@opentelemetry/api" "^1.9.0" - "@opentelemetry/context-async-hooks" "^1.30.1" - "@opentelemetry/core" "^1.30.1" - "@opentelemetry/instrumentation" "^0.57.1" - "@opentelemetry/instrumentation-amqplib" "^0.46.0" - "@opentelemetry/instrumentation-connect" "0.43.0" - "@opentelemetry/instrumentation-dataloader" "0.16.0" - "@opentelemetry/instrumentation-express" "0.47.0" - "@opentelemetry/instrumentation-fastify" "0.44.1" - "@opentelemetry/instrumentation-fs" "0.19.0" - "@opentelemetry/instrumentation-generic-pool" "0.43.0" - "@opentelemetry/instrumentation-graphql" "0.47.0" - "@opentelemetry/instrumentation-hapi" "0.45.1" - "@opentelemetry/instrumentation-http" "0.57.1" - "@opentelemetry/instrumentation-ioredis" "0.47.0" - "@opentelemetry/instrumentation-kafkajs" "0.7.0" - "@opentelemetry/instrumentation-knex" "0.44.0" - "@opentelemetry/instrumentation-koa" "0.47.0" - "@opentelemetry/instrumentation-lru-memoizer" "0.44.0" - "@opentelemetry/instrumentation-mongodb" "0.51.0" - "@opentelemetry/instrumentation-mongoose" "0.46.0" - "@opentelemetry/instrumentation-mysql" "0.45.0" - "@opentelemetry/instrumentation-mysql2" "0.45.0" - "@opentelemetry/instrumentation-nestjs-core" "0.44.0" - "@opentelemetry/instrumentation-pg" "0.50.0" - "@opentelemetry/instrumentation-redis-4" "0.46.0" - "@opentelemetry/instrumentation-tedious" "0.18.0" - "@opentelemetry/instrumentation-undici" "0.10.0" - "@opentelemetry/resources" "^1.30.1" - "@opentelemetry/sdk-trace-base" "^1.30.1" - "@opentelemetry/semantic-conventions" "^1.28.0" - "@prisma/instrumentation" "5.22.0" - "@sentry/core" "8.54.0" - "@sentry/opentelemetry" "8.54.0" - import-in-the-middle "^1.11.2" - -"@sentry/node@^9.0.1": - version "9.0.1" - resolved "https://registry.npmjs.org/@sentry/node/-/node-9.0.1.tgz#6f5bba1adbc2b735b52884706622a5bdab5f5423" - integrity sha512-ofc0dvOoFEIVmV5bcNdvLLBzPvjF1L04MFIVPIUk9+6hm/7sqUdhQe84h56244/u5ILDMPsHxFX34iXGabjqYw== - dependencies: - "@opentelemetry/api" "^1.9.0" - "@opentelemetry/context-async-hooks" "^1.30.1" - "@opentelemetry/core" "^1.30.1" - "@opentelemetry/instrumentation" "^0.57.1" - "@opentelemetry/instrumentation-amqplib" "^0.46.0" - "@opentelemetry/instrumentation-connect" "0.43.0" - "@opentelemetry/instrumentation-dataloader" "0.16.0" - "@opentelemetry/instrumentation-express" "0.47.0" - "@opentelemetry/instrumentation-fastify" "0.44.1" - "@opentelemetry/instrumentation-fs" "0.19.0" - "@opentelemetry/instrumentation-generic-pool" "0.43.0" - "@opentelemetry/instrumentation-graphql" "0.47.0" - "@opentelemetry/instrumentation-hapi" "0.45.1" - "@opentelemetry/instrumentation-http" "0.57.1" - "@opentelemetry/instrumentation-ioredis" "0.47.0" - "@opentelemetry/instrumentation-kafkajs" "0.7.0" - "@opentelemetry/instrumentation-knex" "0.44.0" - "@opentelemetry/instrumentation-koa" "0.47.0" - "@opentelemetry/instrumentation-lru-memoizer" "0.44.0" - "@opentelemetry/instrumentation-mongodb" "0.51.0" - "@opentelemetry/instrumentation-mongoose" "0.46.0" - "@opentelemetry/instrumentation-mysql" "0.45.0" - "@opentelemetry/instrumentation-mysql2" "0.45.0" - "@opentelemetry/instrumentation-pg" "0.50.0" - "@opentelemetry/instrumentation-redis-4" "0.46.0" - "@opentelemetry/instrumentation-tedious" "0.18.0" - "@opentelemetry/instrumentation-undici" "0.10.0" - "@opentelemetry/resources" "^1.30.1" - "@opentelemetry/sdk-trace-base" "^1.30.1" - "@opentelemetry/semantic-conventions" "^1.28.0" - "@prisma/instrumentation" "6.2.1" - "@sentry/core" "9.0.1" - "@sentry/opentelemetry" "9.0.1" - import-in-the-middle "^1.12.0" - -"@sentry/opentelemetry@8.54.0": - version "8.54.0" - resolved "https://registry.npmjs.org/@sentry/opentelemetry/-/opentelemetry-8.54.0.tgz#0fd2c732b6f83ec7a6eb27defbb535784657669d" - integrity sha512-Tkmd8bmXMx0PKZF53ywk/FfvDrphX8NdPH5N53HxyMvGxSf2trZkTuOSFJg6zKibyGYO6+PUeGO3g2WJKUxwGA== - dependencies: - "@sentry/core" "8.54.0" - -"@sentry/opentelemetry@9.0.1": - version "9.0.1" - resolved "https://registry.npmjs.org/@sentry/opentelemetry/-/opentelemetry-9.0.1.tgz#62b056e99129f09f40b83cc74b1a8ccf5e1fb093" - integrity sha512-kWLnCnSGVMBhM6e33u7/NTHOtHHtZZuVV8bUa2Pum6aBAHVcF4/jJI9dFTdNhy93OYsyA3Ip48+Y2G2TUVE5ug== - dependencies: - "@sentry/core" "9.0.1" - -"@sentry/profiling-node@^8.28.0": - version "8.54.0" - resolved "https://registry.npmjs.org/@sentry/profiling-node/-/profiling-node-8.54.0.tgz#c20f3061dbf39aaae74006b3a75888f4f6a4c1a9" - integrity sha512-E2WKaEmQunu1PiUX1HGYVwEw18b4YDBLINeOTwJRqApGSNwc/EggYZzhXSPWjsPh7D5ZRGBr0p1bKQwkNMvtRg== - dependencies: - "@sentry/core" "8.54.0" - "@sentry/node" "8.54.0" - detect-libc "^2.0.2" - node-abi "^3.61.0" - -"@sentry/react@8.54.0": - version "8.54.0" - resolved "https://registry.npmjs.org/@sentry/react/-/react-8.54.0.tgz#16cec103b5d5697bdfebacf6e2d35f19699b3ab3" - integrity sha512-42T/fp8snYN19Fy/2P0Mwotu4gcdy+1Lx+uYCNcYP1o7wNGigJ7qb27sW7W34GyCCHjoCCfQgeOqDQsyY8LC9w== - dependencies: - "@sentry/browser" "8.54.0" - "@sentry/core" "8.54.0" - hoist-non-react-statics "^3.3.2" - -"@sentry/vercel-edge@8.54.0": - version "8.54.0" - resolved "https://registry.npmjs.org/@sentry/vercel-edge/-/vercel-edge-8.54.0.tgz#aee82fa4970ed4de8f85d7402ad583b83bf108a6" - integrity sha512-1oct5P0iTPJOBCzNKZZ+H1ja7b1izZNCObBRhxscOsDHM4fUFwCP8MfjxGIphzj9XLibzo+4dsn6JtkxIdn5GQ== - dependencies: - "@opentelemetry/api" "^1.9.0" - "@sentry/core" "8.54.0" - -"@sentry/webpack-plugin@2.22.7": - version "2.22.7" - resolved "https://registry.npmjs.org/@sentry/webpack-plugin/-/webpack-plugin-2.22.7.tgz#992c6c782c736f22e72eb318745e28cc24aabad7" - integrity sha512-j5h5LZHWDlm/FQCCmEghQ9FzYXwfZdlOf3FE/X6rK6lrtx0JCAkq+uhMSasoyP4XYKL4P4vRS6WFSos4jxf/UA== - dependencies: - "@sentry/bundler-plugin-core" "2.22.7" - unplugin "1.0.1" - uuid "^9.0.0" - "@sindresorhus/merge-streams@^2.1.0": version "2.3.0" resolved "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz#719df7fb41766bc143369eaa0dd56d8dc87c9958" @@ -3815,13 +3176,6 @@ dependencies: "@types/node" "*" -"@types/connect@3.4.36": - version "3.4.36" - resolved "https://registry.npmjs.org/@types/connect/-/connect-3.4.36.tgz#e511558c15a39cb29bd5357eebb57bd1459cd1ab" - integrity sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w== - dependencies: - "@types/node" "*" - "@types/cors@^2.8.17": version "2.8.17" resolved "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz#5d718a5e494a8166f569d986794e49c48b216b2b" @@ -4113,13 +3467,6 @@ resolved "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz#052aa67a48eccc4309d7f0191b7e41434b90bb78" integrity sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA== -"@types/mysql@2.15.26": - version "2.15.26" - resolved "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.26.tgz#f0de1484b9e2354d587e7d2bd17a873cc8300836" - integrity sha512-DSLCOXhkvfS5WNNPbfn2KdICAmk8lLc+/PNvnPnF7gOdMZCxopXduqv0OQ13y/yA/zXTSikZZqVgybUxOEg6YQ== - dependencies: - "@types/node" "*" - "@types/node@*", "@types/node@^22.5.4": version "22.13.1" resolved "https://registry.npmjs.org/@types/node/-/node-22.13.1.tgz#a2a3fefbdeb7ba6b89f40371842162fac0934f33" @@ -4159,31 +3506,6 @@ resolved "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz#5950e50960793055845e956c427fc2b0d70c5239" integrity sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw== -"@types/pg-pool@2.0.6": - version "2.0.6" - resolved "https://registry.npmjs.org/@types/pg-pool/-/pg-pool-2.0.6.tgz#1376d9dc5aec4bb2ec67ce28d7e9858227403c77" - integrity sha512-TaAUE5rq2VQYxab5Ts7WZhKNmuN78Q6PiFonTDdpbx8a1H0M1vhy3rhiMjl+e2iHmogyMw7jZF4FrE6eJUy5HQ== - dependencies: - "@types/pg" "*" - -"@types/pg@*": - version "8.11.11" - resolved "https://registry.npmjs.org/@types/pg/-/pg-8.11.11.tgz#3bdce0580e521a62a62339a53d110458d9eae6df" - integrity sha512-kGT1qKM8wJQ5qlawUrEkXgvMSXoV213KfMGXcwfDwUIfUHXqXYXOfS1nE1LINRJVVVx5wCm70XnFlMHaIcQAfw== - dependencies: - "@types/node" "*" - pg-protocol "*" - pg-types "^4.0.1" - -"@types/pg@8.6.1": - version "8.6.1" - resolved "https://registry.npmjs.org/@types/pg/-/pg-8.6.1.tgz#099450b8dc977e8197a44f5229cedef95c8747f9" - integrity sha512-1Kc4oAGzAl7uqUStZCDvaLFqZrW9qWSjXOmBfdgyBP5La7Us6Mg4GBvRlSoaZMhQF/zSj1C8CtKMBkoiT8eL8w== - dependencies: - "@types/node" "*" - pg-protocol "*" - pg-types "^2.2.0" - "@types/prop-types@*", "@types/prop-types@^15.0.0", "@types/prop-types@^15.7.12", "@types/prop-types@^15.7.2": version "15.7.14" resolved "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz#1433419d73b2a7ebfc6918dcefd2ec0d5cd698f2" @@ -4271,18 +3593,6 @@ "@types/node" "*" "@types/send" "*" -"@types/shimmer@^1.2.0": - version "1.2.0" - resolved "https://registry.npmjs.org/@types/shimmer/-/shimmer-1.2.0.tgz#9b706af96fa06416828842397a70dfbbf1c14ded" - integrity sha512-UE7oxhQLLd9gub6JKIAhDq06T0F6FnztwMNRvYgjeQSBeMc1ZG/tA47EwfduvkuQS8apbkM/lpLpWsaCeYsXVg== - -"@types/tedious@^4.0.14": - version "4.0.14" - resolved "https://registry.npmjs.org/@types/tedious/-/tedious-4.0.14.tgz#868118e7a67808258c05158e9cad89ca58a2aec1" - integrity sha512-KHPsfX/FoVbUGbyYvk1q9MMQHLPeRZhRJZdO45Q4YjvFkv4hMNghCWTvy7rdKessBsmtz4euWCWAB6/tVpI1Iw== - dependencies: - "@types/node" "*" - "@types/triple-beam@^1.3.2": version "1.3.5" resolved "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz#74fef9ffbaa198eb8b588be029f38b00299caa2c" @@ -4691,11 +4001,6 @@ accepts@~1.3.8: mime-types "~2.1.34" negotiator "0.6.3" -acorn-import-attributes@^1.9.5: - version "1.9.5" - resolved "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz#7eb1557b1ba05ef18b5ed0ec67591bfab04688ef" - integrity sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ== - acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" @@ -4708,18 +4013,11 @@ acorn-walk@^8.1.1: dependencies: acorn "^8.11.0" -acorn@^8.11.0, acorn@^8.14.0, acorn@^8.4.1, acorn@^8.8.1, acorn@^8.8.2, acorn@^8.9.0: +acorn@^8.11.0, acorn@^8.14.0, acorn@^8.4.1, acorn@^8.8.2, acorn@^8.9.0: version "8.14.0" resolved "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== -agent-base@6: - version "6.0.2" - resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" - integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== - dependencies: - debug "4" - agent-base@^7.1.0, agent-base@^7.1.2: version "7.1.3" resolved "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz#29435eb821bc4194633a5b89e5bc4703bafc25a1" @@ -5378,7 +4676,7 @@ chai@^5.1.1: loupe "^3.1.0" pathval "^2.0.0" -chalk@3.0.0, chalk@^3.0.0: +chalk@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== @@ -5459,7 +4757,7 @@ chrome-trace-event@^1.0.2: resolved "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz#05bffd7ff928465093314708c93bdfa9bd1f0f5b" integrity sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ== -cjs-module-lexer@^1.2.2, cjs-module-lexer@^1.2.3: +cjs-module-lexer@^1.2.3: version "1.4.3" resolved "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz#0f79731eb8cfe1ec72acd4066efac9d61991b00d" integrity sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q== @@ -6040,7 +5338,7 @@ debug@2.6.9: dependencies: ms "2.0.0" -debug@4, debug@^4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5, debug@^4.3.7, debug@^4.4.0: +debug@4, debug@^4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.7, debug@^4.4.0: version "4.4.0" resolved "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== @@ -6900,11 +6198,6 @@ estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== -estree-walker@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" - integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== - estree-walker@^3.0.3: version "3.0.3" resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz#67c3e549ec402a487b4fc193d1953a524752340d" @@ -7071,7 +6364,7 @@ fault@^2.0.0: dependencies: format "^0.2.0" -fdir@^6.2.0, fdir@^6.4.3: +fdir@^6.4.3: version "6.4.3" resolved "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz#011cdacf837eca9b811c89dbb902df714273db72" integrity sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw== @@ -7279,11 +6572,6 @@ format@^0.2.0: resolved "https://registry.npmjs.org/format/-/format-0.2.2.tgz#d6170107e9efdc4ed30c9dc39016df942b5cb58b" integrity sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww== -forwarded-parse@2.1.2: - version "2.1.2" - resolved "https://registry.npmjs.org/forwarded-parse/-/forwarded-parse-2.1.2.tgz#08511eddaaa2ddfd56ba11138eee7df117a09325" - integrity sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw== - forwarded@0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" @@ -7488,7 +6776,7 @@ glob@^7.1.3, glob@^7.2.0: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^9.3.2, glob@^9.3.3: +glob@^9.3.3: version "9.3.5" resolved "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz#ca2ed8ca452781a3009685607fdf025a899dfe21" integrity sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q== @@ -7648,7 +6936,7 @@ highlight.js@~11.8.0: resolved "https://registry.npmjs.org/highlight.js/-/highlight.js-11.8.0.tgz#966518ea83257bae2e7c9a48596231856555bb65" integrity sha512-MedQhoqVdr0U6SSnWPzfiadUcDHfN/Wzq25AkXiQv9oiOO/sG0S7XkvpFIqWBl9Yq1UYyYOOVORs5UW2XlPyzg== -hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2: +hoist-non-react-statics@^3.3.1: version "3.3.2" resolved "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== @@ -7732,14 +7020,6 @@ http-proxy-agent@^7.0.2: agent-base "^7.1.0" debug "^4.3.4" -https-proxy-agent@^5.0.0: - version "5.0.1" - resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" - integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== - dependencies: - agent-base "6" - debug "4" - https-proxy-agent@^7.0.6: version "7.0.6" resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz#da8dfeac7da130b05c2ba4b59c9b6cd66611a6b9" @@ -7807,16 +7087,6 @@ import-fresh@^3.2.1: parent-module "^1.0.0" resolve-from "^4.0.0" -import-in-the-middle@^1.11.2, import-in-the-middle@^1.12.0, import-in-the-middle@^1.8.1: - version "1.13.0" - resolved "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.13.0.tgz#e592583c3f53ff29c6079c0af31feab592ac6b2a" - integrity sha512-YG86SYDtrL/Yu8JgfWb7kjQ0myLeT1whw6fs/ZHFkXFcbk9zJU9lOCsSJHpvaPumU11nN3US7NW6x1YTk+HrUA== - dependencies: - acorn "^8.14.0" - acorn-import-attributes "^1.9.5" - cjs-module-lexer "^1.2.2" - module-details-from-path "^1.0.3" - imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -8089,13 +7359,6 @@ is-potential-custom-element-name@^1.0.1: resolved "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== -is-reference@1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7" - integrity sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ== - dependencies: - "@types/estree" "*" - is-regex@^1.1.4, is-regex@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz#76d70a3ed10ef9be48eb577887d74205bf0cad22" @@ -8594,14 +7857,7 @@ lz-string@^1.5.0: resolved "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz#c1ab50f77887b712621201ba9fd4e3a6ed099941" integrity sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ== -magic-string@0.30.8: - version "0.30.8" - resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz#14e8624246d2bedba70d5462aa99ac9681844613" - integrity sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ== - dependencies: - "@jridgewell/sourcemap-codec" "^1.4.15" - -magic-string@^0.30.3, magic-string@^0.30.5: +magic-string@^0.30.5: version "0.30.17" resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz#450a449673d2460e5bbcfba9a61916a1714c7453" integrity sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA== @@ -9069,11 +8325,6 @@ mobx@^6.10.0, mobx@^6.12.0: resolved "https://registry.npmjs.org/mobx/-/mobx-6.13.6.tgz#3b80895c7c9df456efc86ae0b6983ccea1da6cc6" integrity sha512-r19KNV0uBN4b+ER8Z0gA4y+MzDYIQ2SvOmn3fUrqPnWXdQfakd9yfbPBDBF/p5I+bd3N5Rk1fHONIvMay+bJGA== -module-details-from-path@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.3.tgz#114c949673e2a8a35e9d35788527aa37b679da2b" - integrity sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A== - moment@^2.29.1: version "2.30.1" resolved "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae" @@ -9185,7 +8436,7 @@ no-case@^3.0.4: lower-case "^2.0.2" tslib "^2.0.3" -node-abi@^3.3.0, node-abi@^3.61.0: +node-abi@^3.3.0: version "3.74.0" resolved "https://registry.npmjs.org/node-abi/-/node-abi-3.74.0.tgz#5bfb4424264eaeb91432d2adb9da23c63a301ed0" integrity sha512-c5XK0MjkGBrQPGYG24GBADZud0NCbznxNx0ZkS+ebUTrmV1qTDxPxSL8zEAPURXSbLRWVexxmP4986BziahL5w== @@ -9202,7 +8453,7 @@ node-addon-api@^6.1.0: resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz#ac8470034e58e67d0c6f1204a18ae6995d9c0d76" integrity sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA== -node-fetch@^2.6.7, node-fetch@^2.7.0: +node-fetch@^2.7.0: version "2.7.0" resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== @@ -9360,11 +8611,6 @@ objectorarray@^1.0.5: resolved "https://registry.npmjs.org/objectorarray/-/objectorarray-1.0.5.tgz#2c05248bbefabd8f43ad13b41085951aac5e68a5" integrity sha512-eJJDYkhJFFbBBAxeh8xW+weHlkI28n2ZdQV/J/DNfWfSKlGEf2xcfAbZTv3riEXHAhL9SVOTs2pRmXiSTf78xg== -obuf@~1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" - integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== - on-exit-leak-free@^2.1.0: version "2.1.2" resolved "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz#fed195c9ebddb7d9e4c3842f93f281ac8dadd3b8" @@ -9623,45 +8869,6 @@ pathval@^2.0.0: resolved "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz#7e2550b422601d4f6b8e26f1301bc8f15a741a25" integrity sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA== -pg-int8@1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" - integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== - -pg-numeric@1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/pg-numeric/-/pg-numeric-1.0.2.tgz#816d9a44026086ae8ae74839acd6a09b0636aa3a" - integrity sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw== - -pg-protocol@*: - version "1.7.1" - resolved "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.7.1.tgz#aad61a6f927b51e89dcf721408b76c0e536d43dc" - integrity sha512-gjTHWGYWsEgy9MsY0Gp6ZJxV24IjDqdpTW7Eh0x+WfJLFsm/TJx1MzL6T0D88mBvkpxotCQ6TwW6N+Kko7lhgQ== - -pg-types@^2.2.0: - version "2.2.0" - resolved "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3" - integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA== - dependencies: - pg-int8 "1.0.1" - postgres-array "~2.0.0" - postgres-bytea "~1.0.0" - postgres-date "~1.0.4" - postgres-interval "^1.1.0" - -pg-types@^4.0.1: - version "4.0.2" - resolved "https://registry.npmjs.org/pg-types/-/pg-types-4.0.2.tgz#399209a57c326f162461faa870145bb0f918b76d" - integrity sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng== - dependencies: - pg-int8 "1.0.1" - pg-numeric "1.0.2" - postgres-array "~3.0.1" - postgres-bytea "~3.0.0" - postgres-date "~2.1.0" - postgres-interval "^3.0.0" - postgres-range "^1.1.1" - picocolors@^1.0.0, picocolors@^1.0.1, picocolors@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" @@ -9929,55 +9136,6 @@ postcss@^8.4.33, postcss@^8.4.38, postcss@^8.4.47: picocolors "^1.1.1" source-map-js "^1.2.1" -postgres-array@~2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" - integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA== - -postgres-array@~3.0.1: - version "3.0.2" - resolved "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.2.tgz#68d6182cb0f7f152a7e60dc6a6889ed74b0a5f98" - integrity sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog== - -postgres-bytea@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35" - integrity sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w== - -postgres-bytea@~3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-3.0.0.tgz#9048dc461ac7ba70a6a42d109221619ecd1cb089" - integrity sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw== - dependencies: - obuf "~1.1.2" - -postgres-date@~1.0.4: - version "1.0.7" - resolved "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8" - integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q== - -postgres-date@~2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/postgres-date/-/postgres-date-2.1.0.tgz#b85d3c1fb6fb3c6c8db1e9942a13a3bf625189d0" - integrity sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA== - -postgres-interval@^1.1.0: - version "1.2.0" - resolved "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695" - integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ== - dependencies: - xtend "^4.0.0" - -postgres-interval@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/postgres-interval/-/postgres-interval-3.0.0.tgz#baf7a8b3ebab19b7f38f07566c7aab0962f0c86a" - integrity sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw== - -postgres-range@^1.1.1: - version "1.1.4" - resolved "https://registry.npmjs.org/postgres-range/-/postgres-range-1.1.4.tgz#a59c5f9520909bcec5e63e8cf913a92e4c952863" - integrity sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w== - posthog-js@^1.131.3: version "1.217.1" resolved "https://registry.npmjs.org/posthog-js/-/posthog-js-1.217.1.tgz#f8919cc05ed4851896a47a5a0c949e7ae91731c4" @@ -10068,11 +9226,6 @@ process@^0.11.10: resolved "https://registry.npmjs.org/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== -progress@^2.0.3: - version "2.0.3" - resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" @@ -10818,15 +9971,6 @@ require-from-string@^2.0.2: resolved "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== -require-in-the-middle@^7.1.1: - version "7.5.1" - resolved "https://registry.npmjs.org/require-in-the-middle/-/require-in-the-middle-7.5.1.tgz#9b995014ece7f62d734dcaf822064240d125a659" - integrity sha512-fgZEz/t3FDrU9o7EhI+iNNq1pNNpJImOvX72HUd6RoFiw8MaKd8/gR5tLuc8A0G0e55LMbP6ImjnmXY6zrTmjw== - dependencies: - debug "^4.3.5" - module-details-from-path "^1.0.3" - resolve "^1.22.8" - reselect@^4.1.7: version "4.1.8" resolved "https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz#3f5dc671ea168dccdeb3e141236f69f02eaec524" @@ -10847,15 +9991,6 @@ resolve-pkg-maps@^1.0.0: resolved "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== -resolve@1.22.8: - version "1.22.8" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" - integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== - dependencies: - is-core-module "^2.13.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - resolve@^1.1.7, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.22.1, resolve@^1.22.4, resolve@^1.22.8: version "1.22.10" resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39" @@ -10896,13 +10031,6 @@ robust-predicates@^3.0.2: resolved "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz#d5b28528c4824d20fc48df1928d41d9efa1ad771" integrity sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg== -rollup@3.29.5: - version "3.29.5" - resolved "https://registry.npmjs.org/rollup/-/rollup-3.29.5.tgz#8a2e477a758b520fb78daf04bca4c522c1da8a54" - integrity sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w== - optionalDependencies: - fsevents "~2.3.2" - rollup@^4.34.8: version "4.35.0" resolved "https://registry.npmjs.org/rollup/-/rollup-4.35.0.tgz#76c95dba17a579df4c00c3955aed32aa5d4dc66d" @@ -11078,7 +10206,7 @@ semver@^6.0.0, semver@^6.3.1: resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.3.5, semver@^7.3.7, semver@^7.5.2, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.6.2, semver@^7.6.3: +semver@^7.3.5, semver@^7.3.7, semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.6.2, semver@^7.6.3: version "7.7.1" resolved "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz#abd5098d82b18c6c81f6074ff2647fd3e7220c9f" integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA== @@ -11195,11 +10323,6 @@ shell-quote@^1.8.1: resolved "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz#d2d83e057959d53ec261311e9e9b8f51dcb2934a" integrity sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA== -shimmer@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" - integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw== - side-channel-list@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad" @@ -11365,13 +10488,6 @@ stack-trace@0.0.x: resolved "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" integrity sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg== -stacktrace-parser@^0.1.10: - version "0.1.10" - resolved "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz#29fb0cae4e0d0b85155879402857a1639eb6051a" - integrity sha512-KJP1OCML99+8fhOHxwwzyWrlUuVX5GQ0ZpJTd1DFXhdkrvg1szxfHhawXUZ3g9TkXORQd4/WG68jMlQZ2p8wlg== - dependencies: - type-fest "^0.7.1" - standard-as-callback@^2.1.0: version "2.1.0" resolved "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45" @@ -12090,11 +11206,6 @@ type-fest@^0.20.2: resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== -type-fest@^0.7.1: - version "0.7.1" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz#8dda65feaf03ed78f0a3f9678f1869147f7c5c48" - integrity sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg== - type-fest@^2.19.0: version "2.19.0" resolved "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" @@ -12308,16 +11419,6 @@ unpipe@1.0.0, unpipe@~1.0.0: resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== -unplugin@1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/unplugin/-/unplugin-1.0.1.tgz#83b528b981cdcea1cad422a12cd02e695195ef3f" - integrity sha512-aqrHaVBWW1JVKBHmGo33T5TxeL0qWzfvjWokObHA9bYmN7eNDkwOxmLjhioHl9878qDFMAaT51XNroRyuz7WxA== - dependencies: - acorn "^8.8.1" - chokidar "^3.5.3" - webpack-sources "^3.2.3" - webpack-virtual-modules "^0.5.0" - unplugin@^1.3.1: version "1.16.1" resolved "https://registry.npmjs.org/unplugin/-/unplugin-1.16.1.tgz#a844d2e3c3b14a4ac2945c42be80409321b61199" @@ -12575,11 +11676,6 @@ webpack-sources@^3.2.3: resolved "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -webpack-virtual-modules@^0.5.0: - version "0.5.0" - resolved "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.5.0.tgz#362f14738a56dae107937ab98ea7062e8bdd3b6c" - integrity sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw== - webpack-virtual-modules@^0.6.0, webpack-virtual-modules@^0.6.2: version "0.6.2" resolved "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz#057faa9065c8acf48f24cb57ac0e77739ab9a7e8" @@ -12703,7 +11799,7 @@ which-typed-array@^1.1.16, which-typed-array@^1.1.18, which-typed-array@^1.1.2: gopd "^1.2.0" has-tostringtag "^1.0.2" -which@^2.0.1, which@^2.0.2: +which@^2.0.1: version "2.0.2" resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== @@ -12803,11 +11899,6 @@ xmlchars@^2.2.0: resolved "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== -xtend@^4.0.0: - version "4.0.2" - resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - y-indexeddb@^9.0.12: version "9.0.12" resolved "https://registry.npmjs.org/y-indexeddb/-/y-indexeddb-9.0.12.tgz#73657f31d52886d7532256610babf5cca4ad5e58" From aea5f39059f0ceca8c6004b6750f25fe1763c6c7 Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Tue, 25 Mar 2025 20:15:00 +0530 Subject: [PATCH 023/146] [RANTS-31] improvement: optimistic update for home widget reordering (#6817) --- .../home/widgets/manage/widget-list.tsx | 27 ++++++++++--------- web/core/store/workspace/home.ts | 13 ++++++--- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/web/core/components/home/widgets/manage/widget-list.tsx b/web/core/components/home/widgets/manage/widget-list.tsx index 85957d8cf..ff7db11c2 100644 --- a/web/core/components/home/widgets/manage/widget-list.tsx +++ b/web/core/components/home/widgets/manage/widget-list.tsx @@ -29,20 +29,21 @@ export const WidgetList = observer(({ workspaceSlug }: { workspaceSlug: string } if (!sourceData.id) return; if (droppedId) { - try { - reorderWidget(workspaceSlug, sourceData.id, droppedId, instruction); /** sequence */ - setToast({ - type: TOAST_TYPE.SUCCESS, - title: t("toast.success"), - message: t("home.widget.reordered_successfully"), + reorderWidget(workspaceSlug, sourceData.id, droppedId, instruction) + .then(() => { + setToast({ + type: TOAST_TYPE.SUCCESS, + title: t("toast.success"), + message: t("home.widget.reordered_successfully"), + }); + }) + .catch(() => { + setToast({ + type: TOAST_TYPE.ERROR, + title: t("toast.error"), + message: t("home.widget.reordering_failed"), + }); }); - } catch { - setToast({ - type: TOAST_TYPE.ERROR, - title: t("toast.error"), - message: t("home.widget.reordering_failed"), - }); - } } }; diff --git a/web/core/store/workspace/home.ts b/web/core/store/workspace/home.ts index 023767ef3..109132fb6 100644 --- a/web/core/store/workspace/home.ts +++ b/web/core/store/workspace/home.ts @@ -1,3 +1,4 @@ +import clone from "lodash/clone"; import orderBy from "lodash/orderBy"; import set from "lodash/set"; import { action, computed, makeObservable, observable, runInAction } from "mobx"; @@ -19,7 +20,7 @@ export interface IHomeStore { // actions toggleWidgetSettings: (value?: boolean) => void; fetchWidgets: (workspaceSlug: string) => Promise; - reorderWidget: (workspaceSlug: string, widgetKey: string, destinationId: string, edge: string | undefined) => void; + reorderWidget: (workspaceSlug: string, widgetKey: string, destinationId: string, edge: string | undefined) => Promise; toggleWidget: (workspaceSlug: string, widgetKey: string, is_enabled: boolean) => void; } @@ -102,6 +103,7 @@ export class HomeStore implements IHomeStore { }; reorderWidget = async (workspaceSlug: string, widgetKey: string, destinationId: string, edge: string | undefined) => { + const sortOrderBeforeUpdate = clone(this.widgetsMap[widgetKey]?.sort_order); try { let resultSequence = 10000; if (edge) { @@ -121,14 +123,17 @@ export class HomeStore implements IHomeStore { } } } - await this.workspaceService.updateWorkspaceWidget(workspaceSlug, widgetKey, { - sort_order: resultSequence, - }); runInAction(() => { set(this.widgetsMap, [widgetKey, "sort_order"], resultSequence); }); + await this.workspaceService.updateWorkspaceWidget(workspaceSlug, widgetKey, { + sort_order: resultSequence, + }); } catch (error) { console.error("Failed to move widget"); + runInAction(() => { + set(this.widgetsMap, [widgetKey, "sort_order"], sortOrderBeforeUpdate); + }); throw error; } }; From caa522118dcb5044bd333481510a5941b4ad9f1d Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Tue, 25 Mar 2025 20:15:35 +0530 Subject: [PATCH 024/146] [RANTS-29] fix: enter key does not work in the workspace member invite modal (#6816) --- web/core/components/workspace/invite-modal/form.tsx | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/web/core/components/workspace/invite-modal/form.tsx b/web/core/components/workspace/invite-modal/form.tsx index 1178f1f6e..cbf53e237 100644 --- a/web/core/components/workspace/invite-modal/form.tsx +++ b/web/core/components/workspace/invite-modal/form.tsx @@ -16,13 +16,7 @@ export const InvitationForm = observer((props: TInvitationFormProps) => { const { title, description, children, actions, onSubmit, className } = props; return ( -
{ - if (e.code === "Enter") e.preventDefault(); - }} - className={className} - > +
{title} From cebd0b35997aba9e24dec56d5ae344455ca32dd3 Mon Sep 17 00:00:00 2001 From: Prateek Shourya Date: Tue, 25 Mar 2025 20:16:06 +0530 Subject: [PATCH 025/146] [RANTS-68] fix: z-index for image picker popover button (change project cover) (#6812) --- web/core/components/core/image-picker-popover.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/core/components/core/image-picker-popover.tsx b/web/core/components/core/image-picker-popover.tsx index b3bf73588..b208b9f5f 100644 --- a/web/core/components/core/image-picker-popover.tsx +++ b/web/core/components/core/image-picker-popover.tsx @@ -149,7 +149,7 @@ export const ImagePickerPopover: React.FC = observer((props) => { useOutsideClickDetector(ref, handleClose); return ( - + Date: Tue, 25 Mar 2025 20:17:16 +0530 Subject: [PATCH 026/146] [WEB-3600] fix: private project join issue (#6799) * fix: private project join issue * chore: return network value * fix: refactor * fix: refactor * fix: type * chore: added restricition for private projects * chore: removed extra validations * chore: added value to access enum --------- Co-authored-by: sangeethailango Co-authored-by: NarayanBavisetti --- apiserver/plane/app/views/project/base.py | 1 + apiserver/plane/app/views/project/invite.py | 24 +++++++++++++------ apiserver/plane/db/models/project.py | 10 ++++++++ packages/types/src/enums.ts | 6 +++++ packages/types/src/project/projects.d.ts | 2 +- .../layouts/auth-layout/project-wrapper.tsx | 15 ++++++++++-- 6 files changed, 48 insertions(+), 10 deletions(-) diff --git a/apiserver/plane/app/views/project/base.py b/apiserver/plane/app/views/project/base.py index 00e1ad1eb..b4f0b3aad 100644 --- a/apiserver/plane/app/views/project/base.py +++ b/apiserver/plane/app/views/project/base.py @@ -179,6 +179,7 @@ class ProjectViewSet(BaseViewSet): "inbox_view", "guest_view_all_features", "project_lead", + "network", "created_at", "updated_at", "created_by", diff --git a/apiserver/plane/app/views/project/invite.py b/apiserver/plane/app/views/project/invite.py index e4d46e89f..51eb997f6 100644 --- a/apiserver/plane/app/views/project/invite.py +++ b/apiserver/plane/app/views/project/invite.py @@ -16,17 +16,17 @@ from rest_framework.permissions import AllowAny # Module imports from .base import BaseViewSet, BaseAPIView from plane.app.serializers import ProjectMemberInviteSerializer - from plane.app.permissions import allow_permission, ROLE - from plane.db.models import ( ProjectMember, Workspace, ProjectMemberInvite, User, WorkspaceMember, + Project, IssueUserProperty, ) +from plane.db.models.project import ProjectNetwork class ProjectInvitationsViewset(BaseViewSet): @@ -128,6 +128,7 @@ class UserProjectInvitationsViewset(BaseViewSet): .select_related("workspace", "workspace__owner", "project") ) + @allow_permission([ROLE.ADMIN, ROLE.MEMBER], level="WORKSPACE") def create(self, request, slug): project_ids = request.data.get("project_ids", []) @@ -136,11 +137,20 @@ class UserProjectInvitationsViewset(BaseViewSet): member=request.user, workspace__slug=slug, is_active=True ) - if workspace_member.role not in [ROLE.ADMIN.value, ROLE.MEMBER.value]: - return Response( - {"error": "You do not have permission to join the project"}, - status=status.HTTP_403_FORBIDDEN, - ) + # Get all the projects + projects = Project.objects.filter( + id__in=project_ids, workspace__slug=slug + ).only("id", "network") + # Check if user has permission to join each project + for project in projects: + if ( + project.network == ProjectNetwork.SECRET.value + and workspace_member.role != ROLE.ADMIN.value + ): + return Response( + {"error": "Only workspace admins can join private project"}, + status=status.HTTP_403_FORBIDDEN, + ) workspace_role = workspace_member.role workspace = workspace_member.workspace diff --git a/apiserver/plane/db/models/project.py b/apiserver/plane/db/models/project.py index c97c550ee..c4d097ac8 100644 --- a/apiserver/plane/db/models/project.py +++ b/apiserver/plane/db/models/project.py @@ -1,6 +1,7 @@ # Python imports import pytz from uuid import uuid4 +from enum import Enum # Django imports from django.conf import settings @@ -17,6 +18,15 @@ from .base import BaseModel ROLE_CHOICES = ((20, "Admin"), (15, "Member"), (5, "Guest")) +class ProjectNetwork(Enum): + SECRET = 0 + PUBLIC = 2 + + @classmethod + def choices(cls): + return [(0, "Secret"), (2, "Public")] + + def get_default_props(): return { "filters": { diff --git a/packages/types/src/enums.ts b/packages/types/src/enums.ts index 854c0c614..53138a1d7 100644 --- a/packages/types/src/enums.ts +++ b/packages/types/src/enums.ts @@ -6,6 +6,12 @@ export enum EUserPermissions { export type TUserPermissions = EUserPermissions.ADMIN | EUserPermissions.MEMBER | EUserPermissions.GUEST; +// project network +export enum EProjectNetwork { + PRIVATE = 0, + PUBLIC = 2, +} + // project pages export enum EPageAccess { PUBLIC = 0, diff --git a/packages/types/src/project/projects.d.ts b/packages/types/src/project/projects.d.ts index 40562d362..e1d9117a1 100644 --- a/packages/types/src/project/projects.d.ts +++ b/packages/types/src/project/projects.d.ts @@ -27,6 +27,7 @@ export interface IPartialProject { inbox_view: boolean; guest_view_all_features?: boolean; project_lead?: IUserLite | string | null; + network?: number; // Timestamps created_at?: Date; updated_at?: Date; @@ -50,7 +51,6 @@ export interface IProject extends IPartialProject { anchor?: string | null; is_favorite?: boolean; members?: string[]; - network?: number; timezone?: string; } diff --git a/web/core/layouts/auth-layout/project-wrapper.tsx b/web/core/layouts/auth-layout/project-wrapper.tsx index e79bdd189..c356cb883 100644 --- a/web/core/layouts/auth-layout/project-wrapper.tsx +++ b/web/core/layouts/auth-layout/project-wrapper.tsx @@ -7,6 +7,7 @@ import useSWR from "swr"; import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants"; import { useTranslation } from "@plane/i18n"; // components +import { EProjectNetwork } from "@plane/types/src/enums"; import { JoinProject } from "@/components/auth-screens"; import { LogoSpinner } from "@/components/common"; import { ComicBoxButton, DetailedEmptyState } from "@/components/empty-state"; @@ -70,6 +71,11 @@ export const ProjectAuthWrapper: FC = observer((props) => { workspaceSlug.toString(), projectId?.toString() ); + const isWorkspaceAdmin = allowPermissions( + [EUserPermissions.ADMIN], + EUserPermissionsLevel.WORKSPACE, + workspaceSlug.toString() + ); // Initialize module timeline chart useEffect(() => { @@ -168,10 +174,15 @@ export const ProjectAuthWrapper: FC = observer((props) => { ); // check if the user don't have permission to access the project - if (projectExists && projectId && hasPermissionToCurrentProject === false) return ; + if ( + ((projectExists?.network && projectExists?.network !== EProjectNetwork.PRIVATE) || isWorkspaceAdmin) && + projectId && + hasPermissionToCurrentProject === false + ) + return ; // check if the project info is not found. - if (loader === "loaded" && !projectExists && projectId && !!hasPermissionToCurrentProject === false) + if (loader === "loaded" && projectId && !!hasPermissionToCurrentProject === false) return (
Date: Wed, 26 Mar 2025 20:10:20 +0530 Subject: [PATCH 027/146] [WEB-3686] feat: romanian and indonesian language support (#6825) * Add ro Romanian Language locale (#6809) * feat: add Indonesian language support (#6794) Co-authored-by: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> * chore: core translation added and code refactor --------- Co-authored-by: mnbro <107358316+mnbro@users.noreply.github.com> Co-authored-by: Rasyid Ridho --- packages/i18n/src/constants/language.ts | 2 + .../i18n/src/locales/id/translations.json | 2371 +++++++++++++++++ .../i18n/src/locales/ro/translations.json | 2371 +++++++++++++++++ packages/i18n/src/store/index.ts | 4 + packages/i18n/src/types/language.ts | 18 +- 5 files changed, 4765 insertions(+), 1 deletion(-) create mode 100644 packages/i18n/src/locales/id/translations.json create mode 100644 packages/i18n/src/locales/ro/translations.json diff --git a/packages/i18n/src/constants/language.ts b/packages/i18n/src/constants/language.ts index 132ee68c9..9a9532cdc 100644 --- a/packages/i18n/src/constants/language.ts +++ b/packages/i18n/src/constants/language.ts @@ -17,6 +17,8 @@ export const SUPPORTED_LANGUAGES: ILanguageOption[] = [ { label: "Українська", value: "ua" }, { label: "Polski", value: "pl" }, { label: "한국어", value: "ko" }, + { label: "Indonesian", value: "id" }, + { label: "Română", value: "ro" }, ]; export const LANGUAGE_STORAGE_KEY = "userLanguage"; diff --git a/packages/i18n/src/locales/id/translations.json b/packages/i18n/src/locales/id/translations.json new file mode 100644 index 000000000..84841d0f1 --- /dev/null +++ b/packages/i18n/src/locales/id/translations.json @@ -0,0 +1,2371 @@ +{ + "sidebar": { + "projects": "Projek", + "pages": "Halaman", + "new_work_item": "Item kerja baru", + "home": "Beranda", + "your_work": "Pekerjaan anda", + "inbox": "Inbox", + "workspace": "Workspace", + "views": "Views", + "analytics": "Analitik", + "work_items": "Item kerja", + "cycles": "Siklus", + "modules": "Modul", + "intake": "Intake", + "drafts": "Draft", + "favorites": "Favorit", + "pro": "Pro", + "upgrade": "Upgrade" + }, + + "auth": { + "common": { + "email": { + "label": "Email", + "placeholder": "nama@perusahaan.com", + "errors": { + "required": "Email wajib diisi", + "invalid": "Email tidak valid" + } + }, + "password": { + "label": "Password", + "set_password": "Atur password", + "placeholder": "Masukkan password", + "confirm_password": { + "label": "Konfirmasi password", + "placeholder": "Konfirmasi password" + }, + "current_password": { + "label": "Password saat ini" + }, + "new_password": { + "label": "Password baru", + "placeholder": "Masukkan password baru" + }, + "change_password": { + "label": { + "default": "Ubah password", + "submitting": "Mengubah password" + } + }, + "errors": { + "match": "Password tidak cocok", + "empty": "Silakan masukkan password anda", + "length": "Panjang password harus lebih dari 8 karakter", + "strength": { + "weak": "Password lemah", + "strong": "Password kuat" + } + }, + "submit": "Atur password", + "toast": { + "change_password": { + "success": { + "title": "Berhasil!", + "message": "Password berhasil diubah." + }, + "error": { + "title": "Error!", + "message": "Terjadi kesalahan. Silakan coba lagi." + } + } + } + }, + "unique_code": { + "label": "Kode unik", + "placeholder": "gets-sets-flys", + "paste_code": "Tempelkan kode yang dikirim ke email anda", + "requesting_new_code": "Meminta kode baru", + "sending_code": "Mengirim kode" + }, + "already_have_an_account": "Sudah punya akun?", + "login": "Masuk", + "create_account": "Buat akun", + "new_to_plane": "Baru di Plane?", + "back_to_sign_in": "Kembali ke halaman masuk", + "resend_in": "Kirim ulang dalam {seconds} detik", + "sign_in_with_unique_code": "Masuk dengan kode unik", + "forgot_password": "Lupa password?" + }, + "sign_up": { + "header": { + "label": "Buat akun untuk mulai mengelola pekerjaan dengan tim anda.", + "step": { + "email": { + "header": "Daftar", + "sub_header": "" + }, + "password": { + "header": "Daftar", + "sub_header": "Daftar menggunakan kombinasi email-password." + }, + "unique_code": { + "header": "Daftar", + "sub_header": "Daftar menggunakan kode unik yang dikirim ke alamat email di atas." + } + } + }, + "errors": { + "password": { + "strength": "Coba atur password yang lebih kuat untuk melanjutkan" + } + } + }, + "sign_in": { + "header": { + "label": "Masuk untuk mulai mengelola pekerjaan dengan tim anda.", + "step": { + "email": { + "header": "Masuk atau daftar", + "sub_header": "" + }, + "password": { + "header": "Masuk atau daftar", + "sub_header": "Gunakan kombinasi email-password anda untuk masuk." + }, + "unique_code": { + "header": "Masuk atau daftar", + "sub_header": "Masuk menggunakan kode unik yang dikirim ke alamat email di atas." + } + } + } + }, + "forgot_password": { + "title": "Reset password anda", + "description": "Masukkan alamat email akun anda yang telah diverifikasi dan kami akan mengirimkan link reset password.", + "email_sent": "Kami telah mengirim link reset ke alamat email anda", + "send_reset_link": "Kirim link reset", + "errors": { + "smtp_not_enabled": "Kami melihat bahwa admin anda belum mengaktifkan SMTP, kami tidak dapat mengirimkan link reset password" + }, + "toast": { + "success": { + "title": "Email terkirim", + "message": "Periksa inbox anda untuk link reset password. Jika tidak muncul dalam beberapa menit, periksa folder spam." + }, + "error": { + "title": "Error!", + "message": "Terjadi kesalahan. Silakan coba lagi." + } + } + }, + "reset_password": { + "title": "Atur password baru", + "description": "Amankan akun anda dengan password yang kuat" + }, + "set_password": { + "title": "Amankan akun anda", + "description": "Mengatur password membantu anda masuk dengan aman" + }, + "sign_out": { + "toast": { + "error": { + "title": "Error!", + "message": "Gagal keluar. Silakan coba lagi." + } + } + } + }, + + "submit": "Kirim", + "cancel": "Batal", + "loading": "Memuat", + "error": "Kesalahan", + "success": "Sukses", + "warning": "Peringatan", + "info": "Info", + "close": "Tutup", + "yes": "Ya", + "no": "Tidak", + "ok": "OK", + "name": "Nama", + "description": "Deskripsi", + "search": "Cari", + "add_member": "Tambah anggota", + "adding_members": "Menambah anggota", + "remove_member": "Hapus anggota", + "add_members": "Tambah anggota", + "adding_member": "Menambah anggota", + "remove_members": "Hapus anggota", + "add": "Tambah", + "adding": "Menambah", + "remove": "Hapus", + "add_new": "Tambah baru", + "remove_selected": "Hapus yang dipilih", + "first_name": "Nama depan", + "last_name": "Nama belakang", + "email": "Email", + "display_name": "Nama tampilan", + "role": "Peran", + "timezone": "Zona waktu", + "avatar": "Avatar", + "cover_image": "Gambar sampul", + "password": "Kata sandi", + "change_cover": "Ganti sampul", + "language": "Bahasa", + "saving": "Menyimpan", + "save_changes": "Simpan perubahan", + "deactivate_account": "Nonaktifkan akun", + "deactivate_account_description": "Saat menonaktifkan akun, semua data dan sumber daya dalam akun tersebut akan dihapus secara permanen dan tidak dapat dipulihkan.", + "profile_settings": "Pengaturan profil", + "your_account": "Akun Anda", + "security": "Keamanan", + "activity": "Aktivitas", + "appearance": "Tampilan", + "notifications": "Notifikasi", + "workspaces": "Ruang kerja", + "create_workspace": "Buat ruang kerja", + "invitations": "Undangan", + "summary": "Ringkasan", + "assigned": "Ditetapkan", + "created": "Dibuat", + "subscribed": "Berlangganan", + "you_do_not_have_the_permission_to_access_this_page": "Anda tidak memiliki izin untuk mengakses halaman ini.", + "something_went_wrong_please_try_again": "Terjadi kesalahan. Silakan coba lagi.", + "load_more": "Muat lebih banyak", + "select_or_customize_your_interface_color_scheme": "Pilih atau sesuaikan skema warna antarmuka Anda.", + "theme": "Tema", + "system_preference": "Preferensi sistem", + "light": "Terang", + "dark": "Gelap", + "light_contrast": "Kontras tinggi terang", + "dark_contrast": "Kontras tinggi gelap", + "custom": "Tema kustom", + "select_your_theme": "Pilih tema Anda", + "customize_your_theme": "Sesuaikan tema Anda", + "background_color": "Warna latar belakang", + "text_color": "Warna teks", + "primary_color": "Warna utama (Tema)", + "sidebar_background_color": "Warna latar belakang sidebar", + "sidebar_text_color": "Warna teks sidebar", + "set_theme": "Atur tema", + "enter_a_valid_hex_code_of_6_characters": "Masukkan kode hex yang valid dari 6 karakter", + "background_color_is_required": "Warna latar belakang diperlukan", + "text_color_is_required": "Warna teks diperlukan", + "primary_color_is_required": "Warna utama diperlukan", + "sidebar_background_color_is_required": "Warna latar belakang sidebar diperlukan", + "sidebar_text_color_is_required": "Warna teks sidebar diperlukan", + "updating_theme": "Memperbarui tema", + "theme_updated_successfully": "Tema berhasil diperbarui", + "failed_to_update_the_theme": "Gagal memperbarui tema", + "email_notifications": "Notifikasi email", + "stay_in_the_loop_on_issues_you_are_subscribed_to_enable_this_to_get_notified": "Tetap terupdate tentang item kerja yang Anda langgani. Aktifkan ini untuk mendapatkan notifikasi.", + "email_notification_setting_updated_successfully": "Pengaturan notifikasi email berhasil diperbarui", + "failed_to_update_email_notification_setting": "Gagal memperbarui pengaturan notifikasi email", + "notify_me_when": "Beri tahu saya ketika", + "property_changes": "Perubahan properti", + "property_changes_description": "Beri tahu saya ketika properti item kerja seperti penugasannya, prioritas, estimasi, atau hal lainnya berubah.", + "state_change": "Perubahan status", + "state_change_description": "Beri tahu saya ketika item kerja berpindah ke status yang berbeda", + "issue_completed": "Item kerja selesai", + "issue_completed_description": "Beri tahu saya hanya ketika item kerja selesai", + "comments": "Komentar", + "comments_description": "Beri tahu saya ketika seseorang meninggalkan komentar pada item kerja", + "mentions": "Sebutkan", + "mentions_description": "Beri tahu saya hanya ketika seseorang menyebut saya dalam komentar atau deskripsi", + "old_password": "Kata sandi lama", + "general_settings": "Pengaturan umum", + "sign_out": "Keluar", + "signing_out": "Keluar", + "active_cycles": "Siklus aktif", + "active_cycles_description": "Pantau siklus di seluruh proyek, lacak item kerja prioritas tinggi, dan fokus pada siklus yang membutuhkan perhatian.", + "on_demand_snapshots_of_all_your_cycles": "Snapshot sesuai permintaan dari semua siklus Anda", + "upgrade": "Tingkatkan", + "10000_feet_view": "Tampilan 10.000 kaki dari semua siklus aktif.", + "10000_feet_view_description": "Perbesar untuk melihat siklus yang berjalan di seluruh proyek Anda sekaligus, bukan berpindah dari Siklus ke Siklus di setiap proyek.", + "get_snapshot_of_each_active_cycle": "Dapatkan snapshot dari setiap siklus aktif.", + "get_snapshot_of_each_active_cycle_description": "Lacak metrik tingkat tinggi untuk semua siklus aktif, lihat kemajuan mereka, dan dapatkan gambaran tentang ruang lingkup terhadap tenggat waktu.", + "compare_burndowns": "Bandingkan burndown.", + "compare_burndowns_description": "Pantau bagaimana kinerja setiap tim Anda dengan melihat laporan burndown masing-masing siklus.", + "quickly_see_make_or_break_issues": "Lihat dengan cepat item kerja yang krusial.", + "quickly_see_make_or_break_issues_description": "Prabaca item kerja prioritas tinggi untuk setiap siklus terhadap tanggal jatuh tempo. Lihat semuanya per siklus hanya dengan satu klik.", + "zoom_into_cycles_that_need_attention": "Perbesar siklus yang membutuhkan perhatian.", + "zoom_into_cycles_that_need_attention_description": "Selidiki status siklus mana pun yang tidak sesuai dengan harapan dengan satu klik.", + "stay_ahead_of_blockers": "Tetap di depan penghambat.", + "stay_ahead_of_blockers_description": "Identifikasi tantangan dari satu proyek ke proyek lainnya dan lihat ketergantungan antar siklus yang tidak terlihat dari tampilan lain mana pun.", + "analytics": "Analitik", + "workspace_invites": "Undangan ruang kerja", + "enter_god_mode": "Masuk ke mode dewa", + "workspace_logo": "Logo ruang kerja", + "new_issue": "Item kerja baru", + "your_work": "Pekerjaan Anda", + "drafts": "Draf", + "projects": "Proyek", + "views": "Tampilan", + "workspace": "Ruang kerja", + "archives": "Arsip", + "settings": "Pengaturan", + "failed_to_move_favorite": "Gagal memindahkan favorit", + "favorites": "Favorit", + "no_favorites_yet": "Belum ada favorit", + "create_folder": "Buat folder", + "new_folder": "Folder baru", + "favorite_updated_successfully": "Favorit berhasil diperbarui", + "favorite_created_successfully": "Favorit berhasil dibuat", + "folder_already_exists": "Folder sudah ada", + "folder_name_cannot_be_empty": "Nama folder tidak boleh kosong", + "something_went_wrong": "Terjadi kesalahan", + "failed_to_reorder_favorite": "Gagal mengatur ulang favorit", + "favorite_removed_successfully": "Favorit berhasil dihapus", + "failed_to_create_favorite": "Gagal membuat favorit", + "failed_to_rename_favorite": "Gagal mengganti nama favorit", + "project_link_copied_to_clipboard": "Tautan proyek disalin ke clipboard", + "link_copied": "Tautan disalin", + "add_project": "Tambah proyek", + "create_project": "Buat proyek", + "failed_to_remove_project_from_favorites": "Tidak dapat menghapus proyek dari favorit. Silakan coba lagi.", + "project_created_successfully": "Proyek berhasil dibuat", + "project_created_successfully_description": "Proyek berhasil dibuat. Anda sekarang dapat mulai menambahkan item kerja ke dalamnya.", + "project_cover_image_alt": "Gambar sampul proyek", + "name_is_required": "Nama diperlukan", + "title_should_be_less_than_255_characters": "Judul harus kurang dari 255 karakter", + "project_name": "Nama proyek", + "project_id_must_be_at_least_1_character": "ID proyek harus minimal 1 karakter", + "project_id_must_be_at_most_5_characters": "ID proyek maksimal 5 karakter", + "project_id": "ID proyek", + "project_id_tooltip_content": "Membantu Anda mengidentifikasi item kerja dalam proyek secara unik. Maksimal 5 karakter.", + "description_placeholder": "Deskripsi", + "only_alphanumeric_non_latin_characters_allowed": "Hanya karakter alfanumerik & Non-latin yang diizinkan.", + "project_id_is_required": "ID proyek diperlukan", + "project_id_allowed_char": "Hanya karakter alfanumerik & Non-latin yang diizinkan.", + "project_id_min_char": "ID proyek harus minimal 1 karakter", + "project_id_max_char": "ID proyek maksimal 5 karakter", + "project_description_placeholder": "Masukkan deskripsi proyek", + "select_network": "Pilih jaringan", + "lead": "Pemimpin", + "date_range": "Rentang tanggal", + "private": "Pribadi", + "public": "Umum", + "accessible_only_by_invite": "Diakses hanya dengan undangan", + "anyone_in_the_workspace_except_guests_can_join": "Siapa saja di ruang kerja kecuali Tamu dapat bergabung", + "creating": "Membuat", + "creating_project": "Membuat proyek", + "adding_project_to_favorites": "Menambahkan proyek ke favorit", + "project_added_to_favorites": "Proyek ditambahkan ke favorit", + "couldnt_add_the_project_to_favorites": "Tidak dapat menambahkan proyek ke favorit. Silakan coba lagi.", + "removing_project_from_favorites": "Menghapus proyek dari favorit", + "project_removed_from_favorites": "Proyek dihapus dari favorit", + "couldnt_remove_the_project_from_favorites": "Tidak dapat menghapus proyek dari favorit. Silakan coba lagi.", + "add_to_favorites": "Tambah ke favorit", + "remove_from_favorites": "Hapus dari favorit", + "publish_settings": "Pengaturan publikasi", + "publish": "Publikasikan", + "copy_link": "Salin tautan", + "leave_project": "Tinggalkan proyek", + "join_the_project_to_rearrange": "Bergabunglah dengan proyek untuk menyusun ulang", + "drag_to_rearrange": "Seret untuk menyusun ulang", + "congrats": "Selamat!", + "open_project": "Buka proyek", + "issues": "Item kerja", + "cycles": "Siklus", + "modules": "Modul", + "pages": "Halaman", + "intake": "Penerimaan", + "time_tracking": "Pelacakan waktu", + "work_management": "Manajemen kerja", + "projects_and_issues": "Proyek dan item kerja", + "projects_and_issues_description": "Aktifkan atau nonaktifkan ini untuk proyek ini.", + "cycles_description": "Batasi waktu kerja sesuai keinginan Anda per proyek dan ubah frekuensi dari satu periode ke periode berikutnya.", + "modules_description": "Kerja kelompok menjadi pengaturan sub-proyek dengan pemimpin dan penugasnya sendiri.", + "views_description": "Simpan jenis, filter, dan opsi tampilan untuk nanti atau bagikan.", + "pages_description": "Tulis apapun seperti yang Anda tulis.", + "intake_description": "Tetap terhubung dengan item kerja yang Anda ikuti. Aktifkan ini untuk mendapatkan pemberitahuan.", + "time_tracking_description": "Lacak waktu yang dihabiskan untuk item kerja dan proyek.", + "work_management_description": "Kelola pekerjaan dan proyek Anda dengan mudah.", + "documentation": "Dokumentasi", + "message_support": "Pesan dukungan", + "contact_sales": "Hubungi penjualan", + "hyper_mode": "Mode Hyper", + "keyboard_shortcuts": "Pintasan keyboard", + "whats_new": "Apa yang baru?", + "version": "Versi", + "we_are_having_trouble_fetching_the_updates": "Kami mengalami kesulitan mengambil pembaruan.", + "our_changelogs": "changelog kami", + "for_the_latest_updates": "untuk pembaruan terbaru.", + "please_visit": "Silakan kunjungi", + "docs": "Dokumen", + "full_changelog": "Changelog lengkap", + "support": "Dukungan", + "discord": "Discord", + "powered_by_plane_pages": "Ditenagai oleh Plane Pages", + "please_select_at_least_one_invitation": "Silakan pilih setidaknya satu undangan.", + "please_select_at_least_one_invitation_description": "Silakan pilih setidaknya satu undangan untuk bergabung dengan ruang kerja.", + "we_see_that_someone_has_invited_you_to_join_a_workspace": "Kami melihat bahwa seseorang telah mengundang Anda untuk bergabung dengan ruang kerja", + "join_a_workspace": "Bergabunglah dengan ruang kerja", + "we_see_that_someone_has_invited_you_to_join_a_workspace_description": "Kami melihat bahwa seseorang telah mengundang Anda untuk bergabung dengan ruang kerja", + "join_a_workspace_description": "Bergabunglah dengan ruang kerja", + "accept_and_join": "Terima & Bergabung", + "go_home": "Kembali ke Beranda", + "no_pending_invites": "Tidak ada undangan yang tertunda", + "you_can_see_here_if_someone_invites_you_to_a_workspace": "Anda dapat melihat di sini jika seseorang mengundang Anda untuk bergabung dengan ruang kerja", + "back_to_home": "Kembali ke beranda", + "workspace_name": "nama-ruang-kerja", + "deactivate_your_account": "Nonaktifkan akun Anda", + "deactivate_your_account_description": "Setelah dinonaktifkan, Anda tidak akan dapat ditugaskan item kerja dan ditagih untuk ruang kerja Anda. Untuk mengaktifkan kembali akun Anda, Anda akan memerlukan undangan ke ruang kerja di alamat email ini.", + "deactivating": "Menonaktifkan", + "confirm": "Konfirmasi", + "confirming": "Mengonfirmasi", + "draft_created": "Draf dibuat", + "issue_created_successfully": "Item kerja berhasil dibuat", + "draft_creation_failed": "Pembuatan draf gagal", + "issue_creation_failed": "Pembuatan item kerja gagal", + "draft_issue": "Draf item kerja", + "issue_updated_successfully": "Item kerja berhasil diperbarui", + "issue_could_not_be_updated": "Item kerja tidak dapat diperbarui", + "create_a_draft": "Buat draf", + "save_to_drafts": "Simpan ke Draf", + "save": "Simpan", + "update": "Perbarui", + "updating": "Memperbarui", + "create_new_issue": "Buat item kerja baru", + "editor_is_not_ready_to_discard_changes": "Editor belum siap untuk membuang perubahan", + "failed_to_move_issue_to_project": "Gagal memindahkan item kerja ke proyek", + "create_more": "Buat lebih banyak", + "add_to_project": "Tambahkan ke proyek", + "discard": "Buang", + "duplicate_issue_found": "Item kerja duplikat ditemukan", + "duplicate_issues_found": "Item kerja duplikat ditemukan", + "no_matching_results": "Tidak ada hasil yang cocok", + "title_is_required": "Judul diperlukan", + "title": "Judul", + "state": "Negara", + "priority": "Prioritas", + "none": "Tidak ada", + "urgent": "Penting", + "high": "Tinggi", + "medium": "Sedang", + "low": "Rendah", + "members": "Anggota", + "assignee": "Penugas", + "assignees": "Penugas", + "you": "Anda", + "labels": "Label", + "create_new_label": "Buat label baru", + "start_date": "Tanggal mulai", + "end_date": "Tanggal akhir", + "due_date": "Tanggal jatuh tempo", + "estimate": "Perkiraan", + "change_parent_issue": "Ubah item kerja induk", + "remove_parent_issue": "Hapus item kerja induk", + "add_parent": "Tambahkan induk", + "loading_members": "Memuat anggota", + "view_link_copied_to_clipboard": "Tautan tampilan disalin ke clipboard.", + "required": "Diperlukan", + "optional": "Opsional", + "Cancel": "Batal", + "edit": "Sunting", + "archive": "Arsip", + "restore": "Pulihkan", + "open_in_new_tab": "Buka di tab baru", + "delete": "Hapus", + "deleting": "Menghapus", + "make_a_copy": "Buat salinan", + "move_to_project": "Pindahkan ke proyek", + "good": "Bagus", + "morning": "pagi", + "afternoon": "siang", + "evening": "malam", + "show_all": "Tampilkan semua", + "show_less": "Tampilkan lebih sedikit", + "no_data_yet": "Belum ada data", + "syncing": "Menyinkronkan", + "add_work_item": "Tambahkan item kerja", + "advanced_description_placeholder": "Tekan '/' untuk perintah", + "create_work_item": "Buat item kerja", + "attachments": "Lampiran", + "declining": "Menolak", + "declined": "Ditolak", + "decline": "Tolak", + "unassigned": "Belum ditugaskan", + "work_items": "Item kerja", + "add_link": "Tambahkan tautan", + "points": "Poin", + "no_assignee": "Tidak ada penugas", + "no_assignees_yet": "Belum ada penugas", + "no_labels_yet": "Belum ada label", + "ideal": "Ideal", + "current": "Saat ini", + "no_matching_members": "Tidak ada anggota yang cocok", + "leaving": "Meninggalkan", + "removing": "Menghapus", + "leave": "Tinggalkan", + "refresh": "Segarkan", + "refreshing": "Menyegarkan", + "refresh_status": "Status segar", + "prev": "Sebelumnya", + "next": "Selanjutnya", + "re_generating": "Menghasilkan kembali", + "re_generate": "Hasilkan kembali", + "re_generate_key": "Hasilkan kembali kunci", + "export": "Ekspor", + "member": "{count, plural, one{# anggota} other{# anggota}}", + + "project_view": { + "sort_by": { + "created_at": "Dibuat pada", + "updated_at": "Diperbarui pada", + "name": "Nama" + } + }, + + "toast": { + "success": "Sukses!", + "error": "Kesalahan!" + }, + + "links": { + "toasts": { + "created": { + "title": "Tautan dibuat", + "message": "Tautan telah berhasil dibuat" + }, + "not_created": { + "title": "Tautan tidak dibuat", + "message": "Tautan tidak dapat dibuat" + }, + "updated": { + "title": "Tautan diperbarui", + "message": "Tautan telah berhasil diperbarui" + }, + "not_updated": { + "title": "Tautan tidak diperbarui", + "message": "Tautan tidak dapat diperbarui" + }, + "removed": { + "title": "Tautan dihapus", + "message": "Tautan telah berhasil dihapus" + }, + "not_removed": { + "title": "Tautan tidak dihapus", + "message": "Tautan tidak dapat dihapus" + } + } + }, + + "home": { + "empty": { + "quickstart_guide": "Panduan pemula Anda", + "not_right_now": "Tidak sekarang", + "create_project": { + "title": "Buat proyek", + "description": "Sebagian besar hal dimulai dengan proyek di Plane.", + "cta": "Mulai sekarang" + }, + "invite_team": { + "title": "Undang tim Anda", + "description": "Bangun, kirim, dan kelola dengan rekan kerja.", + "cta": "Ajak mereka" + }, + "configure_workspace": { + "title": "Atur ruang kerja Anda.", + "description": "Hidupkan atau matikan fitur atau lebih dari itu.", + "cta": "Konfigurasi ruang kerja ini" + }, + "personalize_account": { + "title": "Jadikan Plane milik Anda.", + "description": "Pilih gambar Anda, warna, dan lainnya.", + "cta": "Personalisasi sekarang" + }, + "widgets": { + "title": "Sepi Tanpa Widget, Nyalakan Mereka", + "description": "Sepertinya semua widget Anda dimatikan. Aktifkan sekarang untuk meningkatkan pengalaman Anda!", + "primary_button": { + "text": "Kelola widget" + } + } + }, + "quick_links": { + "empty": "Simpan tautan ke hal-hal kerja yang ingin Anda miliki.", + "add": "Tambahkan Tautan Cepat", + "title": "Tautan Cepat", + "title_plural": "Tautan Cepat" + }, + "recents": { + "title": "Terbaru", + "empty": { + "project": "Proyek terbaru Anda akan muncul di sini setelah Anda mengunjunginya.", + "page": "Halaman terbaru Anda akan muncul di sini setelah Anda mengunjunginya.", + "issue": "Item kerja terbaru Anda akan muncul di sini setelah Anda mengunjunginya.", + "default": "Anda belum memiliki yang terbaru." + }, + "filters": { + "all": "Semua item", + "projects": "Proyek", + "pages": "Halaman", + "issues": "Item kerja" + } + }, + "new_at_plane": { + "title": "Baru di Plane" + }, + "quick_tutorial": { + "title": "Tutorial cepat" + }, + "widget": { + "reordered_successfully": "Widget berhasil diurutkan ulang.", + "reordering_failed": "Kesalahan terjadi saat mengurutkan ulang widget." + }, + "manage_widgets": "Kelola widget", + "title": "Beranda", + "star_us_on_github": "Bintang kami di GitHub" + }, + + "link": { + "modal": { + "url": { + "text": "URL", + "required": "URL tidak valid", + "placeholder": "Ketik atau tempel URL" + }, + "title": { + "text": "Judul tampilan", + "placeholder": "Apa yang ingin Anda lihat sebagai tautan ini" + } + } + }, + + "common": { + "all": "Semua", + "states": "Negara-negara", + "state": "Negara", + "state_groups": "Kelompok negara", + "state_group": "Kelompok negara", + "priorities": "Prioritas", + "priority": "Prioritas", + "team_project": "Proyek tim", + "project": "Proyek", + "cycle": "Siklus", + "cycles": "Siklus", + "module": "Modul", + "modules": "Modul", + "labels": "Label", + "label": "Label", + "assignees": "Penugas", + "assignee": "Penugas", + "created_by": "Dibuat oleh", + "none": "Tidak ada", + "link": "Tautan", + "estimates": "Perkiraan", + "estimate": "Perkiraan", + "created_at": "Dibuat pada", + "completed_at": "Selesai pada", + "layout": "Tata letak", + "filters": "Filter", + "display": "Tampilan", + "load_more": "Muat lebih banyak", + "activity": "Aktivitas", + "analytics": "Analitik", + "dates": "Tanggal", + "success": "Sukses!", + "something_went_wrong": "Ada yang salah", + "error": { + "label": "Kesalahan!", + "message": "Terjadi kesalahan. Silakan coba lagi." + }, + "group_by": "Kelompok berdasarkan", + "epic": "Epik", + "epics": "Epik", + "work_item": "Item kerja", + "work_items": "Item kerja", + "sub_work_item": "Sub-item kerja", + "add": "Tambah", + "warning": "Peringatan", + "updating": "Memperbarui", + "adding": "Menambahkan", + "update": "Perbarui", + "creating": "Membuat", + "create": "Buat", + "cancel": "Batalkan", + "description": "Deskripsi", + "title": "Judul", + "attachment": "Lampiran", + "general": "Umum", + "features": "Fitur", + "automation": "Otomatisasi", + "project_name": "Nama proyek", + "project_id": "ID proyek", + "project_timezone": "Zona waktu proyek", + "created_on": "Dibuat pada", + "update_project": "Perbarui proyek", + "identifier_already_exists": "Pengidentifikasi sudah ada", + "add_more": "Tambah lebih banyak", + "defaults": "Pola dasar", + "add_label": "Tambah label", + "customize_time_range": "Sesuaikan rentang waktu", + "loading": "Memuat", + "attachments": "Lampiran", + "property": "Properti", + "properties": "Properti", + "parent": "Induk", + "page": "Halaman", + "remove": "Hapus", + "archiving": "Mengarsipkan", + "archive": "Arsip", + "access": { + "public": "Publik", + "private": "Pribadi" + }, + "done": "Selesai", + "sub_work_items": "Sub-item kerja", + "comment": "Komentar", + "workspace_level": "Tingkat ruang kerja", + "order_by": { + "label": "Urutkan berdasarkan", + "manual": "Manual", + "last_created": "Terakhir dibuat", + "last_updated": "Terakhir diperbarui", + "start_date": "Tanggal mulai", + "due_date": "Tanggal jatuh tempo", + "asc": "Menaik", + "desc": "Menurun", + "updated_on": "Diperbarui pada" + }, + "sort": { + "asc": "Menaik", + "desc": "Menurun", + "created_on": "Dibuat pada", + "updated_on": "Diperbarui pada" + }, + "comments": "Komentar", + "updates": "Pembaruan", + "clear_all": "Hapus semua", + "copied": "Disalin!", + "link_copied": "Tautan disalin!", + "link_copied_to_clipboard": "Tautan disalin ke clipboard", + "copied_to_clipboard": "Tautan item kerja disalin ke clipboard", + "is_copied_to_clipboard": "Item kerja disalin ke clipboard", + "no_links_added_yet": "Belum ada tautan yang ditambahkan", + "add_link": "Tambah tautan", + "links": "Tautan", + "go_to_workspace": "Pergi ke ruang kerja", + "progress": "Kemajuan", + "optional": "Opsional", + "join": "Bergabung", + "go_back": "Kembali", + "continue": "Lanjutkan", + "resend": "Kirim ulang", + "relations": "Hubungan", + "errors": { + "default": { + "title": "Kesalahan!", + "message": "Sesuatu telah salah. Silakan coba lagi." + }, + "required": "Bidang ini diperlukan", + "entity_required": "{entity} diperlukan" + }, + "update_link": "Perbarui tautan", + "attach": "Lampirkan", + "create_new": "Buat baru", + "add_existing": "Tambah yang ada", + "type_or_paste_a_url": "Ketik atau tempel URL", + "url_is_invalid": "URL tidak valid", + "display_title": "Judul tampilan", + "link_title_placeholder": "Apa yang ingin Anda lihat pada tautan ini", + "url": "URL", + "side_peek": "Tampilan samping", + "modal": "Modal", + "full_screen": "Layar penuh", + "close_peek_view": "Tutup tampilan peek", + "toggle_peek_view_layout": "Alihkan tata letak tampilan peek", + "options": "Opsi", + "duration": "Durasi", + "today": "Hari ini", + "week": "Minggu", + "month": "Bulan", + "quarter": "Kuartal", + "press_for_commands": "Tekan '/' untuk perintah", + "click_to_add_description": "Klik untuk menambahkan deskripsi", + "search": { + "label": "Pencarian", + "placeholder": "Ketik untuk mencari", + "no_matches_found": "Tidak ada kecocokan ditemukan", + "no_matching_results": "Tidak ada hasil yang cocok" + }, + "actions": { + "edit": "Edit", + "make_a_copy": "Buat salinan", + "open_in_new_tab": "Buka di tab baru", + "copy_link": "Salin tautan", + "archive": "Arsip", + "restore": "Pulihkan", + "delete": "Hapus", + "remove_relation": "Hapus hubungan", + "subscribe": "Berlangganan", + "unsubscribe": "Berhenti berlangganan", + "clear_sorting": "Hapus pengurutan", + "show_weekends": "Tampilkan akhir pekan", + "enable": "Aktifkan", + "disable": "Nonaktifkan" + }, + "name": "Nama", + "discard": "Buang", + "confirm": "Konfirmasi", + "confirming": "Mengonfirmasi", + "read_the_docs": "Baca dokumen", + "default": "Bawaan", + "active": "Aktif", + "enabled": "Diaktifkan", + "disabled": "Dinonaktifkan", + "mandate": "Mandat", + "mandatory": "Wajib", + "yes": "Ya", + "no": "Tidak", + "please_wait": "Silakan tunggu", + "enabling": "Mengaktifkan", + "disabling": "Menonaktifkan", + "beta": "Beta", + "or": "atau", + "next": "Selanjutnya", + "back": "Kembali", + "cancelling": "Membatalkan", + "configuring": "Mengkonfigurasi", + "clear": "Bersihkan", + "import": "Impor", + "connect": "Sambungkan", + "authorizing": "Mengautentikasi", + "processing": "Memproses", + "no_data_available": "Tidak ada data tersedia", + "from": "dari {name}", + "authenticated": "Terautentikasi", + "select": "Pilih", + "upgrade": "Tingkatkan", + "add_seats": "Tambahkan Kursi", + "projects": "Proyek", + "workspace": "Ruang kerja", + "workspaces": "Ruang kerja", + "team": "Tim", + "teams": "Tim", + "entity": "Entitas", + "entities": "Entitas", + "task": "Tugas", + "tasks": "Tugas", + "section": "Bagian", + "sections": "Bagian", + "edit": "Edit", + "connecting": "Menghubungkan", + "connected": "Terhubung", + "disconnect": "Putuskan", + "disconnecting": "Memutuskan", + "installing": "Menginstal", + "install": "Instal", + "reset": "Atur ulang", + "live": "Langsung", + "change_history": "Riwayat Perubahan", + "coming_soon": "Segera hadir", + "members": "Anggota", + "you": "Anda", + "upgrade_cta": { + "higher_subscription": "Tingkatkan ke langganan yang lebih tinggi", + "talk_to_sales": "Bicaralah dengan Penjualan" + }, + "category": "Kategori", + "categories": "Kategori", + "saving": "Menyimpan", + "save_changes": "Simpan perubahan", + "delete": "Hapus", + "deleting": "Menghapus", + "pending": "Tertunda", + "invite": "Undang", + "view": "Lihat" + }, + + "chart": { + "x_axis": "Sumbu-X", + "y_axis": "Sumbu-Y", + "metric": "Metrik" + }, + + "form": { + "title": { + "required": "Judul wajib diisi", + "max_length": "Judul harus kurang dari {length} karakter" + } + }, + + "entity": { + "grouping_title": "Pengelompokan {entity}", + "priority": "Prioritas {entity}", + "all": "Semua {entity}", + "drop_here_to_move": "Letakkan di sini untuk memindahkan {entity}", + "delete": { + "label": "Hapus {entity}", + "success": "{entity} berhasil dihapus", + "failed": "Gagal menghapus {entity}" + }, + "update": { + "failed": "Gagal memperbarui {entity}", + "success": "{entity} berhasil diperbarui" + }, + "link_copied_to_clipboard": "Tautan {entity} disalin ke papan klip", + "fetch": { + "failed": "Terjadi kesalahan saat mengambil {entity}" + }, + "add": { + "success": "{entity} berhasil ditambahkan", + "failed": "Terjadi kesalahan saat menambahkan {entity}" + } + }, + + "epic": { + "all": "Semua Epik", + "label": "{count, plural, one {Epik} other {Epik}}", + "new": "Epik Baru", + "adding": "Menambahkan epik", + "create": { + "success": "Epik berhasil dibuat" + }, + "add": { + "press_enter": "Tekan 'Enter' untuk menambahkan epik lain", + "label": "Tambahkan Epik" + }, + "title": { + "label": "Judul Epik", + "required": "Judul epik wajib diisi." + } + }, + + "issue": { + "label": "{count, plural, one {Item Kerja} other {Item Kerja}}", + "all": "Semua Item Kerja", + "edit": "Edit item kerja", + "title": { + "label": "Judul item kerja", + "required": "Judul item kerja diperlukan." + }, + "add": { + "press_enter": "Tekan 'Enter' untuk menambahkan item kerja lainnya", + "label": "Tambah item kerja", + "cycle": { + "failed": "Item kerja tidak dapat ditambahkan ke siklus. Silakan coba lagi.", + "success": "{count, plural, one {Item Kerja} other {Item Kerja}} berhasil ditambahkan ke siklus.", + "loading": "Menambahkan {count, plural, one {item kerja} other {item kerja}} ke siklus" + }, + "assignee": "Tambah penugasan", + "start_date": "Tambah tanggal mulai", + "due_date": "Tambah tanggal jatuh tempo", + "parent": "Tambah item kerja induk", + "sub_issue": "Tambah sub-item kerja", + "relation": "Tambah hubungan", + "link": "Tambah tautan", + "existing": "Tambah item kerja yang ada" + }, + "remove": { + "label": "Hapus item kerja", + "cycle": { + "loading": "Menghapus item kerja dari siklus", + "success": "Item kerja berhasil dihapus dari siklus.", + "failed": "Item kerja tidak dapat dihapus dari siklus. Silakan coba lagi." + }, + "module": { + "loading": "Menghapus item kerja dari modul", + "success": "Item kerja berhasil dihapus dari modul.", + "failed": "Item kerja tidak dapat dihapus dari modul. Silakan coba lagi." + }, + "parent": { + "label": "Hapus item kerja induk" + } + }, + "new": "Item Kerja Baru", + "adding": "Menambahkan item kerja", + "create": { + "success": "Item kerja berhasil dibuat" + }, + "priority": { + "urgent": "Mendesak", + "high": "Tinggi", + "medium": "Sedang", + "low": "Rendah" + }, + "display": { + "properties": { + "label": "Tampilkan Properti", + "id": "ID", + "issue_type": "Tipe item kerja", + "sub_issue_count": "Jumlah sub-item kerja", + "attachment_count": "Jumlah lampiran", + "created_on": "Dibuat pada", + "sub_issue": "Sub-item kerja", + "work_item_count": "Jumlah item kerja" + }, + "extra": { + "show_sub_issues": "Tampilkan sub-item kerja", + "show_empty_groups": "Tampilkan grup kosong" + } + }, + "layouts": { + "ordered_by_label": "Tata letak ini diurutkan berdasarkan", + "list": "Daftar", + "kanban": "Papan", + "calendar": "Kalender", + "spreadsheet": "Tabel", + "gantt": "Garis Waktu", + "title": { + "list": "Tata Letak Daftar", + "kanban": "Tata Letak Papan", + "calendar": "Tata Letak Kalender", + "spreadsheet": "Tata Letak Tabel", + "gantt": "Tata Letak Garis Waktu" + } + }, + "states": { + "active": "Aktif", + "backlog": "Backlog" + }, + "comments": { + "placeholder": "Tambah komentar", + "switch": { + "private": "Beralih ke komentar pribadi", + "public": "Beralih ke komentar publik" + }, + "create": { + "success": "Komentar berhasil dibuat", + "error": "Gagal membuat komentar. Silakan coba lagi nanti." + }, + "update": { + "success": "Komentar berhasil diperbarui", + "error": "Gagal memperbarui komentar. Silakan coba lagi nanti." + }, + "remove": { + "success": "Komentar berhasil dihapus", + "error": "Gagal menghapus komentar. Silakan coba lagi nanti." + }, + "upload": { + "error": "Gagal mengunggah aset. Silakan coba lagi nanti." + } + }, + "empty_state": { + "issue_detail": { + "title": "Item kerja tidak ada", + "description": "Item kerja yang Anda cari tidak ada, telah diarsipkan, atau telah dihapus.", + "primary_button": { + "text": "Lihat item kerja lainnya" + } + } + }, + "sibling": { + "label": "Item kerja sejawat" + }, + "archive": { + "description": "Hanya item kerja yang selesai atau dibatalkan\n yang dapat diarsipkan", + "label": "Arsip Item kerja", + "confirm_message": "Apakah Anda yakin ingin mengarsipkan item kerja ini? Semua item kerja yang diarsipkan dapat dipulihkan nanti.", + "success": { + "label": "Sukses mengarsipkan", + "message": "Arsip Anda dapat ditemukan di arsip proyek." + }, + "failed": { + "message": "Item kerja tidak dapat diarsipkan. Silakan coba lagi." + } + }, + "restore": { + "success": { + "title": "Sukses memulihkan", + "message": "Item kerja Anda dapat ditemukan di item kerja proyek." + }, + "failed": { + "message": "Item kerja tidak dapat dipulihkan. Silakan coba lagi." + } + }, + "relation": { + "relates_to": "Berhubungan dengan", + "duplicate": "Duplikat dari", + "blocked_by": "Diblokir oleh", + "blocking": "Memblokir" + }, + "copy_link": "Salin tautan item kerja", + "delete": { + "label": "Hapus item kerja", + "error": "Kesalahan saat menghapus item kerja" + }, + "subscription": { + "actions": { + "subscribed": "Item kerja telah berhasil disubscribe", + "unsubscribed": "Item kerja telah berhasil dibatalkan subscribe" + } + }, + "select": { + "error": "Silakan pilih setidaknya satu item kerja", + "empty": "Tidak ada item kerja yang dipilih", + "add_selected": "Tambah item kerja yang dipilih" + }, + "open_in_full_screen": "Buka item kerja dalam layar penuh" + }, + + "attachment": { + "error": "File tidak dapat dilampirkan. Coba unggah lagi.", + "only_one_file_allowed": "Hanya satu file yang dapat diunggah pada satu waktu.", + "file_size_limit": "File harus berukuran {size}MB atau lebih kecil.", + "drag_and_drop": "Seret dan jatuhkan di mana saja untuk mengunggah", + "delete": "Hapus lampiran" + }, + + "label": { + "select": "Pilih label", + "create": { + "success": "Label berhasil dibuat", + "failed": "Gagal membuat label", + "already_exists": "Label sudah ada", + "type": "Ketik untuk menambah label baru" + } + }, + + "sub_work_item": { + "update": { + "success": "Sub-item kerja berhasil diperbarui", + "error": "Kesalahan saat memperbarui sub-item kerja" + }, + "remove": { + "success": "Sub-item kerja berhasil dihapus", + "error": "Kesalahan saat menghapus sub-item kerja" + } + }, + + "view": { + "label": "{count, plural, one {Tampilan} other {Tampilan}}", + "create": { + "label": "Buat Tampilan" + }, + "update": { + "label": "Perbarui Tampilan" + } + }, + + "inbox_issue": { + "status": { + "pending": { + "title": "Menunggu", + "description": "Menunggu" + }, + "declined": { + "title": "Ditolak", + "description": "Ditolak" + }, + "snoozed": { + "title": "Ditunda", + "description": "{days, plural, one{# hari} other{# hari}} tersisa" + }, + "accepted": { + "title": "Diterima", + "description": "Diterima" + }, + "duplicate": { + "title": "Duplikat", + "description": "Duplikat" + } + }, + "modals": { + "decline": { + "title": "Tolak item kerja", + "content": "Apakah Anda yakin ingin menolak item kerja {value}?" + }, + "delete": { + "title": "Hapus item kerja", + "content": "Apakah Anda yakin ingin menghapus item kerja {value}?", + "success": "Item kerja berhasil dihapus" + } + }, + "errors": { + "snooze_permission": "Hanya admin proyek yang bisa menunda/menghapus penundaan item kerja", + "accept_permission": "Hanya admin proyek yang bisa menerima item kerja", + "decline_permission": "Hanya admin proyek yang bisa menolak item kerja" + }, + "actions": { + "accept": "Terima", + "decline": "Tolak", + "snooze": "Tunda", + "unsnooze": "Hapus penundaan", + "copy": "Salin tautan item kerja", + "delete": "Hapus", + "open": "Buka item kerja", + "mark_as_duplicate": "Tandai sebagai duplikat", + "move": "Pindahkan {value} ke item kerja proyek" + }, + "source": { + "in-app": "dalam aplikasi" + }, + "order_by": { + "created_at": "Dibuat pada", + "updated_at": "Diperbarui pada", + "id": "ID" + }, + "label": "Pendapat", + "page_label": "{workspace} - Pendapat", + "modal": { + "title": "Buat item kerja pendapat" + }, + "tabs": { + "open": "Terbuka", + "closed": "Tutup" + }, + "empty_state": { + "sidebar_open_tab": { + "title": "Tidak ada item kerja terbuka", + "description": "Temukan item kerja terbuka di sini. Buat item kerja baru." + }, + "sidebar_closed_tab": { + "title": "Tidak ada item kerja tertutup", + "description": "Semua item kerja yang diterima atau ditolak dapat ditemukan di sini." + }, + "sidebar_filter": { + "title": "Tidak ada item kerja yang cocok", + "description": "Tidak ada item kerja yang cocok dengan filter yang diterapkan dalam pendapat. Buat item kerja baru." + }, + "detail": { + "title": "Pilih item kerja untuk melihat detailnya." + } + } + }, + + "workspace_creation": { + "heading": "Buat ruang kerja Anda", + "subheading": "Untuk mulai menggunakan Plane, Anda perlu membuat atau bergabung dengan ruang kerja.", + "form": { + "name": { + "label": "Nama ruang kerja Anda", + "placeholder": "Sesuatu yang familiar dan dapat dikenali selalu lebih baik." + }, + "url": { + "label": "Atur URL ruang kerja Anda", + "placeholder": "Ketik atau tempel URL", + "edit_slug": "Anda hanya dapat mengedit slug URL" + }, + "organization_size": { + "label": "Berapa banyak orang yang akan menggunakan ruang kerja ini?", + "placeholder": "Pilih rentang" + } + }, + "errors": { + "creation_disabled": { + "title": "Hanya admin instansi Anda yang dapat membuat ruang kerja", + "description": "Jika Anda tahu alamat email admin instansi Anda, klik tombol di bawah ini untuk menghubungi mereka.", + "request_button": "Minta admin instansi" + }, + "validation": { + "name_alphanumeric": "Nama ruang kerja hanya boleh berisi (' '), ('-'), ('_') dan karakter alfanumerik.", + "name_length": "Batasi nama Anda hingga 80 karakter.", + "url_alphanumeric": "URL hanya boleh berisi ('-') dan karakter alfanumerik.", + "url_length": "Batasi URL Anda hingga 48 karakter.", + "url_already_taken": "URL ruang kerja sudah diambil!" + } + }, + "request_email": { + "subject": "Meminta ruang kerja baru", + "body": "Hai admin instansi,\n\nTolong buat ruang kerja baru dengan URL [/workspace-name] untuk [tujuan pembuatan ruang kerja].\n\nTerima kasih,\n{firstName} {lastName}\n{email}" + }, + "button": { + "default": "Buat ruang kerja", + "loading": "Membuat ruang kerja" + }, + "toast": { + "success": { + "title": "Sukses", + "message": "Ruang kerja berhasil dibuat" + }, + "error": { + "title": "Kesalahan", + "message": "Ruang kerja tidak dapat dibuat. Silakan coba lagi." + } + } + }, + + "workspace_dashboard": { + "empty_state": { + "general": { + "title": "Ikhtisar proyek, aktivitas, dan metrik Anda", + "description": "Selamat datang di Plane, kami sangat senang memiliki Anda di sini. Buat proyek pertama Anda dan lacak item kerja Anda, dan halaman ini akan berubah menjadi ruang yang membantu Anda berkembang. Admin juga akan melihat item yang membantu tim mereka berkembang.", + "primary_button": { + "text": "Bangun proyek pertama Anda", + "comic": { + "title": "Segalanya dimulai dengan proyek di Plane", + "description": "Sebuah proyek bisa menjadi roadmap produk, kampanye pemasaran, atau meluncurkan mobil baru." + } + } + } + } + }, + + "workspace_analytics": { + "label": "Analitik", + "page_label": "{workspace} - Analitik", + "open_tasks": "Jumlah tugas terbuka", + "error": "Terjadi kesalahan dalam mengambil data.", + "work_items_closed_in": "Item kerja yang ditutup dalam", + "selected_projects": "Proyek yang dipilih", + "total_members": "Jumlah anggota total", + "total_cycles": "Jumlah siklus total", + "total_modules": "Jumlah modul total", + "pending_work_items": { + "title": "Item kerja yang menunggu", + "empty_state": "Analisis item kerja yang menunggu oleh rekan kerja muncul di sini." + }, + "work_items_closed_in_a_year": { + "title": "Item kerja yang ditutup dalam setahun", + "empty_state": "Tutup item kerja untuk melihat analisis dari item kerja tersebut dalam bentuk grafik." + }, + "most_work_items_created": { + "title": "Paling banyak item kerja yang dibuat", + "empty_state": "Rekan kerja dan jumlah item kerja yang mereka buat muncul di sini." + }, + "most_work_items_closed": { + "title": "Paling banyak item kerja yang ditutup", + "empty_state": "Rekan kerja dan jumlah item kerja yang mereka tutup muncul di sini." + }, + "tabs": { + "scope_and_demand": "Lingkup dan Permintaan", + "custom": "Analitik Kustom" + }, + "empty_state": { + "general": { + "title": "Lacak kemajuan, beban kerja, dan alokasi. Temukan tren, hilangkan penghalang, dan percepat pekerjaan", + "description": "Lihat lingkup dibandingkan permintaan, perkiraan, dan lingkup cree. Dapatkan kinerja oleh anggota tim dan tim, dan pastikan proyek Anda berjalan tepat waktu.", + "primary_button": { + "text": "Mulai proyek pertama Anda", + "comic": { + "title": "Analitik bekerja terbaik dengan Siklus + Modul", + "description": "Pertama, bagi item kerja Anda ke dalam Siklus dan, jika memungkinkan, kelompokkan item kerja yang menjangkau lebih dari satu siklus ke dalam Modul. Lihat kedua fungsi pada navigasi kiri." + } + } + } + } + }, + + "workspace_projects": { + "label": "{count, plural, one {Proyek} other {Proyek}}", + "create": { + "label": "Tambah Proyek" + }, + "network": { + "label": "Jaringan", + "private": { + "title": "Pribadi", + "description": "Dapat diakses hanya dengan undangan" + }, + "public": { + "title": "Umum", + "description": "Siapa pun di ruang kerja kecuali Tamu dapat bergabung" + } + }, + "error": { + "permission": "Anda tidak memiliki izin untuk melakukan tindakan ini.", + "cycle_delete": "Gagal menghapus siklus", + "module_delete": "Gagal menghapus modul", + "issue_delete": "Gagal menghapus item kerja" + }, + "state": { + "backlog": "Backlog", + "unstarted": "Belum dimulai", + "started": "Dimulai", + "completed": "Selesai", + "cancelled": "Dibatalkan" + }, + "sort": { + "manual": "Manual", + "name": "Nama", + "created_at": "Tanggal dibuat", + "members_length": "Jumlah anggota" + }, + "scope": { + "my_projects": "Proyek saya", + "archived_projects": "Diarsipkan" + }, + "common": { + "months_count": "{months, plural, one{# bulan} other{# bulan}}" + }, + "empty_state": { + "general": { + "title": "Tidak ada proyek aktif", + "description": "Anggap setiap proyek sebagai induk untuk pekerjaan yang terarah pada tujuan. Proyek adalah tempat di mana Pekerjaan, Siklus, dan Modul tinggal dan, bersama rekan-rekan Anda, membantu Anda mencapai tujuan tersebut. Buat proyek baru atau filter untuk proyek yang diarsipkan.", + "primary_button": { + "text": "Mulai proyek pertama Anda", + "comic": { + "title": "Segalanya dimulai dengan proyek di Plane", + "description": "Sebuah proyek bisa menjadi roadmap produk, kampanye pemasaran, atau meluncurkan mobil baru." + } + } + }, + "no_projects": { + "title": "Tidak ada proyek", + "description": "Untuk membuat item kerja atau mengelola pekerjaan Anda, Anda perlu membuat proyek atau menjadi bagian dari salah satunya.", + "primary_button": { + "text": "Mulai proyek pertama Anda", + "comic": { + "title": "Segalanya dimulai dengan proyek di Plane", + "description": "Sebuah proyek bisa menjadi roadmap produk, kampanye pemasaran, atau meluncurkan mobil baru." + } + } + }, + "filter": { + "title": "Tidak ada proyek yang cocok", + "description": "Tidak ada proyek yang terdeteksi dengan kriteria yang cocok. \n Buat proyek baru sebagai gantinya." + }, + "search": { + "description": "Tidak ada proyek yang terdeteksi dengan kriteria yang cocok.\nBuat proyek baru sebagai gantinya" + } + } + }, + + "workspace_views": { + "add_view": "Tambah tampilan", + "empty_state": { + "all-issues": { + "title": "Tidak ada item kerja dalam proyek", + "description": "Proyek pertama sudah selesai! Sekarang, bagi pekerjaan Anda menjadi bagian yang dapat dilacak dengan item kerja. Mari kita mulai!", + "primary_button": { + "text": "Buat item kerja baru" + } + }, + "assigned": { + "title": "Belum ada item kerja", + "description": "Item kerja yang ditugaskan kepada Anda dapat dilacak dari sini.", + "primary_button": { + "text": "Buat item kerja baru" + } + }, + "created": { + "title": "Belum ada item kerja", + "description": "Semua item kerja yang dibuat oleh Anda akan muncul di sini, lacak mereka langsung di sini.", + "primary_button": { + "text": "Buat item kerja baru" + } + }, + "subscribed": { + "title": "Belum ada item kerja", + "description": "Langgan item kerja yang Anda minati, lacak semuanya di sini." + }, + "custom-view": { + "title": "Belum ada item kerja", + "description": "Item kerja yang menerapkan filter ini, lacak semuanya di sini." + } + } + }, + + "workspace_settings": { + "label": "Pengaturan ruang kerja", + "page_label": "{workspace} - Pengaturan Umum", + "key_created": "Kunci dibuat", + "copy_key": "Salin dan simpan kunci rahasia ini di Halaman Plane. Anda tidak dapat melihat kunci ini setelah Anda menekan Tutup. File CSV yang berisi kunci telah diunduh.", + "token_copied": "Token disalin ke clipboard.", + "settings": { + "general": { + "title": "Umum", + "upload_logo": "Unggah logo", + "edit_logo": "Edit logo", + "name": "Nama ruang kerja", + "company_size": "Ukuran perusahaan", + "url": "URL ruang kerja", + "update_workspace": "Perbarui ruang kerja", + "delete_workspace": "Hapus ruang kerja ini", + "delete_workspace_description": "Ketika menghapus ruang kerja, semua data dan sumber daya di dalam ruang kerja tersebut akan dihapus secara permanen dan tidak dapat dipulihkan.", + "delete_btn": "Hapus ruang kerja ini", + "delete_modal": { + "title": "Apakah Anda yakin ingin menghapus ruang kerja ini?", + "description": "Anda memiliki percobaan aktif untuk salah satu rencana berbayar kami. Silakan batalkan terlebih dahulu untuk melanjutkan.", + "dismiss": "Tutup", + "cancel": "Batalkan percobaan", + "success_title": "Ruang kerja dihapus.", + "success_message": "Anda akan segera diarahkan ke halaman profil Anda.", + "error_title": "Itu tidak berhasil.", + "error_message": "Silakan coba lagi." + }, + "errors": { + "name": { + "required": "Nama diperlukan", + "max_length": "Nama ruang kerja tidak boleh lebih dari 80 karakter" + }, + "company_size": { + "required": "Ukuran perusahaan diperlukan", + "select_a_range": "Pilih ukuran organisasi" + } + } + }, + "members": { + "title": "Anggota", + "add_member": "Tambah anggota", + "pending_invites": "Undangan yang tertunda", + "invitations_sent_successfully": "Undangan berhasil dikirim", + "leave_confirmation": "Apakah Anda yakin ingin meninggalkan ruang kerja? Anda tidak akan lagi memiliki akses ke ruang kerja ini. Tindakan ini tidak dapat dibatalkan.", + "details": { + "full_name": "Nama lengkap", + "display_name": "Nama tampilan", + "email_address": "Alamat email", + "account_type": "Tipe akun", + "authentication": "Autentikasi", + "joining_date": "Tanggal bergabung" + }, + "modal": { + "title": "Undang orang untuk berkolaborasi", + "description": "Undang orang untuk berkolaborasi di ruang kerja Anda.", + "button": "Kirim undangan", + "button_loading": "Mengirim undangan", + "placeholder": "name@company.com", + "errors": { + "required": "Kami perlu alamat email untuk mengundang mereka.", + "invalid": "Email tidak valid" + } + } + }, + "billing_and_plans": { + "title": "Penagihan & Rencana", + "current_plan": "Rencana saat ini", + "free_plan": "Anda saat ini menggunakan rencana gratis", + "view_plans": "Lihat rencana" + }, + "exports": { + "title": "Ekspor", + "exporting": "Mengeskpor", + "previous_exports": "Ekspor sebelumnya", + "export_separate_files": "Ekspor data ke file terpisah", + "modal": { + "title": "Ekspor ke", + "toasts": { + "success": { + "title": "Ekspor berhasil", + "message": "Anda akan dapat mengunduh {entity} yang diekspor dari ekspor sebelumnya." + }, + "error": { + "title": "Ekspor gagal", + "message": "Ekspor tidak berhasil. Silakan coba lagi." + } + } + } + }, + "webhooks": { + "title": "Webhook", + "add_webhook": "Tambah webhook", + "modal": { + "title": "Buat webhook", + "details": "Detail webhook", + "payload": "Payload URL", + "question": "Peristiwa apa yang ingin Anda picu untuk webhook ini?", + "error": "URL diperlukan" + }, + "secret_key": { + "title": "Kunci rahasia", + "message": "Hasilkan token untuk masuk ke payload webhook" + }, + "options": { + "all": "Kirim saya semuanya", + "individual": "Pilih peristiwa individu" + }, + "toasts": { + "created": { + "title": "Webhook dibuat", + "message": "Webhook telah berhasil dibuat" + }, + "not_created": { + "title": "Webhook tidak dibuat", + "message": "Webhook tidak dapat dibuat" + }, + "updated": { + "title": "Webhook diperbarui", + "message": "Webhook telah berhasil diperbarui" + }, + "not_updated": { + "title": "Webhook tidak diperbarui", + "message": "Webhook tidak dapat diperbarui" + }, + "removed": { + "title": "Webhook dihapus", + "message": "Webhook telah berhasil dihapus" + }, + "not_removed": { + "title": "Webhook tidak dihapus", + "message": "Webhook tidak dapat dihapus" + }, + "secret_key_copied": { + "message": "Kunci rahasia disalin ke clipboard." + }, + "secret_key_not_copied": { + "message": "Terjadi kesalahan saat menyalin kunci rahasia." + } + } + }, + "api_tokens": { + "title": "Token API", + "add_token": "Tambah token API", + "create_token": "Buat token", + "never_expires": "Tidak pernah kedaluwarsa", + "generate_token": "Hasilkan token", + "generating": "Menghasilkan", + "delete": { + "title": "Hapus token API", + "description": "Setiap aplikasi yang menggunakan token ini tidak akan memiliki akses ke data Plane. Tindakan ini tidak dapat dibatalkan.", + "success": { + "title": "Sukses!", + "message": "Token API telah berhasil dihapus" + }, + "error": { + "title": "Kesalahan!", + "message": "Token API tidak dapat dihapus" + } + } + } + }, + "empty_state": { + "api_tokens": { + "title": "Belum ada token API yang dibuat", + "description": "API Plane dapat digunakan untuk mengintegrasikan data Anda di Plane dengan sistem eksternal mana pun. Buat token untuk memulai." + }, + "webhooks": { + "title": "Belum ada webhook yang ditambahkan", + "description": "Buat webhook untuk menerima pembaruan waktu nyata dan mengotomatiskan tindakan." + }, + "exports": { + "title": "Belum ada ekspor", + "description": "Setiap kali Anda mengekspor, Anda juga akan memiliki salinan di sini untuk referensi." + }, + "imports": { + "title": "Belum ada impor", + "description": "Temukan semua impor Anda sebelumnya di sini dan unduh." + } + } + }, + + "profile": { + "label": "Profil", + "page_label": "Pekerjaan Anda", + "work": "Pekerjaan", + "details": { + "joined_on": "Bergabung pada", + "time_zone": "Zona waktu" + }, + "stats": { + "workload": "Beban kerja", + "overview": "Ikhtisar", + "created": "Item kerja yang dibuat", + "assigned": "Item kerja yang ditugaskan", + "subscribed": "Item kerja yang disubscribe", + "state_distribution": { + "title": "Item kerja berdasarkan status", + "empty": "Buat item kerja untuk melihatnya berdasarkan status dalam grafik untuk analisis yang lebih baik." + }, + "priority_distribution": { + "title": "Item kerja berdasarkan Prioritas", + "empty": "Buat item kerja untuk melihatnya berdasarkan prioritas dalam grafik untuk analisis yang lebih baik." + }, + "recent_activity": { + "title": "Aktivitas terkini", + "empty": "Kami tidak dapat menemukan data. Silakan lihat input Anda", + "button": "Unduh aktivitas hari ini", + "button_loading": "Mengunduh" + } + }, + "actions": { + "profile": "Profil", + "security": "Keamanan", + "activity": "Aktivitas", + "appearance": "Tampilan", + "notifications": "Notifikasi" + }, + "tabs": { + "summary": "Ringkasan", + "assigned": "Ditugaskan", + "created": "Dibuat", + "subscribed": "Disubscribe", + "activity": "Aktivitas" + }, + "empty_state": { + "activity": { + "title": "Belum ada aktivitas", + "description": "Mulai dengan membuat item kerja baru! Tambahkan detail dan properti. Jelajahi lebih lanjut di Plane untuk melihat aktivitas Anda." + }, + "assigned": { + "title": "Tidak ada item kerja yang ditugaskan kepada Anda", + "description": "Item kerja yang ditugaskan kepada Anda dapat dilacak dari sini." + }, + "created": { + "title": "Belum ada item kerja", + "description": "Semua item kerja yang dibuat oleh Anda hadir di sini, dan lacak langsung di sini." + }, + "subscribed": { + "title": "Belum ada item kerja", + "description": "Langganan item kerja yang Anda minati, lacak semuanya di sini." + } + } + }, + + "project_settings": { + "general": { + "enter_project_id": "Masukkan ID proyek", + "please_select_a_timezone": "Silakan pilih zona waktu", + "archive_project": { + "title": "Arsipkan proyek", + "description": "Mengarsipkan proyek akan menghapus proyek Anda dari navigasi samping meskipun Anda masih dapat mengaksesnya dari halaman proyek Anda. Anda dapat memulihkan proyek tersebut atau menghapusnya kapan saja.", + "button": "Arsipkan proyek" + }, + "delete_project": { + "title": "Hapus proyek", + "description": "Ketika menghapus proyek, semua data dan sumber daya di dalam proyek tersebut akan dihapus secara permanen dan tidak dapat dipulihkan.", + "button": "Hapus proyek saya" + }, + "toast": { + "success": "Proyek berhasil diperbarui", + "error": "Proyek tidak dapat diperbarui. Silakan coba lagi." + } + }, + "members": { + "label": "Anggota", + "project_lead": "Pemimpin proyek", + "default_assignee": "Penugas default", + "guest_super_permissions": { + "title": "Beri akses tampilan untuk semua item kerja untuk pengguna tamu:", + "sub_heading": "Ini akan memungkinkan tamu untuk memiliki akses tampilan ke semua item kerja proyek." + }, + "invite_members": { + "title": "Undang anggota", + "sub_heading": "Undang anggota untuk bekerja di proyek Anda.", + "select_co_worker": "Pilih rekan kerja" + } + }, + "states": { + "describe_this_state_for_your_members": "Jelaskan status ini untuk anggota Anda.", + "empty_state": { + "title": "Tidak ada status yang tersedia untuk grup {groupKey}", + "description": "Silakan buat status baru" + } + }, + "labels": { + "label_title": "Judul label", + "label_title_is_required": "Judul label diperlukan", + "label_max_char": "Nama label tidak boleh lebih dari 255 karakter", + "toast": { + "error": "Kesalahan saat memperbarui label" + } + }, + "estimates": { + "title": "Aktifkan estimasi untuk proyek saya", + "description": "Mereka membantu Anda dalam mengkomunikasikan kompleksitas dan beban kerja tim." + }, + "automations": { + "label": "Otomatisasi", + "auto-archive": { + "title": "Otomatis mengarsipkan item kerja yang ditutup", + "description": "Plane akan otomatis mengarsipkan item kerja yang telah diselesaikan atau dibatalkan.", + "duration": "Otomatis mengarsipkan item kerja yang ditutup untuk" + }, + "auto-close": { + "title": "Otomatis menutup item kerja", + "description": "Plane akan secara otomatis menutup item kerja yang belum diselesaikan atau dibatalkan.", + "duration": "Otomatis menutup item kerja yang tidak aktif selama", + "auto_close_status": "Status otomatis tutup" + } + }, + + "empty_state": { + "labels": { + "title": "Belum ada label", + "description": "Buat label untuk membantu mengorganisir dan memfilter item kerja dalam proyek Anda." + }, + "estimates": { + "title": "Belum ada sistem estimasi", + "description": "Buat seperangkat estimasi untuk mengkomunikasikan jumlah pekerjaan per item kerja.", + "primary_button": "Tambah sistem estimasi" + } + } + }, + + "project_cycles": { + "add_cycle": "Tambah siklus", + "more_details": "Detail lebih lanjut", + "cycle": "Siklus", + "update_cycle": "Perbarui siklus", + "create_cycle": "Buat siklus", + "no_matching_cycles": "Tidak ada siklus yang cocok", + "remove_filters_to_see_all_cycles": "Hapus filter untuk melihat semua siklus", + "remove_search_criteria_to_see_all_cycles": "Hapus kriteria pencarian untuk melihat semua siklus", + "only_completed_cycles_can_be_archived": "Hanya siklus yang diselesaikan yang dapat diarsipkan", + "active_cycle": { + "label": "Siklus aktif", + "progress": "Kemajuan", + "chart": "Grafik burndown", + "priority_issue": "Item kerja prioritas", + "assignees": "Penugasan", + "issue_burndown": "Burndown item kerja", + "ideal": "Ideal", + "current": "Sekarang", + "labels": "Label" + }, + "upcoming_cycle": { + "label": "Siklus mendatang" + }, + "completed_cycle": { + "label": "Siklus selesai" + }, + "status": { + "days_left": "Hari tersisa", + "completed": "Selesai", + "yet_to_start": "Belum dimulai", + "in_progress": "Sedang berlangsung", + "draft": "Draf" + }, + "action": { + "restore": { + "title": "Pulihkan siklus", + "success": { + "title": "Siklus dipulihkan", + "description": "Siklus telah dipulihkan." + }, + "failed": { + "title": "Pemulihan siklus gagal", + "description": "Siklus tidak dapat dipulihkan. Silakan coba lagi." + } + }, + "favorite": { + "loading": "Menambahkan siklus ke favorit", + "success": { + "description": "Siklus ditambahkan ke favorit.", + "title": "Sukses!" + }, + "failed": { + "description": "Gagal menambahkan siklus ke favorit. Silakan coba lagi.", + "title": "Kesalahan!" + } + }, + "unfavorite": { + "loading": "Menghapus siklus dari favorit", + "success": { + "description": "Siklus dihapus dari favorit.", + "title": "Sukses!" + }, + "failed": { + "description": "Gagal menghapus siklus dari favorit. Silakan coba lagi.", + "title": "Kesalahan!" + } + }, + "update": { + "loading": "Memperbarui siklus", + "success": { + "description": "Siklus berhasil diperbarui.", + "title": "Sukses!" + }, + "failed": { + "description": "Kesalahan saat memperbarui siklus. Silakan coba lagi.", + "title": "Kesalahan!" + }, + "error": { + "already_exists": "Anda sudah memiliki siklus pada tanggal yang diberikan, jika Anda ingin membuat siklus draf, Anda dapat melakukannya dengan menghapus kedua tanggal tersebut." + } + } + }, + "empty_state": { + "general": { + "title": "Kelompokkan dan bagi pekerjaan Anda dalam Siklus.", + "description": "Pecah pekerjaan menjadi bagian yang dibatasi waktu, kerjakan mundur dari tenggat waktu proyek Anda untuk menetapkan tanggal, dan buat kemajuan nyata sebagai tim.", + "primary_button": { + "text": "Tetapkan siklus pertama Anda", + "comic": { + "title": "Siklus adalah batas waktu berulang.", + "description": "Sprint, iterasi, dan istilah lain apa pun yang Anda gunakan untuk pelacakan pekerjaan mingguan atau dua mingguan adalah siklus." + } + } + }, + "no_issues": { + "title": "Tidak ada item kerja yang ditambahkan ke siklus", + "description": "Tambahkan atau buat item kerja yang ingin Anda batasi waktu dan kirim dalam siklus ini", + "primary_button": { + "text": "Buat item kerja baru" + }, + "secondary_button": { + "text": "Tambah item kerja yang ada" + } + }, + "completed_no_issues": { + "title": "Tidak ada item kerja dalam siklus", + "description": "Tidak ada item kerja dalam siklus. Item kerja baik ditransfer atau disembunyikan. Untuk melihat item kerja yang disembunyikan jika ada, perbarui properti tampilan Anda sesuai." + }, + "active": { + "title": "Tidak ada siklus aktif", + "description": "Siklus aktif mencakup periode apa pun yang mencakup tanggal hari ini dalam rentangnya. Temukan kemajuan dan detail siklus aktif di sini." + }, + "archived": { + "title": "Belum ada siklus yang diarsipkan", + "description": "Untuk membersihkan proyek Anda, arsipkan siklus yang telah diselesaikan. Temukan di sini setelah diarsipkan." + } + } + }, + + "project_issues": { + "empty_state": { + "no_issues": { + "title": "Buat item kerja dan tugaskan kepada seseorang, bahkan kepada diri Anda sendiri", + "description": "Anggap item kerja sebagai pekerjaan, tugas, atau JTBD. Yang kami suka. Item kerja dan sub-item kerjanya biasanya merupakan tindakan berbasis waktu yang ditugaskan kepada anggota tim Anda. Tim Anda membuat, menetapkan, dan menyelesaikan item kerja untuk memindahkan proyek Anda menuju tujuannya.", + "primary_button": { + "text": "Buat item kerja pertama Anda", + "comic": { + "title": "Item kerja adalah blok bangunan di Plane.", + "description": "Mendesain ulang UI Plane, Mengganti merek perusahaan, atau Meluncurkan sistem injeksi bahan bakar baru adalah contoh item kerja yang kemungkinan besar memiliki sub-item kerja." + } + } + }, + "no_archived_issues": { + "title": "Belum ada item kerja yang diarsipkan", + "description": "Secara manual atau melalui otomatisasi, Anda dapat mengarsipkan item kerja yang telah selesai atau dibatalkan. Temukan di sini setelah diarsipkan.", + "primary_button": { + "text": "Tetapkan otomatisasi" + } + }, + "issues_empty_filter": { + "title": "Tidak ada item kerja ditemukan yang cocok dengan filter yang diterapkan", + "secondary_button": { + "text": "Bersihkan semua filter" + } + } + } + }, + + "project_module": { + "add_module": "Tambah Modul", + "update_module": "Perbarui Modul", + "create_module": "Buat Modul", + "archive_module": "Arsipkan Modul", + "restore_module": "Pulihkan Modul", + "delete_module": "Hapus modul", + "empty_state": { + "general": { + "title": "Peta tonggak proyek Anda ke Modul dan lacak pekerjaan terakumulasi dengan mudah.", + "description": "Sekelompok item kerja yang tergolong dalam induk yang logis dan hierarkis membentuk satu modul. Anggap saja mereka sebagai cara untuk melacak pekerjaan berdasarkan tonggak proyek. Mereka memiliki periode dan tenggat waktu sendiri serta analitik untuk membantu Anda melihat seberapa dekat atau jauh Anda dari tonggak tersebut.", + "primary_button": { + "text": "Buat modul pertama Anda", + "comic": { + "title": "Modul membantu mengelompokkan pekerjaan menurut hierarki.", + "description": "Modul kereta, modul sasis, dan modul gudang adalah contoh bagus dari pengelompokan ini." + } + } + }, + "no_issues": { + "title": "Tidak ada item kerja dalam modul", + "description": "Buat atau tambahkan item kerja yang ingin Anda capai sebagai bagian dari modul ini", + "primary_button": { + "text": "Buat item kerja baru" + }, + "secondary_button": { + "text": "Tambahkan item kerja yang ada" + } + }, + "archived": { + "title": "Belum ada Modul yang diarsipkan", + "description": "Untuk membersihkan proyek Anda, arsipkan modul yang telah selesai atau dibatalkan. Temukan di sini setelah diarsipkan." + }, + "sidebar": { + "in_active": "Modul ini belum aktif.", + "invalid_date": "Tanggal tidak valid. Silakan masukkan tanggal yang valid." + } + }, + "quick_actions": { + "archive_module": "Arsipkan modul", + "archive_module_description": "Hanya modul yang telah diselesaikan atau dibatalkan\n yang dapat diarsipkan.", + "delete_module": "Hapus modul" + }, + "toast": { + "copy": { + "success": "Tautan modul disalin ke clipboard" + }, + "delete": { + "success": "Modul berhasil dihapus", + "error": "Gagal menghapus modul" + } + } + }, + + "project_views": { + "empty_state": { + "general": { + "title": "Simpan tampilan yang difilter untuk proyek Anda. Buat sebanyak yang Anda perlukan", + "description": "Tampilan adalah sekumpulan filter yang disimpan yang Anda gunakan secara sering atau ingin akses mudah. Semua rekan Anda dalam proyek dapat melihat tampilan semua orang dan memilih yang paling sesuai dengan kebutuhan mereka.", + "primary_button": { + "text": "Buat tampilan pertama Anda", + "comic": { + "title": "Tampilan bekerja berdasarkan properti item kerja.", + "description": "Anda dapat membuat tampilan dari sini dengan sebanyak mungkin properti sebagai filter yang Anda anggap sesuai." + } + } + }, + "filter": { + "title": "Tidak ada tampilan yang cocok", + "description": "Tidak ada tampilan yang cocok dengan kriteria pencarian. \n Buat tampilan baru sebagai gantinya." + } + } + }, + + "project_page": { + "empty_state": { + "general": { + "title": "Tulis catatan, dokumen, atau seluruh basis pengetahuan. Dapatkan Galileo, asisten AI Plane, untuk membantu Anda memulai", + "description": "Halaman adalah ruang pemikiran di Plane. Catat notul rapat, format dengan mudah, sertakan item kerja, tata letak menggunakan perpustakaan komponen, dan simpan semua di dalam konteks proyek Anda. Untuk menyelesaikan dokumen dengan cepat, panggil Galileo, AI Plane, dengan pintasan atau dengan mengklik tombol.", + "primary_button": { + "text": "Buat halaman pertama Anda" + } + }, + "private": { + "title": "Belum ada halaman pribadi", + "description": "Simpan pemikiran pribadi Anda di sini. Ketika Anda sudah siap untuk berbagi, tim hanya seklik jarak.", + "primary_button": { + "text": "Buat halaman pertama Anda" + } + }, + "public": { + "title": "Belum ada halaman publik", + "description": "Lihat halaman yang dibagikan dengan semua orang di proyek Anda tepat di sini.", + "primary_button": { + "text": "Buat halaman pertama Anda" + } + }, + "archived": { + "title": "Belum ada halaman yang diarsipkan", + "description": "Arsipkan halaman yang tidak ada dalam radar Anda. Akses di sini saat diperlukan." + } + } + }, + + "command_k": { + "empty_state": { + "search": { + "title": "Tidak ada hasil ditemukan" + } + } + }, + + "issue_relation": { + "empty_state": { + "search": { + "title": "Tidak ada item kerja yang cocok ditemukan" + }, + "no_issues": { + "title": "Tidak ada item kerja ditemukan" + } + } + }, + + "issue_comment": { + "empty_state": { + "general": { + "title": "Belum ada komentar", + "description": "Komentar dapat digunakan sebagai ruang diskusi dan tindak lanjut untuk item kerja" + } + } + }, + + "notification": { + "label": "Kotak Masuk", + "page_label": "{workspace} - Kotak Masuk", + "options": { + "mark_all_as_read": "Tandai semua sebagai dibaca", + "mark_read": "Tandai sebagai dibaca", + "mark_unread": "Tandai sebagai tidak dibaca", + "refresh": "Segarkan", + "filters": "Filter Kotak Masuk", + "show_unread": "Tampilkan yang belum dibaca", + "show_snoozed": "Tampilkan yang ditunda", + "show_archived": "Tampilkan yang diarsipkan", + "mark_archive": "Arsipkan", + "mark_unarchive": "Hapus arsip", + "mark_snooze": "Tunda", + "mark_unsnooze": "Hapus tunda" + }, + "toasts": { + "read": "Notifikasi ditandai sebagai dibaca", + "unread": "Notifikasi ditandai sebagai tidak dibaca", + "archived": "Notifikasi ditandai sebagai diarsipkan", + "unarchived": "Notifikasi ditandai sebagai dihapus arsip", + "snoozed": "Notifikasi ditunda", + "unsnoozed": "Notifikasi dihapus tunda" + }, + "empty_state": { + "detail": { + "title": "Pilih untuk melihat detail." + }, + "all": { + "title": "Tidak ada item kerja yang ditugaskan", + "description": "Pembaruan untuk item kerja yang ditugaskan kepada Anda dapat dilihat di sini" + }, + "mentions": { + "title": "Tidak ada item kerja yang ditugaskan", + "description": "Pembaruan untuk item kerja yang ditugaskan kepada Anda dapat dilihat di sini" + } + }, + "tabs": { + "all": "Semua", + "mentions": "Sebut" + }, + "filter": { + "assigned": "Ditugaskan untuk saya", + "created": "Dibuat oleh saya", + "subscribed": "Disubscribe oleh saya" + }, + "snooze": { + "1_day": "1 hari", + "3_days": "3 hari", + "5_days": "5 hari", + "1_week": "1 minggu", + "2_weeks": "2 minggu", + "custom": "Kustom" + } + }, + + "active_cycle": { + "empty_state": { + "progress": { + "title": "Tambahkan item kerja ke siklus untuk melihat kemajuannya" + }, + "chart": { + "title": "Tambahkan item kerja ke siklus untuk melihat grafik burndown." + }, + "priority_issue": { + "title": "Amati item kerja prioritas yang ditangani dalam siklus pada pandangan pertama." + }, + "assignee": { + "title": "Tambahkan penugasan ke item kerja untuk melihat pembagian kerja berdasarkan penugasan." + }, + "label": { + "title": "Tambahkan label ke item kerja untuk melihat pembagian kerja berdasarkan label." + } + } + }, + + "disabled_project": { + "empty_state": { + "inbox": { + "title": "Intake tidak diaktifkan untuk proyek ini.", + "description": "Intake membantu Anda mengelola permintaan yang masuk ke proyek Anda dan menambahkannya sebagai item kerja dalam alur kerja Anda. Aktifkan intake dari pengaturan proyek untuk mengelola permintaan.", + "primary_button": { + "text": "Kelola fitur" + } + }, + "cycle": { + "title": "Siklus tidak diaktifkan untuk proyek ini.", + "description": "Pecah pekerjaan menjadi bagian yang dibatasi waktu, kerjakan mundur dari tenggat waktu proyek Anda untuk menetapkan tanggal, dan buat kemajuan nyata sebagai tim. Aktifkan fitur siklus untuk proyek Anda agar dapat mulai menggunakannya.", + "primary_button": { + "text": "Kelola fitur" + } + }, + "module": { + "title": "Modul tidak diaktifkan untuk proyek ini.", + "description": "Modul adalah blok bangunan dari proyek Anda. Aktifkan modul dari pengaturan proyek untuk mulai menggunakannya.", + "primary_button": { + "text": "Kelola fitur" + } + }, + "page": { + "title": "Halaman tidak diaktifkan untuk proyek ini.", + "description": "Halaman adalah blok bangunan dari proyek Anda. Aktifkan halaman dari pengaturan proyek untuk mulai menggunakannya.", + "primary_button": { + "text": "Kelola fitur" + } + }, + "view": { + "title": "Tampilan tidak diaktifkan untuk proyek ini.", + "description": "Tampilan adalah blok bangunan dari proyek Anda. Aktifkan tampilan dari pengaturan proyek untuk mulai menggunakannya.", + "primary_button": { + "text": "Kelola fitur" + } + } + } + }, + "workspace_draft_issues": { + "draft_an_issue": "Draf item kerja", + "empty_state": { + "title": "Item kerja setengah jadi, dan segera, komentar akan muncul di sini.", + "description": "Untuk mencoba ini, mulai dengan menambahkan item kerja dan tinggalkan di tengah jalan atau buat draf pertama Anda di bawah ini. 😉", + "primary_button": { + "text": "Buat draf pertama Anda" + } + }, + "delete_modal": { + "title": "Hapus draf", + "description": "Apakah Anda yakin ingin menghapus draf ini? Tindakan ini tidak dapat dibatalkan." + }, + "toasts": { + "created": { + "success": "Draf berhasil dibuat", + "error": "Item kerja tidak dapat dibuat. Silakan coba lagi." + }, + "deleted": { + "success": "Draf berhasil dihapus" + } + } + }, + + "stickies": { + "title": "Catatan tempel Anda", + "placeholder": "klik untuk mengetik di sini", + "all": "Semua catatan tempel", + "no-data": "Tuliskan sebuah ide, tangkap momen aha, atau catat pemikiran brilian. Tambahkan catatan tempel untuk memulai.", + "add": "Tambah catatan tempel", + "search_placeholder": "Cari berdasarkan judul", + "delete": "Hapus catatan tempel", + "delete_confirmation": "Apakah Anda yakin ingin menghapus catatan tempel ini?", + "empty_state": { + "simple": "Tuliskan sebuah ide, tangkap momen aha, atau catat pemikiran brilian. Tambahkan catatan tempel untuk memulai.", + "general": { + "title": "Catatan tempel adalah catatan cepat dan tugas yang Anda buat secara langsung.", + "description": "Tangkap pemikiran dan ide Anda dengan mudah dengan membuat catatan tempel yang dapat Anda akses kapan saja dan dari mana saja.", + "primary_button": { + "text": "Tambah catatan tempel" + } + }, + "search": { + "title": "Itu tidak cocok dengan salah satu catatan tempel Anda.", + "description": "Coba istilah yang berbeda atau beri tahu kami\njika Anda yakin pencarian Anda benar. ", + "primary_button": { + "text": "Tambah catatan tempel" + } + } + }, + "toasts": { + "errors": { + "wrong_name": "Nama catatan tempel tidak boleh lebih dari 100 karakter.", + "already_exists": "Sudah ada catatan tempel dengan tidak ada deskripsi" + }, + "created": { + "title": "Catatan tempel berhasil dibuat", + "message": "Catatan tempel telah berhasil dibuat" + }, + "not_created": { + "title": "Catatan tempel tidak dibuat", + "message": "Catatan tempel tidak dapat dibuat" + }, + "updated": { + "title": "Catatan tempel diperbarui", + "message": "Catatan tempel telah berhasil diperbarui" + }, + "not_updated": { + "title": "Catatan tempel tidak diperbarui", + "message": "Catatan tempel tidak dapat diperbarui" + }, + "removed": { + "title": "Catatan tempel dihapus", + "message": "Catatan tempel telah berhasil dihapus" + }, + "not_removed": { + "title": "Catatan tempel tidak dihapus", + "message": "Catatan tempel tidak dapat dihapus" + } + } + }, + + "role_details": { + "guest": { + "title": "Tamu", + "description": "Anggota eksternal organisasi dapat diundang sebagai tamu." + }, + "member": { + "title": "Anggota", + "description": "Kemampuan untuk membaca, menulis, mengedit, dan menghapus entitas di dalam proyek, siklus, dan modul" + }, + "admin": { + "title": "Admin", + "description": "Semua izin diatur ke true dalam ruang kerja." + } + }, + + "user_roles": { + "product_or_project_manager": "Manajer Produk / Proyek", + "development_or_engineering": "Pengembangan / Rekayasa", + "founder_or_executive": "Pendiri / Eksekutif", + "freelancer_or_consultant": "Freelancer / Konsultan", + "marketing_or_growth": "Pemasaran / Pertumbuhan", + "sales_or_business_development": "Penjualan / Pengembangan Bisnis", + "support_or_operations": "Dukungan / Operasi", + "student_or_professor": "Mahasiswa / Profesor", + "human_resources": "Sumber Daya Manusia", + "other": "Lainnya" + }, + + "importer": { + "github": { + "title": "Github", + "description": "Impor item kerja dari repositori GitHub dan sinkronkan." + }, + "jira": { + "title": "Jira", + "description": "Impor item kerja dan epik dari proyek dan epik Jira." + } + }, + + "exporter": { + "csv": { + "title": "CSV", + "description": "Ekspor item kerja ke file CSV.", + "short_description": "Ekspor sebagai csv" + }, + "excel": { + "title": "Excel", + "description": "Ekspor item kerja ke file Excel.", + "short_description": "Ekspor sebagai excel" + }, + "xlsx": { + "title": "Excel", + "description": "Ekspor item kerja ke file Excel.", + "short_description": "Ekspor sebagai excel" + }, + "json": { + "title": "JSON", + "description": "Ekspor item kerja ke file JSON.", + "short_description": "Ekspor sebagai json" + } + }, + "default_global_view": { + "all_issues": "Semua item kerja", + "assigned": "Ditugaskan", + "created": "Dibuat", + "subscribed": "Disubscribe" + }, + + "themes": { + "theme_options": { + "system_preference": { + "label": "Preferensi sistem" + }, + "light": { + "label": "Cerah" + }, + "dark": { + "label": "Gelap" + }, + "light_contrast": { + "label": "Cerah kontras tinggi" + }, + "dark_contrast": { + "label": "Gelap kontras tinggi" + }, + "custom": { + "label": "Tema kustom" + } + } + }, + "project_modules": { + "status": { + "backlog": "Backlog", + "planned": "Direncanakan", + "in_progress": "Dalam Proses", + "paused": "Dijeda", + "completed": "Selesai", + "cancelled": "Dibatalkan" + }, + "layout": { + "list": "Tata letak daftar", + "board": "Tata letak galeri", + "timeline": "Tata letak garis waktu" + }, + "order_by": { + "name": "Nama", + "progress": "Kemajuan", + "issues": "Jumlah item kerja", + "due_date": "Tanggal jatuh tempo", + "created_at": "Tanggal dibuat", + "manual": "Manual" + } + }, + + "cycle": { + "label": "{count, plural, one {Siklus} other {Siklus}}", + "no_cycle": "Tidak ada siklus" + }, + + "module": { + "label": "{count, plural, one {Modul} other {Modul}}", + "no_module": "Tidak ada modul" + } +} diff --git a/packages/i18n/src/locales/ro/translations.json b/packages/i18n/src/locales/ro/translations.json new file mode 100644 index 000000000..43ac9eb28 --- /dev/null +++ b/packages/i18n/src/locales/ro/translations.json @@ -0,0 +1,2371 @@ +{ + "sidebar": { + "projects": "Proiecte", + "pages": "Documentație", + "new_work_item": "Activitate nouă", + "home": "Acasă", + "your_work": "Munca ta", + "inbox": "Căsuță de mesaje", + "workspace": "Spațiu de lucru", + "views": "Perspective", + "analytics": "Statistici", + "work_items": "Activități", + "cycles": "Cicluri", + "modules": "Module", + "intake": "Cereri", + "drafts": "Schițe", + "favorites": "Favorite", + "pro": "Pro", + "upgrade": "Treci la versiunea superioară" + }, + + "auth": { + "common": { + "email": { + "label": "Email", + "placeholder": "nume@companie.ro", + "errors": { + "required": "Email-ul este obligatoriu", + "invalid": "Email-ul nu este valid" + } + }, + "password": { + "label": "Parolă", + "set_password": "Setează o parolă", + "placeholder": "Introdu parola", + "confirm_password": { + "label": "Confirmă parola", + "placeholder": "Confirmă parola" + }, + "current_password": { + "label": "Parola curentă" + }, + "new_password": { + "label": "Parolă nouă", + "placeholder": "Introdu parola nouă" + }, + "change_password": { + "label": { + "default": "Schimbă parola", + "submitting": "Se schimbă parola" + } + }, + "errors": { + "match": "Parolele nu se potrivesc", + "empty": "Te rugăm să introduci parola", + "length": "Parola trebuie să aibă mai mult de 8 caractere", + "strength": { + "weak": "Parola este slabă", + "strong": "Parola este puternică" + } + }, + "submit": "Setează parola", + "toast": { + "change_password": { + "success": { + "title": "Succes!", + "message": "Parola a fost schimbată cu succes." + }, + "error": { + "title": "Eroare!", + "message": "Ceva nu a funcționat. Te rugăm să încerci din nou." + } + } + } + }, + "unique_code": { + "label": "Cod unic", + "placeholder": "exemplu-cod-unic", + "paste_code": "Introdu codul trimis pe email", + "requesting_new_code": "Se solicită un cod nou", + "sending_code": "Se trimite codul" + }, + "already_have_an_account": "Ai deja un cont?", + "login": "Autentificare", + "create_account": "Creează un cont", + "new_to_plane": "Ești nou în Plane?", + "back_to_sign_in": "Înapoi la autentificare", + "resend_in": "Retrimite în {seconds} secunde", + "sign_in_with_unique_code": "Autentificare cu cod unic", + "forgot_password": "Ți-ai uitat parola?" + }, + "sign_up": { + "header": { + "label": "Creează un cont pentru a începe să-ți gestionezi activitatea împreună cu echipa ta.", + "step": { + "email": { + "header": "Înregistrare", + "sub_header": "" + }, + "password": { + "header": "Înregistrare", + "sub_header": "Înregistrează-te folosind o combinație email-parolă." + }, + "unique_code": { + "header": "Înregistrare", + "sub_header": "Înregistrează-te folosind un cod unic trimis pe adresa de email de mai sus." + } + } + }, + "errors": { + "password": { + "strength": "Setează o parolă puternică pentru a continua" + } + } + }, + "sign_in": { + "header": { + "label": "Autentifică-te pentru a începe să-ți gestionezi activitatea împreună cu echipa ta.", + "step": { + "email": { + "header": "Autentificare sau înregistrare", + "sub_header": "" + }, + "password": { + "header": "Autentificare sau înregistrare", + "sub_header": "Folosește combinația email-parolă pentru a te autentifica." + }, + "unique_code": { + "header": "Autentificare sau înregistrare", + "sub_header": "Autentifică-te folosind un cod unic trimis pe adresa de email de mai sus." + } + } + } + }, + "forgot_password": { + "title": "Resetează-ți parola", + "description": "Introdu adresa de email verificată a contului tău și îți vom trimite un link pentru resetarea parolei.", + "email_sent": "Am trimis link-ul de resetare pe adresa ta de email", + "send_reset_link": "Trimite link-ul de resetare", + "errors": { + "smtp_not_enabled": "Se pare că administratorul nu a activat SMTP, nu putem trimite link-ul de resetare a parolei" + }, + "toast": { + "success": { + "title": "Email trimis", + "message": "Verifică-ți căsuța de mesaje pentru link-ul de resetare a parolei. Dacă nu apare în câteva minute, verifică folderul de spam." + }, + "error": { + "title": "Eroare!", + "message": "Ceva nu a funcționat. Te rugăm să încerci din nou." + } + } + }, + "reset_password": { + "title": "Setează o parolă nouă", + "description": "Protejează-ți contul cu o parolă puternică" + }, + "set_password": { + "title": "Protejează-ți contul", + "description": "Setarea parolei te ajută să te autentifici în siguranță" + }, + "sign_out": { + "toast": { + "error": { + "title": "Eroare!", + "message": "Deconectarea a eșuat. Te rugăm să încerci din nou." + } + } + } + }, + + "submit": "Trimite", + "cancel": "Anulează", + "loading": "Se încarcă", + "error": "Eroare", + "success": "Succes", + "warning": "Avertisment", + "info": "Informații", + "close": "Închide", + "yes": "Da", + "no": "Nu", + "ok": "OK", + "name": "Nume", + "description": "Descriere", + "search": "Caută", + "add_member": "Adaugă membru", + "adding_members": "Se adaugă membri", + "remove_member": "Elimină membru", + "add_members": "Adaugă membri", + "adding_member": "Se adaugă membru", + "remove_members": "Elimină membri", + "add": "Adaugă", + "adding": "Se adaugă", + "remove": "Elimină", + "add_new": "Adaugă nou", + "remove_selected": "Elimină selecția", + "first_name": "Prenume", + "last_name": "Nume de familie", + "email": "Email", + "display_name": "Nume afișat", + "role": "Rol", + "timezone": "Fus orar", + "avatar": "Imagine de profil", + "cover_image": "Copertă", + "password": "Parolă", + "change_cover": "Schimbă coperta", + "language": "Limbă", + "saving": "Se salvează", + "save_changes": "Salvează modificările", + "deactivate_account": "Dezactivează contul", + "deactivate_account_description": "Când dezactivezi un cont, toate datele și activitățile din acel cont vor fi șterse permanent și nu pot fi recuperate.", + "profile_settings": "Setări profil", + "your_account": "Contul tău", + "security": "Securitate", + "activity": "Activitate", + "appearance": "Aspect", + "notifications": "Notificări", + "workspaces": "Spații de lucru", + "create_workspace": "Creează spațiu de lucru", + "invitations": "Invitații", + "summary": "Rezumat", + "assigned": "Responsabil", + "created": "Creat", + "subscribed": "Abonat", + "you_do_not_have_the_permission_to_access_this_page": "Nu ai permisiunea de a accesa această pagină.", + "something_went_wrong_please_try_again": "Ceva nu a funcționat. Te rugăm să încerci din nou.", + "load_more": "Încarcă mai mult", + "select_or_customize_your_interface_color_scheme": "Selectează sau personalizează schema de culori a interfeței.", + "theme": "Temă", + "system_preference": "Preferință de sistem", + "light": "Luminos", + "dark": "Întunecat", + "light_contrast": "Luminos - contrast ridicat", + "dark_contrast": "Întunecat - contrast ridicat", + "custom": "Temă personalizată", + "select_your_theme": "Selectează tema", + "customize_your_theme": "Personalizează tema", + "background_color": "Culoare fundal", + "text_color": "Culoare text", + "primary_color": "Culoare principală (temă)", + "sidebar_background_color": "Culoare fundal bară laterală", + "sidebar_text_color": "Culoare text bară laterală", + "set_theme": "Setează tema", + "enter_a_valid_hex_code_of_6_characters": "Introdu un cod hexadecimal valid de 6 caractere", + "background_color_is_required": "Culoarea de fundal este obligatorie", + "text_color_is_required": "Culoarea textului este obligatorie", + "primary_color_is_required": "Culoarea principală este obligatorie", + "sidebar_background_color_is_required": "Culoarea de fundal a barei laterale este obligatorie", + "sidebar_text_color_is_required": "Culoarea textului din bara laterală este obligatorie", + "updating_theme": "Se actualizează tema", + "theme_updated_successfully": "Tema a fost actualizată cu succes", + "failed_to_update_the_theme": "Eroare la actualizarea temei", + "email_notifications": "Notificări prin email", + "stay_in_the_loop_on_issues_you_are_subscribed_to_enable_this_to_get_notified": "Rămâi la curent cu activitățile la care ești abonat. Activează această opțiune pentru a primi notificări.", + "email_notification_setting_updated_successfully": "Setarea notificărilor prin email a fost actualizată cu succes", + "failed_to_update_email_notification_setting": "Eroare la actualizarea setării notificărilor prin email", + "notify_me_when": "Notifică-mă când", + "property_changes": "Se modifică proprietățile", + "property_changes_description": "Notifică-mă când proprietăți precum responsabilii, prioritatea, estimările sau altele se modifică.", + "state_change": "Se schimbă starea", + "state_change_description": "Notifică-mă când activitățile trec într-o stare diferită", + "issue_completed": "Activitate finalizată", + "issue_completed_description": "Notifică-mă doar când o activitate este finalizată", + "comments": "Comentarii", + "comments_description": "Notifică-mă când cineva lasă un comentariu la o activitate", + "mentions": "Mențiuni", + "mentions_description": "Notifică-mă doar când cineva mă menționează în comentarii sau descriere", + "old_password": "Parolă veche", + "general_settings": "Setări generale", + "sign_out": "Deconectează-te", + "signing_out": "Se deconectează", + "active_cycles": "Cicluri active", + "active_cycles_description": "Monitorizează ciclurile din proiecte, urmărește activitățile prioritare și focalizează-te pe ciclurile care necesită atenție.", + "on_demand_snapshots_of_all_your_cycles": "Instantanee la cerere ale tuturor ciclurilor tale", + "upgrade": "Treci la o versiune superioră", + "10000_feet_view": "Vedere de ansamblu asupra tuturor ciclurilor active.", + "10000_feet_view_description": "Vezi în ansamblu și simultan toate ciclurile active din proiectele tale, fără a naviga individual la fiecare ciclu.", + "get_snapshot_of_each_active_cycle": "Obține un instantaneu al fiecărui ciclu activ.", + "get_snapshot_of_each_active_cycle_description": "Urmărește statisticile generale pentru toate ciclurile active, vezi progresul și estimează volumul de muncă în raport cu termenele limită.", + "compare_burndowns": "Compară graficele de finalizare a activităților ", + "compare_burndowns_description": "Monitorizează performanța echipelor tale, analizând graficul de finalizare a activităților ale fiecărui ciclu.", + "quickly_see_make_or_break_issues": "Vezi rapid activitățile critice.", + "quickly_see_make_or_break_issues_description": "Previzualizează activitățile prioritare pentru fiecare ciclu în funcție de termene. Vizualizează-le pe toate dintr-un singur click.", + "zoom_into_cycles_that_need_attention": "Concentrează-te pe ciclurile care necesită atenție.", + "zoom_into_cycles_that_need_attention_description": "Analizează starea oricărui ciclu care nu corespunde așteptărilor, dintr-un singur click.", + "stay_ahead_of_blockers": "Anticipează blocajele.", + "stay_ahead_of_blockers_description": "Identifică provocările între proiecte și vezi dependențele între cicluri care altfel nu sunt evidente.", + "analytics": "Statistici", + "workspace_invites": "Invitațiile din spațiul de lucru", + "enter_god_mode": "Activează modul Dumnezeu", + "workspace_logo": "Sigla spațiului de lucru", + "new_issue": "Activitate nouă", + "your_work": "Munca ta", + "drafts": "Schițe", + "projects": "Proiecte", + "views": "Perspective", + "workspace": "Spațiu de lucru", + "archives": "Arhive", + "settings": "Setări", + "failed_to_move_favorite": "Nu s-a putut muta favorita", + "favorites": "Favorite", + "no_favorites_yet": "Nicio favorită încă", + "create_folder": "Creează dosar", + "new_folder": "Dosar nou", + "favorite_updated_successfully": "Favorita a fost actualizată cu succes", + "favorite_created_successfully": "Favorita a fost creată cu succes", + "folder_already_exists": "Dosarul există deja", + "folder_name_cannot_be_empty": "Numele dosarului nu poate fi gol", + "something_went_wrong": "Ceva nu a funcționat", + "failed_to_reorder_favorite": "Nu s-a putut reordona favorita", + "favorite_removed_successfully": "Favorita a fost eliminată cu succes", + "failed_to_create_favorite": "Nu s-a putut crea favorita", + "failed_to_rename_favorite": "Nu s-a putut redenumi favorita", + "project_link_copied_to_clipboard": "Link-ul proiectului a fost copiat în memoria temporară", + "link_copied": "Link copiat", + "add_project": "Adaugă proiect", + "create_project": "Creează proiect", + "failed_to_remove_project_from_favorites": "Nu s-a putut elimina proiectul din favorite. Încearcă din nou.", + "project_created_successfully": "Proiect creat cu succes", + "project_created_successfully_description": "Proiect creat cu succes. Poți începe să adaugi activități în el.", + "project_cover_image_alt": "Coperta proiectului", + "name_is_required": "Numele este obligatoriu", + "title_should_be_less_than_255_characters": "Titlul trebuie să conțină mai puțin de 255 de caractere", + "project_name": "Numele proiectului", + "project_id_must_be_at_least_1_character": "ID-ul proiectului trebuie să conțină cel puțin 1 caracter", + "project_id_must_be_at_most_5_characters": "ID-ul proiectului trebuie să conțină cel mult 5 caractere", + "project_id": "ID-ul Proiectului", + "project_id_tooltip_content": "Te ajută să identifici unic activitățile din proiect. Maxim 5 caractere.", + "description_placeholder": "Descriere", + "only_alphanumeric_non_latin_characters_allowed": "Sunt permise doar caractere alfanumerice și non-latine.", + "project_id_is_required": "ID-ul proiectului este obligatoriu", + "project_id_allowed_char": "Sunt permise doar caractere alfanumerice și non-latine.", + "project_id_min_char": "ID-ul proiectului trebuie să aibă cel puțin 1 caracter", + "project_id_max_char": "ID-ul proiectului trebuie să aibă cel mult 5 caractere", + "project_description_placeholder": "Introdu descrierea proiectului", + "select_network": "Selectează rețeaua", + "lead": "Lider", + "date_range": "Interval de date", + "private": "Privat", + "public": "Public", + "accessible_only_by_invite": "Accesibil doar prin invitație", + "anyone_in_the_workspace_except_guests_can_join": "Oricine din spațiul de lucru, cu excepția celor de tip Invitat, se poate alătura", + "creating": "Se creează", + "creating_project": "Se creează proiectul", + "adding_project_to_favorites": "Se adaugă proiectul la favorite", + "project_added_to_favorites": "Proiectul a fost adăugat la favorite", + "couldnt_add_the_project_to_favorites": "Nu s-a putut adăuga proiectul la favorite. Încearcă din nou.", + "removing_project_from_favorites": "Se elimină proiectul din favorite", + "project_removed_from_favorites": "Proiectul a fost eliminat din favorite", + "couldnt_remove_the_project_from_favorites": "Nu s-a putut elimina proiectul din favorite. Încearcă din nou.", + "add_to_favorites": "Adaugă la favorite", + "remove_from_favorites": "Elimină din favorite", + "publish_settings": "Setări de publicare", + "publish": "Publică", + "copy_link": "Copiază link-ul", + "leave_project": "Părăsește proiectul", + "join_the_project_to_rearrange": "Alătură-te proiectului pentru a rearanja", + "drag_to_rearrange": "Trage pentru a rearanja", + "congrats": "Felicitări!", + "open_project": "Deschide proiectul", + "issues": "Activități", + "cycles": "Cicluri", + "modules": "Module", + "pages": "Documentație", + "intake": "Cereri", + "time_tracking": "Monitorizare timp", + "work_management": "Gestionare muncă", + "projects_and_issues": "Proiecte și activități", + "projects_and_issues_description": "Activează sau dezactivează aceste opțiuni pentru proiect.", + "cycles_description": "Împarte munca în unități de timp pentru fiecare proiect și modifică frecvența după cum consideri.", + "modules_description": "Grupează munca în sub-proiecte cu lideri și responsabili proprii.", + "views_description": "Salvează sortările, filtrele și opțiunile de afișare pentru mai târziu sau pentru a le distribui.", + "pages_description": "Scrie orice, cum știi tu să scrii.", + "intake_description": "Rămâi la curent cu activitățile la care ești abonat. Activează pentru notificări.", + "time_tracking_description": "Urmărește timpul petrecut pe activități și proiecte.", + "work_management_description": "Gestionează-ți munca și proiectele cu ușurință.", + "documentation": "Documentație", + "message_support": "Trimite mesaj la suport", + "contact_sales": "Contactează vânzările", + "hyper_mode": "Mod Hyper", + "keyboard_shortcuts": "Scurtături tastatură", + "whats_new": "Ce e nou?", + "version": "Versiune", + "we_are_having_trouble_fetching_the_updates": "Avem probleme în a prelua actualizările.", + "our_changelogs": "jurnalele noastre de modificări", + "for_the_latest_updates": "pentru cele mai recente actualizări.", + "please_visit": "Te rugăm să vizitezi", + "docs": "Documentație", + "full_changelog": "Jurnal complet al modificărilor", + "support": "Suport", + "discord": "Discord", + "powered_by_plane_pages": "Oferit de Plane Documentație", + "please_select_at_least_one_invitation": "Te rugăm să selectezi cel puțin o invitație.", + "please_select_at_least_one_invitation_description": "Te rugăm să selectezi cel puțin o invitație pentru a te alătura spațiului de lucru.", + "we_see_that_someone_has_invited_you_to_join_a_workspace": "Se pare că cineva te-a invitat să te alături unui spațiu de lucru", + "join_a_workspace": "Alătură-te unui spațiu de lucru", + "we_see_that_someone_has_invited_you_to_join_a_workspace_description": "Se pare că cineva te-a invitat să te alături unui spațiu de lucru", + "join_a_workspace_description": "Alătură-te unui spațiu de lucru", + "accept_and_join": "Acceptă și alătură-te", + "go_home": "Mergi la început", + "no_pending_invites": "Nicio invitație în așteptare", + "you_can_see_here_if_someone_invites_you_to_a_workspace": "Aici vei vedea dacă cineva te-a invitat într-un spațiu de lucru", + "back_to_home": "Înapoi la început", + "workspace_name": "nume-spațiu-de-lucru", + "deactivate_your_account": "Dezactivează-ți contul", + "deactivate_your_account_description": "Odată dezactivat, nu vei mai putea primi activități sau fi taxat pentru spațiul tău de lucru. Pentru a-ți reactiva contul, vei avea nevoie de o invitație către un spațiu de lucru la această adresă de email.", + "deactivating": "Se dezactivează", + "confirm": "Confirmă", + "confirming": "Se confirmă", + "draft_created": "Schiță creată", + "issue_created_successfully": "Activitate creată cu succes", + "draft_creation_failed": "Crearea schiței a eșuat", + "issue_creation_failed": "Crearea activității a eșuat", + "draft_issue": "Schiță activitate", + "issue_updated_successfully": "Activitate actualizată cu succes", + "issue_could_not_be_updated": "Activitatea nu a putut fi actualizată", + "create_a_draft": "Creează o schiță", + "save_to_drafts": "Salvează în schițe", + "save": "Salvează", + "update": "Actualizează", + "updating": "Se actualizează", + "create_new_issue": "Creează activate nouă", + "editor_is_not_ready_to_discard_changes": "Editorul nu este pregătit să renunțe la modificări", + "failed_to_move_issue_to_project": "Nu s-a putut muta activitatea în proiect", + "create_more": "Creează mai multe", + "add_to_project": "Adaugă la proiect", + "discard": "Renunță", + "duplicate_issue_found": "Activitate duplicată găsită", + "duplicate_issues_found": "Activități duplicate găsite", + "no_matching_results": "Nu există rezultate potrivite", + "title_is_required": "Titlul este obligatoriu", + "title": "Titlu", + "state": "Stare", + "priority": "Prioritate", + "none": "Niciuna", + "urgent": "Urgentă", + "high": "Importantă", + "medium": "Medie", + "low": "Scăzută", + "members": "Membri", + "assignee": "Responsabil", + "assignees": "Responsabili", + "you": "Tu", + "labels": "Etichete", + "create_new_label": "Creează etichetă nouă", + "start_date": "Data de început", + "end_date": "Data de sfârșit", + "due_date": "Data limită", + "estimate": "Estimare", + "change_parent_issue": "Schimbă activitatea părinte", + "remove_parent_issue": "Elimină activitatea părinte", + "add_parent": "Adaugă părinte", + "loading_members": "Se încarcă membrii", + "view_link_copied_to_clipboard": "Link-ul de perspectivă a fost copiat în memoria temporară.", + "required": "Obligatoriu", + "optional": "Opțional", + "Cancel": "Anulează", + "edit": "Editează", + "archive": "Arhivează", + "restore": "Restaurează", + "open_in_new_tab": "Deschide într-un nou tab", + "delete": "Șterge", + "deleting": "Se șterge", + "make_a_copy": "Creează o copie", + "move_to_project": "Mută în proiect", + "good": "Bună", + "morning": "dimineața", + "afternoon": "după-amiaza", + "evening": "seara", + "show_all": "Arată tot", + "show_less": "Arată mai puțin", + "no_data_yet": "Nicio dată încă", + "syncing": "Se sincronizează", + "add_work_item": "Adaugă activitate", + "advanced_description_placeholder": "Apasă '/' pentru comenzi", + "create_work_item": "Creează activitate", + "attachments": "Atașamente", + "declining": "Se refuză", + "declined": "Refuzat", + "decline": "Refuză", + "unassigned": "Fără responsabil", + "work_items": "Activități", + "add_link": "Adaugă link", + "points": "Puncte", + "no_assignee": "Fără responsabil", + "no_assignees_yet": "Niciun responsabil încă", + "no_labels_yet": "Nicio etichetă încă", + "ideal": "Ideal", + "current": "Curent", + "no_matching_members": "Niciun membru potrivit", + "leaving": "Se părăsește", + "removing": "Se elimină", + "leave": "Părăsește", + "refresh": "Reîncarcă", + "refreshing": "Se reîncarcă", + "refresh_status": "Reîncarcă statusul", + "prev": "Înapoi", + "next": "Înainte", + "re_generating": "Se regenerează", + "re_generate": "Regenerează", + "re_generate_key": "Regenerează cheia", + "export": "Exportă", + "member": "{count, plural, one{# membru} other{# membri}}", + + "project_view": { + "sort_by": { + "created_at": "Creat la", + "updated_at": "Actualizat la", + "name": "Nume" + } + }, + + "toast": { + "success": "Succes!", + "error": "Eroare!" + }, + + "links": { + "toasts": { + "created": { + "title": "Link creat", + "message": "Link-ul a fost creat cu succes" + }, + "not_created": { + "title": "Link-ul nu a fost creat", + "message": "Link-ul nu a putut fi creat" + }, + "updated": { + "title": "Link actualizat", + "message": "Link-ul a fost actualizat cu succes" + }, + "not_updated": { + "title": "Link-ul nu a fost actualizat", + "message": "Link-ul nu a putut fi actualizat" + }, + "removed": { + "title": "Link eliminat", + "message": "Link-ul a fost eliminat cu succes" + }, + "not_removed": { + "title": "Link-ul nu a fost eliminat", + "message": "Link-ul nu a putut fi eliminat" + } + } + }, + + "home": { + "empty": { + "quickstart_guide": "Ghid de pornire rapidă", + "not_right_now": "Nu acum", + "create_project": { + "title": "Creează un proiect", + "description": "Majoritatea lucrurilor încep cu un proiect în Plane.", + "cta": "Începe acum" + }, + "invite_team": { + "title": "Invită-ți echipa", + "description": "Construiește, livrează și gestionează împreună cu colegii.", + "cta": "Invită-i" + }, + "configure_workspace": { + "title": "Configurează-ți spațiul de lucru.", + "description": "Activează sau dezactivează opțiuni sau mergi mai departe.", + "cta": "Configurează acest spațiu de lucru" + }, + "personalize_account": { + "title": "Personalizează Plane.", + "description": "Alege-ți poza de profil, culorile și multe altele.", + "cta": "Personalizează acum" + }, + "widgets": { + "title": "Este liniște fără mini-aplicații, activează-le", + "description": "Se pare că toate mini-aplicațiile tale sunt dezactivate. Activează-le acum pentru a-ți îmbunătăți experiența!", + "primary_button": { + "text": "Gestionează mini-aplicațiile" + } + } + }, + "quick_links": { + "empty": "Salvează link-uri către elementele utile pe care vrei să le ai la îndemână.", + "add": "Adaugă link rapid", + "title": "Link rapid", + "title_plural": "Linkuri rapide" + }, + "recents": { + "title": "Recente", + "empty": { + "project": "Proiectele vizitate recent vor apărea aici.", + "page": "Documentele din Documentație vizitate recent vor apărea aici.", + "issue": "Activitățile vizitate recent vor apărea aici.", + "default": "Nu ai nimic recent încă." + }, + "filters": { + "all": "Toate activitățile", + "projects": "Proiecte", + "pages": "Documentație", + "issues": "Activități" + } + }, + "new_at_plane": { + "title": "Noutăți în Plane" + }, + "quick_tutorial": { + "title": "Tutorial rapid" + }, + "widget": { + "reordered_successfully": "Mini-aplicație reordonată cu succes.", + "reordering_failed": "Eroare la reordonarea mini-aplicației." + }, + "manage_widgets": "Gestionează mini-aplicațiile", + "title": "Acasă", + "star_us_on_github": "Dă-ne o stea pe GitHub" + }, + + "link": { + "modal": { + "url": { + "text": "URL", + "required": "URL-ul nu este valid", + "placeholder": "Tastează sau lipește un URL" + }, + "title": { + "text": "Titlu afișat", + "placeholder": "Cum vrei să se vadă acest link" + } + } + }, + + "common": { + "all": "Toate", + "states": "Stări", + "state": "Stare", + "state_groups": "Grupuri de stări", + "state_group": "Grup de stare", + "priorities": "Priorități", + "priority": "Prioritate", + "team_project": "Proiect de echipă", + "project": "Proiect", + "cycle": "Ciclu", + "cycles": "Cicluri", + "module": "Modul", + "modules": "Module", + "labels": "Etichete", + "label": "Etichetă", + "assignees": "Responsabili", + "assignee": "Responsabil", + "created_by": "Creat de", + "none": "Niciuna", + "link": "Link", + "estimates": "Estimări", + "estimate": "Estimare", + "created_at": "Creat la", + "completed_at": "Finalizat la", + "layout": "Aspect", + "filters": "Filtre", + "display": "Afișare", + "load_more": "Încarcă mai mult", + "activity": "Activitate", + "analytics": "Analitice", + "dates": "Date", + "success": "Succes!", + "something_went_wrong": "Ceva a mers greșit", + "error": { + "label": "Eroare!", + "message": "A apărut o eroare. Te rugăm să încerci din nou." + }, + "group_by": "Grupează după", + "epic": "Sarcină majoră", + "epics": "Sarcini majore", + "work_item": "Activitate", + "work_items": "Activități", + "sub_work_item": "Sub-activitate", + "add": "Adaugă", + "warning": "Avertisment", + "updating": "Se actualizează", + "adding": "Se adaugă", + "update": "Actualizează", + "creating": "Se creează", + "create": "Creează", + "cancel": "Anulează", + "description": "Descriere", + "title": "Titlu", + "attachment": "Atașament", + "general": "General", + "features": "Funcționalități", + "automation": "Automatizare", + "project_name": "Nume proiect", + "project_id": "ID Proiect", + "project_timezone": "Fus orar proiect", + "created_on": "Creat la", + "update_project": "Actualizează proiectul", + "identifier_already_exists": "Identificatorul există deja", + "add_more": "Adaugă mai mult", + "defaults": "Implicit", + "add_label": "Adaugă etichetă", + "customize_time_range": "Personalizează intervalul de timp", + "loading": "Se încarcă", + "attachments": "Atașamente", + "property": "Proprietate", + "properties": "Proprietăți", + "parent": "Părinte", + "page": "Document", + "remove": "Elimină", + "archiving": "Se arhivează", + "archive": "Arhivează", + "access": { + "public": "Public", + "private": "Privat" + }, + "done": "Gata", + "sub_work_items": "Sub-activități", + "comment": "Comentariu", + "workspace_level": "La nivel de spațiu de lucru", + "order_by": { + "label": "Ordonează după", + "manual": "Manual", + "last_created": "Ultima creată", + "last_updated": "Ultima actualizată", + "start_date": "Data de început", + "due_date": "Data limită", + "asc": "Crescător", + "desc": "Descrescător", + "updated_on": "Actualizat la" + }, + "sort": { + "asc": "Crescător", + "desc": "Descrescător", + "created_on": "Creată la", + "updated_on": "Actualizată la" + }, + "comments": "Comentarii", + "updates": "Actualizări", + "clear_all": "Șterge tot", + "copied": "Copiat!", + "link_copied": "Link copiat!", + "link_copied_to_clipboard": "Link-ul a fost copiat în memoria temporară", + "copied_to_clipboard": "Link-ul activității copiat în memoria temporară", + "is_copied_to_clipboard": "Activitatea a fost copiată în memoria temporară", + "no_links_added_yet": "Niciun link adăugat încă", + "add_link": "Adaugă link", + "links": "Linkuri", + "go_to_workspace": "Mergi la spațiul de lucru", + "progress": "Progres", + "optional": "Opțional", + "join": "Alătură-te", + "go_back": "Înapoi", + "continue": "Continuă", + "resend": "Retrimite", + "relations": "Relații", + "errors": { + "default": { + "title": "Eroare!", + "message": "Ceva a funcționat greșit. Te rugăm să încerci din nou." + }, + "required": "Acest câmp este obligatoriu", + "entity_required": "{entity} este obligatoriu" + }, + "update_link": "Actualizează link-ul", + "attach": "Atașează", + "create_new": "Creează nou", + "add_existing": "Adaugă existent", + "type_or_paste_a_url": "Tastează sau lipește un URL", + "url_is_invalid": "URL-ul nu este valid", + "display_title": "Titlu afișat", + "link_title_placeholder": "Cum vrei să se vadă acest link", + "url": "URL", + "side_peek": "Previzualizare laterală", + "modal": "Fereastră modală", + "full_screen": "Ecran complet", + "close_peek_view": "Închide previzualizarea", + "toggle_peek_view_layout": "Comută aspectul previzualizării", + "options": "Opțiuni", + "duration": "Durată", + "today": "Astăzi", + "week": "Săptămână", + "month": "Lună", + "quarter": "Trimestru", + "press_for_commands": "Apasă '/' pentru comenzi", + "click_to_add_description": "Apasă pentru a adăuga descriere", + "search": { + "label": "Caută", + "placeholder": "Tastează pentru a căuta", + "no_matches_found": "Nu s-au găsit rezultate", + "no_matching_results": "Nicio potrivire găsită" + }, + "actions": { + "edit": "Editează", + "make_a_copy": "Fă o copie", + "open_in_new_tab": "Deschide într-un nou tab", + "copy_link": "Copiază link-ul", + "archive": "Arhivează", + "restore": "Restaurează", + "delete": "Șterge", + "remove_relation": "Elimină relația", + "subscribe": "Abonează-te", + "unsubscribe": "Dezabonează-te", + "clear_sorting": "Șterge sortarea", + "show_weekends": "Arată sfârșiturile de săptămână", + "enable": "Activează", + "disable": "Dezactivează" + }, + "name": "Nume", + "discard": "Renunță", + "confirm": "Confirmă", + "confirming": "Se confirmă", + "read_the_docs": "Citește documentația", + "default": "Implicit", + "active": "Activ", + "enabled": "Activat", + "disabled": "Dezactivat", + "mandate": "Împuternicire", + "mandatory": "Obligatoriu", + "yes": "Da", + "no": "Nu", + "please_wait": "Te rog așteaptă", + "enabling": "Se activează", + "disabling": "Se dezactivează", + "beta": "Testare", + "or": "sau", + "next": "Înainte", + "back": "Înapoi", + "cancelling": "Se anulează", + "configuring": "Se configurează", + "clear": "Șterge", + "import": "Importă", + "connect": "Conectează", + "authorizing": "Se autorizează", + "processing": "Se procesează", + "no_data_available": "Nicio dată disponibilă", + "from": "de la {name}", + "authenticated": "Autentificat", + "select": "Selectează", + "upgrade": "Treci la o versiune superioră", + "add_seats": "Adaugă locuri", + "projects": "Proiecte", + "workspace": "Spațiu de lucru", + "workspaces": "Spații de lucru", + "team": "Echipă", + "teams": "Echipe", + "entity": "Entitate", + "entities": "Entități", + "task": "Sarcină", + "tasks": "Sarcini", + "section": "Secțiune", + "sections": "Secțiuni", + "edit": "Editează", + "connecting": "Se conectează", + "connected": "Conectat", + "disconnect": "Deconectează", + "disconnecting": "Se deconectează", + "installing": "Se instalează", + "install": "Instalează", + "reset": "Resetează", + "live": "În direct", + "change_history": "Istoric modificări", + "coming_soon": "În curând", + "members": "Membri", + "you": "Tu", + "upgrade_cta": { + "higher_subscription": "Treci la un abonament superior", + "talk_to_sales": "Discută cu vânzările" + }, + "category": "Categorie", + "categories": "Categorii", + "saving": "Se salvează", + "save_changes": "Salvează modificările", + "delete": "Șterge", + "deleting": "Se șterge", + "pending": "În așteptare", + "invite": "Invită", + "view": "Vizualizează" + }, + + "chart": { + "x_axis": "axa-X", + "y_axis": "axa-Y", + "metric": "Indicator" + }, + + "form": { + "title": { + "required": "Titlul este obligatoriu", + "max_length": "Titlul trebuie să conțină mai puțin de {length} caractere" + } + }, + + "entity": { + "grouping_title": "Grupare {entity}", + "priority": "Prioritate {entity}", + "all": "Toate {entity}", + "drop_here_to_move": "Trage aici pentru a muta {entity}", + "delete": { + "label": "Șterge {entity}", + "success": "{entity} a fost ștearsă cu succes", + "failed": "Ștergerea {entity} a eșuat" + }, + "update": { + "failed": "Actualizarea {entity} a eșuat", + "success": "{entity} a fost actualizată cu succes" + }, + "link_copied_to_clipboard": "Link-ul {entity} a fost copiat în memoria temporară", + "fetch": { + "failed": "Eroare la preluarea {entity}" + }, + "add": { + "success": "{entity} a fost adăugată cu succes", + "failed": "Eroare la adăugarea {entity}" + } + }, + + "epic": { + "all": "Toate Sarcinile majore", + "label": "{count, plural, one {Sarcină majoră} other {Sarcini majore}}", + "new": "Sarcină majoră", + "adding": "Se adaugă sarcină majoră", + "create": { + "success": "Sarcină majoră creată cu succes" + }, + "add": { + "press_enter": "Apasă 'Enter' pentru a adăuga o altă sarcină majoră", + "label": "Adaugă sarcină majoră" + }, + "title": { + "label": "Titlu sarcină majoră", + "required": "Titlul sarcinii majore este obligatoriu." + } + }, + + "issue": { + "label": "{count, plural, one {Activitate} other {Activități}}", + "all": "Toate activitățile", + "edit": "Editează activitatea", + "title": { + "label": "Titlul activității", + "required": "Titlul activității este obligatoriu." + }, + "add": { + "press_enter": "Apasă 'Enter' pentru a adăuga o altă activitate", + "label": "Adaugă activitate", + "cycle": { + "failed": "Activitatea nu a putut fi adăugată în ciclu. Te rugăm să încerci din nou.", + "success": "{count, plural, one {Activitate} other {Activități}} adăugată(e) în ciclu cu succes.", + "loading": "Se adaugă {count, plural, one {activitate} other {activități}} în ciclu" + }, + "assignee": "Adaugă responsabili", + "start_date": "Adaugă data de început", + "due_date": "Adaugă termenul limită", + "parent": "Adaugă activitate părinte", + "sub_issue": "Adaugă sub-activitate", + "relation": "Adaugă relație", + "link": "Adaugă link", + "existing": "Adaugă activitate existentă" + }, + "remove": { + "label": "Elimină activitatea", + "cycle": { + "loading": "Se elimină activitatea din ciclu", + "success": "Activitatea a fost eliminată din ciclu cu succes.", + "failed": "Activitatea nu a putut fi eliminată din ciclu. Te rugăm să încerci din nou." + }, + "module": { + "loading": "Se elimină activitatea din modul", + "success": "Activitatea a fost eliminată din modul cu succes.", + "failed": "Activitatea nu a putut fi eliminată din modul. Te rugăm să încerci din nou." + }, + "parent": { + "label": "Elimină activitatea părinte" + } + }, + "new": "Activitate nouă", + "adding": "Se adaugă activitatea", + "create": { + "success": "Activitatea a fost creată cu succes" + }, + "priority": { + "urgent": "Urgentă", + "high": "Ridicată", + "medium": "Medie", + "low": "Scăzută" + }, + "display": { + "properties": { + "label": "Afișează proprietățile", + "id": "ID", + "issue_type": "Tipul activității", + "sub_issue_count": "Număr de sub-activități", + "attachment_count": "Număr de atașamente", + "created_on": "Creată la", + "sub_issue": "Sub-activitate", + "work_item_count": "Număr de activități" + }, + "extra": { + "show_sub_issues": "Afișează sub-activitățile", + "show_empty_groups": "Afișează grupurile goale" + } + }, + "layouts": { + "ordered_by_label": "Această vizualizare este ordonată după", + "list": "Listă", + "kanban": "Tablă", + "calendar": "Calendar", + "spreadsheet": "Tabel", + "gantt": "Cronologic", + "title": { + "list": "Vizualizare tip Listă", + "kanban": "Vizualizare tip Tablă", + "calendar": "Vizualizare tip Calendar", + "spreadsheet": "Vizualizare tip Tabel", + "gantt": "Vizualizare tip Cronologic" + } + }, + "states": { + "active": "Active", + "backlog": "Restante" + }, + "comments": { + "placeholder": "Adaugă comentariu", + "switch": { + "private": "Comută pe comentariu privat", + "public": "Comută pe comentariu public" + }, + "create": { + "success": "Comentariu adăugat cu succes", + "error": "Adăugarea comentariului a eșuat. Te rugăm să încerci mai târziu." + }, + "update": { + "success": "Comentariu actualizat cu succes", + "error": "Actualizarea comentariului a eșuat. Te rugăm să încerci mai târziu." + }, + "remove": { + "success": "Comentariu șters cu succes", + "error": "Ștergerea comentariului a eșuat. Te rugăm să încerci mai târziu." + }, + "upload": { + "error": "Încărcarea fișierului a eșuat. Te rugăm să încerci mai târziu." + } + }, + "empty_state": { + "issue_detail": { + "title": "Activitatea nu există", + "description": "Activitatea căutată nu există, a fost arhivată sau ștearsă.", + "primary_button": { + "text": "Vezi alte activități" + } + } + }, + "sibling": { + "label": "Activități înrudite" + }, + "archive": { + "description": "Doar activitățile finalizate sau anulate\npot fi arhivate", + "label": "Arhivează activitatea", + "confirm_message": "Ești sigur că vrei să arhivezi această activitate? Toate activitățile arhivate pot fi restaurate ulterior.", + "success": { + "label": "Arhivare reușită", + "message": "Arhivele tale pot fi găsite în arhiva proiectului." + }, + "failed": { + "message": "Activitatea nu a putut fi arhivată. Te rugăm să încerci din nou." + } + }, + "restore": { + "success": { + "title": "Restaurare reușită", + "message": "Activitatea poate fi găsită în lista de activități ale proiectului." + }, + "failed": { + "message": "Activitatea nu a putut fi restaurată. Te rugăm să încerci din nou." + } + }, + "relation": { + "relates_to": "Este legată de", + "duplicate": "Duplicată a", + "blocked_by": "Blocată de", + "blocking": "Blochează" + }, + "copy_link": "Copiază link-ul activității", + "delete": { + "label": "Șterge activitatea", + "error": "Eroare la ștergerea activității" + }, + "subscription": { + "actions": { + "subscribed": "Abonarea la activitate realizată cu succes", + "unsubscribed": "Dezabonarea de la activitate realizată cu succes" + } + }, + "select": { + "error": "Selectează cel puțin o activitate", + "empty": "Nicio activitate selectată", + "add_selected": "Adaugă activitățile selectate" + }, + "open_in_full_screen": "Deschide activitatea pe tot ecranul" + }, + + "attachment": { + "error": "Fișierul nu a putut fi atașat. Încearcă să încarci din nou.", + "only_one_file_allowed": "Se poate încărca doar un fișier o dată.", + "file_size_limit": "Fișierul trebuie să aibă {size}MB sau mai puțin.", + "drag_and_drop": "Trage și plasează oriunde pentru a încărca", + "delete": "Șterge atașamentul" + }, + + "label": { + "select": "Selectează eticheta", + "create": { + "success": "Etichetă creată cu succes", + "failed": "Crearea etichetei a eșuat", + "already_exists": "Eticheta există deja", + "type": "Tastează pentru a adăuga o etichetă nouă" + } + }, + + "sub_work_item": { + "update": { + "success": "Sub-activitatea a fost actualizată cu succes", + "error": "Eroare la actualizarea sub-activității" + }, + "remove": { + "success": "Sub-activitatea a fost eliminată cu succes", + "error": "Eroare la eliminarea sub-activității" + } + }, + + "view": { + "label": "{count, plural, one {Perspectivă} other {Perspective}}", + "create": { + "label": "Creează perspectivă" + }, + "update": { + "label": "Actualizează perspectiva" + } + }, + + "inbox_issue": { + "status": { + "pending": { + "title": "În așteptare", + "description": "În așteptare" + }, + "declined": { + "title": "Respinse", + "description": "Respinse" + }, + "snoozed": { + "title": "Amânate", + "description": "{days, plural, one{# zi} other{# zile}} rămase" + }, + "accepted": { + "title": "Acceptate", + "description": "Acceptate" + }, + "duplicate": { + "title": "Duplicate", + "description": "Duplicate" + } + }, + "modals": { + "decline": { + "title": "Respinge activitatea", + "content": "Ești sigur că vrei să respingi activitatea {value}?" + }, + "delete": { + "title": "Șterge activitatea", + "content": "Ești sigur că vrei să ștergi activitatea {value}?", + "success": "Activitatea a fost ștersă cu succes" + } + }, + "errors": { + "snooze_permission": "Doar administratorii proiectului pot amâna/dezactiva amânarea activităților", + "accept_permission": "Doar administratorii proiectului pot accepta activități", + "decline_permission": "Doar administratorii proiectului pot respinge activități" + }, + "actions": { + "accept": "Acceptă", + "decline": "Respinge", + "snooze": "Amână", + "unsnooze": "Dezactivează amânarea", + "copy": "Copiază link-ul activității", + "delete": "Șterge", + "open": "Deschide activitatea", + "mark_as_duplicate": "Marchează ca duplicat", + "move": "Mută {value} în activitățile proiectului" + }, + "source": { + "in-app": "în aplicație" + }, + "order_by": { + "created_at": "Creată la", + "updated_at": "Actualizată la", + "id": "ID" + }, + "label": "Cereri", + "page_label": "{workspace} - Cereri", + "modal": { + "title": "Creează o cerere în Cereri" + }, + "tabs": { + "open": "Deschise", + "closed": "Închise" + }, + "empty_state": { + "sidebar_open_tab": { + "title": "Nicio cerere deschisă", + "description": "Găsește aici cererile primite. Creează o cerere nouă." + }, + "sidebar_closed_tab": { + "title": "Nicio cerere închisă", + "description": "Toate cererile, fie acceptate, fie respinse, pot fi găsite aici." + }, + "sidebar_filter": { + "title": "Nicio cerere gasită", + "description": "Nicio cerere nu se potrivește cu filtrul aplicat în Cereri. Creează o cerere nouă." + }, + "detail": { + "title": "Selectează o cerere pentru a-i vedea detaliile." + } + } + }, + + "workspace_creation": { + "heading": "Creează spațiul tău de lucru", + "subheading": "Pentru a începe să folosești Plane, trebuie să creezi sau să te alături unui spațiu de lucru.", + "form": { + "name": { + "label": "Denumește-ți spațiul de lucru", + "placeholder": "Cel mai bine este să alegi ceva familiar și ușor de recunoscut." + }, + "url": { + "label": "Setează URL-ul spațiului de lucru", + "placeholder": "Tastează sau lipește un URL", + "edit_slug": "Poți edita doar identificatorul URL-ului" + }, + "organization_size": { + "label": "Câți oameni vor folosi acest spațiu de lucru?", + "placeholder": "Selectează un interval" + } + }, + "errors": { + "creation_disabled": { + "title": "Doar administratorul instanței poate crea spații de lucru", + "description": "Dacă știi adresa de email a administratorului instanței tale, apasă butonul de mai jos pentru a-l contacta.", + "request_button": "Solicită administratorul instanței" + }, + "validation": { + "name_alphanumeric": "Numele spațiilor de lucru pot conține doar (' '), ('-'), ('_') și caractere alfanumerice.", + "name_length": "Limitează numele la 80 de caractere.", + "url_alphanumeric": "URL-urile pot conține doar ('-') și caractere alfanumerice.", + "url_length": "Limitează URL-ul la 48 de caractere.", + "url_already_taken": "URL-ul spațiului de lucru este deja folosit!" + } + }, + "request_email": { + "subject": "Solicitare creare spațiu de lucru nou", + "body": "Salut administrator(i) instanței,\n\nVă rog să creați un nou spațiu de lucru cu URL-ul [/workspace-name] pentru [scopul creării spațiului de lucru].\n\nMulțumesc,\n{firstName} {lastName}\n{email}" + }, + "button": { + "default": "Creează spațiu de lucru", + "loading": "Se creează spațiul de lucru" + }, + "toast": { + "success": { + "title": "Succes", + "message": "Spațiul de lucru a fost creat cu succes" + }, + "error": { + "title": "Eroare", + "message": "Spațiul de lucru nu a putut fi creat. Te rugăm să încerci din nou." + } + } + }, + + "workspace_dashboard": { + "empty_state": { + "general": { + "title": "Prezentare generală a proiectelor, activităților și statisticilor tale", + "description": "Bine ai venit în Plane, suntem încântați să te avem aici. Creează primul tău proiect și urmărește activitățile, iar această pagină se va transforma într-un spațiu care te ajută să progresezi. Administratorii vor vedea și elementele care ajută echipa lor să progreseze.", + "primary_button": { + "text": "Creează primul tău proiect", + "comic": { + "title": "Totul începe cu un proiect în Plane", + "description": "Un proiect poate fi planul de dezvoltare a unui produs, o campanie de marketing sau lansarea unei noi mașini." + } + } + } + } + }, + + "workspace_analytics": { + "label": "Statistici", + "page_label": "{workspace} - Statistici", + "open_tasks": "Total activități deschise", + "error": "A apărut o eroare la preluarea datelor.", + "work_items_closed_in": "Activități finalizate în", + "selected_projects": "Proiecte selectate", + "total_members": "Total membri", + "total_cycles": "Total cicluri", + "total_modules": "Total module", + "pending_work_items": { + "title": "Activități în așteptare", + "empty_state": "Aici apare analiza activităților în așteptare atribuite colegilor." + }, + "work_items_closed_in_a_year": { + "title": "Activități finalizate într-un an", + "empty_state": "Închide activități pentru a vedea statisticile sub formă de grafic." + }, + "most_work_items_created": { + "title": "Cele mai multe activități create", + "empty_state": "Aici vor apărea colegii și numărul de activități create de aceștia." + }, + "most_work_items_closed": { + "title": "Cele mai multe activități finalizate", + "empty_state": "Aici vor apărea colegii și numărul de activități finalizate de aceștia." + }, + "tabs": { + "scope_and_demand": "Activități asumate și cerere", + "custom": "Analitice personalizate" + }, + "empty_state": { + "general": { + "title": "Urmărește progresul, activitățile și alocările. Observă tendințele, elimină blocajele și accelerează munca", + "description": "Vezi raportul dintre activitățile asumate și cerere, estimările și eventualele extinderi neplanificate ale activităților asumate. Obține performanța pe membri și echipe și asigură-te că proiectul tău se încadrează în timp.", + "primary_button": { + "text": "Începe primul tău proiect", + "comic": { + "title": "Statisticile funcționează cel mai bine cu Cicluri + Module", + "description": "Mai întâi, încadrează-ți activitățile în Cicluri și, dacă poți, grupează-le pe cele care se întind pe mai multe cicluri în Module. Le găsești în meniul din stânga." + } + } + } + } + }, + + "workspace_projects": { + "label": "{count, plural, one {Proiect} other {Proiecte}}", + "create": { + "label": "Adaugă proiect" + }, + "network": { + "label": "Rețea", + "private": { + "title": "Privat", + "description": "Accesibil doar pe bază de invitație" + }, + "public": { + "title": "Public", + "description": "Oricine din spațiul de lucru, cu excepția celor din categoria Invitați, se poate alătura" + } + }, + "error": { + "permission": "Nu ai permisiunea să efectuezi această acțiune.", + "cycle_delete": "Ștergerea ciclului a eșuat", + "module_delete": "Ștergerea modulului a eșuat", + "issue_delete": "Ștergerea activității a eșuat" + }, + "state": { + "backlog": "Restante", + "unstarted": "Neîncepute", + "started": "În desfășurare", + "completed": "Finalizate", + "cancelled": "Anulate" + }, + "sort": { + "manual": "Manual", + "name": "Nume", + "created_at": "Data creării", + "members_length": "Număr de membri" + }, + "scope": { + "my_projects": "Proiectele mele", + "archived_projects": "Arhivate" + }, + "common": { + "months_count": "{months, plural, one{# lună} other{# luni}}" + }, + "empty_state": { + "general": { + "title": "Niciun proiect activ", + "description": "Gândește-te la fiecare proiect ca la părintele muncii orientate pe obiectiv. Proiectele sunt locul unde trăiesc Activitățile, Ciclurile și Modulele și, împreună cu colegii tăi, te ajută să îți atingi obiectivul. Creează un proiect nou sau filtrează pentru a vedea proiectele arhivate.", + "primary_button": { + "text": "Începe primul tău proiect", + "comic": { + "title": "Totul începe cu un proiect în Plane", + "description": "Un proiect poate fi o foaie de parcurs pentru un produs, o campanie de marketing sau lansarea unei noi mașini." + } + } + }, + "no_projects": { + "title": "Niciun proiect", + "description": "Pentru a crea activități sau a-ți gestiona activitatea, trebuie să creezi un proiect sau să faci parte dintr-unul.", + "primary_button": { + "text": "Începe primul tău proiect", + "comic": { + "title": "Totul începe cu un proiect în Plane", + "description": "Un proiect poate fi o foaie de parcurs pentru un produs, o campanie de marketing sau lansarea unei noi mașini." + } + } + }, + "filter": { + "title": "Niciun proiect care să corespundă filtrului", + "description": "Nu s-au găsit proiecte care să corespundă criteriilor aplicate.\n Creează un proiect nou." + }, + "search": { + "description": "Nu s-au găsit proiecte care să corespundă criteriilor.\nCreează un proiect nou." + } + } + }, + + "workspace_views": { + "add_view": "Adaugă perspectivă", + "empty_state": { + "all-issues": { + "title": "Nicio activitate în proiect", + "description": "Primul proiect este gata! Acum împarte-ți munca în bucăți gestionabile prin activități. Hai să începem!", + "primary_button": { + "text": "Creează o nouă activitate" + } + }, + "assigned": { + "title": "Nicio activitate încă", + "description": "Activitățile care ți-au fost atribuite pot fi urmărite de aici.", + "primary_button": { + "text": "Creează o nouă activitate" + } + }, + "created": { + "title": "Nicio activitate încă", + "description": "Toate activitățile create de tine vor apărea aici. Le poți urmări direct din această pagină.", + "primary_button": { + "text": "Creează o nouă activitate" + } + }, + "subscribed": { + "title": "Nicio activitate încă", + "description": "Abonează-te la activitățile care te interesează și urmărește-le pe toate aici." + }, + "custom-view": { + "title": "Nicio activitate încă", + "description": "Elementele de lucru care corespund filtrelor aplicate vor fi afișate aici." + } + } + }, + + "workspace_settings": { + "label": "Setări spațiu de lucru", + "page_label": "{workspace} - Setări generale", + "key_created": "Cheie creată", + "copy_key": "Copiază și salvează această cheie secretă în Plane Documentație. Nu vei mai putea vedea această cheie după ce închizi. Un fișier CSV care conține cheia a fost descărcat.", + "token_copied": "Token-ul a fost copiat în memoria temporară.", + "settings": { + "general": { + "title": "General", + "upload_logo": "Încarcă siglă", + "edit_logo": "Editează siglă", + "name": "Numele spațiului de lucru", + "company_size": "Dimensiunea companiei", + "url": "URL-ul spațiului de lucru", + "update_workspace": "Actualizează spațiul de lucru", + "delete_workspace": "Șterge acest spațiu de lucru", + "delete_workspace_description": "La ștergerea spațiului de lucru, toate datele și resursele din cadrul acestuia vor fi eliminate definitiv și nu vor putea fi recuperate.", + "delete_btn": "Șterge acest spațiu de lucru", + "delete_modal": { + "title": "Ești sigur că vrei să ștergi acest spațiu de lucru?", + "description": "Ai o perioadă de probă activă pentru unul dintre planurile noastre plătite. Te rugăm să o anulezi înainte de a continua.", + "dismiss": "Renunță", + "cancel": "Anulează perioadă de probă", + "success_title": "Spațiul de lucru a fost șters.", + "success_message": "Vei fi redirecționat în curând către pagina de profil.", + "error_title": "Ceva nu a funcționat.", + "error_message": "Încearcă din nou, te rog." + }, + "errors": { + "name": { + "required": "Numele este obligatoriu", + "max_length": "Numele spațiului de lucru nu trebuie să depășească 80 de caractere" + }, + "company_size": { + "required": "Dimensiunea companiei este obligatorie", + "select_a_range": "Selectează dimensiunea companiei" + } + } + }, + "members": { + "title": "Membri", + "add_member": "Adaugă membru", + "pending_invites": "Invitații în așteptare", + "invitations_sent_successfully": "Invitațiile au fost trimise cu succes", + "leave_confirmation": "Ești sigur că vrei să părăsești spațiul de lucru? Nu vei mai avea acces la acest spațiu. Această acțiune este ireversibilă.", + "details": { + "full_name": "Nume complet", + "display_name": "Nume afișat", + "email_address": "Adresă de email", + "account_type": "Tip cont", + "authentication": "Autentificare", + "joining_date": "Data înscrierii" + }, + "modal": { + "title": "Invită persoane cu care să colaborezi", + "description": "Invită persoane cu care să colaborezi în spațiul tău de lucru.", + "button": "Trimite invitațiile", + "button_loading": "Se trimit invitațiile", + "placeholder": "nume@companie.ro", + "errors": { + "required": "Avem nevoie de o adresă de email pentru a trimite invitația.", + "invalid": "Adresa de email este invalidă" + } + } + }, + "billing_and_plans": { + "title": "Facturare și Abonamente", + "current_plan": "Abonament curent", + "free_plan": "Folosești în prezent abonamentul gratuit", + "view_plans": "Vezi abonamentele" + }, + "exports": { + "title": "Exporturi", + "exporting": "Se exportă", + "previous_exports": "Exporturi anterioare", + "export_separate_files": "Exportă datele în fișiere separate", + "modal": { + "title": "Exportă în", + "toasts": { + "success": { + "title": "Export reușit", + "message": "Vei putea descărca exportul {entity} din secțiunea de exporturi anterioare." + }, + "error": { + "title": "Export eșuat", + "message": "Exportul a eșuat. Te rugăm să încerci din nou." + } + } + } + }, + "webhooks": { + "title": "Puncte de notificare (Webhooks)", + "add_webhook": "Adaugă punct de notificare (webhook)", + "modal": { + "title": "Creează punct de notificare (webhook)", + "details": "Detalii punct de notificare (webhook)", + "payload": " URL-ul de trimitere a datelor", + "question": "La ce evenimente vrei să activezi acest punct de notificare (webhook)?", + "error": "URL-ul este obligatoriu" + }, + "secret_key": { + "title": "Cheie secretă", + "message": "Generează o cheie de acces pentru a semna datele trimise la punctul de notificare (webhook)" + }, + "options": { + "all": "Trimite-mi tot", + "individual": "Selectează evenimente individuale" + }, + "toasts": { + "created": { + "title": "Punct de notificare (webhook) creat", + "message": "Punctul de notificare (webhook) a fost creat cu succes" + }, + "not_created": { + "title": "Punctul de notificare (webhook) nu a fost creat", + "message": "Punctul de notificare (webhook) nu a putut fi creat" + }, + "updated": { + "title": "Punctul de notificare (webhook) actualizat", + "message": "Punctul de notificare (webhook) a fost actualizat cu succes" + }, + "not_updated": { + "title": "Punctul de notificare (webhook) nu a fost actualizat", + "message": "Punctul de notificare (webhook) nu a putut fi actualizat" + }, + "removed": { + "title": "Punct de notificare (webhook) șters", + "message": "Punctul de notificare (webhook) a fost șters cu succes" + }, + "not_removed": { + "title": "Punctul de notificare (webhook) nu a fost șters", + "message": "Punctul de notificare (webhook) nu a putut fi șters" + }, + "secret_key_copied": { + "message": "Cheia secretă a fost copiată în memoria temporară." + }, + "secret_key_not_copied": { + "message": "A apărut o eroare la copierea cheii secrete." + } + } + }, + "api_tokens": { + "title": "Chei secrete API", + "add_token": "Adaugă cheie secretă API", + "create_token": "Creează cheie secretă", + "never_expires": "Nu expiră niciodată", + "generate_token": "Generează cheie secretă", + "generating": "Se generează", + "delete": { + "title": "Șterge cheia secretă API", + "description": "Orice aplicație care folosește această cheie secretă nu va mai avea acces la datele Plane. Această acțiune este ireversibilă.", + "success": { + "title": "Succes!", + "message": "Cheia secretă API a fost ștearsă cu succes" + }, + "error": { + "title": "Eroare!", + "message": "Cheia secretă API nu a putut fi ștearsă" + } + } + } + }, + "empty_state": { + "api_tokens": { + "title": "Nicio cheie secretă API creată", + "description": "API-ul Plane poate fi folosit pentru a integra datele tale din Plane cu orice sistem extern. Creează o cheie secretă pentru a începe." + }, + "webhooks": { + "title": "Niciun punctul de notificare (webhook) adăugat", + "description": "Creează puncte de notificare (webhooks) pentru a primi actualizări în timp real și a automatiza acțiuni." + }, + "exports": { + "title": "Niciun export efectuat", + "description": "Ori de câte ori exporți, vei avea o copie și aici pentru referință." + }, + "imports": { + "title": "Niciun import efectuat", + "description": "Găsește aici toate importurile anterioare și descarcă-le." + } + } + }, + + "profile": { + "label": "Profil", + "page_label": "Munca ta", + "work": "Muncă", + "details": { + "joined_on": "S-a înscris la", + "time_zone": "Fus orar" + }, + "stats": { + "workload": "Volum de muncă", + "overview": "Prezentare generală", + "created": "Activități create", + "assigned": "Activități atribuite", + "subscribed": "Activități urmărite", + "state_distribution": { + "title": "Activități după stare", + "empty": "Creează activități pentru a le vedea distribuite pe stări în grafic, pentru o analiză mai bună." + }, + "priority_distribution": { + "title": "Activități după prioritate", + "empty": "Creează activități pentru a le vedea distribuite pe priorități în grafic, pentru o analiză mai bună." + }, + "recent_activity": { + "title": "Activitate recentă", + "empty": "Nu am găsit date. Te rugăm să verifici activitățile tale.", + "button": "Descarcă activitatea de azi", + "button_loading": "Se descarcă" + } + }, + "actions": { + "profile": "Profil", + "security": "Securitate", + "activity": "Activitate", + "appearance": "Aspect", + "notifications": "Notificări" + }, + "tabs": { + "summary": "Sumar", + "assigned": "Atribuite", + "created": "Create", + "subscribed": "Urmărite", + "activity": "Activitate" + }, + "empty_state": { + "activity": { + "title": "Nicio activitate încă", + "description": "Începe prin a crea o nouă activitate! Adaugă detalii și proprietăți. Explorează mai mult în Plane pentru a-ți vedea activitatea." + }, + "assigned": { + "title": "Nicio activitate atribuită ție", + "description": "Elementele de lucru care ți-au fost atribuite pot fi urmărite de aici." + }, + "created": { + "title": "Nicio activitate creată", + "description": "Toate activitățile create de tine vor apărea aici. Le poți urmări direct din această pagină." + }, + "subscribed": { + "title": "Nicio activitate urmărită", + "description": "Abonează-te la activitățile care te interesează și urmărește-le pe toate aici." + } + } + }, + + "project_settings": { + "general": { + "enter_project_id": "Introdu ID-ul proiectului", + "please_select_a_timezone": "Te rugăm să selectezi un fus orar", + "archive_project": { + "title": "Arhivează proiectul", + "description": "Arhivarea unui proiect îl va elimina din navigarea laterală, dar vei putea accesa proiectul din pagina ta de proiecte. Poți restaura sau șterge proiectul oricând dorești.", + "button": "Arhivează proiectul" + }, + "delete_project": { + "title": "Șterge proiectul", + "description": "La ștergerea unui proiect, toate datele și resursele din cadrul proiectului vor fi eliminate definitiv și nu vor putea fi recuperate.", + "button": "Șterge proiectul meu" + }, + "toast": { + "success": "Proiect actualizat cu succes", + "error": "Proiectul nu a putut fi actualizat. Te rugăm să încerci din nou." + } + }, + "members": { + "label": "Membri", + "project_lead": "Lider de proiect", + "default_assignee": "Persoană atribuită implicit", + "guest_super_permissions": { + "title": "Acordă acces la perspectivă pentru toți utilizatorii de tip Invitat:", + "sub_heading": "Aceasta va permite utilizatorilor din categoria Invitați să vadă toate activitățile din proiect." + }, + "invite_members": { + "title": "Invită membri", + "sub_heading": "Invită membri să lucreze la proiectul tău.", + "select_co_worker": "Selectează colegul de echipă" + } + }, + "states": { + "describe_this_state_for_your_members": "Descrie această stare pentru membrii tăi.", + "empty_state": { + "title": "Nicio stare disponibilă pentru grupul {groupKey}", + "description": "Te rog să creezi o stare nouă" + } + }, + "labels": { + "label_title": "Titlu etichetă", + "label_title_is_required": "Titlul etichetei este obligatoriu", + "label_max_char": "Numele etichetei nu trebuie să depășească 255 de caractere", + "toast": { + "error": "Eroare la actualizarea etichetei" + } + }, + "estimates": { + "title": "Activează estimările pentru proiectul meu", + "description": "Acestea te ajută să comunici complexitatea și volumul de muncă al echipei." + }, + "automations": { + "label": "Automatizări", + "auto-archive": { + "title": "Auto-arhivează activitățile finalizate", + "description": "Plane va arhiva automat activitățile care au fost finalizate sau anulate.", + "duration": "Auto-arhivează activitățile finalizate de" + }, + "auto-close": { + "title": "Închide automat activitățile", + "description": "Plane va închide automat activitățile care nu au fost finalizate sau anulate.", + "duration": "Închide automat activitățile inactive de", + "auto_close_status": "Stare închidere automată" + } + }, + + "empty_state": { + "labels": { + "title": "Nicio etichetă încă", + "description": "Creează etichete pentru a organiza și filtra activitățile din proiect." + }, + "estimates": { + "title": "Nicio estimare configurată", + "description": "Creează un set de estimări pentru a comunica volumul de muncă pentru fiecare activitate.", + "primary_button": "Adaugă sistem de estimare" + } + } + }, + + "project_cycles": { + "add_cycle": "Adaugă ciclu", + "more_details": "Mai multe detalii", + "cycle": "Ciclu", + "update_cycle": "Actualizează ciclul", + "create_cycle": "Creează ciclu", + "no_matching_cycles": "Niciun ciclu găsit", + "remove_filters_to_see_all_cycles": "Elimină filtrele pentru a vedea toate ciclurile", + "remove_search_criteria_to_see_all_cycles": "Elimină criteriile de căutare pentru a vedea toate ciclurile", + "only_completed_cycles_can_be_archived": "Doar ciclurile finalizate pot fi arhivate", + "active_cycle": { + "label": "Ciclu activ", + "progress": "Progres", + "chart": "Ritmul de finalizare a activităților", + "priority_issue": "Activități prioritare", + "assignees": "Persoane atribuite", + "issue_burndown": "Grafic de finalizare a activităților", + "ideal": "Ideal", + "current": "Curent", + "labels": "Etichete" + }, + "upcoming_cycle": { + "label": "Ciclu viitor" + }, + "completed_cycle": { + "label": "Ciclu finalizat" + }, + "status": { + "days_left": "Zile rămase", + "completed": "Finalizat", + "yet_to_start": "Nu a început", + "in_progress": "În desfășurare", + "draft": "Schiță" + }, + "action": { + "restore": { + "title": "Restaurează ciclul", + "success": { + "title": "Ciclu restaurat", + "description": "Ciclul a fost restaurat." + }, + "failed": { + "title": "Restaurarea ciclului a eșuat", + "description": "Ciclul nu a putut fi restaurat. Te rugăm să încerci din nou." + } + }, + "favorite": { + "loading": "Se adaugă ciclul la favorite", + "success": { + "description": "Ciclul a fost adăugat la favorite.", + "title": "Succes!" + }, + "failed": { + "description": "Nu s-a putut adăuga ciclul la favorite. Te rugăm să încerci din nou.", + "title": "Eroare!" + } + }, + "unfavorite": { + "loading": "Se elimină ciclul din favorite", + "success": { + "description": "Ciclul a fost eliminat din favorite.", + "title": "Succes!" + }, + "failed": { + "description": "Nu s-a putut elimina ciclul din favorite. Te rugăm să încerci din nou.", + "title": "Eroare!" + } + }, + "update": { + "loading": "Se actualizează ciclul", + "success": { + "description": "Ciclul a fost actualizat cu succes.", + "title": "Succes!" + }, + "failed": { + "description": "Eroare la actualizarea ciclului. Te rugăm să încerci din nou.", + "title": "Eroare!" + }, + "error": { + "already_exists": "Ai deja un ciclu în datele selectate. Dacă vrei să creezi o schiță, poți face asta eliminând ambele date." + } + } + }, + "empty_state": { + "general": { + "title": "Grupează și delimitează în timp munca ta în Cicluri.", + "description": "Împarte munca în intervale de timp, stabilește datele în funcție de termenul limită al proiectului și progresează vizibil ca echipă.", + "primary_button": { + "text": "Setează primul tău ciclu", + "comic": { + "title": "Ciclurile sunt intervale repetitive de timp.", + "description": "O iterație sau orice alt termen folosit pentru urmărirea săptămânală sau bilunară a muncii este un ciclu." + } + } + }, + "no_issues": { + "title": "Nicio activitate adăugată în ciclu", + "description": "Adaugă sau creează activități pe care vrei să le implementezi în acest ciclu", + "primary_button": { + "text": "Creează o activitate nouă" + }, + "secondary_button": { + "text": "Adaugă o activitate existentă" + } + }, + "completed_no_issues": { + "title": "Nicio activitate în ciclu", + "description": "Nu există activități în ciclu. Acestea au fost fie transferate, fie ascunse. Pentru a vedea activitățile ascunse, actualizează proprietățile de afișare." + }, + "active": { + "title": "Niciun ciclu activ", + "description": "Un ciclu activ include orice perioadă care conține data de azi în intervalul său. Progresul și detaliile ciclului activ apar aici." + }, + "archived": { + "title": "Niciun ciclu arhivat încă", + "description": "Pentru a păstra proiectul ordonat, arhivează ciclurile completate. Le vei găsi aici după arhivare." + } + } + }, + + "project_issues": { + "empty_state": { + "no_issues": { + "title": "Creează o activitate și atribuie-o cuiva, chiar și ție", + "description": "Gândește-te la activități ca la sarcini sau lucruri care trebuie făcute. O activitate și sub-activitățile sale sunt acțiuni care trebuie realizate într-un interval de timp de către membrii echipei tale. Echipa creează, atribuie și finalizează activități pentru a duce proiectul spre obiectivul său.", + "primary_button": { + "text": "Creează prima ta activitate", + "comic": { + "title": "Activitățile sunt elemente de bază în Plane.", + "description": "Reproiectarea interfeței Plane, modernizarea imaginii companiei sau lansarea noului sistem de injecție sunt exemple de activități care au, cel mai probabil, sub-activități." + } + } + }, + "no_archived_issues": { + "title": "Nicio activitate arhivată încă", + "description": "Manual sau automat, poți arhiva activitățile care sunt finalizate sau anulate. Le vei găsi aici după arhivare.", + "primary_button": { + "text": "Setează automatizarea" + } + }, + "issues_empty_filter": { + "title": "Nicio activitate găsită conform filtrelor aplicate", + "secondary_button": { + "text": "Șterge toate filtrele" + } + } + } + }, + + "project_module": { + "add_module": "Adaugă Modul", + "update_module": "Actualizează Modul", + "create_module": "Creează Modul", + "archive_module": "Arhivează Modul", + "restore_module": "Restaurează Modul", + "delete_module": "Șterge modulul", + "empty_state": { + "general": { + "title": "Mapează etapele proiectului în Module și urmărește munca agregată cu ușurință.", + "description": "Un grup de activități care aparțin unui părinte logic și ierarhic formează un modul. Gândește-te la module ca la un mod de a urmări munca în funcție de etapele proiectului. Au propriile perioade, termene limită și statistici pentru a-ți arăta cât de aproape sau departe ești de un reper.", + "primary_button": { + "text": "Construiește primul tău modul", + "comic": { + "title": "Modulele ajută la organizarea muncii pe niveluri ierarhice.", + "description": "Un modul pentru caroserie, un modul pentru șasiu sau un modul pentru depozit sunt exemple bune de astfel de grupare." + } + } + }, + "no_issues": { + "title": "Nicio activitate în modul", + "description": "Creează sau adaugă activități pe care vrei să le finalizezi ca parte a acestui modul", + "primary_button": { + "text": "Creează activități noi" + }, + "secondary_button": { + "text": "Adaugă o activitate existentă" + } + }, + "archived": { + "title": "Niciun modul arhivat încă", + "description": "Pentru a păstra proiectul ordonat, arhivează modulele finalizate sau anulate. Le vei găsi aici după arhivare." + }, + "sidebar": { + "in_active": "Acest modul nu este încă activ.", + "invalid_date": "Dată invalidă. Te rugăm să introduci o dată validă." + } + }, + "quick_actions": { + "archive_module": "Arhivează modulul", + "archive_module_description": "Doar modulele finalizate sau anulate pot fi arhivate.", + "delete_module": "Șterge modulul" + }, + "toast": { + "copy": { + "success": "Link-ul modulului a fost copiat în memoria temporară" + }, + "delete": { + "success": "Modulul a fost șters cu succes", + "error": "Ștergerea modulului a eșuat" + } + } + }, + + "project_views": { + "empty_state": { + "general": { + "title": "Salvează perspective filtrate pentru proiectul tău. Creează câte ai nevoie", + "description": "Perspectivele sunt seturi de filtre salvate pe care le folosești frecvent sau la care vrei acces rapid. Toți colegii tăi dintr-un proiect pot vedea perspectivele tuturor și pot alege ce li se potrivește cel mai bine.", + "primary_button": { + "text": "Creează prima ta perspectivă", + "comic": { + "title": "Perspectivele funcționează pe baza proprietăților activităților.", + "description": "Poți crea o perspectivă de aici, cu oricâte proprietăți și filtre consideri necesare." + } + } + }, + "filter": { + "title": "Nicio perspectivă potrivită", + "description": "Nicio perspectivă nu se potrivește criteriilor de căutare.\n Creează o nouă perspectivă în schimb." + } + } + }, + + "project_page": { + "empty_state": { + "general": { + "title": "Scrie o notiță, un document sau o bază completă de cunoștințe. Folosește-l pe Galileo, Inteligența Artificială a Plane, ca să te ajute să începi", + "description": "Documentația e spațiul în care îți notezi gândurile în Plane. Ia notițe de la ședințe, formatează-le ușor, inserează activități, așază-le folosind o bibliotecă de componente și păstrează-le pe toate în contextul proiectului tău. Pentru a redacta rapid orice document, apelează la Galileo, Inteligența Artificială a Plane, cu un shortcut sau un click.", + "primary_button": { + "text": "Creează primul tău document" + } + }, + "private": { + "title": "Niciun document privată încă", + "description": "Păstrează-ți gândurile private aici. Când ești gata să le împarți, echipa e la un click distanță.", + "primary_button": { + "text": "Creează primul tău document" + } + }, + "public": { + "title": "Niciun document public încă", + "description": "Vezi aici documentele distribuite cu toată echipa ta din proiect.", + "primary_button": { + "text": "Creează primul tău document" + } + }, + "archived": { + "title": "Niciun document arhivat încă", + "description": "Arhivează documentele de care nu mai ai nevoie. Le poți accesa de aici oricând." + } + } + }, + + "command_k": { + "empty_state": { + "search": { + "title": "Niciun rezultat găsit" + } + } + }, + + "issue_relation": { + "empty_state": { + "search": { + "title": "Nu au fost găsite activități potrivite" + }, + "no_issues": { + "title": "Nu au fost găsite activități" + } + } + }, + + "issue_comment": { + "empty_state": { + "general": { + "title": "Niciun comentariu încă", + "description": "Comentariile pot fi folosite ca spațiu de discuții și urmărire pentru activități" + } + } + }, + + "notification": { + "label": "Căsuță de mesaje", + "page_label": "{workspace} - Căsuță de mesaje", + "options": { + "mark_all_as_read": "Marchează toate ca citite", + "mark_read": "Marchează ca citit", + "mark_unread": "Marchează ca necitit", + "refresh": "Reîmprospătează", + "filters": "Filtre Căsuță de mesaje", + "show_unread": "Afișează necitite", + "show_snoozed": "Afișează amânate", + "show_archived": "Afișează arhivate", + "mark_archive": "Arhivează", + "mark_unarchive": "Dezarhivează", + "mark_snooze": "Amână", + "mark_unsnooze": "Dezactivează amânarea" + }, + "toasts": { + "read": "Notificare marcată ca citită", + "unread": "Notificare marcată ca necitită", + "archived": "Notificare arhivată", + "unarchived": "Notificare dezarhivată", + "snoozed": "Notificare amânată", + "unsnoozed": "Notificare reactivată" + }, + "empty_state": { + "detail": { + "title": "Selectează pentru a vedea detalii." + }, + "all": { + "title": "Nicio activitate atribuită", + "description": "Actualizările pentru activitățile atribuite ție pot fi\nvăzute aici" + }, + "mentions": { + "title": "Nicio activitate atribuită", + "description": "Actualizările pentru activitățile atribuite ție pot fi\nvăzute aici" + } + }, + "tabs": { + "all": "Toate", + "mentions": "Mențiuni" + }, + "filter": { + "assigned": "Atribuite mie", + "created": "Create de mine", + "subscribed": "Urmărite de mine" + }, + "snooze": { + "1_day": "1 zi", + "3_days": "3 zile", + "5_days": "5 zile", + "1_week": "1 săptămână", + "2_weeks": "2 săptămâni", + "custom": "Personalizat" + } + }, + + "active_cycle": { + "empty_state": { + "progress": { + "title": "Adaugă activități în ciclu pentru a vedea progresul" + }, + "chart": { + "title": "Adaugă activități în ciclu pentru a vedea graficul de finalizare a activităților." + }, + "priority_issue": { + "title": "Observă rapid activitățile cu prioritate ridicată abordate în ciclu." + }, + "assignee": { + "title": "Adaugă responsabili pentru a vedea repartizarea muncii pe persoane." + }, + "label": { + "title": "Adaugă etichete activităților pentru a vedea repartizarea muncii pe etichete." + } + } + }, + + "disabled_project": { + "empty_state": { + "inbox": { + "title": "Funcția Cereri nu este activată pentru proiect.", + "description": "Funcția Cereri te ajută să gestionezi cererile care vin în proiectul tău și să le adaugi ca activități în fluxul tău. Activează Cereri din setările proiectului pentru a gestiona cererile.", + "primary_button": { + "text": "Gestionează funcțiile" + } + }, + "cycle": { + "title": "Funcția Cicluri nu este activată pentru acest proiect.", + "description": "Împarte munca în intervale de timp, pleacă de la termenul limită al proiectului pentru a seta date și progresează vizibil ca echipă. Activează funcția de cicluri pentru a începe să o folosești.", + "primary_button": { + "text": "Gestionează funcțiile" + } + }, + "module": { + "title": "Funcția Module nu este activată pentru proiect.", + "description": "Modulele sunt componentele de bază ale proiectului tău. Activează modulele din setările proiectului pentru a începe să le folosești.", + "primary_button": { + "text": "Gestionează funcțiile" + } + }, + "page": { + "title": "Funcția Documentație nu este activată pentru proiect.", + "description": "Paginile sunt componentele de bază ale proiectului tău. Activează paginile din setările proiectului pentru a începe să le folosești.", + "primary_button": { + "text": "Gestionează funcțiile" + } + }, + "view": { + "title": "Funcția Perspective nu este activată pentru proiect.", + "description": "Perspectivele sunt componentele de bază ale proiectului tău. Activează perspectivele din setările proiectului pentru a începe să le folosești.", + "primary_button": { + "text": "Gestionează funcțiile" + } + } + } + }, + "workspace_draft_issues": { + "draft_an_issue": "Salvează o activitate ca schiță", + "empty_state": { + "title": "Elementele de lucru scrise pe jumătate, și în curând și comentariile, vor apărea aici.", + "description": "Ca să testezi, începe să adaugi o activitate și las-o nefinalizată sau creează prima ta schiță mai jos. 😉", + "primary_button": { + "text": "Creează prima ta schiță" + } + }, + "delete_modal": { + "title": "Șterge schița", + "description": "Ești sigur că vrei să ștergi această schiță? Această acțiune este ireversibilă." + }, + "toasts": { + "created": { + "success": "Schiță creată", + "error": "Activitatea nu a putut fi creată. Te rugăm să încerci din nou." + }, + "deleted": { + "success": "Schiță ștearsă" + } + } + }, + + "stickies": { + "title": "Notițele tale", + "placeholder": "click pentru a scrie aici", + "all": "Toate notițele", + "no-data": "Notează o idee, surprinde un moment de inspirație sau înregistrează o idee. Adaugă o notiță pentru a începe.", + "add": "Adaugă notiță", + "search_placeholder": "Caută după titlu", + "delete": "Șterge notița", + "delete_confirmation": "Ești sigur că vrei să ștergi această notiță?", + "empty_state": { + "simple": "Notează o idee, surprinde un moment de inspirație sau înregistrează o idee. Adaugă o notiță pentru a începe.", + "general": { + "title": "Notițele sunt observații rapide și lucruri de făcut pe care le notezi din mers.", + "description": "Surprinde-ți gândurile și ideile fără efort, creând notițe la care poți avea acces oricând și de oriunde.", + "primary_button": { + "text": "Adaugă notiță" + } + }, + "search": { + "title": "Nu se potrivește cu nicio notiță existentă.", + "description": "Încearcă un alt termen sau anunță-ne\n dacă ești sigur că ai căutat corect.", + "primary_button": { + "text": "Adaugă notiță" + } + } + }, + "toasts": { + "errors": { + "wrong_name": "Numele notiței nu poate depăși 100 de caractere.", + "already_exists": "Există deja o notiță fără descriere" + }, + "created": { + "title": "Notiță creată", + "message": "Notița a fost creată cu succes" + }, + "not_created": { + "title": "Notiță necreată", + "message": "Notița nu a putut fi creată" + }, + "updated": { + "title": "Notiță actualizată", + "message": "Notița a fost actualizată cu succes" + }, + "not_updated": { + "title": "Notiță neactualizată", + "message": "Notița nu a putut fi actualizată" + }, + "removed": { + "title": "Notiță ștearsă", + "message": "Notița a fost ștearsă cu succes" + }, + "not_removed": { + "title": "Notiță neștearsă", + "message": "Notița nu a putut fi ștearsă" + } + } + }, + + "role_details": { + "guest": { + "title": "Invitat", + "description": "Membrii externi ai organizațiilor pot fi incluși ca invitați." + }, + "member": { + "title": "Membru", + "description": "Poate citi, scrie, edita și șterge entități în proiecte, cicluri și module" + }, + "admin": { + "title": "Administrator", + "description": "Toate permisiunile setate pe adevărat în cadrul workspace-ului." + } + }, + + "user_roles": { + "product_or_project_manager": "Manager de produs / proiect", + "development_or_engineering": "Dezvoltare / Inginerie", + "founder_or_executive": "Fondator / Director executiv", + "freelancer_or_consultant": "Liber profesionist / Consultant", + "marketing_or_growth": "Marketing / Creștere", + "sales_or_business_development": "Vânzări / Dezvoltare afaceri", + "support_or_operations": "Suport / Operațiuni", + "student_or_professor": "Student / Profesor", + "human_resources": "Resurse umane", + "other": "Altceva" + }, + + "importer": { + "github": { + "title": "Github", + "description": "Importă activități din arhivele de cod GitHub și sincronizează-le." + }, + "jira": { + "title": "Jira", + "description": "Importă activități și episoade din proiectele și episoadele Jira." + } + }, + + "exporter": { + "csv": { + "title": "CSV", + "description": "Exportă activitățile într-un fișier CSV.", + "short_description": "Exportă ca CSV" + }, + "excel": { + "title": "Excel", + "description": "Exportă activitățile într-un fișier Excel.", + "short_description": "Exportă ca Excel" + }, + "xlsx": { + "title": "Excel", + "description": "Exportă activitățile într-un fișier Excel.", + "short_description": "Exportă ca Excel" + }, + "json": { + "title": "JSON", + "description": "Exportă activitățile într-un fișier JSON.", + "short_description": "Exportă ca JSON" + } + }, + "default_global_view": { + "all_issues": "Toate activitățile", + "assigned": "Atribuite", + "created": "Create", + "subscribed": "Urmărite" + }, + + "themes": { + "theme_options": { + "system_preference": { + "label": "Preferință sistem" + }, + "light": { + "label": "Luminos" + }, + "dark": { + "label": "Întunecat" + }, + "light_contrast": { + "label": "Luminos cu contrast ridicat" + }, + "dark_contrast": { + "label": "Întunecat cu contrast ridicat" + }, + "custom": { + "label": "Temă personalizată" + } + } + }, + "project_modules": { + "status": { + "backlog": "Restante", + "planned": "Planificate", + "in_progress": "În desfășurare", + "paused": "În pauză", + "completed": "Finalizat", + "cancelled": "Anulat" + }, + "layout": { + "list": "Aspect listă", + "board": "Aspect galerie", + "timeline": "Aspect cronologic" + }, + "order_by": { + "name": "Nume", + "progress": "Progres", + "issues": "Număr de activități", + "due_date": "Termen limită", + "created_at": "Dată creare", + "manual": "Manual" + } + }, + + "cycle": { + "label": "{count, plural, one {Ciclu} other {Cicluri}}", + "no_cycle": "Niciun ciclu" + }, + + "module": { + "label": "{count, plural, one {Modul} other {Module}}", + "no_module": "Niciun modul" + } +} diff --git a/packages/i18n/src/store/index.ts b/packages/i18n/src/store/index.ts index c711e0e63..ceeed0ed0 100644 --- a/packages/i18n/src/store/index.ts +++ b/packages/i18n/src/store/index.ts @@ -165,6 +165,10 @@ export class TranslationStore { return import("../locales/pl/translations.json"); case "ko": return import("../locales/ko/translations.json"); + case "id": + return import("../locales/id/translations.json"); + case "ro": + return import("../locales/ro/translations.json"); default: throw new Error(`Unsupported language: ${language}`); } diff --git a/packages/i18n/src/types/language.ts b/packages/i18n/src/types/language.ts index 9e345064a..32fa033a8 100644 --- a/packages/i18n/src/types/language.ts +++ b/packages/i18n/src/types/language.ts @@ -1,4 +1,20 @@ -export type TLanguage = "en" | "fr" | "es" | "ja" | "zh-CN" | "zh-TW" | "ru" | "it" | "cs" | "sk" | "de" | "ua" | "pl" | "ko"; +export type TLanguage = + | "en" + | "fr" + | "es" + | "ja" + | "zh-CN" + | "zh-TW" + | "ru" + | "it" + | "cs" + | "sk" + | "de" + | "ua" + | "pl" + | "ko" + | "id" + | "ro"; export interface ILanguageOption { label: string; From ae6e5a48fab73aaaa80ebf5130706391c3b3b019 Mon Sep 17 00:00:00 2001 From: Vamsi Krishna <46787868+vamsikrishnamathala@users.noreply.github.com> Date: Wed, 26 Mar 2025 20:23:19 +0530 Subject: [PATCH 028/146] [WEB-3681]feat: added user timezone dates for cycle (#6820) * feat: added user timezone dates for cycle * *chore: added translations *chore: refactored user timezone functions --- .../i18n/src/locales/cs/translations.json | 6 + .../i18n/src/locales/de/translations.json | 8 +- .../i18n/src/locales/en/translations.json | 6 + .../i18n/src/locales/es/translations.json | 6 + .../i18n/src/locales/fr/translations.json | 6 + .../i18n/src/locales/it/translations.json | 6 + .../i18n/src/locales/ja/translations.json | 6 + .../i18n/src/locales/ko/translations.json | 6 + .../i18n/src/locales/pl/translations.json | 8 +- .../i18n/src/locales/ru/translations.json | 6 + .../i18n/src/locales/sk/translations.json | 6 + .../i18n/src/locales/ua/translations.json | 6 + .../i18n/src/locales/zh-CN/translations.json | 6 + .../i18n/src/locales/zh-TW/translations.json | 6 + .../cycles/list/cycle-list-item-action.tsx | 103 +++++++++++++----- .../cycles/list/cycles-list-item.tsx | 2 + web/core/components/dropdowns/date-range.tsx | 25 +++-- web/core/hooks/use-timezone-converter.tsx | 69 ++++++++++++ 18 files changed, 247 insertions(+), 40 deletions(-) create mode 100644 web/core/hooks/use-timezone-converter.tsx diff --git a/packages/i18n/src/locales/cs/translations.json b/packages/i18n/src/locales/cs/translations.json index 1315ba75c..0e2764ec4 100644 --- a/packages/i18n/src/locales/cs/translations.json +++ b/packages/i18n/src/locales/cs/translations.json @@ -1774,6 +1774,12 @@ "remove_filters_to_see_all_cycles": "Odeberte filtry pro zobrazení všech cyklů", "remove_search_criteria_to_see_all_cycles": "Odeberte kritéria pro zobrazení všech cyklů", "only_completed_cycles_can_be_archived": "Lze archivovat pouze dokončené cykly", + "start_date": "Začátek data", + "end_date": "Konec data", + "in_your_timezone": "V časovém pásmu", + "transfer_work_items": "Převést {count} pracovních položek", + "date_range": "Období data", + "add_date": "Přidat datum", "active_cycle": { "label": "Aktivní cyklus", "progress": "Pokrok", diff --git a/packages/i18n/src/locales/de/translations.json b/packages/i18n/src/locales/de/translations.json index 4a3a5c06d..872fc1746 100644 --- a/packages/i18n/src/locales/de/translations.json +++ b/packages/i18n/src/locales/de/translations.json @@ -1747,6 +1747,12 @@ "remove_filters_to_see_all_cycles": "Entfernen Sie Filter, um alle Zyklen anzuzeigen", "remove_search_criteria_to_see_all_cycles": "Entfernen Sie Suchkriterien, um alle Zyklen anzuzeigen", "only_completed_cycles_can_be_archived": "Nur abgeschlossene Zyklen können archiviert werden", + "start_date": "Startdatum", + "end_date": "Enddatum", + "in_your_timezone": "In Ihrer Zeitzone", + "transfer_work_items": "Übertragen von {count} Arbeitselementen", + "date_range": "Datumsbereich", + "add_date": "Datum hinzufügen", "active_cycle": { "label": "Aktiver Zyklus", "progress": "Fortschritt", @@ -2321,4 +2327,4 @@ "label": "{count, plural, one {Modul} few {Module} other {Module}}", "no_module": "Kein Modul" } -} \ No newline at end of file +} diff --git a/packages/i18n/src/locales/en/translations.json b/packages/i18n/src/locales/en/translations.json index 6beb2917b..3566ae980 100644 --- a/packages/i18n/src/locales/en/translations.json +++ b/packages/i18n/src/locales/en/translations.json @@ -1606,6 +1606,12 @@ "remove_filters_to_see_all_cycles": "Remove the filters to see all cycles", "remove_search_criteria_to_see_all_cycles": "Remove the search criteria to see all cycles", "only_completed_cycles_can_be_archived": "Only completed cycles can be archived", + "start_date": "Start date", + "end_date": "End date", + "in_your_timezone": "In your timezone", + "transfer_work_items": "Transfer {count} work items", + "date_range": "Date range", + "add_date": "Add date", "active_cycle": { "label": "Active cycle", "progress": "Progress", diff --git a/packages/i18n/src/locales/es/translations.json b/packages/i18n/src/locales/es/translations.json index c349364d4..3c30865de 100644 --- a/packages/i18n/src/locales/es/translations.json +++ b/packages/i18n/src/locales/es/translations.json @@ -1776,6 +1776,12 @@ "remove_filters_to_see_all_cycles": "Elimina los filtros para ver todos los ciclos", "remove_search_criteria_to_see_all_cycles": "Elimina los criterios de búsqueda para ver todos los ciclos", "only_completed_cycles_can_be_archived": "Solo los ciclos completados pueden ser archivados", + "start_date": "Fecha de inicio", + "end_date": "Fecha de finalización", + "in_your_timezone": "En tu zona horaria", + "transfer_work_items": "Transferir {count} elementos de trabajo", + "date_range": "Rango de fechas", + "add_date": "Agregar fecha", "active_cycle": { "label": "Ciclo activo", "progress": "Progreso", diff --git a/packages/i18n/src/locales/fr/translations.json b/packages/i18n/src/locales/fr/translations.json index 651622b97..1b1332d5f 100644 --- a/packages/i18n/src/locales/fr/translations.json +++ b/packages/i18n/src/locales/fr/translations.json @@ -1774,6 +1774,12 @@ "remove_filters_to_see_all_cycles": "Supprimez les filtres pour voir tous les cycles", "remove_search_criteria_to_see_all_cycles": "Supprimez les critères de recherche pour voir tous les cycles", "only_completed_cycles_can_be_archived": "Seuls les cycles terminés peuvent être archivés", + "start_date": "Date de début", + "end_date": "Date de fin", + "in_your_timezone": "Dans votre fuseau horaire", + "transfer_work_items": "Transférer {count} éléments de travail", + "date_range": "Plage de dates", + "add_date": "Ajouter une date", "active_cycle": { "label": "Cycle actif", "progress": "Progression", diff --git a/packages/i18n/src/locales/it/translations.json b/packages/i18n/src/locales/it/translations.json index ba40f5b9b..c83af70a4 100644 --- a/packages/i18n/src/locales/it/translations.json +++ b/packages/i18n/src/locales/it/translations.json @@ -1772,6 +1772,12 @@ "remove_filters_to_see_all_cycles": "Rimuovi i filtri per vedere tutti i cicli", "remove_search_criteria_to_see_all_cycles": "Rimuovi i criteri di ricerca per vedere tutti i cicli", "only_completed_cycles_can_be_archived": "Solo i cicli completati possono essere archiviati", + "start_date": "Data di inizio", + "end_date": "Data di fine", + "in_your_timezone": "Nel tuo fuso orario", + "transfer_work_items": "Trasferisci {count} elementi di lavoro", + "date_range": "Intervallo di date", + "add_date": "Aggiungi data", "active_cycle": { "label": "Ciclo attivo", "progress": "Avanzamento", diff --git a/packages/i18n/src/locales/ja/translations.json b/packages/i18n/src/locales/ja/translations.json index 8f3c82e05..cb4a2ac78 100644 --- a/packages/i18n/src/locales/ja/translations.json +++ b/packages/i18n/src/locales/ja/translations.json @@ -1774,6 +1774,12 @@ "remove_filters_to_see_all_cycles": "すべてのサイクルを表示するにはフィルターを解除してください", "remove_search_criteria_to_see_all_cycles": "すべてのサイクルを表示するには検索条件を解除してください", "only_completed_cycles_can_be_archived": "完了したサイクルのみアーカイブできます", + "start_date": "開始日", + "end_date": "終了日", + "in_your_timezone": "あなたのタイムゾーン", + "transfer_work_items": "作業項目を転送 {count}", + "date_range": "日付範囲", + "add_date": "日付を追加", "active_cycle": { "label": "アクティブなサイクル", "progress": "進捗", diff --git a/packages/i18n/src/locales/ko/translations.json b/packages/i18n/src/locales/ko/translations.json index b3b0a29d4..794f97e84 100644 --- a/packages/i18n/src/locales/ko/translations.json +++ b/packages/i18n/src/locales/ko/translations.json @@ -1776,6 +1776,12 @@ "remove_filters_to_see_all_cycles": "모든 주기를 보려면 필터를 제거하세요", "remove_search_criteria_to_see_all_cycles": "모든 주기를 보려면 검색 기준을 제거하세요", "only_completed_cycles_can_be_archived": "완료된 주기만 아카이브할 수 있습니다", + "start_date": "시작일", + "end_date": "종료일", + "in_your_timezone": "내 시간대", + "transfer_work_items": "{count}개의 작업 항목 이전", + "date_range": "날짜 범위", + "add_date": "날짜 추가", "active_cycle": { "label": "활성 주기", "progress": "진행", diff --git a/packages/i18n/src/locales/pl/translations.json b/packages/i18n/src/locales/pl/translations.json index 3cee65853..98c8713b1 100644 --- a/packages/i18n/src/locales/pl/translations.json +++ b/packages/i18n/src/locales/pl/translations.json @@ -1747,6 +1747,12 @@ "remove_filters_to_see_all_cycles": "Usuń filtry, aby wyświetlić wszystkie cykle", "remove_search_criteria_to_see_all_cycles": "Usuń kryteria wyszukiwania, aby wyświetlić wszystkie cykle", "only_completed_cycles_can_be_archived": "Można archiwizować tylko ukończone cykle", + "start_date": "Data początku", + "end_date": "Data końca", + "in_your_timezone": "W Twojej strefie czasowej", + "transfer_work_items": "Przenieś {count} elementów pracy", + "date_range": "Zakres dat", + "add_date": "Dodaj datę", "active_cycle": { "label": "Aktywny cykl", "progress": "Postęp", @@ -2321,4 +2327,4 @@ "label": "{count, plural, one {Moduł} few {Moduły} other {Modułów}}", "no_module": "Brak modułu" } -} \ No newline at end of file +} diff --git a/packages/i18n/src/locales/ru/translations.json b/packages/i18n/src/locales/ru/translations.json index d753b30ba..52c403d18 100644 --- a/packages/i18n/src/locales/ru/translations.json +++ b/packages/i18n/src/locales/ru/translations.json @@ -1774,6 +1774,12 @@ "remove_filters_to_see_all_cycles": "Снимите фильтры для просмотра всех циклов", "remove_search_criteria_to_see_all_cycles": "Очистите поиск для просмотра всех циклов", "only_completed_cycles_can_be_archived": "Только завершённые циклы можно архивировать", + "start_date": "Дата начала", + "end_date": "Дата окончания", + "in_your_timezone": "В вашем часовом поясе", + "transfer_work_items": "Перенести {count} рабочих элементов", + "date_range": "Диапазон дат", + "add_date": "Добавить дату", "active_cycle": { "label": "Активный цикл", "progress": "Прогресс", diff --git a/packages/i18n/src/locales/sk/translations.json b/packages/i18n/src/locales/sk/translations.json index 30a1a4db8..8a4645fd4 100644 --- a/packages/i18n/src/locales/sk/translations.json +++ b/packages/i18n/src/locales/sk/translations.json @@ -1773,6 +1773,12 @@ "remove_filters_to_see_all_cycles": "Odstráňte filtre pre zobrazenie všetkých cyklov", "remove_search_criteria_to_see_all_cycles": "Odstráňte kritériá pre zobrazenie všetkých cyklov", "only_completed_cycles_can_be_archived": "Archivovať je možné iba dokončené cykly", + "start_date": "Dátum začiatku", + "end_date": "Dátum konca", + "in_your_timezone": "Váš časový pásmo", + "transfer_work_items": "Presunúť {count} pracovných položiek", + "date_range": "Dátumový rozsah", + "add_date": "Pridať dátum", "active_cycle": { "label": "Aktívny cyklus", "progress": "Pokrok", diff --git a/packages/i18n/src/locales/ua/translations.json b/packages/i18n/src/locales/ua/translations.json index ace8349ff..044cfbadc 100644 --- a/packages/i18n/src/locales/ua/translations.json +++ b/packages/i18n/src/locales/ua/translations.json @@ -1747,6 +1747,12 @@ "remove_filters_to_see_all_cycles": "Приберіть фільтри, щоб побачити всі цикли", "remove_search_criteria_to_see_all_cycles": "Приберіть критерії пошуку, щоб побачити всі цикли", "only_completed_cycles_can_be_archived": "Архівувати можна лише завершені цикли", + "start_date": "Дата початку", + "end_date": "Дата завершення", + "in_your_timezone": "У вашому часовому поясі", + "transfer_work_items": "Перенести {count} робочих одиниць", + "date_range": "Діапазон дат", + "add_date": "Додати дату", "active_cycle": { "label": "Активний цикл", "progress": "Прогрес", diff --git a/packages/i18n/src/locales/zh-CN/translations.json b/packages/i18n/src/locales/zh-CN/translations.json index 5e2725127..4620d0617 100644 --- a/packages/i18n/src/locales/zh-CN/translations.json +++ b/packages/i18n/src/locales/zh-CN/translations.json @@ -1774,6 +1774,12 @@ "remove_filters_to_see_all_cycles": "移除筛选器以查看所有周期", "remove_search_criteria_to_see_all_cycles": "移除搜索条件以查看所有周期", "only_completed_cycles_can_be_archived": "只能归档已完成的周期", + "start_date": "开始日期", + "end_date": "结束日期", + "in_your_timezone": "在您的时区", + "transfer_work_items": "转移 {count} 工作项", + "date_range": "日期范围", + "add_date": "添加日期", "active_cycle": { "label": "活动周期", "progress": "进度", diff --git a/packages/i18n/src/locales/zh-TW/translations.json b/packages/i18n/src/locales/zh-TW/translations.json index a59d78e4d..c371f6fc6 100644 --- a/packages/i18n/src/locales/zh-TW/translations.json +++ b/packages/i18n/src/locales/zh-TW/translations.json @@ -1776,6 +1776,12 @@ "remove_filters_to_see_all_cycles": "移除篩選器以檢視所有週期", "remove_search_criteria_to_see_all_cycles": "移除搜尋條件以檢視所有週期", "only_completed_cycles_can_be_archived": "只有已完成的週期可以封存", + "start_date": "開始日期", + "end_date": "結束日期", + "in_your_timezone": "在您的時區", + "transfer_work_items": "轉移 {count} 工作事項", + "date_range": "日期範圍", + "add_date": "新增日期", "active_cycle": { "label": "使用中的週期", "progress": "進度", diff --git a/web/core/components/cycles/list/cycle-list-item-action.tsx b/web/core/components/cycles/list/cycle-list-item-action.tsx index bc627fdf2..8b346b3cd 100644 --- a/web/core/components/cycles/list/cycle-list-item-action.tsx +++ b/web/core/components/cycles/list/cycle-list-item-action.tsx @@ -1,10 +1,11 @@ "use client"; import React, { FC, MouseEvent, useEffect, useMemo, useState } from "react"; +import { format, parseISO } from "date-fns"; import { observer } from "mobx-react"; import { useParams, usePathname, useSearchParams } from "next/navigation"; import { useForm } from "react-hook-form"; -import { Eye, Users } from "lucide-react"; +import { Eye, Users, ArrowRight, CalendarDays } from "lucide-react"; // types import { CYCLE_FAVORITED, @@ -29,6 +30,7 @@ import { generateQueryParams } from "@/helpers/router.helper"; import { useCycle, useEventTracker, useMember, useUserPermissions } from "@/hooks/store"; import { useAppRouter } from "@/hooks/use-app-router"; import { usePlatformOS } from "@/hooks/use-platform-os"; +import { useTimeZoneConverter } from "@/hooks/use-timezone-converter"; // plane web components import { CycleAdditionalActions } from "@/plane-web/components/cycles"; @@ -55,6 +57,8 @@ export const CycleListItemAction: FC = observer((props) => { // hooks const { isMobile } = usePlatformOS(); const { t } = useTranslation(); + const { isProjectTimeZoneDifferent, getProjectUTCOffset, renderFormattedDateInUserTimezone } = + useTimeZoneConverter(projectId); // router const router = useAppRouter(); const searchParams = useSearchParams(); @@ -88,6 +92,8 @@ export const CycleListItemAction: FC = observer((props) => { const showTransferIssues = routerProjectId && transferableIssuesCount > 0 && cycleStatus === "completed"; + const projectUTCOffset = getProjectUTCOffset(); + const isEditingAllowed = allowPermissions( [EUserPermissions.ADMIN, EUserPermissions.MEMBER], EUserPermissionsLevel.PROJECT, @@ -189,14 +195,12 @@ export const CycleListItemAction: FC = observer((props) => { {t("project_cycles.more_details")} - {showIssueCount && (
{cycleDetails.total_issues}
)} - {showTransferIssues && (
= observer((props) => { }} > - Transfer {transferableIssuesCount} work items + {t("project_cycles.transfer_work_items", { count: transferableIssuesCount })}
)} - - {!isActive && cycleDetails.start_date && ( - div]:hover:bg-transparent`} - buttonClassName="p-0" - minDate={new Date()} - value={{ - from: getDate(cycleDetails.start_date), - to: getDate(cycleDetails.end_date), - }} - placeholder={{ - from: "Start date", - to: "End date", - }} - showTooltip - required={cycleDetails.status !== "draft"} - disabled - hideIcon={{ - from: false, - to: false, - }} - /> + {isActive ? ( + <> +
+ {/* Duration */} + + {renderFormattedDateInUserTimezone(cycleDetails.start_date ?? "")} + + {renderFormattedDateInUserTimezone(cycleDetails.end_date ?? "")} + + } + disabled={!isProjectTimeZoneDifferent()} + tooltipHeading={t("project_cycles.date_range")} + > +
+ + {cycleDetails.start_date && {format(parseISO(cycleDetails.start_date), "MMM dd, yyyy")}} + + {cycleDetails.end_date && {format(parseISO(cycleDetails.end_date), "MMM dd, yyyy")}} +
+
+ {projectUTCOffset && ( + + {projectUTCOffset} + + )} + {/* created by */} + {createdByDetails && } +
+ + ) : ( + cycleDetails.start_date && ( + <> + div]:hover:bg-transparent`} + buttonClassName="p-0" + minDate={new Date()} + value={{ + from: getDate(cycleDetails.start_date), + to: getDate(cycleDetails.end_date), + }} + placeholder={{ + from: t("project_cycles.start_date"), + to: t("project_cycles.end_date"), + }} + showTooltip={isProjectTimeZoneDifferent()} + customTooltipHeading={t("project_cycles.in_your_timezone")} + customTooltipContent={ + + {renderFormattedDateInUserTimezone(cycleDetails.start_date ?? "")} + + {renderFormattedDateInUserTimezone(cycleDetails.end_date ?? "")} + + } + required={cycleDetails.status !== "draft"} + disabled + hideIcon={{ + from: false, + to: false, + }} + /> + + ) )} - {/* created by */} {createdByDetails && !isActive && } - {!isActive && (
@@ -255,7 +299,6 @@ export const CycleListItemAction: FC = observer((props) => {
)} - {isEditingAllowed && !cycleDetails.archived_at && ( { diff --git a/web/core/components/cycles/list/cycles-list-item.tsx b/web/core/components/cycles/list/cycles-list-item.tsx index aad2f6922..5fca9a9e7 100644 --- a/web/core/components/cycles/list/cycles-list-item.tsx +++ b/web/core/components/cycles/list/cycles-list-item.tsx @@ -53,6 +53,7 @@ export const CyclesListItem: FC = observer((props) => { // TODO: change this logic once backend fix the response const cycleStatus = cycleDetails.status ? (cycleDetails.status.toLocaleLowerCase() as TCycleGroups) : "draft"; const isCompleted = cycleStatus === "completed"; + const isActive = cycleStatus === "current"; const cycleTotalIssues = cycleDetails.backlog_issues + @@ -113,6 +114,7 @@ export const CyclesListItem: FC = observer((props) => { cycleId={cycleId} cycleDetails={cycleDetails} parentRef={parentRef} + isActive={isActive} /> } quickActionElement={ diff --git a/web/core/components/dropdowns/date-range.tsx b/web/core/components/dropdowns/date-range.tsx index f33a8f8b7..0ab9fd44b 100644 --- a/web/core/components/dropdowns/date-range.tsx +++ b/web/core/components/dropdowns/date-range.tsx @@ -6,6 +6,8 @@ import { DateRange, Matcher } from "react-day-picker"; import { usePopper } from "react-popper"; import { ArrowRight, CalendarCheck2, CalendarDays } from "lucide-react"; import { Combobox } from "@headlessui/react"; +// plane imports +import { useTranslation } from "@plane/i18n"; // ui import { ComboDropDown, Calendar } from "@plane/ui"; // helpers @@ -50,9 +52,12 @@ type Props = { }; renderByDefault?: boolean; renderPlaceholder?: boolean; + customTooltipContent?: React.ReactNode; + customTooltipHeading?: string; }; export const DateRangeDropdown: React.FC = (props) => { + const { t } = useTranslation(); const { buttonClassName, buttonContainerClassName, @@ -69,8 +74,8 @@ export const DateRangeDropdown: React.FC = (props) => { maxDate, onSelect, placeholder = { - from: "Add date", - to: "Add date", + from: t("project_cycles.add_date"), + to: t("project_cycles.add_date"), }, placement, showTooltip = false, @@ -78,6 +83,8 @@ export const DateRangeDropdown: React.FC = (props) => { value, renderByDefault = true, renderPlaceholder = true, + customTooltipContent, + customTooltipHeading, } = props; // states const [isOpen, setIsOpen] = useState(false); @@ -147,13 +154,15 @@ export const DateRangeDropdown: React.FC = (props) => { - {dateRange.from ? renderFormattedDate(dateRange.from) : "N/A"} - {" - "} - {dateRange.to ? renderFormattedDate(dateRange.to) : "N/A"} - + customTooltipContent ?? ( + <> + {dateRange.from ? renderFormattedDate(dateRange.from) : "N/A"} + {" - "} + {dateRange.to ? renderFormattedDate(dateRange.to) : "N/A"} + + ) } showTooltip={showTooltip} variant={buttonVariant} diff --git a/web/core/hooks/use-timezone-converter.tsx b/web/core/hooks/use-timezone-converter.tsx new file mode 100644 index 000000000..97646a339 --- /dev/null +++ b/web/core/hooks/use-timezone-converter.tsx @@ -0,0 +1,69 @@ +import { useCallback } from "react"; +import { format } from "date-fns"; +import { useProject, useUser } from "@/hooks/store"; + +export const useTimeZoneConverter = (projectId: string) => { + const { data: user } = useUser(); + const { getProjectById } = useProject(); + const userTimezone = user?.user_timezone; + const projectTimezone = getProjectById(projectId)?.timezone; + + /** + * Render a date in the user's timezone + * @param date - The date to render + * @param formatToken - The format token to use + * @returns The formatted date + */ + const renderFormattedDateInUserTimezone = useCallback( + (date: string, formatToken: string = "MMM dd, yyyy") => { + // return if undefined + if (!date || !userTimezone) return; + // convert the date to the user's timezone + const convertedDate = new Date(date).toLocaleString("en-US", { timeZone: userTimezone }); + // return the formatted date + return format(convertedDate, formatToken); + }, + [userTimezone] + ); + + /** + * Get the project's UTC offset + * @returns The project's UTC offset + */ + const getProjectUTCOffset = useCallback(() => { + if (!projectTimezone) return; + + // Get date in user's timezone + const projectDate = new Date(new Date().toLocaleString("en-US", { timeZone: projectTimezone })); + const utcDate = new Date(new Date().toLocaleString("en-US", { timeZone: "UTC" })); + + // Calculate offset in minutes + const offsetInMinutes = (projectDate.getTime() - utcDate.getTime()) / 60000; + + // return if undefined + if (!offsetInMinutes) return; + + // Convert to hours and minutes + const hours = Math.floor(Math.abs(offsetInMinutes) / 60); + const minutes = Math.abs(offsetInMinutes) % 60; + + // Format as +/-HH:mm + const sign = offsetInMinutes >= 0 ? "+" : "-"; + return `UTC ${sign}${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}`; + }, [projectTimezone]); + + /** + * Check if the project's timezone is different from the user's timezone + * @returns True if the project's timezone is different from the user's timezone, false otherwise + */ + const isProjectTimeZoneDifferent = useCallback(() => { + if (!projectTimezone || !userTimezone) return false; + return projectTimezone !== userTimezone; + }, [projectTimezone, userTimezone]); + + return { + renderFormattedDateInUserTimezone, + getProjectUTCOffset, + isProjectTimeZoneDifferent, + }; +}; From 993713925ae27c17d51daf4070801b94c05951ad Mon Sep 17 00:00:00 2001 From: "M. Palanikannan" <73993394+Palanikannan1437@users.noreply.github.com> Date: Wed, 26 Mar 2025 20:24:05 +0530 Subject: [PATCH 029/146] feat: express decorators for rest apis and websocket (#6818) * feat: express decorators for rest apis and websocket * fix: added package dependency * fix: refactor decorators --- packages/decorators/.eslintignore | 4 + packages/decorators/.eslintrc.js | 10 + packages/decorators/README.md | 99 +++++++ packages/decorators/package.json | 42 +++ packages/decorators/src/controller.ts | 61 +++++ packages/decorators/src/index.ts | 15 ++ packages/decorators/src/rest.ts | 61 +++++ .../decorators/src/websocket-controller.ts | 85 ++++++ packages/decorators/src/websocket.ts | 17 ++ packages/decorators/tsconfig.json | 21 ++ packages/decorators/tsup.config.ts | 12 + packages/typescript-config/node-library.json | 26 ++ packages/typescript-config/package.json | 3 +- yarn.lock | 241 +++++++++++++++++- 14 files changed, 690 insertions(+), 7 deletions(-) create mode 100644 packages/decorators/.eslintignore create mode 100644 packages/decorators/.eslintrc.js create mode 100644 packages/decorators/README.md create mode 100644 packages/decorators/package.json create mode 100644 packages/decorators/src/controller.ts create mode 100644 packages/decorators/src/index.ts create mode 100644 packages/decorators/src/rest.ts create mode 100644 packages/decorators/src/websocket-controller.ts create mode 100644 packages/decorators/src/websocket.ts create mode 100644 packages/decorators/tsconfig.json create mode 100644 packages/decorators/tsup.config.ts create mode 100644 packages/typescript-config/node-library.json diff --git a/packages/decorators/.eslintignore b/packages/decorators/.eslintignore new file mode 100644 index 000000000..31ca21417 --- /dev/null +++ b/packages/decorators/.eslintignore @@ -0,0 +1,4 @@ +node_modules +build/* +dist/* +out/* diff --git a/packages/decorators/.eslintrc.js b/packages/decorators/.eslintrc.js new file mode 100644 index 000000000..c1728ac28 --- /dev/null +++ b/packages/decorators/.eslintrc.js @@ -0,0 +1,10 @@ +/** @type {import("eslint").Linter.Config} */ +module.exports = { + root: true, + extends: ["@plane/eslint-config/library.js"], + parser: "@typescript-eslint/parser", + parserOptions: { + project: true, + }, +}; + diff --git a/packages/decorators/README.md b/packages/decorators/README.md new file mode 100644 index 000000000..e9c308e9e --- /dev/null +++ b/packages/decorators/README.md @@ -0,0 +1,99 @@ +# @plane/decorators + +A lightweight TypeScript decorator library for building Express.js controllers with a clean, declarative syntax. + +## Features + +- TypeScript-first design +- Decorators for HTTP methods (GET, POST, PUT, PATCH, DELETE) +- WebSocket support +- Middleware support +- No build step required - works directly with TypeScript files + +## Installation + +This package is part of the Plane workspace and can be used by adding it to your project's dependencies: + +```json +{ + "dependencies": { + "@plane/decorators": "*" + } +} +``` + +## Usage + +### Basic REST Controller + +```typescript +import { Controller, Get, Post, BaseController } from "@plane/decorators"; +import { Router, Request, Response } from "express"; + +@Controller("/api/users") +class UserController extends BaseController { + @Get("/") + async getUsers(req: Request, res: Response) { + return res.json({ users: [] }); + } + + @Post("/") + async createUser(req: Request, res: Response) { + return res.json({ success: true }); + } +} + +// Register routes +const router = Router(); +const userController = new UserController(); +userController.registerRoutes(router); +``` + +### WebSocket Controller + +```typescript +import { + Controller, + WebSocket, + BaseWebSocketController, +} from "@plane/decorators"; +import { Request } from "express"; +import { WebSocket as WS } from "ws"; + +@Controller("/ws/chat") +class ChatController extends BaseWebSocketController { + @WebSocket("/") + handleConnection(ws: WS, req: Request) { + ws.on("message", (message) => { + ws.send(`Received: ${message}`); + }); + } +} + +// Register WebSocket routes +const router = require("express-ws")(app).router; +const chatController = new ChatController(); +chatController.registerWebSocketRoutes(router); +``` + +## API Reference + +### Decorators + +- `@Controller(baseRoute: string)` - Class decorator for defining a base route +- `@Get(route: string)` - Method decorator for HTTP GET endpoints +- `@Post(route: string)` - Method decorator for HTTP POST endpoints +- `@Put(route: string)` - Method decorator for HTTP PUT endpoints +- `@Patch(route: string)` - Method decorator for HTTP PATCH endpoints +- `@Delete(route: string)` - Method decorator for HTTP DELETE endpoints +- `@WebSocket(route: string)` - Method decorator for WebSocket endpoints +- `@Middleware(middleware: RequestHandler)` - Method decorator for applying middleware + +### Classes + +- `BaseController` - Base class for REST controllers +- `BaseWebSocketController` - Base class for WebSocket controllers + +## License + +This project is licensed under the [GNU Affero General Public License v3.0](https://github.com/makeplane/plane/blob/master/LICENSE.txt). diff --git a/packages/decorators/package.json b/packages/decorators/package.json new file mode 100644 index 000000000..013dcac5f --- /dev/null +++ b/packages/decorators/package.json @@ -0,0 +1,42 @@ +{ + "name": "@plane/decorators", + "version": "0.1.0", + "description": "Controller and route decorators for Express.js applications", + "license": "AGPL-3.0", + "private": true, + "main": "./dist/index.js", + "module": "./dist/index.mjs", + "types": "./dist/index.d.ts", + "files": [ + "dist/**" + ], + "scripts": { + "build": "tsup src/index.ts --format esm,cjs --dts --external express,ws", + "dev": "tsup src/index.ts --format esm,cjs --watch --dts --external express,ws", + "lint": "eslint src --ext .ts,.tsx", + "lint:errors": "eslint src --ext .ts,.tsx --quiet" + }, + "dependencies": { + "reflect-metadata": "^0.2.2", + "express": "^4.21.2" + }, + "devDependencies": { + "@plane/eslint-config": "*", + "@types/express": "^4.17.21", + "@types/reflect-metadata": "^0.1.0", + "@plane/typescript-config": "*", + "@types/node": "^20.14.9", + "@types/ws": "^8.5.10", + "tsup": "8.3.0", + "typescript": "^5.3.3" + }, + "peerDependencies": { + "express": ">=4.21.2", + "ws": ">=8.0.0" + }, + "peerDependenciesMeta": { + "ws": { + "optional": true + } + } +} diff --git a/packages/decorators/src/controller.ts b/packages/decorators/src/controller.ts new file mode 100644 index 000000000..a9185a848 --- /dev/null +++ b/packages/decorators/src/controller.ts @@ -0,0 +1,61 @@ +import { RequestHandler, Router } from "express"; +import "reflect-metadata"; + +type HttpMethod = + | "get" + | "post" + | "put" + | "delete" + | "patch" + | "options" + | "head" + | "ws"; + +interface ControllerInstance { + [key: string]: unknown; +} + +interface ControllerConstructor { + new (...args: any[]): ControllerInstance; + prototype: ControllerInstance; +} + +export function registerControllers( + router: Router, + Controller: ControllerConstructor, +): void { + const instance = new Controller(); + const baseRoute = Reflect.getMetadata("baseRoute", Controller) as string; + + Object.getOwnPropertyNames(Controller.prototype).forEach((methodName) => { + if (methodName === "constructor") return; // Skip the constructor + + const method = Reflect.getMetadata( + "method", + instance, + methodName, + ) as HttpMethod; + const route = Reflect.getMetadata("route", instance, methodName) as string; + const middlewares = + (Reflect.getMetadata( + "middlewares", + instance, + methodName, + ) as RequestHandler[]) || []; + + if (method && route) { + const handler = instance[methodName] as unknown; + + if (typeof handler === "function") { + if (method !== "ws") { + ( + router[method] as ( + path: string, + ...handlers: RequestHandler[] + ) => void + )(`${baseRoute}${route}`, ...middlewares, handler.bind(instance)); + } + } + } + }); +} diff --git a/packages/decorators/src/index.ts b/packages/decorators/src/index.ts new file mode 100644 index 000000000..ef7136059 --- /dev/null +++ b/packages/decorators/src/index.ts @@ -0,0 +1,15 @@ +// Export individual decorators +export { Controller, Middleware } from "./rest"; +export { Get, Post, Put, Patch, Delete } from "./rest"; +export { WebSocket } from "./websocket"; +export { registerControllers } from "./controller"; +export { registerWebSocketControllers } from "./websocket-controller"; + +// Also provide namespaced exports for better organization +import * as RestDecorators from "./rest"; +import * as WebSocketDecorators from "./websocket"; + +// Named namespace exports +export const Rest = RestDecorators; +export const WebSocketNS = WebSocketDecorators; + diff --git a/packages/decorators/src/rest.ts b/packages/decorators/src/rest.ts new file mode 100644 index 000000000..68c0fba54 --- /dev/null +++ b/packages/decorators/src/rest.ts @@ -0,0 +1,61 @@ +import "reflect-metadata"; +import { RequestHandler } from "express"; + +// Define valid HTTP methods +type RestMethod = "get" | "post" | "put" | "patch" | "delete"; + +/** + * Controller decorator + * @param baseRoute + * @returns + */ +export function Controller(baseRoute: string = ""): ClassDecorator { + return function (target: Function) { + Reflect.defineMetadata("baseRoute", baseRoute, target); + }; +} + +/** + * Factory function to create HTTP method decorators + * @param method HTTP method to handle + * @returns Method decorator + */ +function createHttpMethodDecorator( + method: RestMethod +): (route: string) => MethodDecorator { + return function (route: string): MethodDecorator { + return function ( + target: object, + propertyKey: string | symbol, + descriptor: PropertyDescriptor + ) { + Reflect.defineMetadata("method", method, target, propertyKey); + Reflect.defineMetadata("route", route, target, propertyKey); + }; + }; +} + +// Export HTTP method decorators using the factory +export const Get = createHttpMethodDecorator("get"); +export const Post = createHttpMethodDecorator("post"); +export const Put = createHttpMethodDecorator("put"); +export const Patch = createHttpMethodDecorator("patch"); +export const Delete = createHttpMethodDecorator("delete"); + +/** + * Middleware decorator + * @param middleware + * @returns + */ +export function Middleware(middleware: RequestHandler): MethodDecorator { + return function ( + target: object, + propertyKey: string | symbol, + descriptor: PropertyDescriptor, + ) { + const middlewares = + Reflect.getMetadata("middlewares", target, propertyKey) || []; + middlewares.push(middleware); + Reflect.defineMetadata("middlewares", middlewares, target, propertyKey); + }; +} diff --git a/packages/decorators/src/websocket-controller.ts b/packages/decorators/src/websocket-controller.ts new file mode 100644 index 000000000..85a018da0 --- /dev/null +++ b/packages/decorators/src/websocket-controller.ts @@ -0,0 +1,85 @@ +import { Router, Request } from "express"; +import type { WebSocket } from "ws"; +import "reflect-metadata"; + +interface ControllerInstance { + [key: string]: unknown; +} + +interface ControllerConstructor { + new (...args: any[]): ControllerInstance; + prototype: ControllerInstance; +} + +export function registerWebSocketControllers( + router: Router, + Controller: ControllerConstructor, + existingInstance?: ControllerInstance, +): void { + const instance = existingInstance || new Controller(); + const baseRoute = Reflect.getMetadata("baseRoute", Controller) as string; + + Object.getOwnPropertyNames(Controller.prototype).forEach((methodName) => { + if (methodName === "constructor") return; // Skip the constructor + + const method = Reflect.getMetadata( + "method", + instance, + methodName, + ) as string; + const route = Reflect.getMetadata("route", instance, methodName) as string; + + if (method === "ws" && route) { + const handler = instance[methodName] as unknown; + + if ( + typeof handler === "function" && + typeof (router as any).ws === "function" + ) { + (router as any).ws( + `${baseRoute}${route}`, + (ws: WebSocket, req: Request) => { + try { + handler.call(instance, ws, req); + } catch (error) { + console.error( + `WebSocket error in ${Controller.name}.${methodName}`, + error, + ); + ws.close( + 1011, + error instanceof Error + ? error.message + : "Internal server error", + ); + } + }, + ); + } + } + }); +} + +/** + * Base controller class for WebSocket endpoints + */ +export abstract class BaseWebSocketController { + protected router: Router; + + constructor() { + this.router = Router(); + } + + /** + * Get the base route for this controller + */ + protected getBaseRoute(): string { + return Reflect.getMetadata("baseRoute", this.constructor) || ""; + } + + /** + * Abstract method to handle WebSocket connections + * Implement this in your derived class + */ + abstract handleConnection(ws: WebSocket, req: Request): void; +} diff --git a/packages/decorators/src/websocket.ts b/packages/decorators/src/websocket.ts new file mode 100644 index 000000000..5b6b6a7b1 --- /dev/null +++ b/packages/decorators/src/websocket.ts @@ -0,0 +1,17 @@ +import "reflect-metadata"; + +/** + * WebSocket method decorator + * @param route + * @returns + */ +export function WebSocket(route: string): MethodDecorator { + return function ( + target: object, + propertyKey: string | symbol, + descriptor: PropertyDescriptor, + ) { + Reflect.defineMetadata("method", "ws", target, propertyKey); + Reflect.defineMetadata("route", route, target, propertyKey); + }; +} diff --git a/packages/decorators/tsconfig.json b/packages/decorators/tsconfig.json new file mode 100644 index 000000000..02b459b9f --- /dev/null +++ b/packages/decorators/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "@plane/typescript-config/node-library.json", + "compilerOptions": { + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "lib": ["ES2020"], + "rootDir": ".", + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": [ + "./src" + ], + "exclude": [ + "dist", + "build", + "node_modules" + ] +} diff --git a/packages/decorators/tsup.config.ts b/packages/decorators/tsup.config.ts new file mode 100644 index 000000000..757dd8ba3 --- /dev/null +++ b/packages/decorators/tsup.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from 'tsup'; + +export default defineConfig({ + entry: ['src/index.ts'], + format: ['esm', 'cjs'], + dts: true, + splitting: false, + sourcemap: true, + clean: true, + external: ['express', 'ws'], + treeshake: true, +}); \ No newline at end of file diff --git a/packages/typescript-config/node-library.json b/packages/typescript-config/node-library.json new file mode 100644 index 000000000..afb41eff3 --- /dev/null +++ b/packages/typescript-config/node-library.json @@ -0,0 +1,26 @@ +{ + "$schema": "https://json.schemastore.org/tsconfig", + "display": "Node.js Library", + "extends": "./base.json", + "compilerOptions": { + "module": "NodeNext", + "moduleResolution": "NodeNext", + "target": "ES2020", + "lib": ["ES2020"], + "outDir": "./dist", + "rootDir": "./src", + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + }, + "sourceMap": true, + "inlineSources": true, + "experimentalDecorators": true, + "emitDecoratorMetadata": true, + "resolveJsonModule": true, + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "build"] +} \ No newline at end of file diff --git a/packages/typescript-config/package.json b/packages/typescript-config/package.json index cac5df873..914fef03a 100644 --- a/packages/typescript-config/package.json +++ b/packages/typescript-config/package.json @@ -6,6 +6,7 @@ "files": [ "base.json", "nextjs.json", - "react-library.json" + "react-library.json", + "node-library.json" ] } diff --git a/yarn.lock b/yarn.lock index e2f842081..52a74dccb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2241,96 +2241,196 @@ resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.35.0.tgz#e1d7700735f7e8de561ef7d1fa0362082a180c43" integrity sha512-uYQ2WfPaqz5QtVgMxfN6NpLD+no0MYHDBywl7itPYd3K5TjjSghNKmX8ic9S8NU8w81NVhJv/XojcHptRly7qQ== +"@rollup/rollup-android-arm-eabi@4.37.0": + version "4.37.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.37.0.tgz#9bedc746a97fe707154086365f269ced92ff4aa9" + integrity sha512-l7StVw6WAa8l3vA1ov80jyetOAEo1FtHvZDbzXDO/02Sq/QVvqlHkYoFwDJPIMj0GKiistsBudfx5tGFnwYWDQ== + "@rollup/rollup-android-arm64@4.35.0": version "4.35.0" resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.35.0.tgz#fa6cdfb1fc9e2c8e227a7f35d524d8f7f90cf4db" integrity sha512-FtKddj9XZudurLhdJnBl9fl6BwCJ3ky8riCXjEw3/UIbjmIY58ppWwPEvU3fNu+W7FUsAsB1CdH+7EQE6CXAPA== +"@rollup/rollup-android-arm64@4.37.0": + version "4.37.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.37.0.tgz#6edc6ffc8af8773e4bc28c72894dd5e846b8ee6c" + integrity sha512-6U3SlVyMxezt8Y+/iEBcbp945uZjJwjZimu76xoG7tO1av9VO691z8PkhzQ85ith2I8R2RddEPeSfcbyPfD4hA== + "@rollup/rollup-darwin-arm64@4.35.0": version "4.35.0" resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.35.0.tgz#6da5a1ddc4f11d4a7ae85ab443824cb6bf614e30" integrity sha512-Uk+GjOJR6CY844/q6r5DR/6lkPFOw0hjfOIzVx22THJXMxktXG6CbejseJFznU8vHcEBLpiXKY3/6xc+cBm65Q== +"@rollup/rollup-darwin-arm64@4.37.0": + version "4.37.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.37.0.tgz#737a7b8be9ff79bd24a7efaae0903e8c66ac0676" + integrity sha512-+iTQ5YHuGmPt10NTzEyMPbayiNTcOZDWsbxZYR1ZnmLnZxG17ivrPSWFO9j6GalY0+gV3Jtwrrs12DBscxnlYA== + "@rollup/rollup-darwin-x64@4.35.0": version "4.35.0" resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.35.0.tgz#25b74ce2d8d3f9ea8e119b01384d44a1c0a0d3ae" integrity sha512-3IrHjfAS6Vkp+5bISNQnPogRAW5GAV1n+bNCrDwXmfMHbPl5EhTmWtfmwlJxFRUCBZ+tZ/OxDyU08aF6NI/N5Q== +"@rollup/rollup-darwin-x64@4.37.0": + version "4.37.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.37.0.tgz#a6a697bb685ca9462a7caeea5f22f6a686acff1f" + integrity sha512-m8W2UbxLDcmRKVjgl5J/k4B8d7qX2EcJve3Sut7YGrQoPtCIQGPH5AMzuFvYRWZi0FVS0zEY4c8uttPfX6bwYQ== + "@rollup/rollup-freebsd-arm64@4.35.0": version "4.35.0" resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.35.0.tgz#be3d39e3441df5d6e187c83d158c60656c82e203" integrity sha512-sxjoD/6F9cDLSELuLNnY0fOrM9WA0KrM0vWm57XhrIMf5FGiN8D0l7fn+bpUeBSU7dCgPV2oX4zHAsAXyHFGcQ== +"@rollup/rollup-freebsd-arm64@4.37.0": + version "4.37.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.37.0.tgz#18113e8e133ccb6de4b9dc9d3e09f7acff344cb7" + integrity sha512-FOMXGmH15OmtQWEt174v9P1JqqhlgYge/bUjIbiVD1nI1NeJ30HYT9SJlZMqdo1uQFyt9cz748F1BHghWaDnVA== + "@rollup/rollup-freebsd-x64@4.35.0": version "4.35.0" resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.35.0.tgz#cd932d3ec679711efd65ca25821fb318e25b7ce4" integrity sha512-2mpHCeRuD1u/2kruUiHSsnjWtHjqVbzhBkNVQ1aVD63CcexKVcQGwJ2g5VphOd84GvxfSvnnlEyBtQCE5hxVVw== +"@rollup/rollup-freebsd-x64@4.37.0": + version "4.37.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.37.0.tgz#5e56ffd4a0d7ccfcbc86867c40b8f0e6a2c0c81e" + integrity sha512-SZMxNttjPKvV14Hjck5t70xS3l63sbVwl98g3FlVVx2YIDmfUIy29jQrsw06ewEYQ8lQSuY9mpAPlmgRD2iSsA== + "@rollup/rollup-linux-arm-gnueabihf@4.35.0": version "4.35.0" resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.35.0.tgz#d300b74c6f805474225632f185daaeae760ac2bb" integrity sha512-mrA0v3QMy6ZSvEuLs0dMxcO2LnaCONs1Z73GUDBHWbY8tFFocM6yl7YyMu7rz4zS81NDSqhrUuolyZXGi8TEqg== +"@rollup/rollup-linux-arm-gnueabihf@4.37.0": + version "4.37.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.37.0.tgz#5addf1a51e1495ae7ff28d26442a88adf629c980" + integrity sha512-hhAALKJPidCwZcj+g+iN+38SIOkhK2a9bqtJR+EtyxrKKSt1ynCBeqrQy31z0oWU6thRZzdx53hVgEbRkuI19w== + "@rollup/rollup-linux-arm-musleabihf@4.35.0": version "4.35.0" resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.35.0.tgz#2caac622380f314c41934ed1e68ceaf6cc380cc3" integrity sha512-DnYhhzcvTAKNexIql8pFajr0PiDGrIsBYPRvCKlA5ixSS3uwo/CWNZxB09jhIapEIg945KOzcYEAGGSmTSpk7A== +"@rollup/rollup-linux-arm-musleabihf@4.37.0": + version "4.37.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.37.0.tgz#00cddb9ab51086c5f2cd33cd4738259e24be4e73" + integrity sha512-jUb/kmn/Gd8epbHKEqkRAxq5c2EwRt0DqhSGWjPFxLeFvldFdHQs/n8lQ9x85oAeVb6bHcS8irhTJX2FCOd8Ag== + "@rollup/rollup-linux-arm64-gnu@4.35.0": version "4.35.0" resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.35.0.tgz#1ec841650b038cc15c194c26326483fd7ebff3e3" integrity sha512-uagpnH2M2g2b5iLsCTZ35CL1FgyuzzJQ8L9VtlJ+FckBXroTwNOaD0z0/UF+k5K3aNQjbm8LIVpxykUOQt1m/A== +"@rollup/rollup-linux-arm64-gnu@4.37.0": + version "4.37.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.37.0.tgz#c3b4324496236b6fd9f31fda5701c6d6060b1512" + integrity sha512-oNrJxcQT9IcbcmKlkF+Yz2tmOxZgG9D9GRq+1OE6XCQwCVwxixYAa38Z8qqPzQvzt1FCfmrHX03E0pWoXm1DqA== + "@rollup/rollup-linux-arm64-musl@4.35.0": version "4.35.0" resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.35.0.tgz#2fc70a446d986e27f6101ea74e81746987f69150" integrity sha512-XQxVOCd6VJeHQA/7YcqyV0/88N6ysSVzRjJ9I9UA/xXpEsjvAgDTgH3wQYz5bmr7SPtVK2TsP2fQ2N9L4ukoUg== +"@rollup/rollup-linux-arm64-musl@4.37.0": + version "4.37.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.37.0.tgz#b5222180bb1a50e6e9bc8263efd771c1ce770b6f" + integrity sha512-pfxLBMls+28Ey2enpX3JvjEjaJMBX5XlPCZNGxj4kdJyHduPBXtxYeb8alo0a7bqOoWZW2uKynhHxF/MWoHaGQ== + "@rollup/rollup-linux-loongarch64-gnu@4.35.0": version "4.35.0" resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.35.0.tgz#561bd045cd9ce9e08c95f42e7a8688af8c93d764" integrity sha512-5pMT5PzfgwcXEwOaSrqVsz/LvjDZt+vQ8RT/70yhPU06PTuq8WaHhfT1LW+cdD7mW6i/J5/XIkX/1tCAkh1W6g== +"@rollup/rollup-linux-loongarch64-gnu@4.37.0": + version "4.37.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.37.0.tgz#5660181c1c1efb7b19c7a531d496e685236c5ce7" + integrity sha512-yCE0NnutTC/7IGUq/PUHmoeZbIwq3KRh02e9SfFh7Vmc1Z7atuJRYWhRME5fKgT8aS20mwi1RyChA23qSyRGpA== + "@rollup/rollup-linux-powerpc64le-gnu@4.35.0": version "4.35.0" resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.35.0.tgz#45d849a0b33813f33fe5eba9f99e0ff15ab5caad" integrity sha512-c+zkcvbhbXF98f4CtEIP1EBA/lCic5xB0lToneZYvMeKu5Kamq3O8gqrxiYYLzlZH6E3Aq+TSW86E4ay8iD8EA== +"@rollup/rollup-linux-powerpc64le-gnu@4.37.0": + version "4.37.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.37.0.tgz#8273166495d2f5d3fbc556cf42a5a6e24b78bdab" + integrity sha512-NxcICptHk06E2Lh3a4Pu+2PEdZ6ahNHuK7o6Np9zcWkrBMuv21j10SQDJW3C9Yf/A/P7cutWoC/DptNLVsZ0VQ== + "@rollup/rollup-linux-riscv64-gnu@4.35.0": version "4.35.0" resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.35.0.tgz#78dde3e6fcf5b5733a97d0a67482d768aa1e83a5" integrity sha512-s91fuAHdOwH/Tad2tzTtPX7UZyytHIRR6V4+2IGlV0Cej5rkG0R61SX4l4y9sh0JBibMiploZx3oHKPnQBKe4g== +"@rollup/rollup-linux-riscv64-gnu@4.37.0": + version "4.37.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.37.0.tgz#9677e39288ccc91ebcd707cdd794732d701cd174" + integrity sha512-PpWwHMPCVpFZLTfLq7EWJWvrmEuLdGn1GMYcm5MV7PaRgwCEYJAwiN94uBuZev0/J/hFIIJCsYw4nLmXA9J7Pw== + +"@rollup/rollup-linux-riscv64-musl@4.37.0": + version "4.37.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.37.0.tgz#71cc5ca7be1ed263357618bfe4f8f50c09725a7e" + integrity sha512-DTNwl6a3CfhGTAOYZ4KtYbdS8b+275LSLqJVJIrPa5/JuIufWWZ/QFvkxp52gpmguN95eujrM68ZG+zVxa8zHA== + "@rollup/rollup-linux-s390x-gnu@4.35.0": version "4.35.0" resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.35.0.tgz#2e34835020f9e03dfb411473a5c2a0e8a9c5037b" integrity sha512-hQRkPQPLYJZYGP+Hj4fR9dDBMIM7zrzJDWFEMPdTnTy95Ljnv0/4w/ixFw3pTBMEuuEuoqtBINYND4M7ujcuQw== +"@rollup/rollup-linux-s390x-gnu@4.37.0": + version "4.37.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.37.0.tgz#6b0b7df33eb32b0ee7423898b183acc1b5fee33e" + integrity sha512-hZDDU5fgWvDdHFuExN1gBOhCuzo/8TMpidfOR+1cPZJflcEzXdCy1LjnklQdW8/Et9sryOPJAKAQRw8Jq7Tg+A== + "@rollup/rollup-linux-x64-gnu@4.35.0": version "4.35.0" resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.35.0.tgz#4f9774beddc6f4274df57ac99862eb23040de461" integrity sha512-Pim1T8rXOri+0HmV4CdKSGrqcBWX0d1HoPnQ0uw0bdp1aP5SdQVNBy8LjYncvnLgu3fnnCt17xjWGd4cqh8/hA== +"@rollup/rollup-linux-x64-gnu@4.37.0": + version "4.37.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.37.0.tgz#52c27717d3c4819d13b5ebc2373ddea099d2e71b" + integrity sha512-pKivGpgJM5g8dwj0ywBwe/HeVAUSuVVJhUTa/URXjxvoyTT/AxsLTAbkHkDHG7qQxLoW2s3apEIl26uUe08LVQ== + "@rollup/rollup-linux-x64-musl@4.35.0": version "4.35.0" resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.35.0.tgz#dfcff2c1aed518b3d23ccffb49afb349d74fb608" integrity sha512-QysqXzYiDvQWfUiTm8XmJNO2zm9yC9P/2Gkrwg2dH9cxotQzunBHYr6jk4SujCTqnfGxduOmQcI7c2ryuW8XVg== +"@rollup/rollup-linux-x64-musl@4.37.0": + version "4.37.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.37.0.tgz#c134a22d30642345de8b799c816345674bf68019" + integrity sha512-E2lPrLKE8sQbY/2bEkVTGDEk4/49UYRVWgj90MY8yPjpnGBQ+Xi1Qnr7b7UIWw1NOggdFQFOLZ8+5CzCiz143w== + "@rollup/rollup-win32-arm64-msvc@4.35.0": version "4.35.0" resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.35.0.tgz#b0b37e2d77041e3aa772f519291309abf4c03a84" integrity sha512-OUOlGqPkVJCdJETKOCEf1mw848ZyJ5w50/rZ/3IBQVdLfR5jk/6Sr5m3iO2tdPgwo0x7VcncYuOvMhBWZq8ayg== +"@rollup/rollup-win32-arm64-msvc@4.37.0": + version "4.37.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.37.0.tgz#8063d5f8195dd1845e056d069366fbe06a424d09" + integrity sha512-Jm7biMazjNzTU4PrQtr7VS8ibeys9Pn29/1bm4ph7CP2kf21950LgN+BaE2mJ1QujnvOc6p54eWWiVvn05SOBg== + "@rollup/rollup-win32-ia32-msvc@4.35.0": version "4.35.0" resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.35.0.tgz#5b5a40e44a743ddc0e06b8e1b3982f856dc9ce0a" integrity sha512-2/lsgejMrtwQe44glq7AFFHLfJBPafpsTa6JvP2NGef/ifOa4KBoglVf7AKN7EV9o32evBPRqfg96fEHzWo5kw== +"@rollup/rollup-win32-ia32-msvc@4.37.0": + version "4.37.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.37.0.tgz#891d90e3b5517f9d290bb416afdfe2ebfb12139e" + integrity sha512-e3/1SFm1OjefWICB2Ucstg2dxYDkDTZGDYgwufcbsxTHyqQps1UQf33dFEChBNmeSsTOyrjw2JJq0zbG5GF6RA== + "@rollup/rollup-win32-x64-msvc@4.35.0": version "4.35.0" resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.35.0.tgz#05f25dbc9981bee1ae6e713daab10397044a46ca" integrity sha512-PIQeY5XDkrOysbQblSW7v3l1MDZzkTEzAfTPkj5VAu3FW8fS4ynyLg2sINp0fp3SjZ8xkRYpLqoKcYqAkhU1dw== +"@rollup/rollup-win32-x64-msvc@4.37.0": + version "4.37.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.37.0.tgz#a54d7304c3bd45573d8bcd1270de89771f8195fe" + integrity sha512-LWbXUBwn/bcLx2sSsqy7pK5o+Nr+VCoRoAohfJ5C/aBio9nfJmGQqHAhU6pwxV/RmyTk5AqdySma7uwWGlmeuA== + "@rtsao/scc@^1.1.0": version "1.1.0" resolved "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" @@ -3566,6 +3666,13 @@ resolved "https://registry.npmjs.org/@types/reactcss/-/reactcss-1.2.13.tgz#11c7468cc96b5353f7af998a5664deae21c7af08" integrity sha512-gi3S+aUi6kpkF5vdhUsnkwbiSEIU/BEJyD7kBy2SudWBUuKmJk8AQKE0OVcQQeEy40Azh0lV6uynxlikYIJuwg== +"@types/reflect-metadata@^0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@types/reflect-metadata/-/reflect-metadata-0.1.0.tgz#592805bdf6d63dd7229773218afeba37ac2eab16" + integrity sha512-bXltFLY3qhzCnVYP5iUpeSICagQ8rc9K2liS+8M0lBcz54BHs3O6W5UvqespVSuebo1BXLi+/y9ioELAW9SC2A== + dependencies: + reflect-metadata "*" + "@types/resolve@^1.20.2": version "1.20.6" resolved "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.6.tgz#e6e60dad29c2c8c206c026e6dd8d6d1bdda850b8" @@ -3635,6 +3742,13 @@ dependencies: "@types/node" "*" +"@types/ws@^8.5.10": + version "8.18.0" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.18.0.tgz#8a2ec491d6f0685ceaab9a9b7ff44146236993b5" + integrity sha512-8svvI3hMyvN0kKCJMvTJP/x6Y/EoQbepff882wL+Sn5QsXb3etnamgrJq4isrBxSJj5L2AuXcI0+bgkoAXGUJw== + dependencies: + "@types/node" "*" + "@types/zxcvbn@^4.4.4", "@types/zxcvbn@^4.4.5": version "4.4.5" resolved "https://registry.npmjs.org/@types/zxcvbn/-/zxcvbn-4.4.5.tgz#8ce8623ed7a36e3a76d1c0b539708dfb2e859bc0" @@ -4578,7 +4692,7 @@ buffer@^6.0.3: base64-js "^1.3.1" ieee754 "^1.2.1" -bundle-require@^5.1.0: +bundle-require@^5.0.0, bundle-require@^5.1.0: version "5.1.0" resolved "https://registry.npmjs.org/bundle-require/-/bundle-require-5.1.0.tgz#8db66f41950da3d77af1ef3322f4c3e04009faee" integrity sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA== @@ -4966,6 +5080,11 @@ concurrently@^9.0.1: tree-kill "^1.2.2" yargs "^17.7.2" +consola@^3.2.3: + version "3.4.2" + resolved "https://registry.yarnpkg.com/consola/-/consola-3.4.2.tgz#5af110145397bb67afdab77013fdc34cae590ea7" + integrity sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA== + consola@^3.4.0: version "3.4.0" resolved "https://registry.npmjs.org/consola/-/consola-3.4.0.tgz#4cfc9348fd85ed16a17940b3032765e31061ab88" @@ -5073,7 +5192,7 @@ cross-fetch@^3.1.5: dependencies: node-fetch "^2.7.0" -cross-spawn@^7.0.0, cross-spawn@^7.0.2: +cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.6" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== @@ -5338,7 +5457,7 @@ debug@2.6.9: dependencies: ms "2.0.0" -debug@4, debug@^4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.7, debug@^4.4.0: +debug@4, debug@^4, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5, debug@^4.3.7, debug@^4.4.0: version "4.4.0" resolved "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== @@ -5904,7 +6023,7 @@ esbuild-register@^3.5.0: dependencies: debug "^4.3.4" -esbuild@0.25.0, "esbuild@^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0", esbuild@^0.25.0: +esbuild@0.25.0, "esbuild@^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0", esbuild@^0.23.0, esbuild@^0.25.0: version "0.25.0" resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.25.0.tgz#0de1787a77206c5a79eeb634a623d39b5006ce92" integrity sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw== @@ -6235,6 +6354,21 @@ events@^3.2.0, events@^3.3.0: resolved "https://registry.npmjs.org/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== +execa@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + expand-template@^2.0.3: version "2.0.3" resolved "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" @@ -6701,6 +6835,11 @@ get-stdin@^9.0.0: resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz#3983ff82e03d56f1b2ea0d3e60325f39d703a575" integrity sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA== +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + get-symbol-description@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz#7bdd54e0befe8ffc9f3b4e203220d9f1e881b6ee" @@ -7028,6 +7167,11 @@ https-proxy-agent@^7.0.6: agent-base "^7.1.2" debug "4" +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + hyphen@^1.6.4: version "1.10.6" resolved "https://registry.npmjs.org/hyphen/-/hyphen-1.10.6.tgz#0e779d280e696102b97d7e42f5ca5de2cc97e274" @@ -8250,6 +8394,11 @@ mime@1.6.0: resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + mimic-response@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" @@ -8511,6 +8660,13 @@ normalize.css@^8.0.1: resolved "https://registry.npmjs.org/normalize.css/-/normalize.css-8.0.1.tgz#9b98a208738b9cc2634caacbc42d131c97487bf3" integrity sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg== +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + nprogress@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz#cb8f34c53213d895723fcbab907e9422adbcafb1" @@ -8649,6 +8805,13 @@ one-time@^1.0.0: dependencies: fn.name "1.x.x" +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + open@^8.0.4: version "8.4.2" resolved "https://registry.npmjs.org/open/-/open-8.4.2.tgz#5b5ffe2a8f793dcd2aad73e550cb87b59cb084f9" @@ -8831,7 +8994,7 @@ path-is-absolute@^1.0.0: resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== -path-key@^3.1.0: +path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== @@ -9852,6 +10015,11 @@ redlock@^4.2.0: dependencies: bluebird "^3.7.2" +reflect-metadata@*, reflect-metadata@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.2.2.tgz#400c845b6cba87a21f2c65c4aeb158f4fa4d9c5b" + integrity sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q== + reflect.getprototypeof@^1.0.6, reflect.getprototypeof@^1.0.9: version "1.0.10" resolved "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz#c629219e78a3316d8b604c765ef68996964e7bf9" @@ -10031,6 +10199,35 @@ robust-predicates@^3.0.2: resolved "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.2.tgz#d5b28528c4824d20fc48df1928d41d9efa1ad771" integrity sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg== +rollup@^4.19.0: + version "4.37.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.37.0.tgz#e4172f8bdb6ea7df08a1b0acf99abeccb2250378" + integrity sha512-iAtQy/L4QFU+rTJ1YUjXqJOJzuwEghqWzCEYD2FEghT7Gsy1VdABntrO4CLopA5IkflTyqNiLNwPcOJ3S7UKLg== + dependencies: + "@types/estree" "1.0.6" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.37.0" + "@rollup/rollup-android-arm64" "4.37.0" + "@rollup/rollup-darwin-arm64" "4.37.0" + "@rollup/rollup-darwin-x64" "4.37.0" + "@rollup/rollup-freebsd-arm64" "4.37.0" + "@rollup/rollup-freebsd-x64" "4.37.0" + "@rollup/rollup-linux-arm-gnueabihf" "4.37.0" + "@rollup/rollup-linux-arm-musleabihf" "4.37.0" + "@rollup/rollup-linux-arm64-gnu" "4.37.0" + "@rollup/rollup-linux-arm64-musl" "4.37.0" + "@rollup/rollup-linux-loongarch64-gnu" "4.37.0" + "@rollup/rollup-linux-powerpc64le-gnu" "4.37.0" + "@rollup/rollup-linux-riscv64-gnu" "4.37.0" + "@rollup/rollup-linux-riscv64-musl" "4.37.0" + "@rollup/rollup-linux-s390x-gnu" "4.37.0" + "@rollup/rollup-linux-x64-gnu" "4.37.0" + "@rollup/rollup-linux-x64-musl" "4.37.0" + "@rollup/rollup-win32-arm64-msvc" "4.37.0" + "@rollup/rollup-win32-ia32-msvc" "4.37.0" + "@rollup/rollup-win32-x64-msvc" "4.37.0" + fsevents "~2.3.2" + rollup@^4.34.8: version "4.35.0" resolved "https://registry.npmjs.org/rollup/-/rollup-4.35.0.tgz#76c95dba17a579df4c00c3955aed32aa5d4dc66d" @@ -10363,6 +10560,11 @@ side-channel@^1.0.6, side-channel@^1.1.0: side-channel-map "^1.0.1" side-channel-weakmap "^1.0.2" +signal-exit@^3.0.3: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + signal-exit@^4.0.1: version "4.1.0" resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" @@ -10648,6 +10850,11 @@ strip-bom@^3.0.0: resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + strip-indent@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" @@ -10933,7 +11140,7 @@ tinyexec@^0.3.2: resolved "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz#941794e657a85e496577995c6eef66f53f42b3d2" integrity sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA== -tinyglobby@^0.2.11: +tinyglobby@^0.2.1, tinyglobby@^0.2.11: version "0.2.12" resolved "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.12.tgz#ac941a42e0c5773bd0b5d08f32de82e74a1a61b5" integrity sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww== @@ -11111,6 +11318,28 @@ tslib@~2.5.0: resolved "https://registry.npmjs.org/tslib/-/tslib-2.5.3.tgz#24944ba2d990940e6e982c4bea147aba80209913" integrity sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w== +tsup@8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/tsup/-/tsup-8.3.0.tgz#c7dae40b13d11d81fb144c0f90077a99102a572a" + integrity sha512-ALscEeyS03IomcuNdFdc0YWGVIkwH1Ws7nfTbAPuoILvEV2hpGQAY72LIOjglGo4ShWpZfpBqP/jpQVCzqYQag== + dependencies: + bundle-require "^5.0.0" + cac "^6.7.14" + chokidar "^3.6.0" + consola "^3.2.3" + debug "^4.3.5" + esbuild "^0.23.0" + execa "^5.1.1" + joycon "^3.1.1" + picocolors "^1.0.1" + postcss-load-config "^6.0.1" + resolve-from "^5.0.0" + rollup "^4.19.0" + source-map "0.8.0-beta.0" + sucrase "^3.35.0" + tinyglobby "^0.2.1" + tree-kill "^1.2.2" + tsup@^8.4.0: version "8.4.0" resolved "https://registry.npmjs.org/tsup/-/tsup-8.4.0.tgz#2fdf537e7abc8f1ccbbbfe4228f16831457d4395" From a25cd426a9c6959e991da0e2ca34afbb7fbfbc25 Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com> Date: Wed, 26 Mar 2025 21:10:44 +0530 Subject: [PATCH 030/146] style: page editor width and layout updates (#6826) --- .../editors/document/collaborative-editor.tsx | 10 +- .../components/editors/document/loader.tsx | 79 +++++----- .../editors/document/page-renderer.tsx | 2 +- .../editors/document/read-only-editor.tsx | 4 +- .../components/editors/editor-container.tsx | 1 + packages/editor/src/core/constants/config.ts | 1 + packages/editor/src/core/helpers/common.ts | 2 +- packages/editor/src/core/types/config.ts | 1 + packages/editor/src/styles/editor.css | 2 +- packages/editor/src/styles/variables.css | 137 ++++++++++++++++++ .../editor/embed/issue-embed-upgrade-card.tsx | 30 ++-- .../components/pages/editor/editor-body.tsx | 135 +++++++++-------- .../pages/editor/header/extra-options.tsx | 2 +- .../pages/editor/header/mobile-root.tsx | 18 +-- .../components/pages/editor/header/root.tsx | 61 +++----- .../components/pages/editor/page-root.tsx | 11 +- .../pages/editor/summary/content-browser.tsx | 43 +++--- .../editor/summary/heading-components.tsx | 18 +-- .../components/pages/editor/summary/index.ts | 1 - .../pages/editor/summary/popover.tsx | 74 ---------- web/core/components/pages/editor/title.tsx | 18 ++- .../pages/loaders/page-content-loader.tsx | 107 +++++++------- web/core/components/pages/version/editor.tsx | 9 +- 23 files changed, 402 insertions(+), 364 deletions(-) delete mode 100644 web/core/components/pages/editor/summary/popover.tsx diff --git a/packages/editor/src/core/components/editors/document/collaborative-editor.tsx b/packages/editor/src/core/components/editors/document/collaborative-editor.tsx index 751c79101..623ec9508 100644 --- a/packages/editor/src/core/components/editors/document/collaborative-editor.tsx +++ b/packages/editor/src/core/components/editors/document/collaborative-editor.tsx @@ -1,5 +1,7 @@ import { Extensions } from "@tiptap/core"; import React from "react"; +// plane imports +import { cn } from "@plane/utils"; // components import { DocumentContentLoader, PageRenderer } from "@/components/editors"; // constants @@ -73,7 +75,11 @@ const CollaborativeDocumentEditor = (props: ICollaborativeDocumentEditor) => { if (!editor) return null; - if (!hasServerSynced && !hasServerConnectionFailed) return ; + const blockWidthClassName = cn("w-full max-w-[720px] mx-auto transition-all duration-200 ease-in-out", { + "max-w-[1152px]": displayConfig.wideLayout, + }); + + if (!hasServerSynced && !hasServerConnectionFailed) return ; return ( { bubbleMenuEnabled={bubbleMenuEnabled} displayConfig={displayConfig} editor={editor} - editorContainerClassName={editorContainerClassNames} + editorContainerClassName={cn(editorContainerClassNames, "document-editor")} id={id} tabIndex={tabIndex} /> diff --git a/packages/editor/src/core/components/editors/document/loader.tsx b/packages/editor/src/core/components/editors/document/loader.tsx index ab9c3b479..ece0d4b77 100644 --- a/packages/editor/src/core/components/editors/document/loader.tsx +++ b/packages/editor/src/core/components/editors/document/loader.tsx @@ -1,42 +1,51 @@ -// ui +// plane imports import { Loader } from "@plane/ui"; +import { cn } from "@plane/utils"; -export const DocumentContentLoader = () => ( -
- -
-
- -
- -
- - -
-
- -
- - -
- - -
-
- -
- -
- -
- -
+type Props = { + className?: string; +}; + +export const DocumentContentLoader = (props: Props) => { + const { className } = props; + + return ( +
+ +
+ +
+ +
+ +
+
+ +
+ + +
+ + +
+
+ +
+ +
+
+
+
+ +
+ +
-
- -
-); + +
+ ); +}; diff --git a/packages/editor/src/core/components/editors/document/page-renderer.tsx b/packages/editor/src/core/components/editors/document/page-renderer.tsx index a29768656..2b4c094c5 100644 --- a/packages/editor/src/core/components/editors/document/page-renderer.tsx +++ b/packages/editor/src/core/components/editors/document/page-renderer.tsx @@ -132,7 +132,7 @@ export const PageRenderer = (props: IPageRenderer) => { return ( <> -
+
{ bubbleMenuEnabled={false} displayConfig={displayConfig} editor={editor} - editorContainerClassName={editorContainerClassName} + editorContainerClassName={cn(editorContainerClassName, "document-editor")} id={id} /> ); diff --git a/packages/editor/src/core/components/editors/editor-container.tsx b/packages/editor/src/core/components/editors/editor-container.tsx index b742a5265..02f0a0217 100644 --- a/packages/editor/src/core/components/editors/editor-container.tsx +++ b/packages/editor/src/core/components/editors/editor-container.tsx @@ -74,6 +74,7 @@ export const EditorContainer: FC = (props) => { `editor-container cursor-text relative line-spacing-${displayConfig.lineSpacing ?? DEFAULT_DISPLAY_CONFIG.lineSpacing}`, { "active-editor": editor?.isFocused && editor?.isEditable, + "wide-layout": displayConfig.wideLayout, }, displayConfig.fontSize ?? DEFAULT_DISPLAY_CONFIG.fontSize, displayConfig.fontStyle ?? DEFAULT_DISPLAY_CONFIG.fontStyle, diff --git a/packages/editor/src/core/constants/config.ts b/packages/editor/src/core/constants/config.ts index 788454f96..ac6d63dd1 100644 --- a/packages/editor/src/core/constants/config.ts +++ b/packages/editor/src/core/constants/config.ts @@ -5,6 +5,7 @@ export const DEFAULT_DISPLAY_CONFIG: TDisplayConfig = { fontSize: "large-font", fontStyle: "sans-serif", lineSpacing: "regular", + wideLayout: false, }; export const ACCEPTED_FILE_MIME_TYPES = ["image/jpeg", "image/jpg", "image/png", "image/webp", "image/gif"]; diff --git a/packages/editor/src/core/helpers/common.ts b/packages/editor/src/core/helpers/common.ts index 8638d2c15..04f827ece 100644 --- a/packages/editor/src/core/helpers/common.ts +++ b/packages/editor/src/core/helpers/common.ts @@ -49,7 +49,7 @@ export const isValidHttpUrl = (string: string): boolean => { try { url = new URL(string); - } catch (_) { + } catch { return false; } diff --git a/packages/editor/src/core/types/config.ts b/packages/editor/src/core/types/config.ts index 12df0aa42..4c91fec5d 100644 --- a/packages/editor/src/core/types/config.ts +++ b/packages/editor/src/core/types/config.ts @@ -29,4 +29,5 @@ export type TDisplayConfig = { fontStyle?: TEditorFontStyle; fontSize?: TEditorFontSize; lineSpacing?: TEditorLineSpacing; + wideLayout?: boolean; }; diff --git a/packages/editor/src/styles/editor.css b/packages/editor/src/styles/editor.css index be686a5cc..ba910d144 100644 --- a/packages/editor/src/styles/editor.css +++ b/packages/editor/src/styles/editor.css @@ -8,7 +8,7 @@ -moz-user-select: text; -ms-user-select: text; user-select: text; - outline: none; + outline: none !important; cursor: text; font-family: var(--font-style); font-size: var(--font-size-regular); diff --git a/packages/editor/src/styles/variables.css b/packages/editor/src/styles/variables.css index ea70fe1ab..31b64fa56 100644 --- a/packages/editor/src/styles/variables.css +++ b/packages/editor/src/styles/variables.css @@ -1,3 +1,47 @@ +:root { + /* text colors */ + --editor-colors-gray-text: #5c5e63; + --editor-colors-peach-text: #ff5b59; + --editor-colors-pink-text: #f65385; + --editor-colors-orange-text: #fd9038; + --editor-colors-green-text: #0fc27b; + --editor-colors-light-blue-text: #17bee9; + --editor-colors-dark-blue-text: #266df0; + --editor-colors-purple-text: #9162f9; + /* end text colors */ + + /* layout */ + --normal-content-width: 720px; + --wide-content-width: 1152px; + --normal-content-margin: 20px; + --wide-content-margin: 96px; + /* end layout */ +} + +/* text background colors */ +[data-theme*="light"] { + --editor-colors-gray-background: #d6d6d8; + --editor-colors-peach-background: #ffd5d7; + --editor-colors-pink-background: #fdd4e3; + --editor-colors-orange-background: #ffe3cd; + --editor-colors-green-background: #c3f0de; + --editor-colors-light-blue-background: #c5eff9; + --editor-colors-dark-blue-background: #c9dafb; + --editor-colors-purple-background: #e3d8fd; +} +[data-theme*="dark"] { + --editor-colors-gray-background: #404144; + --editor-colors-peach-background: #593032; + --editor-colors-pink-background: #562e3d; + --editor-colors-orange-background: #583e2a; + --editor-colors-green-background: #1d4a3b; + --editor-colors-light-blue-background: #1f495c; + --editor-colors-dark-blue-background: #223558; + --editor-colors-purple-background: #3d325a; +} +/* end text background colors */ + +/* font size and style */ .editor-container { --color-placeholder: rgba(var(--color-text-100), 0.5); @@ -47,6 +91,8 @@ /* end font sizes and line heights */ /* font styles */ + --font-style: "Inter", sans-serif; + &.sans-serif { --font-style: "Inter", sans-serif; } @@ -102,3 +148,94 @@ } /* end spacing */ } +/* end font size and style */ + +/* layout config */ +#page-header-container { + container-name: page-header-container; + container-type: inline-size; + + .page-header-content { + --header-width: var(--normal-content-width); + + &.wide-layout { + --header-width: var(--wide-content-width); + } + + padding-left: calc(((100% - var(--header-width)) / 2) - 10px); + } +} + +#page-content-container { + container-name: page-content-container; + container-type: inline-size; +} + +.editor-container.document-editor { + --editor-content-width: var(--normal-content-width); + + &.wide-layout { + --editor-content-width: var(--wide-content-width); + } + + .ProseMirror { + max-width: var(--editor-content-width); + margin: 0 auto; + transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); + } +} + +/* keep a static padding of 96px for wide layouts for container width >912px and <1344px */ +@container page-header-container (min-width: 912px) and (max-width: 1344px) { + .page-header-content.wide-layout { + padding-left: var(--wide-content-margin) !important; + } +} + +/* keep a static padding of 96px for wide layouts for container width <912px */ +@container page-header-container (max-width: 912) { + .page-header-content.wide-layout { + padding-left: var(--wide-content-margin) !important; + } +} +/* end layout config */ + +/* keep a static padding of 20px for wide layouts for container width <760px */ +@container page-header-container (max-width: 760px) { + .page-header-content { + padding-left: var(--normal-content-margin) !important; + } +} +/* end layout config */ + +/* keep a static padding of 96px for wide layouts for container width >912px and <1344px */ +@container page-content-container (min-width: 912px) and (max-width: 1344px) { + .editor-container.wide-layout, + .page-title-container { + padding-left: var(--wide-content-margin); + padding-right: var(--wide-content-margin); + } +} + +/* keep a static padding of 20px for wide layouts for container width <912px */ +@container page-content-container (max-width: 912px) { + .editor-container.wide-layout, + .page-title-container { + padding-left: var(--normal-content-margin); + padding-right: var(--normal-content-margin); + } +} + +/* keep a static padding of 20px for normal layouts for container width <760px */ +@container page-content-container (max-width: 760px) { + .editor-container:not(.wide-layout), + .page-title-container { + padding-left: var(--normal-content-margin); + padding-right: var(--normal-content-margin); + } + + .page-summary-container { + display: none; + } +} +/* end layout config */ diff --git a/web/ce/components/pages/editor/embed/issue-embed-upgrade-card.tsx b/web/ce/components/pages/editor/embed/issue-embed-upgrade-card.tsx index b4f68028d..1f698f0a7 100644 --- a/web/ce/components/pages/editor/embed/issue-embed-upgrade-card.tsx +++ b/web/ce/components/pages/editor/embed/issue-embed-upgrade-card.tsx @@ -8,27 +8,25 @@ import { cn } from "@/helpers/common.helper"; export const IssueEmbedUpgradeCard: React.FC = (props) => (
-
-
- -

- Embed and access work items in pages seamlessly, upgrade to Plane Pro now. -

-
- - Upgrade - +
+ +

+ Embed and access issues in pages seamlessly, upgrade to Plane Pro now. +

+ + Upgrade +
); diff --git a/web/core/components/pages/editor/editor-body.tsx b/web/core/components/pages/editor/editor-body.tsx index aba274aff..fce7f2e88 100644 --- a/web/core/components/pages/editor/editor-body.tsx +++ b/web/core/components/pages/editor/editor-body.tsx @@ -1,6 +1,6 @@ import { Dispatch, SetStateAction, useCallback, useMemo } from "react"; import { observer } from "mobx-react"; -// document-editor +// plane imports import { CollaborativeDocumentEditorWithRef, EditorRefApi, @@ -10,15 +10,14 @@ import { TRealtimeConfig, TServerHandler, } from "@plane/editor"; -// plane types import { TSearchEntityRequestPayload, TSearchResponse, TWebhookConnectionQueryParams } from "@plane/types"; -// plane ui -import { Row } from "@plane/ui"; +import { ERowVariant, Row } from "@plane/ui"; +import { cn } from "@plane/utils"; // components import { EditorMentionsRoot } from "@/components/editor"; import { PageContentBrowser, PageContentLoader, PageEditorTitle } from "@/components/pages"; // helpers -import { cn, LIVE_BASE_PATH, LIVE_BASE_URL } from "@/helpers/common.helper"; +import { LIVE_BASE_PATH, LIVE_BASE_URL } from "@/helpers/common.helper"; import { generateRandomColor } from "@/helpers/string.helper"; // hooks import { useEditorMention } from "@/hooks/editor"; @@ -48,7 +47,6 @@ type Props = { handleEditorReady: Dispatch>; handlers: TEditorBodyHandlers; page: TPageInstance; - sidePeekVisible: boolean; webhookConnectionParams: TWebhookConnectionQueryParams; workspaceSlug: string; }; @@ -61,7 +59,6 @@ export const PageEditorBody: React.FC = observer((props) => { handleEditorReady, handlers, page, - sidePeekVisible, webhookConnectionParams, workspaceSlug, } = props; @@ -91,8 +88,9 @@ export const PageEditorBody: React.FC = observer((props) => { () => ({ fontSize, fontStyle, + wideLayout: isFullWidth, }), - [fontSize, fontStyle] + [fontSize, fontStyle, isFullWidth] ); const getAIMenu = useCallback( @@ -152,69 +150,70 @@ export const PageEditorBody: React.FC = observer((props) => { [currentUser?.display_name, currentUser?.id] ); - if (pageId === undefined || !realtimeConfig) return ; + const blockWidthClassName = cn( + "block bg-transparent w-full max-w-[720px] mx-auto transition-all duration-200 ease-in-out", + { + "max-w-[1152px]": isFullWidth, + } + ); + + if (pageId === undefined || !realtimeConfig) return ; return ( -
- -
-
- - { - const res = await fetchMentions(query); - if (!res) throw new Error("Failed in fetching mentions"); - return res; - }, - renderComponent: (props) => , - getMentionedEntityDetails: (id: string) => ({ display_name: getUserDetails(id)?.display_name ?? "" }), - }} - embedHandler={{ - issue: issueEmbedProps, - }} - realtimeConfig={realtimeConfig} - serverHandler={serverHandler} - user={userConfig} - disabledExtensions={disabledExtensions} - aiHandler={{ - menu: getAIMenu, - }} - /> + +
+ {/* table of content */} +
+
+
+
+ +
+
+ +
+
+
+ + { + const res = await fetchMentions(query); + if (!res) throw new Error("Failed in fetching mentions"); + return res; + }, + renderComponent: (props) => , + getMentionedEntityDetails: (id: string) => ({ display_name: getUserDetails(id)?.display_name ?? "" }), + }} + embedHandler={{ + issue: issueEmbedProps, + }} + realtimeConfig={realtimeConfig} + serverHandler={serverHandler} + user={userConfig} + disabledExtensions={disabledExtensions} + aiHandler={{ + menu: getAIMenu, + }} + />
-
-
+
); }); diff --git a/web/core/components/pages/editor/header/extra-options.tsx b/web/core/components/pages/editor/header/extra-options.tsx index 0b81d1452..d9198b84f 100644 --- a/web/core/components/pages/editor/header/extra-options.tsx +++ b/web/core/components/pages/editor/header/extra-options.tsx @@ -69,7 +69,7 @@ export const PageExtraOptions: React.FC = observer((props) => { }; return ( -
+
{is_locked && } {archived_at && (
diff --git a/web/core/components/pages/editor/header/mobile-root.tsx b/web/core/components/pages/editor/header/mobile-root.tsx index 22f25e254..a3cde27f4 100644 --- a/web/core/components/pages/editor/header/mobile-root.tsx +++ b/web/core/components/pages/editor/header/mobile-root.tsx @@ -2,9 +2,7 @@ import { observer } from "mobx-react"; import { EditorRefApi } from "@plane/editor"; // components import { Header, EHeaderVariant } from "@plane/ui"; -import { PageExtraOptions, PageSummaryPopover, PageToolbar } from "@/components/pages"; -// hooks -import { usePageFilters } from "@/hooks/use-page-filters"; +import { PageExtraOptions, PageToolbar } from "@/components/pages"; // plane web hooks import { EPageStoreType } from "@/plane-web/hooks/store"; // store @@ -13,29 +11,17 @@ import { TPageInstance } from "@/store/pages/base-page"; type Props = { editorRef: EditorRefApi; page: TPageInstance; - setSidePeekVisible: (sidePeekState: boolean) => void; - sidePeekVisible: boolean; storeType: EPageStoreType; }; export const PageEditorMobileHeaderRoot: React.FC = observer((props) => { - const { editorRef, page, setSidePeekVisible, sidePeekVisible, storeType } = props; + const { editorRef, page, storeType } = props; // derived values const { isContentEditable } = page; - // page filters - const { isFullWidth } = usePageFilters(); return ( <>
-
- -
diff --git a/web/core/components/pages/editor/header/root.tsx b/web/core/components/pages/editor/header/root.tsx index 552ba6009..1099e838f 100644 --- a/web/core/components/pages/editor/header/root.tsx +++ b/web/core/components/pages/editor/header/root.tsx @@ -1,8 +1,7 @@ import { observer } from "mobx-react"; import { EditorRefApi } from "@plane/editor"; // components -import { Header, EHeaderVariant } from "@plane/ui"; -import { PageEditorMobileHeaderRoot, PageExtraOptions, PageSummaryPopover, PageToolbar } from "@/components/pages"; +import { PageEditorMobileHeaderRoot, PageExtraOptions, PageToolbar } from "@/components/pages"; // helpers import { cn } from "@/helpers/common.helper"; // hooks @@ -16,13 +15,11 @@ type Props = { editorReady: boolean; editorRef: React.RefObject; page: TPageInstance; - setSidePeekVisible: (sidePeekState: boolean) => void; - sidePeekVisible: boolean; storeType: EPageStoreType; }; export const PageEditorHeaderRoot: React.FC = observer((props) => { - const { editorReady, editorRef, page, setSidePeekVisible, sidePeekVisible, storeType } = props; + const { editorReady, editorRef, page, storeType } = props; // derived values const { isContentEditable } = page; // page filters @@ -33,39 +30,27 @@ export const PageEditorHeaderRoot: React.FC = observer((props) => { if (!resolvedEditorRef) return null; return ( - <> -
- - {editorReady && ( -
- -
- )} - {isStickyToolbarEnabled && editorReady && isContentEditable && editorRef.current && ( - - )} -
- -
-
- +
+
+
+
+ {isStickyToolbarEnabled && editorReady && isContentEditable && editorRef.current && ( + + )} +
+ +
- +
+ +
+
); }); diff --git a/web/core/components/pages/editor/page-root.tsx b/web/core/components/pages/editor/page-root.tsx index c80a52d43..8949d1556 100644 --- a/web/core/components/pages/editor/page-root.tsx +++ b/web/core/components/pages/editor/page-root.tsx @@ -48,7 +48,6 @@ export const PageRoot = observer((props: TPageRootProps) => { // states const [editorReady, setEditorReady] = useState(false); const [hasConnectionFailed, setHasConnectionFailed] = useState(false); - const [sidePeekVisible, setSidePeekVisible] = useState(window.innerWidth >= 768); const [isVersionsOverlayOpen, setIsVersionsOverlayOpen] = useState(false); // refs const editorRef = useRef(null); @@ -104,14 +103,7 @@ export const PageRoot = observer((props: TPageRootProps) => { pageId={page.id ?? ""} restoreEnabled={isContentEditable} /> - setSidePeekVisible(state)} - sidePeekVisible={sidePeekVisible} - storeType={storeType} - /> + { handleEditorReady={setEditorReady} handlers={handlers} page={page} - sidePeekVisible={sidePeekVisible} webhookConnectionParams={webhookConnectionParams} workspaceSlug={workspaceSlug} /> diff --git a/web/core/components/pages/editor/summary/content-browser.tsx b/web/core/components/pages/editor/summary/content-browser.tsx index 16d818aae..f3a92d2ae 100644 --- a/web/core/components/pages/editor/summary/content-browser.tsx +++ b/web/core/components/pages/editor/summary/content-browser.tsx @@ -7,10 +7,11 @@ import { OutlineHeading1, OutlineHeading2, OutlineHeading3 } from "./heading-com type Props = { editorRef: EditorRefApi | null; setSidePeekVisible?: (sidePeekState: boolean) => void; + showOutline?: boolean; }; export const PageContentBrowser: React.FC = (props) => { - const { editorRef, setSidePeekVisible } = props; + const { editorRef, setSidePeekVisible, showOutline = false } = props; // states const [headings, setHeadings] = useState([]); @@ -37,24 +38,28 @@ export const PageContentBrowser: React.FC = (props) => { }; return ( -
-
- {headings && headings.length !== 0 ? ( - headings.map((marking) => { - const Component = HeadingComponent[marking.level]; - if (!Component) return null; - return ( - handleOnClick(marking)} - /> - ); - }) - ) : ( -

Headings will be displayed here for navigation

- )} -
+
+ {headings.map((marking) => { + const Component = HeadingComponent[marking.level]; + if (!Component) return null; + if (showOutline === true) + return ( +
+ ); + return ( + handleOnClick(marking)} + /> + ); + })}
); }; diff --git a/web/core/components/pages/editor/summary/heading-components.tsx b/web/core/components/pages/editor/summary/heading-components.tsx index 5ed1752de..c2e78dd67 100644 --- a/web/core/components/pages/editor/summary/heading-components.tsx +++ b/web/core/components/pages/editor/summary/heading-components.tsx @@ -1,36 +1,36 @@ -// document editor -import { IMarking } from "@plane/editor"; +// plane editor +import type { IMarking } from "@plane/editor"; -type HeadingProps = { +export type THeadingComponentProps = { marking: IMarking; onClick: (event: React.MouseEvent) => void; }; -export const OutlineHeading1 = ({ marking, onClick }: HeadingProps) => ( +export const OutlineHeading1 = ({ marking, onClick }: THeadingComponentProps) => ( ); -export const OutlineHeading2 = ({ marking, onClick }: HeadingProps) => ( +export const OutlineHeading2 = ({ marking, onClick }: THeadingComponentProps) => ( ); -export const OutlineHeading3 = ({ marking, onClick }: HeadingProps) => ( +export const OutlineHeading3 = ({ marking, onClick }: THeadingComponentProps) => ( diff --git a/web/core/components/pages/editor/summary/index.ts b/web/core/components/pages/editor/summary/index.ts index 3c4afb4d8..779b78548 100644 --- a/web/core/components/pages/editor/summary/index.ts +++ b/web/core/components/pages/editor/summary/index.ts @@ -1,2 +1 @@ export * from "./content-browser"; -export * from "./popover"; diff --git a/web/core/components/pages/editor/summary/popover.tsx b/web/core/components/pages/editor/summary/popover.tsx deleted file mode 100644 index 9acc4a7cc..000000000 --- a/web/core/components/pages/editor/summary/popover.tsx +++ /dev/null @@ -1,74 +0,0 @@ -import { useState } from "react"; -import { usePopper } from "react-popper"; -import { List } from "lucide-react"; -// document editor -import { EditorRefApi } from "@plane/editor"; -// helpers -import { cn } from "@/helpers/common.helper"; -// components -import { PageContentBrowser } from "./content-browser"; - -type Props = { - editorRef: EditorRefApi | null; - isFullWidth: boolean; - sidePeekVisible: boolean; - setSidePeekVisible: (sidePeekState: boolean) => void; -}; - -export const PageSummaryPopover: React.FC = (props) => { - const { editorRef, sidePeekVisible, setSidePeekVisible } = props; - // refs - const [referenceElement, setReferenceElement] = useState(null); - const [popperElement, setPopperElement] = useState(null); - // popper-js - const { styles: summaryPopoverStyles, attributes: summaryPopoverAttributes } = usePopper( - referenceElement, - popperElement, - { - placement: "bottom-start", - } - ); - - return ( -
- -
- {sidePeekVisible && ( -
- -
- )} -
-
- {!sidePeekVisible && ( -
- -
- )} -
-
- ); -}; diff --git a/web/core/components/pages/editor/title.tsx b/web/core/components/pages/editor/title.tsx index 9e85c33d3..f9cd7f1f2 100644 --- a/web/core/components/pages/editor/title.tsx +++ b/web/core/components/pages/editor/title.tsx @@ -17,26 +17,28 @@ type Props = { readOnly: boolean; title: string | undefined; updateTitle: (title: string) => void; + widthClassName: string; }; export const PageEditorTitle: React.FC = observer((props) => { - const { editorRef, readOnly, title, updateTitle } = props; + const { editorRef, readOnly, title, updateTitle, widthClassName } = props; // states const [isLengthVisible, setIsLengthVisible] = useState(false); // page filters const { fontSize } = usePageFilters(); // ui - const titleClassName = cn("bg-transparent tracking-[-2%] font-bold", { + const titleFontClassName = cn("tracking-[-2%] font-bold", { "text-[1.6rem] leading-[1.9rem]": fontSize === "small-font", "text-[2rem] leading-[2.375rem]": fontSize === "large-font", }); return ( -
+
{readOnly ? (
= observer((props) => { {getPageName(title)}
) : ( - <> +