mirror of
https://github.com/makeplane/plane.git
synced 2026-07-13 05:49:40 +02:00
Merge pull request #571 from makeplane/sync/ce-ee
sync: community changes
This commit is contained in:
2
.github/ISSUE_TEMPLATE/--bug-report.yaml
vendored
2
.github/ISSUE_TEMPLATE/--bug-report.yaml
vendored
@@ -2,7 +2,7 @@ name: Bug report
|
||||
description: Create a bug report to help us improve Plane
|
||||
title: "[bug]: "
|
||||
labels: [🐛bug]
|
||||
assignees: [srinivaspendem, pushya22]
|
||||
assignees: [vihar, pushya22]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
|
||||
@@ -2,7 +2,7 @@ name: Feature request
|
||||
description: Suggest a feature to improve Plane
|
||||
title: "[feature]: "
|
||||
labels: [✨feature]
|
||||
assignees: [srinivaspendem, pushya22]
|
||||
assignees: [vihar, pushya22]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
|
||||
@@ -223,8 +223,14 @@ class PageViewSet(BaseViewSet):
|
||||
status=status.HTTP_404_NOT_FOUND,
|
||||
)
|
||||
else:
|
||||
issue_ids = PageLog.objects.filter(
|
||||
page_id=pk, entity_name="issue"
|
||||
).values_list("entity_identifier", flat=True)
|
||||
data = PageDetailSerializer(page).data
|
||||
data["issue_ids"] = issue_ids
|
||||
return Response(
|
||||
PageDetailSerializer(page).data, status=status.HTTP_200_OK
|
||||
data,
|
||||
status=status.HTTP_200_OK,
|
||||
)
|
||||
|
||||
def lock(self, request, slug, project_id, pk):
|
||||
|
||||
@@ -12,7 +12,7 @@ from django.db.models import (
|
||||
Sum,
|
||||
Value,
|
||||
When,
|
||||
IntegerField,
|
||||
FloatField,
|
||||
)
|
||||
from django.db.models.functions import (
|
||||
Coalesce,
|
||||
@@ -98,7 +98,7 @@ def build_graph_plot(queryset, x_axis, y_axis, segment=None):
|
||||
# Estimate
|
||||
else:
|
||||
queryset = queryset.annotate(
|
||||
estimate=Sum(Cast("estimate_point__value", IntegerField()))
|
||||
estimate=Sum(Cast("estimate_point__value", FloatField()))
|
||||
).order_by(x_axis)
|
||||
queryset = (
|
||||
queryset.annotate(segment=F(segment)) if segment else queryset
|
||||
|
||||
@@ -3,3 +3,4 @@ export * from "./embed";
|
||||
export * from "./image";
|
||||
export * from "./mention-suggestion";
|
||||
export * from "./slash-commands-suggestion";
|
||||
export * from "@/plane-editor/types";
|
||||
|
||||
@@ -1 +1 @@
|
||||
export * from "./issue-embed";
|
||||
export * from "./issue-embed-upgrade-card";
|
||||
|
||||
@@ -2,11 +2,10 @@ import { Crown } from "lucide-react";
|
||||
// ui
|
||||
import { Button } from "@plane/ui";
|
||||
|
||||
export const IssueEmbedCard: React.FC<any> = (props) => (
|
||||
export const IssueEmbedUpgradeCard: React.FC<any> = (props) => (
|
||||
<div
|
||||
className={`${
|
||||
props.selected ? "border-custom-primary-200 border-[2px]" : ""
|
||||
} w-full h-[100px] cursor-pointer space-y-2 rounded-md border-[0.5px] border-custom-border-200 shadow-custom-shadow-2xs`}
|
||||
className={`${props.selected ? "border-custom-primary-200 border-[2px]" : ""
|
||||
} w-full h-[100px] cursor-pointer space-y-2 rounded-md border-[0.5px] border-custom-border-200 shadow-custom-shadow-2xs`}
|
||||
>
|
||||
<h5 className="h-[20%] text-xs text-custom-text-300 p-2">
|
||||
{props.node?.attrs?.project_identifier}-{props?.node?.attrs?.sequence_id}
|
||||
@@ -1 +0,0 @@
|
||||
export const ENABLE_BULK_OPERATIONS = false;
|
||||
1
web/ce/hooks/use-bulk-operation-status.ts
Normal file
1
web/ce/hooks/use-bulk-operation-status.ts
Normal file
@@ -0,0 +1 @@
|
||||
export const useBulkOperationStatus = () => false;
|
||||
24
web/ce/hooks/use-issue-embed.tsx
Normal file
24
web/ce/hooks/use-issue-embed.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
// editor
|
||||
import { TEmbedConfig, TReadOnlyEmbedConfig } from "@plane/editor";
|
||||
// types
|
||||
import { TPageEmbedType } from "@plane/types";
|
||||
// plane web components
|
||||
import { IssueEmbedUpgradeCard } from "@/plane-web/components/pages";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
export const useIssueEmbed = (workspaceSlug: string, projectId: string, queryType: TPageEmbedType = "issue") => {
|
||||
const widgetCallback = () => <IssueEmbedUpgradeCard />;
|
||||
|
||||
const issueEmbedProps: TEmbedConfig["issue"] = {
|
||||
widgetCallback,
|
||||
};
|
||||
|
||||
const issueEmbedReadOnlyProps: TReadOnlyEmbedConfig["issue"] = {
|
||||
widgetCallback,
|
||||
};
|
||||
|
||||
return {
|
||||
issueEmbedProps,
|
||||
issueEmbedReadOnlyProps,
|
||||
};
|
||||
};
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { mutate } from "swr";
|
||||
// types
|
||||
import type { CycleDateCheckData, ICycle, TCycleTabOptions } from "@plane/types";
|
||||
// ui
|
||||
@@ -43,6 +44,16 @@ export const CycleCreateUpdateModal: React.FC<CycleModalProps> = (props) => {
|
||||
const selectedProjectId = payload.project_id ?? projectId.toString();
|
||||
await createCycle(workspaceSlug, selectedProjectId, payload)
|
||||
.then((res) => {
|
||||
// mutate when the current cycle creation is active
|
||||
if (payload.start_date && payload.end_date) {
|
||||
const currentDate = new Date();
|
||||
const cycleStartDate = new Date(payload.start_date);
|
||||
const cycleEndDate = new Date(payload.end_date);
|
||||
if (currentDate >= cycleStartDate && currentDate <= cycleEndDate) {
|
||||
mutate(`PROJECT_ACTIVE_CYCLE_${selectedProjectId}`);
|
||||
}
|
||||
}
|
||||
|
||||
setToast({
|
||||
type: TOAST_TYPE.SUCCESS,
|
||||
title: "Success!",
|
||||
|
||||
@@ -23,8 +23,8 @@ import {
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
// plane web components
|
||||
import { IssueBulkOperationsRoot } from "@/plane-web/components/issues";
|
||||
// plane web constants
|
||||
import { ENABLE_BULK_OPERATIONS } from "@/plane-web/constants/issue";
|
||||
// plane web hooks
|
||||
import { useBulkOperationStatus } from "@/plane-web/hooks/use-bulk-operation-status";
|
||||
// constants
|
||||
import { GANTT_SELECT_GROUP } from "../constants";
|
||||
// hooks
|
||||
@@ -78,6 +78,8 @@ export const GanttChartMainContent: React.FC<Props> = observer((props) => {
|
||||
const ganttContainerRef = useRef<HTMLDivElement>(null);
|
||||
// chart hook
|
||||
const { currentView, currentViewData } = useGanttChart();
|
||||
// plane web hooks
|
||||
const isBulkOperationsEnabled = useBulkOperationStatus();
|
||||
|
||||
// Enable Auto Scroll for Ganttlist
|
||||
useEffect(() => {
|
||||
@@ -126,7 +128,7 @@ export const GanttChartMainContent: React.FC<Props> = observer((props) => {
|
||||
entities={{
|
||||
[GANTT_SELECT_GROUP]: blockIds ?? [],
|
||||
}}
|
||||
disabled={!ENABLE_BULK_OPERATIONS}
|
||||
disabled={!isBulkOperationsEnabled}
|
||||
>
|
||||
{(helpers) => (
|
||||
<>
|
||||
|
||||
@@ -14,8 +14,8 @@ import { getIssueBlocksStructure } from "@/helpers/issue.helper";
|
||||
import { useIssues, useUser } from "@/hooks/store";
|
||||
import { useIssueStoreType } from "@/hooks/use-issue-layout-store";
|
||||
import { useIssuesActions } from "@/hooks/use-issues-actions";
|
||||
// plane web constants
|
||||
import { ENABLE_BULK_OPERATIONS } from "@/plane-web/constants/issue";
|
||||
// plane web hooks
|
||||
import { useBulkOperationStatus } from "@/plane-web/hooks/use-bulk-operation-status";
|
||||
|
||||
import { IssueLayoutHOC } from "../issue-layout-HOC";
|
||||
|
||||
@@ -42,6 +42,8 @@ export const BaseGanttRoot: React.FC<IBaseGanttRoot> = observer((props: IBaseGan
|
||||
membership: { currentProjectRole },
|
||||
} = useUser();
|
||||
const appliedDisplayFilters = issuesFilter.issueFilters?.displayFilters;
|
||||
// plane web hooks
|
||||
const isBulkOperationsEnabled = useBulkOperationStatus();
|
||||
|
||||
useEffect(() => {
|
||||
fetchIssues("init-loader", { canGroup: false, perPageCount: 100 }, viewId);
|
||||
@@ -99,7 +101,7 @@ export const BaseGanttRoot: React.FC<IBaseGanttRoot> = observer((props: IBaseGan
|
||||
enableBlockMove={isAllowed}
|
||||
enableReorder={appliedDisplayFilters?.order_by === "sort_order" && isAllowed}
|
||||
enableAddBlock={isAllowed}
|
||||
enableSelection={ENABLE_BULK_OPERATIONS && isAllowed}
|
||||
enableSelection={isBulkOperationsEnabled && isAllowed}
|
||||
quickAdd={
|
||||
enableIssueCreation && isAllowed ? <GanttQuickAddIssueForm quickAddCallback={quickAddIssue} /> : undefined
|
||||
}
|
||||
|
||||
@@ -22,8 +22,8 @@ import { useCycle, useLabel, useMember, useModule, useProject, useProjectState }
|
||||
import { useIssueStoreType } from "@/hooks/use-issue-layout-store";
|
||||
// plane web components
|
||||
import { IssueBulkOperationsRoot } from "@/plane-web/components/issues";
|
||||
// plane web constants
|
||||
import { ENABLE_BULK_OPERATIONS } from "@/plane-web/constants/issue";
|
||||
// plane web hooks
|
||||
import { useBulkOperationStatus } from "@/plane-web/hooks/use-bulk-operation-status";
|
||||
// utils
|
||||
import { getGroupByColumns, isWorkspaceLevel, GroupDropLocation, isSubGrouped } from "../utils";
|
||||
import { ListGroup } from "./list-group";
|
||||
@@ -76,6 +76,8 @@ export const List: React.FC<IList> = observer((props) => {
|
||||
const projectState = useProjectState();
|
||||
const cycle = useCycle();
|
||||
const projectModule = useModule();
|
||||
// plane web hooks
|
||||
const isBulkOperationsEnabled = useBulkOperationStatus();
|
||||
|
||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
@@ -129,7 +131,7 @@ export const List: React.FC<IList> = observer((props) => {
|
||||
return (
|
||||
<div className="relative size-full flex flex-col">
|
||||
{groups && (
|
||||
<MultipleSelectGroup containerRef={containerRef} entities={entities} disabled={!ENABLE_BULK_OPERATIONS}>
|
||||
<MultipleSelectGroup containerRef={containerRef} entities={entities} disabled={!isBulkOperationsEnabled}>
|
||||
{(helpers) => (
|
||||
<>
|
||||
<div
|
||||
|
||||
@@ -12,8 +12,8 @@ import { SPREADSHEET_PROPERTY_LIST, SPREADSHEET_SELECT_GROUP } from "@/constants
|
||||
import { useProject } from "@/hooks/store";
|
||||
// plane web components
|
||||
import { IssueBulkOperationsRoot } from "@/plane-web/components/issues";
|
||||
// plane web constants
|
||||
import { ENABLE_BULK_OPERATIONS } from "@/plane-web/constants/issue";
|
||||
// plane web hooks
|
||||
import { useBulkOperationStatus } from "@/plane-web/hooks/use-bulk-operation-status";
|
||||
// types
|
||||
import { TRenderQuickActions } from "../list/list-view-types";
|
||||
import { SpreadsheetTable } from "./spreadsheet-table";
|
||||
@@ -54,8 +54,10 @@ export const SpreadsheetView: React.FC<Props> = observer((props) => {
|
||||
// refs
|
||||
const containerRef = useRef<HTMLTableElement | null>(null);
|
||||
const portalRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
// store hooks
|
||||
const { currentProjectDetails } = useProject();
|
||||
// plane web hooks
|
||||
const isBulkOperationsEnabled = useBulkOperationStatus();
|
||||
|
||||
const isEstimateEnabled: boolean = currentProjectDetails?.estimate !== null;
|
||||
|
||||
@@ -82,7 +84,7 @@ export const SpreadsheetView: React.FC<Props> = observer((props) => {
|
||||
entities={{
|
||||
[SPREADSHEET_SELECT_GROUP]: issueIds,
|
||||
}}
|
||||
disabled={!ENABLE_BULK_OPERATIONS}
|
||||
disabled={!isBulkOperationsEnabled}
|
||||
>
|
||||
{(helpers) => (
|
||||
<>
|
||||
|
||||
@@ -19,8 +19,8 @@ import { cn } from "@/helpers/common.helper";
|
||||
import { useMember, useMention, useUser, useWorkspace } from "@/hooks/store";
|
||||
import { useIssueEmbed } from "@/hooks/use-issue-embed";
|
||||
import { usePageFilters } from "@/hooks/use-page-filters";
|
||||
// plane web components
|
||||
import { IssueEmbedCard } from "@/plane-web/components/pages";
|
||||
// plane web hooks
|
||||
import { useIssueEmbed } from "@/plane-web/hooks/use-issue-embed";
|
||||
// services
|
||||
import { FileService } from "@/services/file.service";
|
||||
// store
|
||||
@@ -85,13 +85,17 @@ export const PageEditorBody: React.FC<Props> = observer((props) => {
|
||||
// page filters
|
||||
const { isFullWidth } = usePageFilters();
|
||||
// issue-embed
|
||||
const { fetchIssues } = useIssueEmbed(workspaceSlug?.toString() ?? "", projectId?.toString() ?? "");
|
||||
const { issueEmbedProps, issueEmbedReadOnlyProps } = useIssueEmbed(
|
||||
workspaceSlug?.toString() ?? "",
|
||||
projectId?.toString() ?? ""
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
updateMarkings(pageDescription ?? "<p></p>");
|
||||
}, [pageDescription, updateMarkings]);
|
||||
|
||||
if (pageId === undefined || !pageDescriptionYJS || !isDescriptionReady) return <PageContentLoader />;
|
||||
if (pageId === undefined || pageDescription === undefined || !pageDescriptionYJS || !isDescriptionReady)
|
||||
return <PageContentLoader />;
|
||||
|
||||
const handleIssueSearch = async (searchQuery: string) => {
|
||||
const response = await fetchIssues(searchQuery);
|
||||
@@ -151,35 +155,7 @@ export const PageEditorBody: React.FC<Props> = observer((props) => {
|
||||
suggestions: mentionSuggestions,
|
||||
}}
|
||||
embedHandler={{
|
||||
issue: {
|
||||
searchCallback: async (query) =>
|
||||
new Promise((resolve) => {
|
||||
setTimeout(async () => {
|
||||
const response = await handleIssueSearch(query);
|
||||
const issueItemsWithIdentifiers = response?.map((issue) => ({
|
||||
...issue,
|
||||
projectId: projectId.toString(),
|
||||
workspaceSlug: workspaceSlug.toString(),
|
||||
}));
|
||||
resolve(issueItemsWithIdentifiers);
|
||||
}, 300);
|
||||
}),
|
||||
widgetCallback: ({
|
||||
issueId,
|
||||
projectId: projectIdFromEmbed,
|
||||
workspaceSlug: workspaceSlugFromEmbed,
|
||||
}) => {
|
||||
const resolvedProjectId = projectIdFromEmbed ?? projectId?.toString() ?? "";
|
||||
const resolvedWorkspaceSlug = workspaceSlugFromEmbed ?? workspaceSlug?.toString() ?? "";
|
||||
return (
|
||||
<IssueEmbedCard
|
||||
issueId={issueId}
|
||||
projectId={resolvedProjectId}
|
||||
workspaceSlug={resolvedWorkspaceSlug}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
issue: issueEmbedProps,
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
@@ -193,24 +169,7 @@ export const PageEditorBody: React.FC<Props> = observer((props) => {
|
||||
highlights: mentionHighlights,
|
||||
}}
|
||||
embedHandler={{
|
||||
issue: {
|
||||
widgetCallback: ({
|
||||
issueId,
|
||||
projectId: projectIdFromEmbed,
|
||||
workspaceSlug: workspaceSlugFromEmbed,
|
||||
}) => {
|
||||
const resolvedProjectId = projectIdFromEmbed ?? projectId?.toString() ?? "";
|
||||
const resolvedWorkspaceSlug = workspaceSlugFromEmbed ?? workspaceSlug?.toString() ?? "";
|
||||
|
||||
return (
|
||||
<IssueEmbedCard
|
||||
issueId={issueId}
|
||||
projectId={resolvedProjectId}
|
||||
workspaceSlug={resolvedWorkspaceSlug}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
issue: issueEmbedReadOnlyProps,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export const ENABLE_BULK_OPERATIONS = true;
|
||||
1
web/ee/hooks/use-issue-embed.tsx
Normal file
1
web/ee/hooks/use-issue-embed.tsx
Normal file
@@ -0,0 +1 @@
|
||||
export * from "ce/hooks/use-issue-embed";
|
||||
Reference in New Issue
Block a user