forked from github/plane
[WEB-756] chore: module and cycle feature toggle validation (#4112)
* chore: cycle and module feature issue block validation * chore: cycle and module feature display properties validation * chore: cycle and module feature display filters validation * chore: cycle and module feature project view validation
This commit is contained in:
parent
bc0752f7e8
commit
e9518ced89
@ -10,7 +10,7 @@ import { CustomMenu } from "@plane/ui";
|
|||||||
import { ProjectAnalyticsModal } from "@/components/analytics";
|
import { ProjectAnalyticsModal } from "@/components/analytics";
|
||||||
import { DisplayFiltersSelection, FilterSelection, FiltersDropdown } from "@/components/issues";
|
import { DisplayFiltersSelection, FilterSelection, FiltersDropdown } from "@/components/issues";
|
||||||
import { EIssueFilterType, EIssuesStoreType, ISSUE_DISPLAY_FILTERS_BY_LAYOUT, ISSUE_LAYOUTS } from "@/constants/issue";
|
import { EIssueFilterType, EIssuesStoreType, ISSUE_DISPLAY_FILTERS_BY_LAYOUT, ISSUE_LAYOUTS } from "@/constants/issue";
|
||||||
import { useIssues, useCycle, useProjectState, useLabel, useMember } from "@/hooks/store";
|
import { useIssues, useCycle, useProjectState, useLabel, useMember, useProject } from "@/hooks/store";
|
||||||
|
|
||||||
export const CycleMobileHeader = () => {
|
export const CycleMobileHeader = () => {
|
||||||
const [analyticsModal, setAnalyticsModal] = useState(false);
|
const [analyticsModal, setAnalyticsModal] = useState(false);
|
||||||
@ -24,6 +24,7 @@ export const CycleMobileHeader = () => {
|
|||||||
const { workspaceSlug, projectId, cycleId } = router.query;
|
const { workspaceSlug, projectId, cycleId } = router.query;
|
||||||
const cycleDetails = cycleId ? getCycleById(cycleId.toString()) : undefined;
|
const cycleDetails = cycleId ? getCycleById(cycleId.toString()) : undefined;
|
||||||
// store hooks
|
// store hooks
|
||||||
|
const { currentProjectDetails } = useProject();
|
||||||
const {
|
const {
|
||||||
issuesFilter: { issueFilters, updateFilters },
|
issuesFilter: { issueFilters, updateFilters },
|
||||||
} = useIssues(EIssuesStoreType.CYCLE);
|
} = useIssues(EIssuesStoreType.CYCLE);
|
||||||
@ -151,6 +152,8 @@ export const CycleMobileHeader = () => {
|
|||||||
labels={projectLabels}
|
labels={projectLabels}
|
||||||
memberIds={projectMemberIds ?? undefined}
|
memberIds={projectMemberIds ?? undefined}
|
||||||
states={projectStates}
|
states={projectStates}
|
||||||
|
cycleViewDisabled={!currentProjectDetails?.cycle_view}
|
||||||
|
moduleViewDisabled={!currentProjectDetails?.module_view}
|
||||||
/>
|
/>
|
||||||
</FiltersDropdown>
|
</FiltersDropdown>
|
||||||
</div>
|
</div>
|
||||||
@ -174,6 +177,8 @@ export const CycleMobileHeader = () => {
|
|||||||
displayProperties={issueFilters?.displayProperties ?? {}}
|
displayProperties={issueFilters?.displayProperties ?? {}}
|
||||||
handleDisplayPropertiesUpdate={handleDisplayProperties}
|
handleDisplayPropertiesUpdate={handleDisplayProperties}
|
||||||
ignoreGroupedFilters={["cycle"]}
|
ignoreGroupedFilters={["cycle"]}
|
||||||
|
cycleViewDisabled={!currentProjectDetails?.cycle_view}
|
||||||
|
moduleViewDisabled={!currentProjectDetails?.module_view}
|
||||||
/>
|
/>
|
||||||
</FiltersDropdown>
|
</FiltersDropdown>
|
||||||
</div>
|
</div>
|
||||||
|
@ -250,6 +250,8 @@ export const CycleIssuesHeader: React.FC = observer(() => {
|
|||||||
labels={projectLabels}
|
labels={projectLabels}
|
||||||
memberIds={projectMemberIds ?? undefined}
|
memberIds={projectMemberIds ?? undefined}
|
||||||
states={projectStates}
|
states={projectStates}
|
||||||
|
cycleViewDisabled={!currentProjectDetails?.cycle_view}
|
||||||
|
moduleViewDisabled={!currentProjectDetails?.module_view}
|
||||||
/>
|
/>
|
||||||
</FiltersDropdown>
|
</FiltersDropdown>
|
||||||
<FiltersDropdown title="Display" placement="bottom-end">
|
<FiltersDropdown title="Display" placement="bottom-end">
|
||||||
@ -262,6 +264,8 @@ export const CycleIssuesHeader: React.FC = observer(() => {
|
|||||||
displayProperties={issueFilters?.displayProperties ?? {}}
|
displayProperties={issueFilters?.displayProperties ?? {}}
|
||||||
handleDisplayPropertiesUpdate={handleDisplayProperties}
|
handleDisplayPropertiesUpdate={handleDisplayProperties}
|
||||||
ignoreGroupedFilters={["cycle"]}
|
ignoreGroupedFilters={["cycle"]}
|
||||||
|
cycleViewDisabled={!currentProjectDetails?.cycle_view}
|
||||||
|
moduleViewDisabled={!currentProjectDetails?.module_view}
|
||||||
/>
|
/>
|
||||||
</FiltersDropdown>
|
</FiltersDropdown>
|
||||||
|
|
||||||
|
@ -252,6 +252,8 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
|
|||||||
labels={projectLabels}
|
labels={projectLabels}
|
||||||
memberIds={projectMemberIds ?? undefined}
|
memberIds={projectMemberIds ?? undefined}
|
||||||
states={projectStates}
|
states={projectStates}
|
||||||
|
cycleViewDisabled={!currentProjectDetails?.cycle_view}
|
||||||
|
moduleViewDisabled={!currentProjectDetails?.module_view}
|
||||||
/>
|
/>
|
||||||
</FiltersDropdown>
|
</FiltersDropdown>
|
||||||
<FiltersDropdown title="Display" placement="bottom-end">
|
<FiltersDropdown title="Display" placement="bottom-end">
|
||||||
@ -264,6 +266,8 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
|
|||||||
displayProperties={issueFilters?.displayProperties ?? {}}
|
displayProperties={issueFilters?.displayProperties ?? {}}
|
||||||
handleDisplayPropertiesUpdate={handleDisplayProperties}
|
handleDisplayPropertiesUpdate={handleDisplayProperties}
|
||||||
ignoreGroupedFilters={["module"]}
|
ignoreGroupedFilters={["module"]}
|
||||||
|
cycleViewDisabled={!currentProjectDetails?.cycle_view}
|
||||||
|
moduleViewDisabled={!currentProjectDetails?.module_view}
|
||||||
/>
|
/>
|
||||||
</FiltersDropdown>
|
</FiltersDropdown>
|
||||||
</div>
|
</div>
|
||||||
|
@ -141,6 +141,8 @@ export const ProjectDraftIssueHeader: FC = observer(() => {
|
|||||||
labels={projectLabels}
|
labels={projectLabels}
|
||||||
memberIds={projectMemberIds ?? undefined}
|
memberIds={projectMemberIds ?? undefined}
|
||||||
states={projectStates}
|
states={projectStates}
|
||||||
|
cycleViewDisabled={!currentProjectDetails?.cycle_view}
|
||||||
|
moduleViewDisabled={!currentProjectDetails?.module_view}
|
||||||
/>
|
/>
|
||||||
</FiltersDropdown>
|
</FiltersDropdown>
|
||||||
<FiltersDropdown title="Display" placement="bottom-end">
|
<FiltersDropdown title="Display" placement="bottom-end">
|
||||||
@ -152,6 +154,8 @@ export const ProjectDraftIssueHeader: FC = observer(() => {
|
|||||||
handleDisplayFiltersUpdate={handleDisplayFilters}
|
handleDisplayFiltersUpdate={handleDisplayFilters}
|
||||||
displayProperties={issueFilters?.displayProperties ?? {}}
|
displayProperties={issueFilters?.displayProperties ?? {}}
|
||||||
handleDisplayPropertiesUpdate={handleDisplayProperties}
|
handleDisplayPropertiesUpdate={handleDisplayProperties}
|
||||||
|
cycleViewDisabled={!currentProjectDetails?.cycle_view}
|
||||||
|
moduleViewDisabled={!currentProjectDetails?.module_view}
|
||||||
/>
|
/>
|
||||||
</FiltersDropdown>
|
</FiltersDropdown>
|
||||||
</div>
|
</div>
|
||||||
|
@ -192,6 +192,8 @@ export const ProjectIssuesHeader: React.FC = observer(() => {
|
|||||||
labels={projectLabels}
|
labels={projectLabels}
|
||||||
memberIds={projectMemberIds ?? undefined}
|
memberIds={projectMemberIds ?? undefined}
|
||||||
states={projectStates}
|
states={projectStates}
|
||||||
|
cycleViewDisabled={!currentProjectDetails?.cycle_view}
|
||||||
|
moduleViewDisabled={!currentProjectDetails?.module_view}
|
||||||
/>
|
/>
|
||||||
</FiltersDropdown>
|
</FiltersDropdown>
|
||||||
<FiltersDropdown title="Display" placement="bottom-end">
|
<FiltersDropdown title="Display" placement="bottom-end">
|
||||||
@ -203,6 +205,8 @@ export const ProjectIssuesHeader: React.FC = observer(() => {
|
|||||||
handleDisplayFiltersUpdate={handleDisplayFilters}
|
handleDisplayFiltersUpdate={handleDisplayFilters}
|
||||||
displayProperties={issueFilters?.displayProperties ?? {}}
|
displayProperties={issueFilters?.displayProperties ?? {}}
|
||||||
handleDisplayPropertiesUpdate={handleDisplayProperties}
|
handleDisplayPropertiesUpdate={handleDisplayProperties}
|
||||||
|
cycleViewDisabled={!currentProjectDetails?.cycle_view}
|
||||||
|
moduleViewDisabled={!currentProjectDetails?.module_view}
|
||||||
/>
|
/>
|
||||||
</FiltersDropdown>
|
</FiltersDropdown>
|
||||||
</div>
|
</div>
|
||||||
|
@ -210,6 +210,8 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => {
|
|||||||
labels={projectLabels}
|
labels={projectLabels}
|
||||||
memberIds={projectMemberIds ?? undefined}
|
memberIds={projectMemberIds ?? undefined}
|
||||||
states={projectStates}
|
states={projectStates}
|
||||||
|
cycleViewDisabled={!currentProjectDetails?.cycle_view}
|
||||||
|
moduleViewDisabled={!currentProjectDetails?.module_view}
|
||||||
/>
|
/>
|
||||||
</FiltersDropdown>
|
</FiltersDropdown>
|
||||||
<FiltersDropdown title="Display" placement="bottom-end">
|
<FiltersDropdown title="Display" placement="bottom-end">
|
||||||
@ -221,6 +223,8 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => {
|
|||||||
handleDisplayFiltersUpdate={handleDisplayFilters}
|
handleDisplayFiltersUpdate={handleDisplayFilters}
|
||||||
displayProperties={issueFilters?.displayProperties ?? {}}
|
displayProperties={issueFilters?.displayProperties ?? {}}
|
||||||
handleDisplayPropertiesUpdate={handleDisplayProperties}
|
handleDisplayPropertiesUpdate={handleDisplayProperties}
|
||||||
|
cycleViewDisabled={!currentProjectDetails?.cycle_view}
|
||||||
|
moduleViewDisabled={!currentProjectDetails?.module_view}
|
||||||
/>
|
/>
|
||||||
</FiltersDropdown>
|
</FiltersDropdown>
|
||||||
{canUserCreateIssue && (
|
{canUserCreateIssue && (
|
||||||
|
@ -9,13 +9,14 @@ import { DisplayFiltersSelection, FilterSelection, FiltersDropdown } from "@/com
|
|||||||
// constants
|
// constants
|
||||||
import { EIssueFilterType, EIssuesStoreType, ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "@/constants/issue";
|
import { EIssueFilterType, EIssuesStoreType, ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "@/constants/issue";
|
||||||
// hooks
|
// hooks
|
||||||
import { useIssues, useLabel, useMember, useProjectState } from "@/hooks/store";
|
import { useIssues, useLabel, useMember, useProject, useProjectState } from "@/hooks/store";
|
||||||
|
|
||||||
export const ArchivedIssuesHeader: FC = observer(() => {
|
export const ArchivedIssuesHeader: FC = observer(() => {
|
||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId } = router.query;
|
const { workspaceSlug, projectId } = router.query;
|
||||||
// store hooks
|
// store hooks
|
||||||
|
const { currentProjectDetails } = useProject();
|
||||||
const {
|
const {
|
||||||
issuesFilter: { issueFilters, updateFilters },
|
issuesFilter: { issueFilters, updateFilters },
|
||||||
} = useIssues(EIssuesStoreType.ARCHIVED);
|
} = useIssues(EIssuesStoreType.ARCHIVED);
|
||||||
@ -89,6 +90,8 @@ export const ArchivedIssuesHeader: FC = observer(() => {
|
|||||||
layoutDisplayFiltersOptions={
|
layoutDisplayFiltersOptions={
|
||||||
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_LAYOUT.issues[activeLayout] : undefined
|
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_LAYOUT.issues[activeLayout] : undefined
|
||||||
}
|
}
|
||||||
|
cycleViewDisabled={!currentProjectDetails?.cycle_view}
|
||||||
|
moduleViewDisabled={!currentProjectDetails?.module_view}
|
||||||
/>
|
/>
|
||||||
</FiltersDropdown>
|
</FiltersDropdown>
|
||||||
</div>
|
</div>
|
||||||
|
@ -21,6 +21,8 @@ type Props = {
|
|||||||
handleDisplayPropertiesUpdate: (updatedDisplayProperties: Partial<IIssueDisplayProperties>) => void;
|
handleDisplayPropertiesUpdate: (updatedDisplayProperties: Partial<IIssueDisplayProperties>) => void;
|
||||||
layoutDisplayFiltersOptions: ILayoutDisplayFiltersOptions | undefined;
|
layoutDisplayFiltersOptions: ILayoutDisplayFiltersOptions | undefined;
|
||||||
ignoreGroupedFilters?: Partial<TIssueGroupByOptions>[];
|
ignoreGroupedFilters?: Partial<TIssueGroupByOptions>[];
|
||||||
|
cycleViewDisabled?: boolean;
|
||||||
|
moduleViewDisabled?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DisplayFiltersSelection: React.FC<Props> = observer((props) => {
|
export const DisplayFiltersSelection: React.FC<Props> = observer((props) => {
|
||||||
@ -31,17 +33,32 @@ export const DisplayFiltersSelection: React.FC<Props> = observer((props) => {
|
|||||||
handleDisplayPropertiesUpdate,
|
handleDisplayPropertiesUpdate,
|
||||||
layoutDisplayFiltersOptions,
|
layoutDisplayFiltersOptions,
|
||||||
ignoreGroupedFilters = [],
|
ignoreGroupedFilters = [],
|
||||||
|
cycleViewDisabled = false,
|
||||||
|
moduleViewDisabled = false,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const isDisplayFilterEnabled = (displayFilter: keyof IIssueDisplayFilterOptions) =>
|
const isDisplayFilterEnabled = (displayFilter: keyof IIssueDisplayFilterOptions) =>
|
||||||
Object.keys(layoutDisplayFiltersOptions?.display_filters ?? {}).includes(displayFilter);
|
Object.keys(layoutDisplayFiltersOptions?.display_filters ?? {}).includes(displayFilter);
|
||||||
|
|
||||||
|
const computedIgnoreGroupedFilters: Partial<TIssueGroupByOptions>[] = [];
|
||||||
|
if (cycleViewDisabled) {
|
||||||
|
ignoreGroupedFilters.push("cycle");
|
||||||
|
}
|
||||||
|
if (moduleViewDisabled) {
|
||||||
|
ignoreGroupedFilters.push("module");
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="vertical-scrollbar scrollbar-sm relative h-full w-full divide-y divide-custom-border-200 overflow-hidden overflow-y-auto px-2.5">
|
<div className="vertical-scrollbar scrollbar-sm relative h-full w-full divide-y divide-custom-border-200 overflow-hidden overflow-y-auto px-2.5">
|
||||||
{/* display properties */}
|
{/* display properties */}
|
||||||
{layoutDisplayFiltersOptions?.display_properties && (
|
{layoutDisplayFiltersOptions?.display_properties && (
|
||||||
<div className="py-2">
|
<div className="py-2">
|
||||||
<FilterDisplayProperties displayProperties={displayProperties} handleUpdate={handleDisplayPropertiesUpdate} />
|
<FilterDisplayProperties
|
||||||
|
displayProperties={displayProperties}
|
||||||
|
handleUpdate={handleDisplayPropertiesUpdate}
|
||||||
|
cycleViewDisabled={cycleViewDisabled}
|
||||||
|
moduleViewDisabled={moduleViewDisabled}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@ -56,7 +73,7 @@ export const DisplayFiltersSelection: React.FC<Props> = observer((props) => {
|
|||||||
group_by: val,
|
group_by: val,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ignoreGroupedFilters={ignoreGroupedFilters}
|
ignoreGroupedFilters={[...ignoreGroupedFilters, ...computedIgnoreGroupedFilters]}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@ -74,7 +91,7 @@ export const DisplayFiltersSelection: React.FC<Props> = observer((props) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
subGroupByOptions={layoutDisplayFiltersOptions?.display_filters.sub_group_by ?? []}
|
subGroupByOptions={layoutDisplayFiltersOptions?.display_filters.sub_group_by ?? []}
|
||||||
ignoreGroupedFilters={ignoreGroupedFilters}
|
ignoreGroupedFilters={[...ignoreGroupedFilters, ...computedIgnoreGroupedFilters]}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -10,13 +10,22 @@ import { FilterHeader } from "../helpers/filter-header";
|
|||||||
type Props = {
|
type Props = {
|
||||||
displayProperties: IIssueDisplayProperties;
|
displayProperties: IIssueDisplayProperties;
|
||||||
handleUpdate: (updatedDisplayProperties: Partial<IIssueDisplayProperties>) => void;
|
handleUpdate: (updatedDisplayProperties: Partial<IIssueDisplayProperties>) => void;
|
||||||
|
cycleViewDisabled?: boolean;
|
||||||
|
moduleViewDisabled?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FilterDisplayProperties: React.FC<Props> = observer((props) => {
|
export const FilterDisplayProperties: React.FC<Props> = observer((props) => {
|
||||||
const { displayProperties, handleUpdate } = props;
|
const { displayProperties, handleUpdate, cycleViewDisabled = false, moduleViewDisabled = false } = props;
|
||||||
|
|
||||||
const [previewEnabled, setPreviewEnabled] = React.useState(true);
|
const [previewEnabled, setPreviewEnabled] = React.useState(true);
|
||||||
|
|
||||||
|
// Filter out "cycle" and "module" keys if cycleViewDisabled or moduleViewDisabled is true
|
||||||
|
const filteredDisplayProperties = ISSUE_DISPLAY_PROPERTIES.filter((property) => {
|
||||||
|
if (cycleViewDisabled && property.key === "cycle") return false;
|
||||||
|
if (moduleViewDisabled && property.key === "modules") return false;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<FilterHeader
|
<FilterHeader
|
||||||
@ -26,23 +35,25 @@ export const FilterDisplayProperties: React.FC<Props> = observer((props) => {
|
|||||||
/>
|
/>
|
||||||
{previewEnabled && (
|
{previewEnabled && (
|
||||||
<div className="mt-1 flex flex-wrap items-center gap-2">
|
<div className="mt-1 flex flex-wrap items-center gap-2">
|
||||||
{ISSUE_DISPLAY_PROPERTIES.map((displayProperty) => (
|
{filteredDisplayProperties.map((displayProperty) => (
|
||||||
<button
|
<>
|
||||||
key={displayProperty.key}
|
<button
|
||||||
type="button"
|
key={displayProperty.key}
|
||||||
className={`rounded border px-2 py-0.5 text-xs transition-all ${
|
type="button"
|
||||||
displayProperties?.[displayProperty.key]
|
className={`rounded border px-2 py-0.5 text-xs transition-all ${
|
||||||
? "border-custom-primary-100 bg-custom-primary-100 text-white"
|
displayProperties?.[displayProperty.key]
|
||||||
: "border-custom-border-200 hover:bg-custom-background-80"
|
? "border-custom-primary-100 bg-custom-primary-100 text-white"
|
||||||
}`}
|
: "border-custom-border-200 hover:bg-custom-background-80"
|
||||||
onClick={() =>
|
}`}
|
||||||
handleUpdate({
|
onClick={() =>
|
||||||
[displayProperty.key]: !displayProperties?.[displayProperty.key],
|
handleUpdate({
|
||||||
})
|
[displayProperty.key]: !displayProperties?.[displayProperty.key],
|
||||||
}
|
})
|
||||||
>
|
}
|
||||||
{displayProperty.title}
|
>
|
||||||
</button>
|
{displayProperty.title}
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -30,10 +30,21 @@ type Props = {
|
|||||||
labels?: IIssueLabel[] | undefined;
|
labels?: IIssueLabel[] | undefined;
|
||||||
memberIds?: string[] | undefined;
|
memberIds?: string[] | undefined;
|
||||||
states?: IState[] | undefined;
|
states?: IState[] | undefined;
|
||||||
|
cycleViewDisabled?: boolean;
|
||||||
|
moduleViewDisabled?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FilterSelection: React.FC<Props> = observer((props) => {
|
export const FilterSelection: React.FC<Props> = observer((props) => {
|
||||||
const { filters, handleFiltersUpdate, layoutDisplayFiltersOptions, labels, memberIds, states } = props;
|
const {
|
||||||
|
filters,
|
||||||
|
handleFiltersUpdate,
|
||||||
|
layoutDisplayFiltersOptions,
|
||||||
|
labels,
|
||||||
|
memberIds,
|
||||||
|
states,
|
||||||
|
cycleViewDisabled = false,
|
||||||
|
moduleViewDisabled = false,
|
||||||
|
} = props;
|
||||||
// hooks
|
// hooks
|
||||||
const {
|
const {
|
||||||
router: { moduleId, cycleId },
|
router: { moduleId, cycleId },
|
||||||
@ -111,7 +122,7 @@ export const FilterSelection: React.FC<Props> = observer((props) => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* cycle */}
|
{/* cycle */}
|
||||||
{isFilterEnabled("cycle") && !cycleId && (
|
{isFilterEnabled("cycle") && !cycleId && !cycleViewDisabled && (
|
||||||
<div className="py-2">
|
<div className="py-2">
|
||||||
<FilterCycle
|
<FilterCycle
|
||||||
appliedFilters={filters.cycle ?? null}
|
appliedFilters={filters.cycle ?? null}
|
||||||
@ -122,7 +133,7 @@ export const FilterSelection: React.FC<Props> = observer((props) => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* module */}
|
{/* module */}
|
||||||
{isFilterEnabled("module") && !moduleId && (
|
{isFilterEnabled("module") && !moduleId && !moduleViewDisabled && (
|
||||||
<div className="py-2">
|
<div className="py-2">
|
||||||
<FilterModule
|
<FilterModule
|
||||||
appliedFilters={filters.module ?? null}
|
appliedFilters={filters.module ?? null}
|
||||||
|
@ -24,7 +24,7 @@ import { EIssuesStoreType } from "@/constants/issue";
|
|||||||
import { cn } from "@/helpers/common.helper";
|
import { cn } from "@/helpers/common.helper";
|
||||||
import { getDate, renderFormattedPayloadDate } from "@/helpers/date-time.helper";
|
import { getDate, renderFormattedPayloadDate } from "@/helpers/date-time.helper";
|
||||||
import { shouldHighlightIssueDueDate } from "@/helpers/issue.helper";
|
import { shouldHighlightIssueDueDate } from "@/helpers/issue.helper";
|
||||||
import { useEventTracker, useEstimate, useLabel, useIssues, useProjectState } from "@/hooks/store";
|
import { useEventTracker, useEstimate, useLabel, useIssues, useProjectState, useProject } from "@/hooks/store";
|
||||||
import { usePlatformOS } from "@/hooks/use-platform-os";
|
import { usePlatformOS } from "@/hooks/use-platform-os";
|
||||||
// components
|
// components
|
||||||
import { IssuePropertyLabels } from "../properties/labels";
|
import { IssuePropertyLabels } from "../properties/labels";
|
||||||
@ -45,6 +45,7 @@ export interface IIssueProperties {
|
|||||||
export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
||||||
const { issue, updateIssue, displayProperties, activeLayout, isReadOnly, className } = props;
|
const { issue, updateIssue, displayProperties, activeLayout, isReadOnly, className } = props;
|
||||||
// store hooks
|
// store hooks
|
||||||
|
const { getProjectById } = useProject();
|
||||||
const { labelMap } = useLabel();
|
const { labelMap } = useLabel();
|
||||||
const { captureIssueEvent } = useEventTracker();
|
const { captureIssueEvent } = useEventTracker();
|
||||||
const {
|
const {
|
||||||
@ -56,6 +57,7 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
|||||||
const { areEstimatesEnabledForCurrentProject } = useEstimate();
|
const { areEstimatesEnabledForCurrentProject } = useEstimate();
|
||||||
const { getStateById } = useProjectState();
|
const { getStateById } = useProjectState();
|
||||||
const { isMobile } = usePlatformOS();
|
const { isMobile } = usePlatformOS();
|
||||||
|
const projectDetails = getProjectById(issue.project_id);
|
||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug } = router.query;
|
const { workspaceSlug } = router.query;
|
||||||
@ -349,36 +351,40 @@ export const IssueProperties: React.FC<IIssueProperties> = observer((props) => {
|
|||||||
</WithDisplayPropertiesHOC>
|
</WithDisplayPropertiesHOC>
|
||||||
|
|
||||||
{/* modules */}
|
{/* modules */}
|
||||||
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="modules">
|
{projectDetails?.module_view && (
|
||||||
<div className="h-5">
|
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="modules">
|
||||||
<ModuleDropdown
|
<div className="h-5">
|
||||||
buttonContainerClassName="truncate max-w-40"
|
<ModuleDropdown
|
||||||
projectId={issue?.project_id}
|
buttonContainerClassName="truncate max-w-40"
|
||||||
value={issue?.module_ids ?? []}
|
projectId={issue?.project_id}
|
||||||
onChange={handleModule}
|
value={issue?.module_ids ?? []}
|
||||||
disabled={isReadOnly}
|
onChange={handleModule}
|
||||||
multiple
|
disabled={isReadOnly}
|
||||||
buttonVariant="border-with-text"
|
multiple
|
||||||
showCount
|
buttonVariant="border-with-text"
|
||||||
showTooltip
|
showCount
|
||||||
/>
|
showTooltip
|
||||||
</div>
|
/>
|
||||||
</WithDisplayPropertiesHOC>
|
</div>
|
||||||
|
</WithDisplayPropertiesHOC>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* cycles */}
|
{/* cycles */}
|
||||||
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="cycle">
|
{projectDetails?.cycle_view && (
|
||||||
<div className="h-5">
|
<WithDisplayPropertiesHOC displayProperties={displayProperties} displayPropertyKey="cycle">
|
||||||
<CycleDropdown
|
<div className="h-5">
|
||||||
buttonContainerClassName="truncate max-w-40"
|
<CycleDropdown
|
||||||
projectId={issue?.project_id}
|
buttonContainerClassName="truncate max-w-40"
|
||||||
value={issue?.cycle_id}
|
projectId={issue?.project_id}
|
||||||
onChange={handleCycle}
|
value={issue?.cycle_id}
|
||||||
disabled={isReadOnly}
|
onChange={handleCycle}
|
||||||
buttonVariant="border-with-text"
|
disabled={isReadOnly}
|
||||||
showTooltip
|
buttonVariant="border-with-text"
|
||||||
/>
|
showTooltip
|
||||||
</div>
|
/>
|
||||||
</WithDisplayPropertiesHOC>
|
</div>
|
||||||
|
</WithDisplayPropertiesHOC>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* estimates */}
|
{/* estimates */}
|
||||||
{areEstimatesEnabledForCurrentProject && (
|
{areEstimatesEnabledForCurrentProject && (
|
||||||
|
@ -132,6 +132,8 @@ export const IssuesMobileHeader = observer(() => {
|
|||||||
labels={projectLabels}
|
labels={projectLabels}
|
||||||
memberIds={projectMemberIds ?? undefined}
|
memberIds={projectMemberIds ?? undefined}
|
||||||
states={projectStates}
|
states={projectStates}
|
||||||
|
cycleViewDisabled={!currentProjectDetails?.cycle_view}
|
||||||
|
moduleViewDisabled={!currentProjectDetails?.module_view}
|
||||||
/>
|
/>
|
||||||
</FiltersDropdown>
|
</FiltersDropdown>
|
||||||
</div>
|
</div>
|
||||||
@ -154,6 +156,8 @@ export const IssuesMobileHeader = observer(() => {
|
|||||||
handleDisplayFiltersUpdate={handleDisplayFilters}
|
handleDisplayFiltersUpdate={handleDisplayFilters}
|
||||||
displayProperties={issueFilters?.displayProperties ?? {}}
|
displayProperties={issueFilters?.displayProperties ?? {}}
|
||||||
handleDisplayPropertiesUpdate={handleDisplayProperties}
|
handleDisplayPropertiesUpdate={handleDisplayProperties}
|
||||||
|
cycleViewDisabled={!currentProjectDetails?.cycle_view}
|
||||||
|
moduleViewDisabled={!currentProjectDetails?.module_view}
|
||||||
/>
|
/>
|
||||||
</FiltersDropdown>
|
</FiltersDropdown>
|
||||||
</div>
|
</div>
|
||||||
|
@ -11,12 +11,13 @@ import { ProjectAnalyticsModal } from "@/components/analytics";
|
|||||||
import { DisplayFiltersSelection, FilterSelection, FiltersDropdown } from "@/components/issues";
|
import { DisplayFiltersSelection, FilterSelection, FiltersDropdown } from "@/components/issues";
|
||||||
// hooks
|
// hooks
|
||||||
import { EIssueFilterType, EIssuesStoreType, ISSUE_DISPLAY_FILTERS_BY_LAYOUT, ISSUE_LAYOUTS } from "@/constants/issue";
|
import { EIssueFilterType, EIssuesStoreType, ISSUE_DISPLAY_FILTERS_BY_LAYOUT, ISSUE_LAYOUTS } from "@/constants/issue";
|
||||||
import { useIssues, useLabel, useMember, useModule, useProjectState } from "@/hooks/store";
|
import { useIssues, useLabel, useMember, useModule, useProject, useProjectState } from "@/hooks/store";
|
||||||
// types
|
// types
|
||||||
// constants
|
// constants
|
||||||
|
|
||||||
export const ModuleMobileHeader = observer(() => {
|
export const ModuleMobileHeader = observer(() => {
|
||||||
const [analyticsModal, setAnalyticsModal] = useState(false);
|
const [analyticsModal, setAnalyticsModal] = useState(false);
|
||||||
|
const { currentProjectDetails } = useProject();
|
||||||
const { getModuleById } = useModule();
|
const { getModuleById } = useModule();
|
||||||
const layouts = [
|
const layouts = [
|
||||||
{ key: "list", title: "List", icon: List },
|
{ key: "list", title: "List", icon: List },
|
||||||
@ -134,6 +135,8 @@ export const ModuleMobileHeader = observer(() => {
|
|||||||
labels={projectLabels}
|
labels={projectLabels}
|
||||||
memberIds={projectMemberIds ?? undefined}
|
memberIds={projectMemberIds ?? undefined}
|
||||||
states={projectStates}
|
states={projectStates}
|
||||||
|
cycleViewDisabled={!currentProjectDetails?.cycle_view}
|
||||||
|
moduleViewDisabled={!currentProjectDetails?.module_view}
|
||||||
/>
|
/>
|
||||||
</FiltersDropdown>
|
</FiltersDropdown>
|
||||||
</div>
|
</div>
|
||||||
@ -157,6 +160,8 @@ export const ModuleMobileHeader = observer(() => {
|
|||||||
displayProperties={issueFilters?.displayProperties ?? {}}
|
displayProperties={issueFilters?.displayProperties ?? {}}
|
||||||
handleDisplayPropertiesUpdate={handleDisplayProperties}
|
handleDisplayPropertiesUpdate={handleDisplayProperties}
|
||||||
ignoreGroupedFilters={["module"]}
|
ignoreGroupedFilters={["module"]}
|
||||||
|
cycleViewDisabled={!currentProjectDetails?.cycle_view}
|
||||||
|
moduleViewDisabled={!currentProjectDetails?.module_view}
|
||||||
/>
|
/>
|
||||||
</FiltersDropdown>
|
</FiltersDropdown>
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,7 +6,7 @@ import { IProjectView, IIssueFilterOptions } from "@plane/types";
|
|||||||
import { Button, Input, TextArea } from "@plane/ui";
|
import { Button, Input, TextArea } from "@plane/ui";
|
||||||
import { AppliedFiltersList, FilterSelection, FiltersDropdown } from "@/components/issues";
|
import { AppliedFiltersList, FilterSelection, FiltersDropdown } from "@/components/issues";
|
||||||
import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "@/constants/issue";
|
import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "@/constants/issue";
|
||||||
import { useLabel, useMember, useProjectState } from "@/hooks/store";
|
import { useLabel, useMember, useProject, useProjectState } from "@/hooks/store";
|
||||||
// components
|
// components
|
||||||
// ui
|
// ui
|
||||||
// types
|
// types
|
||||||
@ -27,6 +27,7 @@ const defaultValues: Partial<IProjectView> = {
|
|||||||
export const ProjectViewForm: React.FC<Props> = observer((props) => {
|
export const ProjectViewForm: React.FC<Props> = observer((props) => {
|
||||||
const { handleFormSubmit, handleClose, data, preLoadedData } = props;
|
const { handleFormSubmit, handleClose, data, preLoadedData } = props;
|
||||||
// store hooks
|
// store hooks
|
||||||
|
const { currentProjectDetails } = useProject();
|
||||||
const { projectStates } = useProjectState();
|
const { projectStates } = useProjectState();
|
||||||
const { projectLabels } = useLabel();
|
const { projectLabels } = useLabel();
|
||||||
const {
|
const {
|
||||||
@ -184,6 +185,8 @@ export const ProjectViewForm: React.FC<Props> = observer((props) => {
|
|||||||
labels={projectLabels ?? undefined}
|
labels={projectLabels ?? undefined}
|
||||||
memberIds={projectMemberIds ?? undefined}
|
memberIds={projectMemberIds ?? undefined}
|
||||||
states={projectStates}
|
states={projectStates}
|
||||||
|
cycleViewDisabled={!currentProjectDetails?.cycle_view}
|
||||||
|
moduleViewDisabled={!currentProjectDetails?.module_view}
|
||||||
/>
|
/>
|
||||||
</FiltersDropdown>
|
</FiltersDropdown>
|
||||||
)}
|
)}
|
||||||
@ -212,8 +215,8 @@ export const ProjectViewForm: React.FC<Props> = observer((props) => {
|
|||||||
? "Updating View..."
|
? "Updating View..."
|
||||||
: "Update View"
|
: "Update View"
|
||||||
: isSubmitting
|
: isSubmitting
|
||||||
? "Creating View..."
|
? "Creating View..."
|
||||||
: "Create View"}
|
: "Create View"}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
Loading…
Reference in New Issue
Block a user