mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
chore: applying query params to the global issues filters in the global views (#3464)
* chore: applying filters from the route params to the global issue filters store and Typos * chore: enabled posthog * fix: labels disbaled and loader while creating the label in isse detail and relation modal loader and mutation issue
This commit is contained in:
parent
336c97d336
commit
ec3cad1f25
@ -27,8 +27,8 @@ export const ExistingIssuesListModal: React.FC<Props> = (props) => {
|
|||||||
// states
|
// states
|
||||||
const [searchTerm, setSearchTerm] = useState("");
|
const [searchTerm, setSearchTerm] = useState("");
|
||||||
const [issues, setIssues] = useState<ISearchIssueResponse[]>([]);
|
const [issues, setIssues] = useState<ISearchIssueResponse[]>([]);
|
||||||
const [isSearching, setIsSearching] = useState(false);
|
|
||||||
const [selectedIssues, setSelectedIssues] = useState<ISearchIssueResponse[]>([]);
|
const [selectedIssues, setSelectedIssues] = useState<ISearchIssueResponse[]>([]);
|
||||||
|
const [isSearching, setIsSearching] = useState(false);
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
const [isWorkspaceLevel, setIsWorkspaceLevel] = useState(false);
|
const [isWorkspaceLevel, setIsWorkspaceLevel] = useState(false);
|
||||||
|
|
||||||
@ -72,8 +72,7 @@ export const ExistingIssuesListModal: React.FC<Props> = (props) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isOpen || !workspaceSlug || !projectId) return;
|
if (!isOpen || !workspaceSlug || !projectId) return;
|
||||||
|
if (issues.length <= 0) setIsSearching(true);
|
||||||
setIsSearching(true);
|
|
||||||
|
|
||||||
projectService
|
projectService
|
||||||
.projectIssuesSearch(workspaceSlug as string, projectId as string, {
|
.projectIssuesSearch(workspaceSlug as string, projectId as string, {
|
||||||
@ -83,7 +82,16 @@ export const ExistingIssuesListModal: React.FC<Props> = (props) => {
|
|||||||
})
|
})
|
||||||
.then((res) => setIssues(res))
|
.then((res) => setIssues(res))
|
||||||
.finally(() => setIsSearching(false));
|
.finally(() => setIsSearching(false));
|
||||||
}, [debouncedSearchTerm, isOpen, isWorkspaceLevel, projectId, searchParams, workspaceSlug]);
|
}, [issues, debouncedSearchTerm, isOpen, isWorkspaceLevel, projectId, searchParams, workspaceSlug]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setSearchTerm("");
|
||||||
|
setIssues([]);
|
||||||
|
setSelectedIssues([]);
|
||||||
|
setIsSearching(false);
|
||||||
|
setIsSubmitting(false);
|
||||||
|
setIsWorkspaceLevel(false);
|
||||||
|
}, [isOpen]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { FC, useState, Fragment, useEffect } from "react";
|
import { FC, useState, Fragment, useEffect } from "react";
|
||||||
import { Plus, X } from "lucide-react";
|
import { Plus, X, Loader } from "lucide-react";
|
||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
import { TwitterPicker } from "react-color";
|
import { TwitterPicker } from "react-color";
|
||||||
import { Popover, Transition } from "@headlessui/react";
|
import { Popover, Transition } from "@headlessui/react";
|
||||||
@ -138,6 +138,7 @@ export const LabelCreate: FC<ILabelCreate> = (props) => {
|
|||||||
hasError={Boolean(errors.name)}
|
hasError={Boolean(errors.name)}
|
||||||
placeholder="Title"
|
placeholder="Title"
|
||||||
className="w-full"
|
className="w-full"
|
||||||
|
disabled={isSubmitting}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@ -150,7 +151,7 @@ export const LabelCreate: FC<ILabelCreate> = (props) => {
|
|||||||
<X className="h-4 w-4 text-white" />
|
<X className="h-4 w-4 text-white" />
|
||||||
</button>
|
</button>
|
||||||
<button type="submit" className="grid place-items-center rounded bg-green-500 p-1.5" disabled={isSubmitting}>
|
<button type="submit" className="grid place-items-center rounded bg-green-500 p-1.5" disabled={isSubmitting}>
|
||||||
<Plus className="h-4 w-4 text-white" />
|
{isSubmitting ? <Loader className="h-4 w-4 text-white spin" /> : <Plus className="h-4 w-4 text-white" />}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
)}
|
)}
|
||||||
|
@ -7,14 +7,14 @@ import { AppliedFiltersList } from "components/issues";
|
|||||||
// types
|
// types
|
||||||
import { IIssueFilterOptions } from "@plane/types";
|
import { IIssueFilterOptions } from "@plane/types";
|
||||||
import { EIssueFilterType, EIssuesStoreType } from "constants/issue";
|
import { EIssueFilterType, EIssuesStoreType } from "constants/issue";
|
||||||
import { useWorskspaceIssueProperties } from "hooks/use-worskspace-issue-properties";
|
import { useWorkspaceIssueProperties } from "hooks/use-workspace-issue-properties";
|
||||||
|
|
||||||
export const ProfileIssuesAppliedFiltersRoot: React.FC = observer(() => {
|
export const ProfileIssuesAppliedFiltersRoot: React.FC = observer(() => {
|
||||||
// router
|
// router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, userId } = router.query;
|
const { workspaceSlug, userId } = router.query;
|
||||||
//swr hook for fetching issue properties
|
//swr hook for fetching issue properties
|
||||||
useWorskspaceIssueProperties(workspaceSlug);
|
useWorkspaceIssueProperties(workspaceSlug);
|
||||||
// store hooks
|
// store hooks
|
||||||
const {
|
const {
|
||||||
issuesFilter: { issueFilters, updateFilters },
|
issuesFilter: { issueFilters, updateFilters },
|
||||||
|
@ -2,9 +2,10 @@ import React, { useCallback, useMemo } from "react";
|
|||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
|
import isEmpty from "lodash/isEmpty";
|
||||||
// hooks
|
// hooks
|
||||||
import { useApplication, useGlobalView, useIssues, useProject, useUser } from "hooks/store";
|
import { useApplication, useGlobalView, useIssues, useProject, useUser } from "hooks/store";
|
||||||
import { useWorskspaceIssueProperties } from "hooks/use-worskspace-issue-properties";
|
import { useWorkspaceIssueProperties } from "hooks/use-workspace-issue-properties";
|
||||||
// components
|
// components
|
||||||
import { GlobalViewsAppliedFiltersRoot, IssuePeekOverview } from "components/issues";
|
import { GlobalViewsAppliedFiltersRoot, IssuePeekOverview } from "components/issues";
|
||||||
import { SpreadsheetView } from "components/issues/issue-layouts";
|
import { SpreadsheetView } from "components/issues/issue-layouts";
|
||||||
@ -17,7 +18,7 @@ import { TIssue, IIssueDisplayFilterOptions } from "@plane/types";
|
|||||||
import { EIssueActions } from "../types";
|
import { EIssueActions } from "../types";
|
||||||
// constants
|
// constants
|
||||||
import { EUserProjectRoles } from "constants/project";
|
import { EUserProjectRoles } from "constants/project";
|
||||||
import { EIssueFilterType, EIssuesStoreType } from "constants/issue";
|
import { EIssueFilterType, EIssuesStoreType, ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue";
|
||||||
import { ALL_ISSUES_EMPTY_STATE_DETAILS, EUserWorkspaceRoles } from "constants/workspace";
|
import { ALL_ISSUES_EMPTY_STATE_DETAILS, EUserWorkspaceRoles } from "constants/workspace";
|
||||||
|
|
||||||
export const AllIssueLayoutRoot: React.FC = observer(() => {
|
export const AllIssueLayoutRoot: React.FC = observer(() => {
|
||||||
@ -25,7 +26,7 @@ export const AllIssueLayoutRoot: React.FC = observer(() => {
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, globalViewId } = router.query;
|
const { workspaceSlug, globalViewId } = router.query;
|
||||||
//swr hook for fetching issue properties
|
//swr hook for fetching issue properties
|
||||||
useWorskspaceIssueProperties(workspaceSlug);
|
useWorkspaceIssueProperties(workspaceSlug);
|
||||||
// store
|
// store
|
||||||
const { commandPalette: commandPaletteStore } = useApplication();
|
const { commandPalette: commandPaletteStore } = useApplication();
|
||||||
const {
|
const {
|
||||||
@ -47,6 +48,40 @@ export const AllIssueLayoutRoot: React.FC = observer(() => {
|
|||||||
|
|
||||||
const emptyStateImage = getEmptyStateImagePath("all-issues", currentView, currentUser?.theme.theme === "light");
|
const emptyStateImage = getEmptyStateImagePath("all-issues", currentView, currentUser?.theme.theme === "light");
|
||||||
|
|
||||||
|
// filter init from the query params
|
||||||
|
|
||||||
|
const routerFilterParams = () => {
|
||||||
|
if (
|
||||||
|
workspaceSlug &&
|
||||||
|
globalViewId &&
|
||||||
|
["all-issues", "assigned", "created", "subscribed"].includes(globalViewId.toString())
|
||||||
|
) {
|
||||||
|
const routerQueryParams = { ...router.query };
|
||||||
|
const { ["workspaceSlug"]: _workspaceSlug, ["globalViewId"]: _globalViewId, ...filters } = routerQueryParams;
|
||||||
|
|
||||||
|
let issueFilters: any = {};
|
||||||
|
Object.keys(filters).forEach((key) => {
|
||||||
|
const filterKey: any = key;
|
||||||
|
const filterValue = filters[key]?.toString() || undefined;
|
||||||
|
if (
|
||||||
|
ISSUE_DISPLAY_FILTERS_BY_LAYOUT.my_issues.spreadsheet.filters.includes(filterKey) &&
|
||||||
|
filterKey &&
|
||||||
|
filterValue
|
||||||
|
)
|
||||||
|
issueFilters = { ...issueFilters, [filterKey]: filterValue.split(",") };
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!isEmpty(filters))
|
||||||
|
updateFilters(
|
||||||
|
workspaceSlug.toString(),
|
||||||
|
undefined,
|
||||||
|
EIssueFilterType.FILTERS,
|
||||||
|
issueFilters,
|
||||||
|
globalViewId.toString()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
useSWR(workspaceSlug ? `WORKSPACE_GLOBAL_VIEWS${workspaceSlug}` : null, async () => {
|
useSWR(workspaceSlug ? `WORKSPACE_GLOBAL_VIEWS${workspaceSlug}` : null, async () => {
|
||||||
if (workspaceSlug) {
|
if (workspaceSlug) {
|
||||||
await fetchAllGlobalViews(workspaceSlug.toString());
|
await fetchAllGlobalViews(workspaceSlug.toString());
|
||||||
@ -60,6 +95,7 @@ export const AllIssueLayoutRoot: React.FC = observer(() => {
|
|||||||
await fetchAllGlobalViews(workspaceSlug.toString());
|
await fetchAllGlobalViews(workspaceSlug.toString());
|
||||||
await fetchFilters(workspaceSlug.toString(), globalViewId.toString());
|
await fetchFilters(workspaceSlug.toString(), globalViewId.toString());
|
||||||
await fetchIssues(workspaceSlug.toString(), globalViewId.toString(), issueIds ? "mutation" : "init-loader");
|
await fetchIssues(workspaceSlug.toString(), globalViewId.toString(), issueIds ? "mutation" : "init-loader");
|
||||||
|
routerFilterParams();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import { useEstimate, useLabel, useProjectState } from "./store";
|
import { useEstimate, useLabel, useProjectState } from "./store";
|
||||||
|
|
||||||
export const useWorskspaceIssueProperties = (workspaceSlug: string | string[] | undefined) => {
|
export const useWorkspaceIssueProperties = (workspaceSlug: string | string[] | undefined) => {
|
||||||
const { fetchWorkspaceLabels } = useLabel();
|
const { fetchWorkspaceLabels } = useLabel();
|
||||||
|
|
||||||
const { fetchWorkspaceStates } = useProjectState();
|
const { fetchWorkspaceStates } = useProjectState();
|
||||||
|
|
||||||
const { fetchWorskpaceEstimates } = useEstimate();
|
const { fetchWorkspaceEstimates } = useEstimate();
|
||||||
|
|
||||||
// fetch workspace labels
|
// fetch workspace labels
|
||||||
useSWR(
|
useSWR(
|
||||||
@ -23,6 +23,6 @@ export const useWorskspaceIssueProperties = (workspaceSlug: string | string[] |
|
|||||||
// fetch workspace estimates
|
// fetch workspace estimates
|
||||||
useSWR(
|
useSWR(
|
||||||
workspaceSlug ? `WORKSPACE_ESTIMATES_${workspaceSlug}` : null,
|
workspaceSlug ? `WORKSPACE_ESTIMATES_${workspaceSlug}` : null,
|
||||||
workspaceSlug ? () => fetchWorskpaceEstimates(workspaceSlug.toString()) : null
|
workspaceSlug ? () => fetchWorkspaceEstimates(workspaceSlug.toString()) : null
|
||||||
);
|
);
|
||||||
};
|
};
|
@ -23,7 +23,7 @@ export interface IEstimateStore {
|
|||||||
getProjectActiveEstimateDetails: (projectId: string) => IEstimate | null;
|
getProjectActiveEstimateDetails: (projectId: string) => IEstimate | null;
|
||||||
// fetch actions
|
// fetch actions
|
||||||
fetchProjectEstimates: (workspaceSlug: string, projectId: string) => Promise<IEstimate[]>;
|
fetchProjectEstimates: (workspaceSlug: string, projectId: string) => Promise<IEstimate[]>;
|
||||||
fetchWorskpaceEstimates: (workspaceSlug: string) => Promise<IEstimate[]>;
|
fetchWorkspaceEstimates: (workspaceSlug: string) => Promise<IEstimate[]>;
|
||||||
// crud actions
|
// crud actions
|
||||||
createEstimate: (workspaceSlug: string, projectId: string, data: IEstimateFormData) => Promise<IEstimate>;
|
createEstimate: (workspaceSlug: string, projectId: string, data: IEstimateFormData) => Promise<IEstimate>;
|
||||||
updateEstimate: (
|
updateEstimate: (
|
||||||
@ -56,7 +56,7 @@ export class EstimateStore implements IEstimateStore {
|
|||||||
activeEstimateDetails: computed,
|
activeEstimateDetails: computed,
|
||||||
// actions
|
// actions
|
||||||
fetchProjectEstimates: action,
|
fetchProjectEstimates: action,
|
||||||
fetchWorskpaceEstimates: action,
|
fetchWorkspaceEstimates: action,
|
||||||
createEstimate: action,
|
createEstimate: action,
|
||||||
updateEstimate: action,
|
updateEstimate: action,
|
||||||
deleteEstimate: action,
|
deleteEstimate: action,
|
||||||
@ -158,7 +158,7 @@ export class EstimateStore implements IEstimateStore {
|
|||||||
* @param workspaceSlug
|
* @param workspaceSlug
|
||||||
* @param projectId
|
* @param projectId
|
||||||
*/
|
*/
|
||||||
fetchWorskpaceEstimates = async (workspaceSlug: string) =>
|
fetchWorkspaceEstimates = async (workspaceSlug: string) =>
|
||||||
await this.estimateService.getWorkspaceEstimatesList(workspaceSlug).then((response) => {
|
await this.estimateService.getWorkspaceEstimatesList(workspaceSlug).then((response) => {
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
response.forEach((estimate) => {
|
response.forEach((estimate) => {
|
||||||
|
@ -162,14 +162,17 @@ export class WorkspaceIssuesFilter extends IssueFilterHelperStore implements IWo
|
|||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
if (!viewId) throw new Error("View id is required");
|
if (!viewId) throw new Error("View id is required");
|
||||||
|
const issueFilters = this.getIssueFilters(viewId);
|
||||||
|
|
||||||
if (isEmpty(this.filters) || isEmpty(this.filters[viewId]) || isEmpty(filters)) return;
|
console.log("issueFilters", issueFilters);
|
||||||
|
|
||||||
|
if (!issueFilters || isEmpty(filters)) return;
|
||||||
|
|
||||||
const _filters = {
|
const _filters = {
|
||||||
filters: this.filters[viewId].filters as IIssueFilterOptions,
|
filters: issueFilters.filters as IIssueFilterOptions,
|
||||||
displayFilters: this.filters[viewId].displayFilters as IIssueDisplayFilterOptions,
|
displayFilters: issueFilters.displayFilters as IIssueDisplayFilterOptions,
|
||||||
displayProperties: this.filters[viewId].displayProperties as IIssueDisplayProperties,
|
displayProperties: issueFilters.displayProperties as IIssueDisplayProperties,
|
||||||
kanbanFilters: this.filters[viewId].kanbanFilters as TIssueKanbanFilters,
|
kanbanFilters: issueFilters.kanbanFilters as TIssueKanbanFilters,
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
Loading…
Reference in New Issue
Block a user