mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
added cycle events
This commit is contained in:
parent
81dfc15d1f
commit
acf3faa11d
@ -15,13 +15,14 @@ import { StateDropdown } from "@/components/dropdowns";
|
||||
import { EmptyState } from "@/components/empty-state";
|
||||
// constants
|
||||
import { EmptyStateType } from "@/constants/empty-state";
|
||||
import { ACYCLE_TAB_CHANGED } from "@/constants/event-tracker";
|
||||
import { CYCLE_ISSUES_WITH_PARAMS } from "@/constants/fetch-keys";
|
||||
import { EIssuesStoreType } from "@/constants/issue";
|
||||
// helper
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
import { renderFormattedDate, renderFormattedDateWithoutYear } from "@/helpers/date-time.helper";
|
||||
// hooks
|
||||
import { useIssues, useProject } from "@/hooks/store";
|
||||
import { useIssues, useProject, useEventTracker } from "@/hooks/store";
|
||||
import useLocalStorage from "@/hooks/use-local-storage";
|
||||
|
||||
export type ActiveCycleStatsProps = {
|
||||
@ -34,6 +35,7 @@ export const ActiveCycleStats: FC<ActiveCycleStatsProps> = observer((props) => {
|
||||
const { workspaceSlug, projectId, cycle } = props;
|
||||
|
||||
const { storedValue: tab, setValue: setTab } = useLocalStorage("activeCycleTab", "Assignees");
|
||||
const { captureEvent } = useEventTracker();
|
||||
|
||||
const currentValue = (tab: string | null) => {
|
||||
switch (tab) {
|
||||
@ -47,6 +49,18 @@ export const ActiveCycleStats: FC<ActiveCycleStatsProps> = observer((props) => {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
const getCurrentTab = (index: number) => {
|
||||
switch (index) {
|
||||
case 0:
|
||||
return "Priority-Issues";
|
||||
case 1:
|
||||
return "Assignees";
|
||||
case 2:
|
||||
return "Labels";
|
||||
default:
|
||||
return "Priority-Issues";
|
||||
}
|
||||
};
|
||||
const {
|
||||
issues: { fetchActiveCycleIssues },
|
||||
} = useIssues(EIssuesStoreType.CYCLE);
|
||||
@ -66,17 +80,9 @@ export const ActiveCycleStats: FC<ActiveCycleStatsProps> = observer((props) => {
|
||||
as={Fragment}
|
||||
defaultIndex={currentValue(tab)}
|
||||
onChange={(i) => {
|
||||
switch (i) {
|
||||
case 0:
|
||||
return setTab("Priority-Issues");
|
||||
case 1:
|
||||
return setTab("Assignees");
|
||||
case 2:
|
||||
return setTab("Labels");
|
||||
|
||||
default:
|
||||
return setTab("Priority-Issues");
|
||||
}
|
||||
const currentTab = getCurrentTab(i);
|
||||
setTab(currentTab);
|
||||
captureEvent(ACYCLE_TAB_CHANGED, { tab: currentTab });
|
||||
}}
|
||||
>
|
||||
<Tab.List
|
||||
|
@ -3,8 +3,10 @@ import { useRouter } from "next/router";
|
||||
import { Dialog, Transition } from "@headlessui/react";
|
||||
// ui
|
||||
import { Button, TOAST_TYPE, setToast } from "@plane/ui";
|
||||
// constants
|
||||
import { CYCLE_ARCHIVED } from "@/constants/event-tracker";
|
||||
// hooks
|
||||
import { useCycle } from "@/hooks/store";
|
||||
import { useCycle, useEventTracker } from "@/hooks/store";
|
||||
|
||||
type Props = {
|
||||
workspaceSlug: string;
|
||||
@ -23,6 +25,7 @@ export const ArchiveCycleModal: React.FC<Props> = (props) => {
|
||||
const [isArchiving, setIsArchiving] = useState(false);
|
||||
// store hooks
|
||||
const { getCycleNameById, archiveCycle } = useCycle();
|
||||
const {captureEvent} =useEventTracker();
|
||||
|
||||
const cycleName = getCycleNameById(cycleId);
|
||||
|
||||
@ -42,6 +45,9 @@ export const ArchiveCycleModal: React.FC<Props> = (props) => {
|
||||
});
|
||||
onClose();
|
||||
router.push(`/${workspaceSlug}/projects/${projectId}/cycles`);
|
||||
captureEvent(CYCLE_ARCHIVED, {
|
||||
cycle_id: cycleId,
|
||||
});
|
||||
})
|
||||
.catch(() =>
|
||||
setToast({
|
||||
|
@ -10,10 +10,11 @@ import { EmptyState } from "@/components/empty-state";
|
||||
import { CycleModuleListLayout } from "@/components/ui";
|
||||
// constants
|
||||
import { EmptyStateType } from "@/constants/empty-state";
|
||||
import { CYCLES_FILTER_REMOVED } from "@/constants/event-tracker";
|
||||
// helpers
|
||||
import { calculateTotalFilters } from "@/helpers/filter.helper";
|
||||
// hooks
|
||||
import { useCycle, useCycleFilter } from "@/hooks/store";
|
||||
import { useCycle, useCycleFilter, useEventTracker } from "@/hooks/store";
|
||||
|
||||
export const ArchivedCycleLayoutRoot: React.FC = observer(() => {
|
||||
// router
|
||||
@ -21,6 +22,7 @@ export const ArchivedCycleLayoutRoot: React.FC = observer(() => {
|
||||
const { workspaceSlug, projectId } = router.query;
|
||||
// hooks
|
||||
const { fetchArchivedCycles, currentProjectArchivedCycleIds, loader } = useCycle();
|
||||
const { captureEvent } = useEventTracker();
|
||||
// cycle filters hook
|
||||
const { clearAllFilters, currentProjectArchivedFilters, updateFilters } = useCycleFilter();
|
||||
// derived values
|
||||
@ -43,6 +45,11 @@ export const ArchivedCycleLayoutRoot: React.FC = observer(() => {
|
||||
if (!value) newValues = [];
|
||||
else newValues = newValues.filter((val) => val !== value);
|
||||
|
||||
captureEvent(CYCLES_FILTER_REMOVED, {
|
||||
filter_type: key,
|
||||
filter_property: value,
|
||||
current_filters: currentProjectArchivedFilters,
|
||||
});
|
||||
updateFilters(projectId.toString(), { [key]: newValues }, "archived");
|
||||
};
|
||||
|
||||
|
@ -7,11 +7,13 @@ import { TCycleFilters } from "@plane/types";
|
||||
// components
|
||||
import { CycleFiltersSelection } from "@/components/cycles";
|
||||
import { FiltersDropdown } from "@/components/issues";
|
||||
// constants
|
||||
import { CYCLES_FILTER_APPLIED, CYCLES_FILTER_REMOVED } from "@/constants/event-tracker";
|
||||
// helpers
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
import { calculateTotalFilters } from "@/helpers/filter.helper";
|
||||
// hooks
|
||||
import { useCycleFilter } from "@/hooks/store";
|
||||
import { useCycleFilter, useEventTracker } from "@/hooks/store";
|
||||
import useOutsideClickDetector from "@/hooks/use-outside-click-detector";
|
||||
|
||||
type Props = {
|
||||
@ -24,6 +26,7 @@ export const CyclesViewHeader: React.FC<Props> = observer((props) => {
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
// hooks
|
||||
const { currentProjectFilters, searchQuery, updateFilters, updateSearchQuery } = useCycleFilter();
|
||||
const { captureEvent } = useEventTracker();
|
||||
// states
|
||||
const [isSearchOpen, setIsSearchOpen] = useState(searchQuery !== "" ? true : false);
|
||||
// outside click detector hook
|
||||
@ -34,7 +37,7 @@ export const CyclesViewHeader: React.FC<Props> = observer((props) => {
|
||||
const handleFilters = useCallback(
|
||||
(key: keyof TCycleFilters, value: string | string[]) => {
|
||||
if (!projectId) return;
|
||||
const newValues = currentProjectFilters?.[key] ?? [];
|
||||
const newValues = Array.from(currentProjectFilters?.[key] ?? []);
|
||||
|
||||
if (Array.isArray(value))
|
||||
value.forEach((val) => {
|
||||
@ -46,6 +49,14 @@ export const CyclesViewHeader: React.FC<Props> = observer((props) => {
|
||||
else newValues.push(value);
|
||||
}
|
||||
|
||||
captureEvent(
|
||||
(currentProjectFilters?.[key] ?? []).length > newValues.length ? CYCLES_FILTER_REMOVED : CYCLES_FILTER_APPLIED,
|
||||
{
|
||||
filter_type: key,
|
||||
filter_property: value,
|
||||
current_filters: currentProjectFilters,
|
||||
}
|
||||
);
|
||||
updateFilters(projectId, { [key]: newValues });
|
||||
},
|
||||
[currentProjectFilters, projectId, updateFilters]
|
||||
|
@ -57,7 +57,6 @@ export const CycleListItemAction: FC<Props> = observer((props) => {
|
||||
() => {
|
||||
captureEvent(CYCLE_FAVORITED, {
|
||||
cycle_id: cycleId,
|
||||
element: "List layout",
|
||||
state: "SUCCESS",
|
||||
});
|
||||
}
|
||||
@ -87,7 +86,6 @@ export const CycleListItemAction: FC<Props> = observer((props) => {
|
||||
).then(() => {
|
||||
captureEvent(CYCLE_UNFAVORITED, {
|
||||
cycle_id: cycleId,
|
||||
element: "List layout",
|
||||
state: "SUCCESS",
|
||||
});
|
||||
});
|
||||
|
@ -8,6 +8,7 @@ import { ArchiveIcon, ContextMenu, CustomMenu, TContextMenuItem, TOAST_TYPE, set
|
||||
// components
|
||||
import { ArchiveCycleModal, CycleCreateUpdateModal, CycleDeleteModal } from "@/components/cycles";
|
||||
// constants
|
||||
import { CYCLE_ARCHIVED, CYCLE_RESTORED, E_CYCLES } from "@/constants/event-tracker";
|
||||
import { EUserProjectRoles } from "@/constants/project";
|
||||
// helpers
|
||||
import { cn } from "@/helpers/common.helper";
|
||||
@ -31,7 +32,7 @@ export const CycleQuickActions: React.FC<Props> = observer((props) => {
|
||||
const [archiveCycleModal, setArchiveCycleModal] = useState(false);
|
||||
const [deleteModal, setDeleteModal] = useState(false);
|
||||
// store hooks
|
||||
const { setTrackElement } = useEventTracker();
|
||||
const { setTrackElement, captureEvent } = useEventTracker();
|
||||
const {
|
||||
membership: { currentWorkspaceAllProjectsRole },
|
||||
} = useUser();
|
||||
@ -56,7 +57,7 @@ export const CycleQuickActions: React.FC<Props> = observer((props) => {
|
||||
const handleOpenInNewTab = () => window.open(`/${cycleLink}`, "_blank");
|
||||
|
||||
const handleEditCycle = () => {
|
||||
setTrackElement("Cycles page list layout");
|
||||
setTrackElement(E_CYCLES);
|
||||
setUpdateModal(true);
|
||||
};
|
||||
|
||||
@ -65,6 +66,9 @@ export const CycleQuickActions: React.FC<Props> = observer((props) => {
|
||||
const handleRestoreCycle = async () =>
|
||||
await restoreCycle(workspaceSlug, projectId, cycleId)
|
||||
.then(() => {
|
||||
captureEvent(CYCLE_RESTORED, {
|
||||
cycle_id: cycleId,
|
||||
});
|
||||
setToast({
|
||||
type: TOAST_TYPE.SUCCESS,
|
||||
title: "Restore success",
|
||||
@ -81,7 +85,7 @@ export const CycleQuickActions: React.FC<Props> = observer((props) => {
|
||||
);
|
||||
|
||||
const handleDeleteCycle = () => {
|
||||
setTrackElement("Cycles page list layout");
|
||||
setTrackElement(E_CYCLES);
|
||||
setDeleteModal(true);
|
||||
};
|
||||
|
||||
|
@ -154,6 +154,12 @@ export const CYCLE_UPDATED = "Cycle updated";
|
||||
export const CYCLE_DELETED = "Cycle deleted";
|
||||
export const CYCLE_FAVORITED = "Cycle favorited";
|
||||
export const CYCLE_UNFAVORITED = "Cycle unfavorited";
|
||||
export const ACYCLE_TAB_CHANGED = "Active cycle tab changed";
|
||||
export const CYCLES_FILTER_APPLIED = "Cycles filter applied";
|
||||
export const CYCLES_FILTER_REMOVED = "Cycles filter removed";
|
||||
export const CYCLE_ARCHIVED = "Cycle archived";
|
||||
export const CYCLE_RESTORED = "Cycle restored";
|
||||
export const CYCLE_LAYOUT_CHANGED = "Cycle layout changed";
|
||||
// Module Events
|
||||
export const MODULE_CREATED = "Module created";
|
||||
export const MODULE_UPDATED = "Module updated";
|
||||
@ -222,3 +228,6 @@ export const SNOOZED_NOTIFICATIONS = "Snoozed notifications viewed";
|
||||
export const ARCHIVED_NOTIFICATIONS = "Archived notifications viewed";
|
||||
// Groups
|
||||
export const GROUP_WORKSPACE = "Workspace_metrics";
|
||||
|
||||
// Elements
|
||||
export const E_CYCLES = "Cycles";
|
@ -12,6 +12,7 @@ import { CyclesHeader } from "@/components/headers";
|
||||
import { CycleModuleListLayout } from "@/components/ui";
|
||||
// constants
|
||||
import { EmptyStateType } from "@/constants/empty-state";
|
||||
import { CYCLES_FILTER_REMOVED } from "@/constants/event-tracker";
|
||||
// helpers
|
||||
import { calculateTotalFilters } from "@/helpers/filter.helper";
|
||||
// hooks
|
||||
@ -25,7 +26,7 @@ const ProjectCyclesPage: NextPageWithLayout = observer(() => {
|
||||
// states
|
||||
const [createModal, setCreateModal] = useState(false);
|
||||
// store hooks
|
||||
const { setTrackElement } = useEventTracker();
|
||||
const { setTrackElement,captureEvent } = useEventTracker();
|
||||
const { currentProjectCycleIds, loader } = useCycle();
|
||||
const { getProjectById, currentProjectDetails } = useProject();
|
||||
// router
|
||||
@ -45,6 +46,12 @@ const ProjectCyclesPage: NextPageWithLayout = observer(() => {
|
||||
if (!value) newValues = [];
|
||||
else newValues = newValues.filter((val) => val !== value);
|
||||
|
||||
captureEvent(CYCLES_FILTER_REMOVED, {
|
||||
filter_type: key,
|
||||
filter_property: value,
|
||||
current_filters: currentProjectFilters,
|
||||
});
|
||||
|
||||
updateFilters(projectId.toString(), { [key]: newValues });
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user