mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
Merge branch 'feat/list-autojoins' into chore/page-transactions
This commit is contained in:
commit
51af9e4d12
3
.github/workflows/codeql.yml
vendored
3
.github/workflows/codeql.yml
vendored
@ -1,8 +1,9 @@
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: ["master"]
|
||||
branches: ["develop", "preview", "master"]
|
||||
pull_request:
|
||||
branches: ["develop", "preview", "master"]
|
||||
schedule:
|
||||
|
@ -1,32 +1,33 @@
|
||||
from lxml import html
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.validators import URLValidator
|
||||
|
||||
# Django imports
|
||||
from django.utils import timezone
|
||||
from django.core.validators import URLValidator
|
||||
from django.core.exceptions import ValidationError
|
||||
from lxml import html
|
||||
|
||||
# Third party imports
|
||||
from rest_framework import serializers
|
||||
|
||||
# Module imports
|
||||
from plane.db.models import (
|
||||
User,
|
||||
Issue,
|
||||
State,
|
||||
IssueActivity,
|
||||
IssueAssignee,
|
||||
Label,
|
||||
IssueAttachment,
|
||||
IssueComment,
|
||||
IssueLabel,
|
||||
IssueLink,
|
||||
IssueComment,
|
||||
IssueAttachment,
|
||||
IssueActivity,
|
||||
Label,
|
||||
ProjectMember,
|
||||
State,
|
||||
User,
|
||||
)
|
||||
|
||||
from .base import BaseSerializer
|
||||
from .cycle import CycleSerializer, CycleLiteSerializer
|
||||
from .module import ModuleSerializer, ModuleLiteSerializer
|
||||
from .user import UserLiteSerializer
|
||||
from .cycle import CycleLiteSerializer, CycleSerializer
|
||||
from .module import ModuleLiteSerializer, ModuleSerializer
|
||||
from .state import StateLiteSerializer
|
||||
from .user import UserLiteSerializer
|
||||
|
||||
|
||||
class IssueSerializer(BaseSerializer):
|
||||
@ -79,7 +80,7 @@ class IssueSerializer(BaseSerializer):
|
||||
data["description_html"] = parsed_str
|
||||
|
||||
except Exception as e:
|
||||
raise serializers.ValidationError(f"Invalid HTML: {str(e)}")
|
||||
raise serializers.ValidationError("Invalid HTML passed")
|
||||
|
||||
# Validate assignees are from project
|
||||
if data.get("assignees", []):
|
||||
@ -294,7 +295,7 @@ class IssueLinkSerializer(BaseSerializer):
|
||||
raise serializers.ValidationError("Invalid URL format.")
|
||||
|
||||
# Check URL scheme
|
||||
if not value.startswith(('http://', 'https://')):
|
||||
if not value.startswith(("http://", "https://")):
|
||||
raise serializers.ValidationError("Invalid URL scheme.")
|
||||
|
||||
return value
|
||||
@ -366,7 +367,7 @@ class IssueCommentSerializer(BaseSerializer):
|
||||
data["comment_html"] = parsed_str
|
||||
|
||||
except Exception as e:
|
||||
raise serializers.ValidationError(f"Invalid HTML: {str(e)}")
|
||||
raise serializers.ValidationError("Invalid HTML passed")
|
||||
return data
|
||||
|
||||
|
||||
|
@ -103,7 +103,8 @@ class CycleViewSet(WebhookMixin, BaseViewSet):
|
||||
.annotate(is_favorite=Exists(favorite_subquery))
|
||||
.annotate(
|
||||
total_issues=Count(
|
||||
"issue_cycle",
|
||||
"issue_cycle__issue__id",
|
||||
distinct=True,
|
||||
filter=Q(
|
||||
issue_cycle__issue__archived_at__isnull=True,
|
||||
issue_cycle__issue__is_draft=False,
|
||||
@ -112,7 +113,8 @@ class CycleViewSet(WebhookMixin, BaseViewSet):
|
||||
)
|
||||
.annotate(
|
||||
completed_issues=Count(
|
||||
"issue_cycle__issue__state__group",
|
||||
"issue_cycle__issue__id",
|
||||
distinct=True,
|
||||
filter=Q(
|
||||
issue_cycle__issue__state__group="completed",
|
||||
issue_cycle__issue__archived_at__isnull=True,
|
||||
@ -122,7 +124,8 @@ class CycleViewSet(WebhookMixin, BaseViewSet):
|
||||
)
|
||||
.annotate(
|
||||
cancelled_issues=Count(
|
||||
"issue_cycle__issue__state__group",
|
||||
"issue_cycle__issue__id",
|
||||
distinct=True,
|
||||
filter=Q(
|
||||
issue_cycle__issue__state__group="cancelled",
|
||||
issue_cycle__issue__archived_at__isnull=True,
|
||||
@ -132,7 +135,8 @@ class CycleViewSet(WebhookMixin, BaseViewSet):
|
||||
)
|
||||
.annotate(
|
||||
started_issues=Count(
|
||||
"issue_cycle__issue__state__group",
|
||||
"issue_cycle__issue__id",
|
||||
distinct=True,
|
||||
filter=Q(
|
||||
issue_cycle__issue__state__group="started",
|
||||
issue_cycle__issue__archived_at__isnull=True,
|
||||
@ -142,7 +146,8 @@ class CycleViewSet(WebhookMixin, BaseViewSet):
|
||||
)
|
||||
.annotate(
|
||||
unstarted_issues=Count(
|
||||
"issue_cycle__issue__state__group",
|
||||
"issue_cycle__issue__id",
|
||||
distinct=True,
|
||||
filter=Q(
|
||||
issue_cycle__issue__state__group="unstarted",
|
||||
issue_cycle__issue__archived_at__isnull=True,
|
||||
@ -152,7 +157,8 @@ class CycleViewSet(WebhookMixin, BaseViewSet):
|
||||
)
|
||||
.annotate(
|
||||
backlog_issues=Count(
|
||||
"issue_cycle__issue__state__group",
|
||||
"issue_cycle__issue__id",
|
||||
distinct=True,
|
||||
filter=Q(
|
||||
issue_cycle__issue__state__group="backlog",
|
||||
issue_cycle__issue__archived_at__isnull=True,
|
||||
|
@ -1,54 +1,57 @@
|
||||
# Python imports
|
||||
import json
|
||||
|
||||
# Django Imports
|
||||
from django.utils import timezone
|
||||
from django.db.models import (
|
||||
Prefetch,
|
||||
F,
|
||||
OuterRef,
|
||||
Exists,
|
||||
Count,
|
||||
Q,
|
||||
Func,
|
||||
Subquery,
|
||||
IntegerField,
|
||||
)
|
||||
from django.contrib.postgres.aggregates import ArrayAgg
|
||||
from django.contrib.postgres.fields import ArrayField
|
||||
from django.db.models import Value, UUIDField
|
||||
from django.db.models import (
|
||||
Count,
|
||||
Exists,
|
||||
F,
|
||||
Func,
|
||||
IntegerField,
|
||||
OuterRef,
|
||||
Prefetch,
|
||||
Q,
|
||||
Subquery,
|
||||
UUIDField,
|
||||
Value,
|
||||
)
|
||||
from django.db.models.functions import Coalesce
|
||||
|
||||
# Django Imports
|
||||
from django.utils import timezone
|
||||
from rest_framework import status
|
||||
|
||||
# Third party imports
|
||||
from rest_framework.response import Response
|
||||
from rest_framework import status
|
||||
|
||||
# Module imports
|
||||
from .. import BaseViewSet, BaseAPIView, WebhookMixin
|
||||
from plane.app.serializers import (
|
||||
ModuleWriteSerializer,
|
||||
ModuleSerializer,
|
||||
ModuleLinkSerializer,
|
||||
ModuleFavoriteSerializer,
|
||||
ModuleUserPropertiesSerializer,
|
||||
ModuleDetailSerializer,
|
||||
)
|
||||
from plane.app.permissions import (
|
||||
ProjectEntityPermission,
|
||||
ProjectLitePermission,
|
||||
)
|
||||
from plane.db.models import (
|
||||
Module,
|
||||
ModuleIssue,
|
||||
Project,
|
||||
Issue,
|
||||
ModuleLink,
|
||||
ModuleFavorite,
|
||||
ModuleUserProperties,
|
||||
from plane.app.serializers import (
|
||||
ModuleDetailSerializer,
|
||||
ModuleFavoriteSerializer,
|
||||
ModuleLinkSerializer,
|
||||
ModuleSerializer,
|
||||
ModuleUserPropertiesSerializer,
|
||||
ModuleWriteSerializer,
|
||||
)
|
||||
from plane.bgtasks.issue_activites_task import issue_activity
|
||||
from plane.db.models import (
|
||||
Issue,
|
||||
Module,
|
||||
ModuleFavorite,
|
||||
ModuleIssue,
|
||||
ModuleLink,
|
||||
ModuleUserProperties,
|
||||
Project,
|
||||
)
|
||||
from plane.utils.analytics_plot import burndown_plot
|
||||
|
||||
# Module imports
|
||||
from .. import BaseAPIView, BaseViewSet, WebhookMixin
|
||||
|
||||
|
||||
class ModuleViewSet(WebhookMixin, BaseViewSet):
|
||||
model = Module
|
||||
@ -392,9 +395,11 @@ class ModuleViewSet(WebhookMixin, BaseViewSet):
|
||||
"completion_chart": {},
|
||||
}
|
||||
|
||||
if queryset.first().start_date and queryset.first().target_date:
|
||||
# Fetch the modules
|
||||
modules = queryset.first()
|
||||
if modules and modules.start_date and modules.target_date:
|
||||
data["distribution"]["completion_chart"] = burndown_plot(
|
||||
queryset=queryset.first(),
|
||||
queryset=modules,
|
||||
slug=slug,
|
||||
project_id=project_id,
|
||||
module_id=pk,
|
||||
|
@ -3,15 +3,10 @@ from rest_framework import status
|
||||
from rest_framework.response import Response
|
||||
|
||||
# Module imports
|
||||
from plane.app.permissions import WorkspaceEntityPermission
|
||||
from plane.app.serializers import WorkspaceEstimateSerializer
|
||||
from plane.app.views.base import BaseAPIView
|
||||
from plane.db.models import Project, Estimate
|
||||
from plane.app.permissions import WorkspaceEntityPermission
|
||||
|
||||
# Django imports
|
||||
from django.db.models import (
|
||||
Prefetch,
|
||||
)
|
||||
from plane.db.models import Estimate, Project
|
||||
from plane.utils.cache import cache_response
|
||||
|
||||
|
||||
@ -25,15 +20,11 @@ class WorkspaceEstimatesEndpoint(BaseAPIView):
|
||||
estimate_ids = Project.objects.filter(
|
||||
workspace__slug=slug, estimate__isnull=False
|
||||
).values_list("estimate_id", flat=True)
|
||||
estimates = Estimate.objects.filter(
|
||||
pk__in=estimate_ids
|
||||
).prefetch_related(
|
||||
Prefetch(
|
||||
"points",
|
||||
queryset=Project.objects.select_related(
|
||||
"estimate", "workspace"
|
||||
),
|
||||
)
|
||||
estimates = (
|
||||
Estimate.objects.filter(pk__in=estimate_ids, workspace__slug=slug)
|
||||
.prefetch_related("points")
|
||||
.select_related("workspace", "project")
|
||||
)
|
||||
|
||||
serializer = WorkspaceEstimateSerializer(estimates, many=True)
|
||||
return Response(serializer.data, status=status.HTTP_200_OK)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -4,18 +4,15 @@ import { Node } from "@tiptap/pm/model";
|
||||
import { findListItemPos } from "src/ui/extensions/custom-list-keymap/list-helpers/find-list-item-pos";
|
||||
import { hasListBefore } from "src/ui/extensions/custom-list-keymap/list-helpers/has-list-before";
|
||||
|
||||
import { hasListItemBefore } from "src/ui/extensions/custom-list-keymap/list-helpers/has-list-item-before";
|
||||
import { listItemHasSubList } from "src/ui/extensions/custom-list-keymap/list-helpers/list-item-has-sub-list";
|
||||
|
||||
export const handleBackspace = (editor: Editor, name: string, parentListTypes: string[]) => {
|
||||
// this is required to still handle the undo handling
|
||||
if (editor.commands.undoInputRule()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// if the cursor is not at the start of a node
|
||||
// do nothing and proceed
|
||||
if (!isAtStartOfNode(editor.state)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if the current item is NOT inside a list item &
|
||||
// the previous item is a list (orderedList or bulletList)
|
||||
// move the cursor into the list and delete the current item
|
||||
@ -53,14 +50,31 @@ export const handleBackspace = (editor: Editor, name: string, parentListTypes: s
|
||||
return false;
|
||||
}
|
||||
|
||||
// if the cursor is not at the start of a node
|
||||
// do nothing and proceed
|
||||
if (!isAtStartOfNode(editor.state)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const listItemPos = findListItemPos(name, editor.state);
|
||||
|
||||
if (!listItemPos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if current node is a list item and cursor it at start of a list node,
|
||||
// simply lift the list item i.e. remove it as a list item (task/bullet/ordered)
|
||||
// irrespective of above node being a list or not
|
||||
const $prev = editor.state.doc.resolve(listItemPos.$pos.pos - 2);
|
||||
const prevNode = $prev.node(listItemPos.depth);
|
||||
|
||||
const previousListItemHasSubList = listItemHasSubList(name, editor.state, prevNode);
|
||||
|
||||
// if the previous item is a list item and doesn't have a sublist, join the list items
|
||||
if (hasListItemBefore(name, editor.state) && previousListItemHasSubList) {
|
||||
return editor.chain().liftListItem(name).run();
|
||||
// return editor.commands.joinItemBackward();
|
||||
}
|
||||
|
||||
// otherwise in the end, a backspace should
|
||||
// always just lift the list item if
|
||||
// joining / merging is not possible
|
||||
return editor.chain().liftListItem(name).run();
|
||||
};
|
||||
|
@ -0,0 +1,21 @@
|
||||
import { getNodeType } from "@tiptap/core";
|
||||
import { Node } from "@tiptap/pm/model";
|
||||
import { EditorState } from "@tiptap/pm/state";
|
||||
|
||||
export const listItemHasSubList = (typeOrName: string, state: EditorState, node?: Node) => {
|
||||
if (!node) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const nodeType = getNodeType(typeOrName, state.schema);
|
||||
|
||||
let hasSubList = false;
|
||||
|
||||
node.descendants((child) => {
|
||||
if (child.type === nodeType) {
|
||||
hasSubList = true;
|
||||
}
|
||||
});
|
||||
|
||||
return hasSubList;
|
||||
};
|
@ -41,12 +41,12 @@ export const CoreEditorExtensions = (
|
||||
StarterKit.configure({
|
||||
bulletList: {
|
||||
HTMLAttributes: {
|
||||
class: "list-disc list-outside leading-3 -mt-2",
|
||||
class: "list-disc list-outside leading-3",
|
||||
},
|
||||
},
|
||||
orderedList: {
|
||||
HTMLAttributes: {
|
||||
class: "list-decimal list-outside leading-3 -mt-2",
|
||||
class: "list-decimal list-outside leading-3 -mt-2 -mb-2",
|
||||
},
|
||||
},
|
||||
listItem: {
|
||||
@ -98,7 +98,7 @@ export const CoreEditorExtensions = (
|
||||
}),
|
||||
TaskItem.configure({
|
||||
HTMLAttributes: {
|
||||
class: "flex items-start my-4",
|
||||
class: "flex items-start mt-4",
|
||||
},
|
||||
nested: true,
|
||||
}),
|
||||
|
@ -1,4 +1,7 @@
|
||||
import { Extension } from "@tiptap/core";
|
||||
import { Plugin, PluginKey, Transaction } from "@tiptap/pm/state";
|
||||
import { canJoin } from "@tiptap/pm/transform";
|
||||
import { NodeType } from "@tiptap/pm/model";
|
||||
|
||||
declare module "@tiptap/core" {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
@ -12,6 +15,51 @@ declare module "@tiptap/core" {
|
||||
}
|
||||
}
|
||||
|
||||
function autoJoin(tr: Transaction, newTr: Transaction, nodeType: NodeType) {
|
||||
if (!tr.isGeneric) return false;
|
||||
|
||||
// Find all ranges where we might want to join.
|
||||
const ranges: Array<number> = [];
|
||||
for (let i = 0; i < tr.mapping.maps.length; i++) {
|
||||
const map = tr.mapping.maps[i];
|
||||
for (let j = 0; j < ranges.length; j++) ranges[j] = map.map(ranges[j]);
|
||||
map.forEach((_s, _e, from, to) => ranges.push(from, to));
|
||||
}
|
||||
|
||||
// Figure out which joinable points exist inside those ranges,
|
||||
// by checking all node boundaries in their parent nodes.
|
||||
const joinable = [];
|
||||
for (let i = 0; i < ranges.length; i += 2) {
|
||||
const from = ranges[i],
|
||||
to = ranges[i + 1];
|
||||
const $from = tr.doc.resolve(from),
|
||||
depth = $from.sharedDepth(to),
|
||||
parent = $from.node(depth);
|
||||
for (let index = $from.indexAfter(depth), pos = $from.after(depth + 1); pos <= to; ++index) {
|
||||
const after = parent.maybeChild(index);
|
||||
if (!after) break;
|
||||
if (index && joinable.indexOf(pos) == -1) {
|
||||
const before = parent.child(index - 1);
|
||||
if (before.type == after.type && before.type === nodeType) joinable.push(pos);
|
||||
}
|
||||
pos += after.nodeSize;
|
||||
}
|
||||
}
|
||||
|
||||
let joined = false;
|
||||
|
||||
// Join the joinable points
|
||||
joinable.sort((a, b) => a - b);
|
||||
for (let i = joinable.length - 1; i >= 0; i--) {
|
||||
if (canJoin(tr.doc, joinable[i])) {
|
||||
newTr.join(joinable[i]);
|
||||
joined = true;
|
||||
}
|
||||
}
|
||||
|
||||
return joined;
|
||||
}
|
||||
|
||||
export const CustomKeymap = Extension.create({
|
||||
name: "CustomKeymap",
|
||||
|
||||
@ -32,6 +80,42 @@ export const CustomKeymap = Extension.create({
|
||||
};
|
||||
},
|
||||
|
||||
addProseMirrorPlugins() {
|
||||
return [
|
||||
new Plugin({
|
||||
key: new PluginKey("ordered-list-merging"),
|
||||
appendTransaction(transactions, oldState, newState) {
|
||||
// Create a new transaction.
|
||||
const newTr = newState.tr;
|
||||
|
||||
let joined = false;
|
||||
for (const transaction of transactions) {
|
||||
const anotherJoin = autoJoin(transaction, newTr, newState.schema.nodes["orderedList"]);
|
||||
joined = anotherJoin || joined;
|
||||
}
|
||||
if (joined) {
|
||||
return newTr;
|
||||
}
|
||||
},
|
||||
}),
|
||||
new Plugin({
|
||||
key: new PluginKey("unordered-list-merging"),
|
||||
appendTransaction(transactions, oldState, newState) {
|
||||
// Create a new transaction.
|
||||
const newTr = newState.tr;
|
||||
|
||||
let joined = false;
|
||||
for (const transaction of transactions) {
|
||||
const anotherJoin = autoJoin(transaction, newTr, newState.schema.nodes["bulletList"]);
|
||||
joined = anotherJoin || joined;
|
||||
}
|
||||
if (joined) {
|
||||
return newTr;
|
||||
}
|
||||
},
|
||||
}),
|
||||
];
|
||||
},
|
||||
addKeyboardShortcuts() {
|
||||
return {
|
||||
"Mod-a": ({ editor }) => {
|
||||
|
@ -28,12 +28,12 @@ export const CoreReadOnlyEditorExtensions = (mentionConfig: {
|
||||
StarterKit.configure({
|
||||
bulletList: {
|
||||
HTMLAttributes: {
|
||||
class: "list-disc list-outside leading-3 -mt-2",
|
||||
class: "list-disc list-outside leading-3",
|
||||
},
|
||||
},
|
||||
orderedList: {
|
||||
HTMLAttributes: {
|
||||
class: "list-decimal list-outside leading-3 -mt-2",
|
||||
class: "list-decimal list-outside leading-3 -mt-2 -mb-2",
|
||||
},
|
||||
},
|
||||
listItem: {
|
||||
@ -81,7 +81,7 @@ export const CoreReadOnlyEditorExtensions = (mentionConfig: {
|
||||
}),
|
||||
TaskItem.configure({
|
||||
HTMLAttributes: {
|
||||
class: "flex items-start my-4",
|
||||
class: "flex items-start mt-4",
|
||||
},
|
||||
nested: true,
|
||||
}),
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
/** @type {import('next').NextConfig} */
|
||||
require("dotenv").config({ path: ".env" });
|
||||
const { withSentryConfig } = require("@sentry/nextjs");
|
||||
@ -26,8 +27,11 @@ const nextConfig = {
|
||||
output: "standalone",
|
||||
};
|
||||
|
||||
if (parseInt(process.env.NEXT_PUBLIC_ENABLE_SENTRY || "0")) {
|
||||
module.exports = withSentryConfig(nextConfig, { silent: true }, { hideSourceMaps: true });
|
||||
if (parseInt(process.env.NEXT_PUBLIC_ENABLE_SENTRY || "0"), 10) {
|
||||
module.exports = withSentryConfig(nextConfig,
|
||||
{ silent: true, authToken: process.env.SENTRY_AUTH_TOKEN },
|
||||
{ hideSourceMaps: true }
|
||||
);
|
||||
} else {
|
||||
module.exports = nextConfig;
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
||||
"@plane/rich-text-editor": "*",
|
||||
"@plane/types": "*",
|
||||
"@plane/ui": "*",
|
||||
"@sentry/nextjs": "^7.85.0",
|
||||
"@sentry/nextjs": "^7.108.0",
|
||||
"axios": "^1.3.4",
|
||||
"clsx": "^2.0.0",
|
||||
"dotenv": "^16.3.1",
|
||||
|
24
turbo.json
24
turbo.json
@ -17,37 +17,25 @@
|
||||
"NEXT_PUBLIC_POSTHOG_KEY",
|
||||
"NEXT_PUBLIC_POSTHOG_HOST",
|
||||
"NEXT_PUBLIC_POSTHOG_DEBUG",
|
||||
"JITSU_TRACKER_ACCESS_KEY",
|
||||
"JITSU_TRACKER_HOST"
|
||||
"SENTRY_AUTH_TOKEN"
|
||||
],
|
||||
"pipeline": {
|
||||
"build": {
|
||||
"dependsOn": [
|
||||
"^build"
|
||||
],
|
||||
"outputs": [
|
||||
".next/**",
|
||||
"dist/**"
|
||||
]
|
||||
"dependsOn": ["^build"],
|
||||
"outputs": [".next/**", "dist/**"]
|
||||
},
|
||||
"develop": {
|
||||
"cache": false,
|
||||
"persistent": true,
|
||||
"dependsOn": [
|
||||
"^build"
|
||||
]
|
||||
"dependsOn": ["^build"]
|
||||
},
|
||||
"dev": {
|
||||
"cache": false,
|
||||
"persistent": true,
|
||||
"dependsOn": [
|
||||
"^build"
|
||||
]
|
||||
"dependsOn": ["^build"]
|
||||
},
|
||||
"test": {
|
||||
"dependsOn": [
|
||||
"^build"
|
||||
],
|
||||
"dependsOn": ["^build"],
|
||||
"outputs": []
|
||||
},
|
||||
"lint": {
|
||||
|
@ -144,7 +144,7 @@ export const ImagePickerPopover: React.FC<Props> = observer((props) => {
|
||||
useEffect(() => {
|
||||
if (!unsplashImages || value !== null) return;
|
||||
|
||||
onChange(unsplashImages[0].urls.regular);
|
||||
onChange(unsplashImages[0]?.urls.regular);
|
||||
}, [value, onChange, unsplashImages]);
|
||||
|
||||
const handleClose = () => {
|
||||
|
@ -201,7 +201,7 @@ export const ActiveCycleStats: FC<ActiveCycleStatsProps> = observer((props) => {
|
||||
as="div"
|
||||
className="flex h-52 w-full flex-col gap-1 overflow-y-auto text-custom-text-200 vertical-scrollbar scrollbar-sm"
|
||||
>
|
||||
{cycleIssues.length > 0 ? (
|
||||
{cycle?.distribution?.assignees && cycle.distribution.assignees.length > 0 ? (
|
||||
cycle.distribution?.assignees?.map((assignee, index) => {
|
||||
if (assignee.assignee_id)
|
||||
return (
|
||||
@ -246,8 +246,8 @@ export const ActiveCycleStats: FC<ActiveCycleStatsProps> = observer((props) => {
|
||||
as="div"
|
||||
className="flex h-52 w-full flex-col gap-1 overflow-y-auto text-custom-text-200 vertical-scrollbar scrollbar-sm"
|
||||
>
|
||||
{cycleIssues.length > 0 ? (
|
||||
cycle.distribution?.labels?.map((label, index) => (
|
||||
{cycle?.distribution?.labels && cycle.distribution.labels.length > 0 ? (
|
||||
cycle.distribution.labels?.map((label, index) => (
|
||||
<SingleProgressStats
|
||||
key={label.label_id ?? `no-label-${index}`}
|
||||
title={
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { RefreshCw } from "lucide-react";
|
||||
import { TIssue } from "@plane/types";
|
||||
// types
|
||||
@ -9,7 +10,7 @@ type Props = {
|
||||
issueDetail?: TIssue;
|
||||
};
|
||||
|
||||
export const IssueUpdateStatus: React.FC<Props> = (props) => {
|
||||
export const IssueUpdateStatus: React.FC<Props> = observer((props) => {
|
||||
const { isSubmitting, issueDetail } = props;
|
||||
// hooks
|
||||
const { getProjectById } = useProject();
|
||||
@ -33,4 +34,4 @@ export const IssueUpdateStatus: React.FC<Props> = (props) => {
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
// hooks
|
||||
@ -6,7 +7,7 @@ import { EUserWorkspaceRoles, WORKSPACE_SETTINGS_LINKS } from "@/constants/works
|
||||
import { useUser } from "@/hooks/store";
|
||||
// constants
|
||||
|
||||
export const WorkspaceSettingsSidebar = () => {
|
||||
export const WorkspaceSettingsSidebar = observer(() => {
|
||||
// router
|
||||
const router = useRouter();
|
||||
const { workspaceSlug } = router.query;
|
||||
@ -44,4 +45,4 @@ export const WorkspaceSettingsSidebar = () => {
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
require("dotenv").config({ path: ".env" });
|
||||
const { withSentryConfig } = require("@sentry/nextjs");
|
||||
|
||||
@ -24,8 +25,11 @@ const nextConfig = {
|
||||
output: "standalone",
|
||||
};
|
||||
|
||||
if (parseInt(process.env.NEXT_PUBLIC_ENABLE_SENTRY || "0")) {
|
||||
module.exports = withSentryConfig(nextConfig, { silent: true }, { hideSourceMaps: true });
|
||||
if (parseInt(process.env.NEXT_PUBLIC_ENABLE_SENTRY || "0"), 10) {
|
||||
module.exports = withSentryConfig(nextConfig,
|
||||
{ silent: true, authToken: process.env.SENTRY_AUTH_TOKEN },
|
||||
{ hideSourceMaps: true }
|
||||
);
|
||||
} else {
|
||||
module.exports = nextConfig;
|
||||
}
|
||||
|
@ -28,7 +28,7 @@
|
||||
"@plane/types": "*",
|
||||
"@plane/ui": "*",
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@sentry/nextjs": "^7.85.0",
|
||||
"@sentry/nextjs": "^7.108.0",
|
||||
"axios": "^1.1.3",
|
||||
"clsx": "^2.0.0",
|
||||
"cmdk": "^0.2.0",
|
||||
|
189
yarn.lock
189
yarn.lock
@ -2149,35 +2149,46 @@
|
||||
dependencies:
|
||||
"@daybrush/utils" "^1.4.0"
|
||||
|
||||
"@sentry-internal/feedback@7.91.0":
|
||||
version "7.91.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry-internal/feedback/-/feedback-7.91.0.tgz#be09e5aec2959fcf503e2cf78496d5e2d263bc5a"
|
||||
integrity sha512-SJKTSaz68F5YIwF79EttBm915M2LnacgZMYRnRumyTmMKnebGhYQLwWbZdpaDvOa1U18dgRajDX8Qed/8A3tXw==
|
||||
"@sentry-internal/feedback@7.108.0":
|
||||
version "7.108.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry-internal/feedback/-/feedback-7.108.0.tgz#7033352abd304f1383ec47640e056a0dfd5132b7"
|
||||
integrity sha512-8JcgZEnk1uWrXJhsd3iRvFtEiVeaWOEhN0NZwhwQXHfvODqep6JtrkY1yCIyxbpA37aZmrPc2JhyotRERGfUjg==
|
||||
dependencies:
|
||||
"@sentry/core" "7.91.0"
|
||||
"@sentry/types" "7.91.0"
|
||||
"@sentry/utils" "7.91.0"
|
||||
"@sentry/core" "7.108.0"
|
||||
"@sentry/types" "7.108.0"
|
||||
"@sentry/utils" "7.108.0"
|
||||
|
||||
"@sentry-internal/tracing@7.91.0":
|
||||
version "7.91.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.91.0.tgz#fbb6e1e3383e1eeee08633384e004da73ac1c37d"
|
||||
integrity sha512-JH5y6gs6BS0its7WF2DhySu7nkhPDfZcdpAXldxzIlJpqFkuwQKLU5nkYJpiIyZz1NHYYtW5aum2bV2oCOdDRA==
|
||||
"@sentry-internal/replay-canvas@7.108.0":
|
||||
version "7.108.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry-internal/replay-canvas/-/replay-canvas-7.108.0.tgz#641133c19c0e1c423617b8d791f53d6cd0b0a862"
|
||||
integrity sha512-R5tvjGqWUV5vSk0N1eBgVW7wIADinrkfDEBZ9FyKP2mXHBobsyNGt30heJDEqYmVqluRqjU2NuIRapsnnrpGnA==
|
||||
dependencies:
|
||||
"@sentry/core" "7.91.0"
|
||||
"@sentry/types" "7.91.0"
|
||||
"@sentry/utils" "7.91.0"
|
||||
"@sentry/core" "7.108.0"
|
||||
"@sentry/replay" "7.108.0"
|
||||
"@sentry/types" "7.108.0"
|
||||
"@sentry/utils" "7.108.0"
|
||||
|
||||
"@sentry/browser@7.91.0":
|
||||
version "7.91.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.91.0.tgz#de3b9ae3ca7716a35cfabc97ac376944a67e6e34"
|
||||
integrity sha512-lJv3x/xekzC/biiyAsVCioq2XnKNOZhI6jY3ZzLJZClYV8eKRi7D3KCsHRvMiCdGak1d/6sVp8F4NYY+YiWy1Q==
|
||||
"@sentry-internal/tracing@7.108.0":
|
||||
version "7.108.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.108.0.tgz#d1e660701fb860cfae72b6ebfa8fb267533421fa"
|
||||
integrity sha512-zuK5XsTsb+U+hgn3SPetYDAogrXsM16U/LLoMW7+TlC6UjlHGYQvmX3o+M2vntejoU1QZS8m1bCAZSMWEypAEw==
|
||||
dependencies:
|
||||
"@sentry-internal/feedback" "7.91.0"
|
||||
"@sentry-internal/tracing" "7.91.0"
|
||||
"@sentry/core" "7.91.0"
|
||||
"@sentry/replay" "7.91.0"
|
||||
"@sentry/types" "7.91.0"
|
||||
"@sentry/utils" "7.91.0"
|
||||
"@sentry/core" "7.108.0"
|
||||
"@sentry/types" "7.108.0"
|
||||
"@sentry/utils" "7.108.0"
|
||||
|
||||
"@sentry/browser@7.108.0":
|
||||
version "7.108.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.108.0.tgz#b95810bb6572b63781f253615896f5afb1a3a5c0"
|
||||
integrity sha512-FNpzsdTvGvdHJMUelqEouUXMZU7jC+dpN7CdT6IoHVVFEkoAgrjMVUhXZoQ/dmCkdKWHmFSQhJ8Fm6V+e9Aq0A==
|
||||
dependencies:
|
||||
"@sentry-internal/feedback" "7.108.0"
|
||||
"@sentry-internal/replay-canvas" "7.108.0"
|
||||
"@sentry-internal/tracing" "7.108.0"
|
||||
"@sentry/core" "7.108.0"
|
||||
"@sentry/replay" "7.108.0"
|
||||
"@sentry/types" "7.108.0"
|
||||
"@sentry/utils" "7.108.0"
|
||||
|
||||
"@sentry/cli@^1.77.1":
|
||||
version "1.77.1"
|
||||
@ -2191,95 +2202,95 @@
|
||||
proxy-from-env "^1.1.0"
|
||||
which "^2.0.2"
|
||||
|
||||
"@sentry/core@7.91.0":
|
||||
version "7.91.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.91.0.tgz#229334d7f03dd5d90a17495e61ce4215ab730b2a"
|
||||
integrity sha512-tu+gYq4JrTdrR+YSh5IVHF0fJi/Pi9y0HZ5H9HnYy+UMcXIotxf6hIEaC6ZKGeLWkGXffz2gKpQLe/g6vy/lPA==
|
||||
"@sentry/core@7.108.0":
|
||||
version "7.108.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.108.0.tgz#a27e8d6f85f59c5730ce86071474f15ac899fde0"
|
||||
integrity sha512-I/VNZCFgLASxHZaD0EtxZRM34WG9w2gozqgrKGNMzAymwmQ3K9g/1qmBy4e6iS3YRptb7J5UhQkZQHrcwBbjWQ==
|
||||
dependencies:
|
||||
"@sentry/types" "7.91.0"
|
||||
"@sentry/utils" "7.91.0"
|
||||
"@sentry/types" "7.108.0"
|
||||
"@sentry/utils" "7.108.0"
|
||||
|
||||
"@sentry/integrations@7.91.0":
|
||||
version "7.91.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.91.0.tgz#b0496c9e404783bc433b1d2464d8f9aa180ebc8e"
|
||||
integrity sha512-LGRfb+WfG3FaWHtDnJIhtupweat0imCQr2z/5SSbQKzqxHhtlaEU+9IExBmBdzq90n4lRBaVQHA3zGuU02uOhg==
|
||||
"@sentry/integrations@7.108.0":
|
||||
version "7.108.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.108.0.tgz#307c61966208f2a126c1a93e712277c8f86a3d3c"
|
||||
integrity sha512-b/WbK1f3x2rQ4aJJSA4VSwpBXrXFm1Nzrca3Y9qW0MI1wjZEYsDDrh9m6ulLdVBl4YDc2VqYp1COwU/NjuHlog==
|
||||
dependencies:
|
||||
"@sentry/core" "7.91.0"
|
||||
"@sentry/types" "7.91.0"
|
||||
"@sentry/utils" "7.91.0"
|
||||
"@sentry/core" "7.108.0"
|
||||
"@sentry/types" "7.108.0"
|
||||
"@sentry/utils" "7.108.0"
|
||||
localforage "^1.8.1"
|
||||
|
||||
"@sentry/nextjs@^7.85.0":
|
||||
version "7.91.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/nextjs/-/nextjs-7.91.0.tgz#42eb3af10ff230e8a3fe9f0e50cdbac94b7d290e"
|
||||
integrity sha512-wE83+OTEH4yYnDrhMw9eVEARSfZc6xY5qJb9xyYm5rW3+gVjNQZQaUY+wkM61Xdo0T35BN+7U4T88HbwzGeMqA==
|
||||
"@sentry/nextjs@^7.108.0":
|
||||
version "7.108.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/nextjs/-/nextjs-7.108.0.tgz#31d903d75bbf4b4530046360daff4d51dcf62f53"
|
||||
integrity sha512-etBrMSLRbNAzozetBeL6D+lR9lRAyHmV7NUBGCX9lQvgmcdxkQa15EX8pIKjsMejZ8xAZNsqYVIByIs67A77rg==
|
||||
dependencies:
|
||||
"@rollup/plugin-commonjs" "24.0.0"
|
||||
"@sentry/core" "7.91.0"
|
||||
"@sentry/integrations" "7.91.0"
|
||||
"@sentry/node" "7.91.0"
|
||||
"@sentry/react" "7.91.0"
|
||||
"@sentry/types" "7.91.0"
|
||||
"@sentry/utils" "7.91.0"
|
||||
"@sentry/vercel-edge" "7.91.0"
|
||||
"@sentry/core" "7.108.0"
|
||||
"@sentry/integrations" "7.108.0"
|
||||
"@sentry/node" "7.108.0"
|
||||
"@sentry/react" "7.108.0"
|
||||
"@sentry/types" "7.108.0"
|
||||
"@sentry/utils" "7.108.0"
|
||||
"@sentry/vercel-edge" "7.108.0"
|
||||
"@sentry/webpack-plugin" "1.21.0"
|
||||
chalk "3.0.0"
|
||||
resolve "1.22.8"
|
||||
rollup "2.78.0"
|
||||
stacktrace-parser "^0.1.10"
|
||||
|
||||
"@sentry/node@7.91.0":
|
||||
version "7.91.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/node/-/node-7.91.0.tgz#26bf13c3daf988f9725afd1a3cc38ba2ff90d62a"
|
||||
integrity sha512-hTIfSQxD7L+AKIqyjoq8CWBRkEQrrMZmA3GSZgPI5JFWBHgO0HBo5TH/8TU81oEJh6kqqHAl2ObMhmcnaFqlzg==
|
||||
"@sentry/node@7.108.0":
|
||||
version "7.108.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/node/-/node-7.108.0.tgz#ed113dc1d39aaae32f7e9f681dcea41cf28eb5f1"
|
||||
integrity sha512-pMxc9txnDDkU4Z8k2Uw/DPSLPehNtWV3mjJ3+my0AMORGYrXLkJI93tddlE5z/7k+GEJdj1HsOLgxUN0OU+HGA==
|
||||
dependencies:
|
||||
"@sentry-internal/tracing" "7.91.0"
|
||||
"@sentry/core" "7.91.0"
|
||||
"@sentry/types" "7.91.0"
|
||||
"@sentry/utils" "7.91.0"
|
||||
https-proxy-agent "^5.0.0"
|
||||
"@sentry-internal/tracing" "7.108.0"
|
||||
"@sentry/core" "7.108.0"
|
||||
"@sentry/types" "7.108.0"
|
||||
"@sentry/utils" "7.108.0"
|
||||
|
||||
"@sentry/react@7.91.0":
|
||||
version "7.91.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.91.0.tgz#620e6ce9452af025d2cc1b2eca3dd1dd730dc439"
|
||||
integrity sha512-7JH2rWaX3WKHHvBcZQ4f/KnkYIXTf7hMojRFncUwPocdtDlhJw/JUvjAYNpEysixXIgsMes3B32lmtZjGjRhwQ==
|
||||
"@sentry/react@7.108.0":
|
||||
version "7.108.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.108.0.tgz#26a50324f6d7a9576f3753c099e7bcd8def94f3c"
|
||||
integrity sha512-C60arh5/gtO42eMU9l34aWlKDLZUO+1j1goaEf/XRSwUcyJS9tbJrs+mT4nbKxUsEG714It2gRbfSEvh1eXmCg==
|
||||
dependencies:
|
||||
"@sentry/browser" "7.91.0"
|
||||
"@sentry/types" "7.91.0"
|
||||
"@sentry/utils" "7.91.0"
|
||||
"@sentry/browser" "7.108.0"
|
||||
"@sentry/core" "7.108.0"
|
||||
"@sentry/types" "7.108.0"
|
||||
"@sentry/utils" "7.108.0"
|
||||
hoist-non-react-statics "^3.3.2"
|
||||
|
||||
"@sentry/replay@7.91.0":
|
||||
version "7.91.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.91.0.tgz#95077868aee3c3cc670affe13156434f858e1755"
|
||||
integrity sha512-XwbesnLLNtaVXKtDoyBB96GxJuhGi9zy3a662Ba/McmumCnkXrMQYpQPh08U7MgkTyDRgjDwm7PXDhiKpcb03g==
|
||||
"@sentry/replay@7.108.0":
|
||||
version "7.108.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.108.0.tgz#baa679bd19b4e3729e607d3f84cff5048aeb3415"
|
||||
integrity sha512-jo8fDOzcZJclP1+4n9jUtVxTlBFT9hXwxhAMrhrt70FV/nfmCtYQMD3bzIj79nwbhUtFP6pN39JH1o7Xqt1hxQ==
|
||||
dependencies:
|
||||
"@sentry-internal/tracing" "7.91.0"
|
||||
"@sentry/core" "7.91.0"
|
||||
"@sentry/types" "7.91.0"
|
||||
"@sentry/utils" "7.91.0"
|
||||
"@sentry-internal/tracing" "7.108.0"
|
||||
"@sentry/core" "7.108.0"
|
||||
"@sentry/types" "7.108.0"
|
||||
"@sentry/utils" "7.108.0"
|
||||
|
||||
"@sentry/types@7.91.0":
|
||||
version "7.91.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.91.0.tgz#5b68954e08986fecb0d4bef168df58eef62c32c7"
|
||||
integrity sha512-bcQnb7J3P3equbCUc+sPuHog2Y47yGD2sCkzmnZBjvBT0Z1B4f36fI/5WjyZhTjLSiOdg3F2otwvikbMjmBDew==
|
||||
"@sentry/types@7.108.0":
|
||||
version "7.108.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.108.0.tgz#5ceb959c4dabe511fc441fec8c2465f2d624900f"
|
||||
integrity sha512-bKtHITmBN3kqtqE5eVvL8mY8znM05vEodENwRpcm6TSrrBjC2RnwNWVwGstYDdHpNfFuKwC8mLY9bgMJcENo8g==
|
||||
|
||||
"@sentry/utils@7.91.0":
|
||||
version "7.91.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.91.0.tgz#3b1a94c053c885877908cd3e1365e3d23e21a73f"
|
||||
integrity sha512-fvxjrEbk6T6Otu++Ax9ntlQ0sGRiwSC179w68aC3u26Wr30FAIRKqHTCCdc2jyWk7Gd9uWRT/cq+g8NG/8BfSg==
|
||||
"@sentry/utils@7.108.0":
|
||||
version "7.108.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.108.0.tgz#0231042956aed2ef35809891592238530349dfd9"
|
||||
integrity sha512-a45yEFD5qtgZaIFRAcFkG8C8lnDzn6t4LfLXuV4OafGAy/3ZAN3XN8wDnrruHkiUezSSANGsLg3bXaLW/JLvJw==
|
||||
dependencies:
|
||||
"@sentry/types" "7.91.0"
|
||||
"@sentry/types" "7.108.0"
|
||||
|
||||
"@sentry/vercel-edge@7.91.0":
|
||||
version "7.91.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/vercel-edge/-/vercel-edge-7.91.0.tgz#df67ee39d10570b71eccf831a181c064974d62b1"
|
||||
integrity sha512-CounqhXPwFh67zf6L/q4ACBHHqknT6YY9LdgIAnUd0GGgHzrJPyKcthvh8Je4lNdpo5LFg2gnR+6g6JS8DDYDQ==
|
||||
"@sentry/vercel-edge@7.108.0":
|
||||
version "7.108.0"
|
||||
resolved "https://registry.yarnpkg.com/@sentry/vercel-edge/-/vercel-edge-7.108.0.tgz#c5ca35094bc46029ec5a72f7ee09fd3705582baa"
|
||||
integrity sha512-dUuUEswaVIzsJnzTfaJxrvkfOowrlJxxHo2AybPDym2rob7CdaLdDJIYJa83X7QeAKMkTgLny/gYSQYC0E4UyA==
|
||||
dependencies:
|
||||
"@sentry-internal/tracing" "7.91.0"
|
||||
"@sentry/core" "7.91.0"
|
||||
"@sentry/types" "7.91.0"
|
||||
"@sentry/utils" "7.91.0"
|
||||
"@sentry-internal/tracing" "7.108.0"
|
||||
"@sentry/core" "7.108.0"
|
||||
"@sentry/types" "7.108.0"
|
||||
"@sentry/utils" "7.108.0"
|
||||
|
||||
"@sentry/webpack-plugin@1.21.0":
|
||||
version "1.21.0"
|
||||
|
Loading…
Reference in New Issue
Block a user