diff --git a/packages/ui/src/popovers/popover-menu.tsx b/packages/ui/src/popovers/popover-menu.tsx index a22bda3b382..079aa3e25ed 100644 --- a/packages/ui/src/popovers/popover-menu.tsx +++ b/packages/ui/src/popovers/popover-menu.tsx @@ -18,6 +18,7 @@ export const PopoverMenu = (props: TPopoverMenu) => { popoverClassName = "", keyExtractor, render, + popoverButtonRef, } = props; return ( @@ -32,6 +33,7 @@ export const PopoverMenu = (props: TPopoverMenu) => { panelClassName )} popoverClassName={popoverClassName} + popoverButtonRef={popoverButtonRef} > {data.map((item, index) => ( diff --git a/packages/ui/src/popovers/popover.tsx b/packages/ui/src/popovers/popover.tsx index 570d5b15e62..30a168965fd 100644 --- a/packages/ui/src/popovers/popover.tsx +++ b/packages/ui/src/popovers/popover.tsx @@ -1,4 +1,4 @@ -import React, { Fragment, useState } from "react"; +import React, { Fragment, Ref, useState } from "react"; import { usePopper } from "react-popper"; import { Popover as HeadlessReactPopover, Transition } from "@headlessui/react"; // helpers @@ -17,9 +17,10 @@ export const Popover = (props: TPopover) => { disabled = false, panelClassName = "", children, + popoverButtonRef, } = props; // states - const [referenceElement, setReferenceElement] = useState(null); + const [referenceElement, setReferenceElement] = useState(null); const [popperElement, setPopperElement] = useState(null); // react-popper derived values @@ -37,19 +38,21 @@ export const Popover = (props: TPopover) => { return ( - - {button ? button : } - +
+ } + className={cn( + { + "flex justify-center items-center text-base h-6 w-6 rounded transition-all bg-custom-background-90 hover:bg-custom-background-80": + !button, + }, + buttonClassName + )} + disabled={disabled} + > + {button ? button : } + +
; }; export type TPopover = TPopoverDefaultOptions & { diff --git a/web/ce/components/issues/worklog/activity/root.tsx b/web/ce/components/issues/worklog/activity/root.tsx index 045616cd678..0342999d3d0 100644 --- a/web/ce/components/issues/worklog/activity/root.tsx +++ b/web/ce/components/issues/worklog/activity/root.tsx @@ -8,6 +8,7 @@ type TIssueActivityWorklog = { projectId: string; issueId: string; activityComment: TIssueActivityComment; + ends?: "top" | "bottom"; }; export const IssueActivityWorklog: FC = () => <>; diff --git a/web/ce/constants/workspace.ts b/web/ce/constants/workspace.ts index 1511ba93469..b89ced416db 100644 --- a/web/ce/constants/workspace.ts +++ b/web/ce/constants/workspace.ts @@ -4,15 +4,8 @@ import { Props } from "@/components/icons/types"; // constants import { EUserWorkspaceRoles } from "@/constants/workspace"; -export const WORKSPACE_SETTINGS_LINKS: { - key: string; - label: string; - href: string; - access: EUserWorkspaceRoles; - highlight: (pathname: string, baseUrl: string) => boolean; - Icon: React.FC; -}[] = [ - { +export const WORKSPACE_SETTINGS = { + general: { key: "general", label: "General", href: `/settings`, @@ -20,7 +13,7 @@ export const WORKSPACE_SETTINGS_LINKS: { highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/`, Icon: SettingIcon, }, - { + members: { key: "members", label: "Members", href: `/settings/members`, @@ -28,7 +21,7 @@ export const WORKSPACE_SETTINGS_LINKS: { highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/members/`, Icon: SettingIcon, }, - { + "billing-and-plans": { key: "billing-and-plans", label: "Billing and plans", href: `/settings/billing`, @@ -36,7 +29,7 @@ export const WORKSPACE_SETTINGS_LINKS: { highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/billing/`, Icon: SettingIcon, }, - { + export: { key: "export", label: "Exports", href: `/settings/exports`, @@ -44,7 +37,7 @@ export const WORKSPACE_SETTINGS_LINKS: { highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/exports/`, Icon: SettingIcon, }, - { + webhooks: { key: "webhooks", label: "Webhooks", href: `/settings/webhooks`, @@ -52,7 +45,7 @@ export const WORKSPACE_SETTINGS_LINKS: { highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/webhooks/`, Icon: SettingIcon, }, - { + "api-tokens": { key: "api-tokens", label: "API tokens", href: `/settings/api-tokens`, @@ -60,4 +53,20 @@ export const WORKSPACE_SETTINGS_LINKS: { highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/api-tokens/`, Icon: SettingIcon, }, +}; + +export const WORKSPACE_SETTINGS_LINKS: { + key: string; + label: string; + href: string; + access: EUserWorkspaceRoles; + highlight: (pathname: string, baseUrl: string) => boolean; + Icon: React.FC; +}[] = [ + WORKSPACE_SETTINGS["general"], + WORKSPACE_SETTINGS["members"], + WORKSPACE_SETTINGS["billing-and-plans"], + WORKSPACE_SETTINGS["export"], + WORKSPACE_SETTINGS["webhooks"], + WORKSPACE_SETTINGS["api-tokens"], ]; diff --git a/web/core/store/issue/issue-details/activity.store.ts b/web/ce/store/issue/issue-details/activity.store.ts similarity index 84% rename from web/core/store/issue/issue-details/activity.store.ts rename to web/ce/store/issue/issue-details/activity.store.ts index dd4fe10aa24..f76f30cf5e8 100644 --- a/web/core/store/issue/issue-details/activity.store.ts +++ b/web/ce/store/issue/issue-details/activity.store.ts @@ -1,3 +1,5 @@ +/* eslint-disable no-useless-catch */ + import concat from "lodash/concat"; import set from "lodash/set"; import sortBy from "lodash/sortBy"; @@ -5,10 +7,12 @@ import uniq from "lodash/uniq"; import update from "lodash/update"; import { action, makeObservable, observable, runInAction } from "mobx"; import { TIssueActivityComment, TIssueActivity, TIssueActivityMap, TIssueActivityIdMap } from "@plane/types"; +// plane web constants +import { EActivityFilterType } from "@/plane-web/constants/issues"; +// plane web store types +import { RootStore } from "@/plane-web/store/root.store"; // services import { IssueActivityService } from "@/services/issue"; -// types -import { IIssueDetail } from "./root.store"; export type TActivityLoader = "fetch" | "mutate" | undefined; @@ -38,12 +42,11 @@ export class IssueActivityStore implements IIssueActivityStore { loader: TActivityLoader = "fetch"; activities: TIssueActivityIdMap = {}; activityMap: TIssueActivityMap = {}; - // root store - rootIssueDetailStore: IIssueDetail; + // services issueActivityService; - constructor(rootStore: IIssueDetail) { + constructor(protected store: RootStore) { makeObservable(this, { // observables loader: observable.ref, @@ -52,8 +55,6 @@ export class IssueActivityStore implements IIssueActivityStore { // actions fetchActivities: action, }); - // root store - this.rootIssueDetailStore = rootStore; // services this.issueActivityService = new IssueActivityService(); } @@ -69,50 +70,46 @@ export class IssueActivityStore implements IIssueActivityStore { return this.activityMap[activityId] ?? undefined; }; - getActivityCommentByIssueId = (issueId: string) => { + public getActivityCommentByIssueId(issueId: string) { if (!issueId) return undefined; let activityComments: TIssueActivityComment[] = []; const activities = this.getActivitiesByIssueId(issueId) || []; - const comments = this.rootIssueDetailStore.comment.getCommentsByIssueId(issueId) || []; + const comments = this.store.issue.issueDetail.comment.getCommentsByIssueId(issueId) || []; activities.forEach((activityId) => { const activity = this.getActivityById(activityId); if (!activity) return; activityComments.push({ id: activity.id, - activity_type: "ACTIVITY", + activity_type: EActivityFilterType.ACTIVITY, created_at: activity.created_at, }); }); comments.forEach((commentId) => { - const comment = this.rootIssueDetailStore.comment.getCommentById(commentId); + const comment = this.store.issue.issueDetail.comment.getCommentById(commentId); if (!comment) return; activityComments.push({ id: comment.id, - activity_type: "COMMENT", + activity_type: EActivityFilterType.COMMENT, created_at: comment.created_at, }); }); activityComments = sortBy(activityComments, "created_at"); - activityComments = activityComments.map((activityComment) => ({ - id: activityComment.id, - activity_type: activityComment.activity_type, - })); return activityComments; - }; + } // actions - fetchActivities = async ( + public async fetchActivities( workspaceSlug: string, projectId: string, issueId: string, loaderType: TActivityLoader = "fetch" - ) => { + ) { try { this.loader = loaderType; @@ -140,7 +137,8 @@ export class IssueActivityStore implements IIssueActivityStore { return activities; } catch (error) { + this.loader = undefined; throw error; } - }; + } } diff --git a/web/core/components/issues/issue-detail/issue-activity/activity-comment-root.tsx b/web/core/components/issues/issue-detail/issue-activity/activity-comment-root.tsx index 18655ccd52a..a26dbc9c9a6 100644 --- a/web/core/components/issues/issue-detail/issue-activity/activity-comment-root.tsx +++ b/web/core/components/issues/issue-detail/issue-activity/activity-comment-root.tsx @@ -62,6 +62,7 @@ export const IssueActivityCommentRoot: FC = observer( projectId={projectId} issueId={issueId} activityComment={activityComment} + ends={index === 0 ? "top" : index === filteredActivityComments.length - 1 ? "bottom" : undefined} /> ) : ( <> diff --git a/web/core/store/issue/issue-details/root.store.ts b/web/core/store/issue/issue-details/root.store.ts index 88ecac41a82..b0486b6f0e9 100644 --- a/web/core/store/issue/issue-details/root.store.ts +++ b/web/core/store/issue/issue-details/root.store.ts @@ -10,8 +10,14 @@ import { TIssueRelationTypes, TIssueDetailWidget, } from "@plane/types"; +// plane web store +import { + IIssueActivityStore, + IssueActivityStore, + IIssueActivityStoreActions, + TActivityLoader, +} from "@/plane-web/store/issue/issue-details/activity.store"; import { IIssueRootStore } from "../root.store"; -import { IIssueActivityStore, IssueActivityStore, IIssueActivityStoreActions, TActivityLoader } from "./activity.store"; import { IIssueAttachmentStore, IssueAttachmentStore, IIssueAttachmentStoreActions } from "./attachment.store"; import { IIssueCommentStore, IssueCommentStore, IIssueCommentStoreActions, TCommentLoader } from "./comment.store"; import { @@ -187,7 +193,7 @@ export class IssueDetail implements IIssueDetail { this.issue = new IssueStore(this); this.reaction = new IssueReactionStore(this); this.attachment = new IssueAttachmentStore(rootStore); - this.activity = new IssueActivityStore(this); + this.activity = new IssueActivityStore(rootStore.rootStore); this.comment = new IssueCommentStore(this); this.commentReaction = new IssueCommentReactionStore(this); this.subIssues = new IssueSubIssuesStore(this); diff --git a/web/core/store/issue/root.store.ts b/web/core/store/issue/root.store.ts index 232acbba563..10415c0d2e3 100644 --- a/web/core/store/issue/root.store.ts +++ b/web/core/store/issue/root.store.ts @@ -1,9 +1,10 @@ import isEmpty from "lodash/isEmpty"; import { autorun, makeObservable, observable } from "mobx"; import { ICycle, IIssueLabel, IModule, IProject, IState, IUserLite } from "@plane/types"; +// plane web root store +import { RootStore } from "@/plane-web/store/root.store"; // root store import { IWorkspaceMembership } from "@/store/member/workspace-member.store"; -import { CoreRootStore } from "../root.store"; import { IStateStore, StateStore } from "../state.store"; // issues data store import { IArchivedIssuesFilter, ArchivedIssuesFilter, IArchivedIssues, ArchivedIssues } from "./archived"; @@ -43,7 +44,7 @@ export interface IIssueRootStore { moduleMap: Record | undefined; cycleMap: Record | undefined; - rootStore: CoreRootStore; + rootStore: RootStore; issues: IIssueStore; @@ -98,7 +99,7 @@ export class IssueRootStore implements IIssueRootStore { moduleMap: Record | undefined = undefined; cycleMap: Record | undefined = undefined; - rootStore: CoreRootStore; + rootStore: RootStore; issues: IIssueStore; @@ -133,7 +134,7 @@ export class IssueRootStore implements IIssueRootStore { issueKanBanView: IIssueKanBanViewStore; issueCalendarView: ICalendarStore; - constructor(rootStore: CoreRootStore) { + constructor(rootStore: RootStore) { makeObservable(this, { workspaceSlug: observable.ref, projectId: observable.ref, diff --git a/web/ee/store/issue/issue-details/activity.store.ts b/web/ee/store/issue/issue-details/activity.store.ts new file mode 100644 index 00000000000..cda9d84aed2 --- /dev/null +++ b/web/ee/store/issue/issue-details/activity.store.ts @@ -0,0 +1 @@ +export * from "ce/store/issue/issue-details/activity.store";