mirror of
https://github.com/makeplane/plane.git
synced 2026-02-25 04:35:21 +01:00
[WEB-4125] feat: add feature flag for dashboard widgets filters (#4083)
This commit is contained in:
@@ -21,7 +21,10 @@ from plane.ee.utils.chart_validations import validate_chart_config
|
||||
from plane.ee.utils.widget_graph_plot import build_widget_chart
|
||||
from plane.ee.views.base import BaseAPIView
|
||||
from plane.payment.flags.flag import FeatureFlag
|
||||
from plane.payment.flags.flag_decorator import check_feature_flag
|
||||
from plane.payment.flags.flag_decorator import (
|
||||
check_feature_flag,
|
||||
check_workspace_feature_flag,
|
||||
)
|
||||
from plane.utils.filters.complex_filter import ComplexFilterBackend
|
||||
|
||||
|
||||
@@ -275,12 +278,15 @@ class WidgetListEndpoint(BaseAPIView):
|
||||
project_id__in=dashboard_project_ids,
|
||||
)
|
||||
|
||||
# get the widget filter
|
||||
if dashboard_widget.filters:
|
||||
# use the complex filter backend using dashboard widget filters
|
||||
issues = ComplexFilterBackend().filter_queryset(
|
||||
request, issues, self, dashboard_widget.filters
|
||||
)
|
||||
if check_workspace_feature_flag(
|
||||
FeatureFlag.DASHBOARD_WIDGET_FILTERS, slug, user_id=str(request.user.id)
|
||||
):
|
||||
# get the widget filter
|
||||
if dashboard_widget.filters:
|
||||
# use the complex filter backend using dashboard widget filters
|
||||
issues = ComplexFilterBackend().filter_queryset(
|
||||
request, issues, self, dashboard_widget.filters
|
||||
)
|
||||
|
||||
issues = (
|
||||
issues.filter(
|
||||
|
||||
@@ -90,6 +90,8 @@ class FeatureFlag(Enum):
|
||||
PROJECT_AUTOMATIONS = "PROJECT_AUTOMATIONS"
|
||||
# Recurring Work Items
|
||||
RECURRING_WORKITEMS = "RECURRING_WORKITEMS"
|
||||
# Dashboard widgets filters
|
||||
DASHBOARD_WIDGET_FILTERS = "DASHBOARD_WIDGET_FILTERS"
|
||||
|
||||
|
||||
class AdminFeatureFlag(Enum):
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useMemo, useState } from "react";
|
||||
import { useMemo } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import { AtSign, CircleUserRound, Files, Layers, SignalHigh, Tag, Users } from "lucide-react";
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
TIssuePriorities,
|
||||
TIssueType,
|
||||
} from "@plane/types";
|
||||
import { Avatar, CycleGroupIcon, DiceIcon, Loader, PriorityIcon } from "@plane/ui";
|
||||
import { Avatar, CycleGroupIcon, DiceIcon, PriorityIcon } from "@plane/ui";
|
||||
import {
|
||||
cn,
|
||||
getAssigneeFilterConfig,
|
||||
@@ -40,6 +40,7 @@ import { useCycle } from "@/hooks/store/use-cycle";
|
||||
import { useLabel } from "@/hooks/store/use-label";
|
||||
import { useMember } from "@/hooks/store/use-member";
|
||||
import { useModule } from "@/hooks/store/use-module";
|
||||
import { useProject } from "@/hooks/store/use-project";
|
||||
|
||||
import { IssueTypeLogo } from "@/plane-web/components/issue-types/common/issue-type-logo";
|
||||
import { AddFilterButton } from "@/plane-web/components/rich-filters/add-filters-button";
|
||||
@@ -47,7 +48,6 @@ import { FilterItem } from "@/plane-web/components/rich-filters/filter-item";
|
||||
import { useIssueTypes } from "@/plane-web/hooks/store";
|
||||
import { IFilterInstance } from "@/plane-web/store/rich-filters/filter";
|
||||
import { withFilters } from "./with-filters";
|
||||
import { useProject } from "@/hooks/store/use-project";
|
||||
|
||||
type Props = {
|
||||
filters: IFilterInstance<TDashboardWidgetFilterKeys, TExternalDashboardWidgetFilterExpression> | null;
|
||||
@@ -55,22 +55,20 @@ type Props = {
|
||||
handleSubmit: (data: Partial<TDashboardWidget>) => Promise<void>;
|
||||
};
|
||||
|
||||
const WidgetConfigSidebarFilters: React.FC<Props> = observer((props) => {
|
||||
const WidgetConfigSidebarFiltersRoot: React.FC<Props> = observer((props) => {
|
||||
const { filters, projectIds } = props;
|
||||
|
||||
/**
|
||||
* store hooks
|
||||
*/
|
||||
|
||||
const { getProjectLabels, fetchProjectLabels } = useLabel();
|
||||
const { getProjectLabels } = useLabel();
|
||||
const { workspaceSlug } = useParams();
|
||||
const { getUserDetails } = useMember();
|
||||
const { getProjectById } = useProject();
|
||||
const {
|
||||
project: { getProjectMemberIds, fetchProjectMembers },
|
||||
} = useMember();
|
||||
const { getProjectCycleDetails, fetchAllCycles } = useCycle();
|
||||
const { getProjectModuleDetails, fetchModules } = useModule();
|
||||
const { getProjectIssueTypes, fetchAll } = useIssueTypes();
|
||||
const { getProjectCycleDetails } = useCycle();
|
||||
const { getProjectModuleDetails } = useModule();
|
||||
const { getProjectIssueTypes } = useIssueTypes();
|
||||
|
||||
/**
|
||||
* derived values
|
||||
@@ -135,17 +133,12 @@ const WidgetConfigSidebarFilters: React.FC<Props> = observer((props) => {
|
||||
}, [
|
||||
workspaceSlug,
|
||||
projectIds,
|
||||
fetchProjectLabels,
|
||||
getProjectLabels,
|
||||
fetchProjectMembers,
|
||||
getProjectMemberIds,
|
||||
getUserDetails,
|
||||
fetchAllCycles,
|
||||
getProjectById,
|
||||
getProjectCycleDetails,
|
||||
fetchModules,
|
||||
getProjectModuleDetails,
|
||||
fetchAll,
|
||||
getProjectIssueTypes,
|
||||
getUserDetails,
|
||||
]);
|
||||
|
||||
/**
|
||||
@@ -306,4 +299,4 @@ const WidgetConfigSidebarFilters: React.FC<Props> = observer((props) => {
|
||||
);
|
||||
});
|
||||
|
||||
export const EnhancedWidgetConfigSidebarFilters = withFilters(WidgetConfigSidebarFilters);
|
||||
export const WidgetConfigSidebarFilters = withFilters(WidgetConfigSidebarFiltersRoot);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useCallback, useEffect } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
import { FormProvider, useForm } from "react-hook-form";
|
||||
|
||||
// plane imports
|
||||
@@ -10,11 +11,12 @@ import { setToast, TOAST_TYPE } from "@plane/ui";
|
||||
import { cn } from "@plane/utils";
|
||||
|
||||
// plane web hooks
|
||||
import { useDashboards } from "@/plane-web/hooks/store";
|
||||
import { useDashboards, useFlag } from "@/plane-web/hooks/store";
|
||||
|
||||
// local components
|
||||
import { WidgetConfigSidebarAxisConfig } from "./axis-config";
|
||||
import { WidgetConfigSidebarBasicConfig } from "./basic-config";
|
||||
import { EnhancedWidgetConfigSidebarFilters } from "./filters";
|
||||
import { WidgetConfigSidebarFilters } from "./filters";
|
||||
import { WidgetConfigSidebarHeader } from "./header";
|
||||
import { WidgetConfigSidebarStyleConfig } from "./style-config/root";
|
||||
|
||||
@@ -25,6 +27,8 @@ type Props = {
|
||||
|
||||
export const DashboardsWidgetConfigSidebarRoot: React.FC<Props> = observer((props) => {
|
||||
const { className, dashboardId } = props;
|
||||
const { workspaceSlug } = useParams();
|
||||
|
||||
// store hooks
|
||||
const { getDashboardById } = useDashboards();
|
||||
// derived values
|
||||
@@ -33,6 +37,8 @@ export const DashboardsWidgetConfigSidebarRoot: React.FC<Props> = observer((prop
|
||||
const { isViewModeEnabled, widgetsStore, project_ids } = dashboardDetails ?? {};
|
||||
// translation
|
||||
const { t } = useTranslation();
|
||||
// feature flag
|
||||
const isDashboardWidgetsFiltersEnabled = useFlag(workspaceSlug?.toString(), "DASHBOARD_WIDGET_FILTERS");
|
||||
|
||||
const { isEditingWidget: widgetIdToEdit, getWidgetById, toggleEditWidget, toggleDeleteWidget } = widgetsStore ?? {};
|
||||
const isEditingWidget = !!widgetIdToEdit;
|
||||
@@ -49,6 +55,7 @@ export const DashboardsWidgetConfigSidebarRoot: React.FC<Props> = observer((prop
|
||||
filters,
|
||||
} = widget ?? {};
|
||||
const shouldShowSidebar = !isViewModeEnabled && !!widgetIdToEdit;
|
||||
|
||||
// form info
|
||||
const methods = useForm<TDashboardWidget>();
|
||||
const { handleSubmit, reset, setValue } = methods;
|
||||
@@ -134,6 +141,7 @@ export const DashboardsWidgetConfigSidebarRoot: React.FC<Props> = observer((prop
|
||||
handleFormSubmit({ name: autoGeneratedInitialName });
|
||||
}
|
||||
}, [isConfigurationMissing, widget?.name, x_axis_property, y_axis_metric, group_by, t, setValue, handleFormSubmit]);
|
||||
|
||||
return (
|
||||
<form
|
||||
onSubmit={handleSubmit(handleFormSubmit)}
|
||||
@@ -149,11 +157,13 @@ export const DashboardsWidgetConfigSidebarRoot: React.FC<Props> = observer((prop
|
||||
<div className="flex-shrink-0 h-px bg-custom-background-80" />
|
||||
<WidgetConfigSidebarStyleConfig handleSubmit={handleFormSubmit} />
|
||||
<div className="flex-shrink-0 h-px bg-custom-background-80" />
|
||||
<EnhancedWidgetConfigSidebarFilters
|
||||
handleSubmit={handleFormSubmit}
|
||||
projectIds={project_ids}
|
||||
initialFilters={filters ?? undefined}
|
||||
/>
|
||||
{isDashboardWidgetsFiltersEnabled && (
|
||||
<WidgetConfigSidebarFilters
|
||||
handleSubmit={handleFormSubmit}
|
||||
projectIds={project_ids}
|
||||
initialFilters={filters ?? undefined}
|
||||
/>
|
||||
)}
|
||||
</FormProvider>
|
||||
</form>
|
||||
);
|
||||
|
||||
@@ -86,6 +86,7 @@ export enum E_FEATURE_FLAGS {
|
||||
// dashboards
|
||||
DASHBOARDS = "DASHBOARDS",
|
||||
DASHBOARDS_ADVANCED = "DASHBOARDS_ADVANCED",
|
||||
DASHBOARD_WIDGET_FILTERS = "DASHBOARD_WIDGET_FILTERS",
|
||||
// applications
|
||||
APPLICATIONS = "APPLICATIONS",
|
||||
// pages and editor
|
||||
|
||||
Reference in New Issue
Block a user