diff --git a/packages/types/src/issues/activity/base.d.ts b/packages/types/src/issues/activity/base.d.ts index 9f17d78c7..4b3c9ebe8 100644 --- a/packages/types/src/issues/activity/base.d.ts +++ b/packages/types/src/issues/activity/base.d.ts @@ -55,4 +55,9 @@ export type TIssueActivityComment = id: string; activity_type: "ACTIVITY"; created_at?: string; + } + | { + id: string; + activity_type: "WORKLOG"; + created_at?: string; }; diff --git a/packages/types/src/workspace.d.ts b/packages/types/src/workspace.d.ts index 20674bcc6..de653a360 100644 --- a/packages/types/src/workspace.d.ts +++ b/packages/types/src/workspace.d.ts @@ -1,199 +1,199 @@ -import {EUserWorkspaceRoles} from "@/constants/workspace"; +import { EUserWorkspaceRoles } from "@/constants/workspace"; import type { - IProjectMember, - IUser, - IUserLite, - IWorkspaceViewProps, + IProjectMember, + IUser, + IUserLite, + IWorkspaceViewProps, } from "@plane/types"; export interface IWorkspace { - readonly id: string; - readonly owner: IUser; - readonly created_at: Date; - readonly updated_at: Date; - name: string; - url: string; - logo: string | null; - slug: string; - readonly total_members: number; - readonly slug: string; - readonly created_by: string; - readonly updated_by: string; - organization_size: string; - total_issues: number; + readonly id: string; + readonly owner: IUser; + readonly created_at: Date; + readonly updated_at: Date; + name: string; + url: string; + logo: string | null; + slug: string; + readonly total_members: number; + readonly slug: string; + readonly created_by: string; + readonly updated_by: string; + organization_size: string; + total_issues: number; } export interface IWorkspaceLite { - readonly id: string; - name: string; - slug: string; + readonly id: string; + name: string; + slug: string; } export interface IWorkspaceMemberInvitation { - accepted: boolean; - email: string; - id: string; - message: string; - responded_at: Date; - role: EUserWorkspaceRoles; - token: string; - workspace: { - id: string; - logo: string; - name: string; - slug: string; - }; + accepted: boolean; + email: string; + id: string; + message: string; + responded_at: Date; + role: EUserWorkspaceRoles; + token: string; + workspace: { + id: string; + logo: string; + name: string; + slug: string; + }; } export interface IWorkspaceBulkInviteFormData { - emails: {email: string; role: EUserWorkspaceRoles}[]; + emails: { email: string; role: EUserWorkspaceRoles }[]; } export type Properties = { - assignee: boolean; - start_date: boolean; - due_date: boolean; - labels: boolean; - key: boolean; - priority: boolean; - state: boolean; - sub_issue_count: boolean; - link: boolean; - attachment_count: boolean; - estimate: boolean; - created_on: boolean; - updated_on: boolean; + assignee: boolean; + start_date: boolean; + due_date: boolean; + labels: boolean; + key: boolean; + priority: boolean; + state: boolean; + sub_issue_count: boolean; + link: boolean; + attachment_count: boolean; + estimate: boolean; + created_on: boolean; + updated_on: boolean; }; export interface IWorkspaceMember { - id: string; - member: IUserLite; - role: EUserWorkspaceRoles; - created_at: string; - avatar?: string; - email?: string; - first_name?: string; - last_name?: string; - joining_date: string; - display_name?: string; + id: string; + member: IUserLite; + role: EUserWorkspaceRoles; + created_at?: string; + avatar?: string; + email?: string; + first_name?: string; + last_name?: string; + joining_date?: string; + display_name?: string; } export interface IWorkspaceMemberMe { - company_role: string | null; - created_at: Date; - created_by: string; - default_props: IWorkspaceViewProps; - id: string; - member: string; - role: EUserWorkspaceRoles; - updated_at: Date; - updated_by: string; - view_props: IWorkspaceViewProps; - workspace: string; + company_role: string | null; + created_at: Date; + created_by: string; + default_props: IWorkspaceViewProps; + id: string; + member: string; + role: EUserWorkspaceRoles; + updated_at: Date; + updated_by: string; + view_props: IWorkspaceViewProps; + workspace: string; } export interface ILastActiveWorkspaceDetails { - workspace_details: IWorkspace; - project_details?: IProjectMember[]; + workspace_details: IWorkspace; + project_details?: IProjectMember[]; } export interface IWorkspaceDefaultSearchResult { - id: string; - name: string; - project_id: string; - project__identifier: string; - workspace__slug: string; + id: string; + name: string; + project_id: string; + project__identifier: string; + workspace__slug: string; } export interface IWorkspaceSearchResult { - id: string; - name: string; - slug: string; + id: string; + name: string; + slug: string; } export interface IWorkspaceIssueSearchResult { - id: string; - name: string; - project__identifier: string; - project_id: string; - sequence_id: number; - workspace__slug: string; + id: string; + name: string; + project__identifier: string; + project_id: string; + sequence_id: number; + workspace__slug: string; } export interface IWorkspacePageSearchResult { - id: string; - name: string; - project_ids: string[]; - project__identifiers: string[]; - workspace__slug: string; + id: string; + name: string; + project_ids: string[]; + project__identifiers: string[]; + workspace__slug: string; } export interface IWorkspaceProjectSearchResult { - id: string; - identifier: string; - name: string; - workspace__slug: string; + id: string; + identifier: string; + name: string; + workspace__slug: string; } export interface IWorkspaceSearchResults { - results: { - workspace: IWorkspaceSearchResult[]; - project: IWorkspaceProjectSearchResult[]; - issue: IWorkspaceIssueSearchResult[]; - cycle: IWorkspaceDefaultSearchResult[]; - module: IWorkspaceDefaultSearchResult[]; - issue_view: IWorkspaceDefaultSearchResult[]; - page: IWorkspacePageSearchResult[]; - }; + results: { + workspace: IWorkspaceSearchResult[]; + project: IWorkspaceProjectSearchResult[]; + issue: IWorkspaceIssueSearchResult[]; + cycle: IWorkspaceDefaultSearchResult[]; + module: IWorkspaceDefaultSearchResult[]; + issue_view: IWorkspaceDefaultSearchResult[]; + page: IWorkspacePageSearchResult[]; + }; } export interface IProductUpdateResponse { - url: string; - assets_url: string; - upload_url: string; - html_url: string; - id: number; - author: { - login: string; - id: string; - node_id: string; - avatar_url: string; - gravatar_id: ""; - url: string; - html_url: string; - followers_url: string; - following_url: string; - gists_url: string; - starred_url: string; - subscriptions_url: string; - organizations_url: string; - repos_url: string; - events_url: string; - received_events_url: string; - type: string; - site_admin: false; - }; - node_id: string; - tag_name: string; - target_commitish: string; - name: string; - draft: boolean; - prerelease: true; - created_at: string; - published_at: string; - assets: []; - tarball_url: string; - zipball_url: string; - body: string; - reactions: { - url: string; - total_count: number; - "+1": number; - "-1": number; - laugh: number; - hooray: number; - confused: number; - heart: number; - rocket: number; - eyes: number; - }; + url: string; + assets_url: string; + upload_url: string; + html_url: string; + id: number; + author: { + login: string; + id: string; + node_id: string; + avatar_url: string; + gravatar_id: ""; + url: string; + html_url: string; + followers_url: string; + following_url: string; + gists_url: string; + starred_url: string; + subscriptions_url: string; + organizations_url: string; + repos_url: string; + events_url: string; + received_events_url: string; + type: string; + site_admin: false; + }; + node_id: string; + tag_name: string; + target_commitish: string; + name: string; + draft: boolean; + prerelease: true; + created_at: string; + published_at: string; + assets: []; + tarball_url: string; + zipball_url: string; + body: string; + reactions: { + url: string; + total_count: number; + "+1": number; + "-1": number; + laugh: number; + hooray: number; + confused: number; + heart: number; + rocket: number; + eyes: number; + }; } diff --git a/packages/ui/src/popovers/popover-menu.tsx b/packages/ui/src/popovers/popover-menu.tsx index bdc5a9d5f..a22bda3b3 100644 --- a/packages/ui/src/popovers/popover-menu.tsx +++ b/packages/ui/src/popovers/popover-menu.tsx @@ -12,6 +12,7 @@ export const PopoverMenu = (props: TPopoverMenu) => { popperPadding = 0, buttonClassName = "", button, + disabled, panelClassName = "", data, popoverClassName = "", @@ -25,6 +26,7 @@ export const PopoverMenu = (props: TPopoverMenu) => { popperPadding={popperPadding} buttonClassName={buttonClassName} button={button} + disabled={disabled} panelClassName={cn( "my-1 w-48 rounded border-[0.5px] border-custom-border-300 bg-custom-background-100 px-2 py-2 text-xs shadow-custom-shadow-rg focus:outline-none", panelClassName diff --git a/packages/ui/src/popovers/popover.tsx b/packages/ui/src/popovers/popover.tsx index 0bf37ef63..570d5b15e 100644 --- a/packages/ui/src/popovers/popover.tsx +++ b/packages/ui/src/popovers/popover.tsx @@ -14,6 +14,7 @@ export const Popover = (props: TPopover) => { buttonClassName = "", popoverClassName = "", button, + disabled = false, panelClassName = "", children, } = props; @@ -36,19 +37,18 @@ export const Popover = (props: TPopover) => { return ( - - {button ? ( - button - ) : ( -
- -
+ + {button ? button : } { const router = useAppRouter(); @@ -12,10 +12,11 @@ export const MobileWorkspaceSettingsTabs = () => {
{WORKSPACE_SETTINGS_LINKS.map((item, index) => (
router.push(`/${workspaceSlug}${item.href}`)} > diff --git a/web/app/[workspaceSlug]/(projects)/settings/sidebar.tsx b/web/app/[workspaceSlug]/(projects)/settings/sidebar.tsx index 8dfd0d7c3..642a89bc4 100644 --- a/web/app/[workspaceSlug]/(projects)/settings/sidebar.tsx +++ b/web/app/[workspaceSlug]/(projects)/settings/sidebar.tsx @@ -5,9 +5,11 @@ import { observer } from "mobx-react"; import Link from "next/link"; import { useParams, usePathname } from "next/navigation"; // constants -import { EUserWorkspaceRoles, WORKSPACE_SETTINGS_LINKS } from "@/constants/workspace"; +import { EUserWorkspaceRoles } from "@/constants/workspace"; // hooks import { useUser } from "@/hooks/store"; +// plane web constants +import { WORKSPACE_SETTINGS_LINKS } from "@/plane-web/constants/workspace"; export const WorkspaceSettingsSidebar = observer(() => { // router @@ -31,10 +33,11 @@ export const WorkspaceSettingsSidebar = observer(() => {
{link.label}
diff --git a/web/ce/components/issues/index.ts b/web/ce/components/issues/index.ts index 7a5275abe..1c463b9b9 100644 --- a/web/ce/components/issues/index.ts +++ b/web/ce/components/issues/index.ts @@ -1 +1,2 @@ -export * from "./bulk-operations"; \ No newline at end of file +export * from "./bulk-operations"; +export * from "./worklog"; diff --git a/web/ce/components/issues/worklog/activity/index.ts b/web/ce/components/issues/worklog/activity/index.ts new file mode 100644 index 000000000..6060c4afc --- /dev/null +++ b/web/ce/components/issues/worklog/activity/index.ts @@ -0,0 +1,2 @@ +export * from "./root"; +export * from "./worklog-create-button"; diff --git a/web/ce/components/issues/worklog/activity/root.tsx b/web/ce/components/issues/worklog/activity/root.tsx new file mode 100644 index 000000000..045616cd6 --- /dev/null +++ b/web/ce/components/issues/worklog/activity/root.tsx @@ -0,0 +1,13 @@ +"use client"; + +import { FC } from "react"; +import { TIssueActivityComment } from "@plane/types"; + +type TIssueActivityWorklog = { + workspaceSlug: string; + projectId: string; + issueId: string; + activityComment: TIssueActivityComment; +}; + +export const IssueActivityWorklog: FC = () => <>; diff --git a/web/ce/components/issues/worklog/activity/worklog-create-button.tsx b/web/ce/components/issues/worklog/activity/worklog-create-button.tsx new file mode 100644 index 000000000..3a57b53df --- /dev/null +++ b/web/ce/components/issues/worklog/activity/worklog-create-button.tsx @@ -0,0 +1,12 @@ +"use client"; + +import { FC } from "react"; + +type TIssueActivityWorklogCreateButton = { + workspaceSlug: string; + projectId: string; + issueId: string; + disabled: boolean; +}; + +export const IssueActivityWorklogCreateButton: FC = () => <>; diff --git a/web/ce/components/issues/worklog/index.ts b/web/ce/components/issues/worklog/index.ts new file mode 100644 index 000000000..c0ed33ebf --- /dev/null +++ b/web/ce/components/issues/worklog/index.ts @@ -0,0 +1,2 @@ +export * from "./property"; +export * from "./activity"; diff --git a/web/ce/components/issues/worklog/property/index.ts b/web/ce/components/issues/worklog/property/index.ts new file mode 100644 index 000000000..1efe34c51 --- /dev/null +++ b/web/ce/components/issues/worklog/property/index.ts @@ -0,0 +1 @@ +export * from "./root"; diff --git a/web/ce/components/issues/worklog/property/root.tsx b/web/ce/components/issues/worklog/property/root.tsx new file mode 100644 index 000000000..5ccc9ebaa --- /dev/null +++ b/web/ce/components/issues/worklog/property/root.tsx @@ -0,0 +1,12 @@ +"use client"; + +import { FC } from "react"; + +type TIssueWorklogProperty = { + workspaceSlug: string; + projectId: string; + issueId: string; + disabled: boolean; +}; + +export const IssueWorklogProperty: FC = () => <>; diff --git a/web/ce/components/projects/settings/useProjectColumns.tsx b/web/ce/components/projects/settings/useProjectColumns.tsx index 031b425e8..7b87c4de5 100644 --- a/web/ce/components/projects/settings/useProjectColumns.tsx +++ b/web/ce/components/projects/settings/useProjectColumns.tsx @@ -66,7 +66,7 @@ const useProjectColumns = () => { { key: "Joining Date", content: "Joining Date", - tdRender: (rowData: RowData) =>
{getFormattedDate(rowData.member.joining_date)}
, + tdRender: (rowData: RowData) =>
{getFormattedDate(rowData?.member?.joining_date || "")}
, }, ]; return { columns, workspaceSlug, projectId, removeMemberModal, setRemoveMemberModal }; diff --git a/web/ce/components/workspace/settings/useMemberColumns.tsx b/web/ce/components/workspace/settings/useMemberColumns.tsx index c2941a633..8820cf331 100644 --- a/web/ce/components/workspace/settings/useMemberColumns.tsx +++ b/web/ce/components/workspace/settings/useMemberColumns.tsx @@ -60,7 +60,7 @@ const useMemberColumns = () => { { key: "Joining Date", content: "Joining Date", - tdRender: (rowData: RowData) =>
{getFormattedDate(rowData.member.joining_date)}
, + tdRender: (rowData: RowData) =>
{getFormattedDate(rowData?.member?.joining_date || "")}
, }, ]; return { columns, workspaceSlug, removeMemberModal, setRemoveMemberModal }; diff --git a/web/ce/constants/issues.ts b/web/ce/constants/issues.ts new file mode 100644 index 000000000..c4349edf0 --- /dev/null +++ b/web/ce/constants/issues.ts @@ -0,0 +1,23 @@ +import { TIssueActivityComment } from "@plane/types"; + +export enum EActivityFilterType { + ACTIVITY = "activity", + COMMENT = "comment", +} + +export type TActivityFilters = EActivityFilterType; + +export const ACTIVITY_FILTER_TYPE_OPTIONS: Record = { + [EActivityFilterType.ACTIVITY]: { + label: "Updates", + }, + [EActivityFilterType.COMMENT]: { + label: "Comments", + }, +}; + +export const filterActivityOnSelectedFilters = ( + activity: TIssueActivityComment[], + filter: TActivityFilters[] +): TIssueActivityComment[] => + activity.filter((activity) => filter.includes(activity.activity_type as TActivityFilters)); diff --git a/web/ce/constants/workspace.ts b/web/ce/constants/workspace.ts new file mode 100644 index 000000000..1511ba934 --- /dev/null +++ b/web/ce/constants/workspace.ts @@ -0,0 +1,63 @@ +// icons +import { SettingIcon } from "@/components/icons/attachment"; +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; +}[] = [ + { + key: "general", + label: "General", + href: `/settings`, + access: EUserWorkspaceRoles.GUEST, + highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/`, + Icon: SettingIcon, + }, + { + key: "members", + label: "Members", + href: `/settings/members`, + access: EUserWorkspaceRoles.GUEST, + highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/members/`, + Icon: SettingIcon, + }, + { + key: "billing-and-plans", + label: "Billing and plans", + href: `/settings/billing`, + access: EUserWorkspaceRoles.ADMIN, + highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/billing/`, + Icon: SettingIcon, + }, + { + key: "export", + label: "Exports", + href: `/settings/exports`, + access: EUserWorkspaceRoles.MEMBER, + highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/exports/`, + Icon: SettingIcon, + }, + { + key: "webhooks", + label: "Webhooks", + href: `/settings/webhooks`, + access: EUserWorkspaceRoles.ADMIN, + highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/webhooks/`, + Icon: SettingIcon, + }, + { + key: "api-tokens", + label: "API tokens", + href: `/settings/api-tokens`, + access: EUserWorkspaceRoles.ADMIN, + highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/api-tokens/`, + Icon: SettingIcon, + }, +]; diff --git a/web/core/components/command-palette/actions/workspace-settings-actions.tsx b/web/core/components/command-palette/actions/workspace-settings-actions.tsx index 9c62fbe7d..109257ed1 100644 --- a/web/core/components/command-palette/actions/workspace-settings-actions.tsx +++ b/web/core/components/command-palette/actions/workspace-settings-actions.tsx @@ -5,10 +5,12 @@ import { Command } from "cmdk"; import Link from "next/link"; import { useParams } from "next/navigation"; // constants -import { EUserWorkspaceRoles, WORKSPACE_SETTINGS_LINKS } from "@/constants/workspace"; +import { EUserWorkspaceRoles } from "@/constants/workspace"; // hooks import { useUser } from "@/hooks/store"; import { useAppRouter } from "@/hooks/use-app-router"; +// plane wev constants +import { WORKSPACE_SETTINGS_LINKS } from "@/plane-web/constants/workspace"; type Props = { closePalette: () => void; 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 6a5263fd9..18655ccd5 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 @@ -1,8 +1,11 @@ import { FC } from "react"; import { observer } from "mobx-react"; // hooks -import { EActivityFilterType } from "@/constants/issue"; import { useIssueDetail } from "@/hooks/store"; +// plane wev components +import { IssueActivityWorklog } from "@/plane-web/components/issues/worklog/activity/root"; +// plane web constants +import { TActivityFilters, filterActivityOnSelectedFilters } from "@/plane-web/constants/issues"; // components import { IssueActivityItem } from "./activity/activity-list"; import { IssueCommentCard } from "./comments/comment-card"; @@ -13,7 +16,7 @@ type TIssueActivityCommentRoot = { workspaceSlug: string; projectId: string; issueId: string; - selectedFilters: EActivityFilterType[]; + selectedFilters: TActivityFilters[]; activityOperations: TActivityOperations; showAccessSpecifier?: boolean; disabled?: boolean; @@ -32,14 +35,7 @@ export const IssueActivityCommentRoot: FC = observer( if (!activityComments || (activityComments && activityComments.length <= 0)) return <>; - const isCommentFilterSelected = selectedFilters.includes(EActivityFilterType.COMMENT); - const isActivityFilterSelected = selectedFilters.includes(EActivityFilterType.ACTIVITY); - - const filteredActivityComments = activityComments.filter( - (activityComment) => - (activityComment.activity_type === "COMMENT" && isCommentFilterSelected) || - (activityComment.activity_type === "ACTIVITY" && isActivityFilterSelected) - ); + const filteredActivityComments = filterActivityOnSelectedFilters(activityComments, selectedFilters); return (
@@ -60,6 +56,13 @@ export const IssueActivityCommentRoot: FC = observer( activityId={activityComment.id} ends={index === 0 ? "top" : index === filteredActivityComments.length - 1 ? "bottom" : undefined} /> + ) : activityComment.activity_type === "WORKLOG" ? ( + ) : ( <> ) diff --git a/web/core/components/issues/issue-detail/issue-activity/activity-filter.tsx b/web/core/components/issues/issue-detail/issue-activity/activity-filter.tsx index f216d97b3..cecdfa072 100644 --- a/web/core/components/issues/issue-detail/issue-activity/activity-filter.tsx +++ b/web/core/components/issues/issue-detail/issue-activity/activity-filter.tsx @@ -4,14 +4,14 @@ import { Check, ListFilter } from "lucide-react"; import { Popover, Transition } from "@headlessui/react"; // ui import { Button } from "@plane/ui"; -// constants -import { ACTIVITY_FILTER_TYPE_OPTIONS, EActivityFilterType } from "@/constants/issue"; // helper import { cn } from "@/helpers/common.helper"; +// constants +import { TActivityFilters, ACTIVITY_FILTER_TYPE_OPTIONS } from "@/plane-web/constants/issues"; type Props = { - selectedFilters: EActivityFilterType[]; - toggleFilter: (filter: EActivityFilterType) => void; + selectedFilters: TActivityFilters[]; + toggleFilter: (filter: TActivityFilters) => void; }; export const ActivityFilter: FC = observer((props) => { @@ -42,13 +42,15 @@ export const ActivityFilter: FC = observer((props) => { >
- {ACTIVITY_FILTER_TYPE_OPTIONS.map((filter) => { - const isSelected = selectedFilters.includes(filter.value); + {Object.keys(ACTIVITY_FILTER_TYPE_OPTIONS).map((key) => { + const filterKey = key as TActivityFilters; + const filter = ACTIVITY_FILTER_TYPE_OPTIONS[filterKey]; + const isSelected = selectedFilters.includes(filterKey); return (
toggleFilter(filter.value)} + onClick={() => toggleFilter(filterKey)} >
= observer((props) => { const { createComment, updateComment, removeComment } = useIssueDetail(); const { getProjectById } = useProject(); // state - const [selectedFilters, setSelectedFilters] = useState([EActivityFilterType.COMMENT, EActivityFilterType.ACTIVITY]); + const [selectedFilters, setSelectedFilters] = useState([ + EActivityFilterType.ACTIVITY, + EActivityFilterType.COMMENT, + ]); // toggle filter - const toggleFilter = (filter: EActivityFilterType) => { + const toggleFilter = (filter: TActivityFilters) => { setSelectedFilters((prevFilters) => { if (prevFilters.includes(filter)) { if (prevFilters.length === 1) return prevFilters; // Ensure at least one filter is applied @@ -110,7 +116,15 @@ export const IssueActivity: FC = observer((props) => { {/* header */}
Activity
- +
+ + +
{/* rendering activity */} diff --git a/web/core/components/issues/issue-detail/sidebar.tsx b/web/core/components/issues/issue-detail/sidebar.tsx index ba2eaa50c..dec30e597 100644 --- a/web/core/components/issues/issue-detail/sidebar.tsx +++ b/web/core/components/issues/issue-detail/sidebar.tsx @@ -21,6 +21,8 @@ import { getDate, renderFormattedPayloadDate } from "@/helpers/date-time.helper" import { shouldHighlightIssueDueDate } from "@/helpers/issue.helper"; // hooks import { useProjectEstimates, useIssueDetail, useProject, useProjectState, useMember } from "@/hooks/store"; +// plane web components +import { IssueWorklogProperty } from "@/plane-web/components/issues"; // components import type { TIssueOperations } from "./root"; @@ -279,6 +281,13 @@ export const IssueDetailsSidebar: React.FC = observer((props) => { />
+ +
diff --git a/web/core/components/issues/peek-overview/properties.tsx b/web/core/components/issues/peek-overview/properties.tsx index 0812f1a0e..8f9d785c0 100644 --- a/web/core/components/issues/peek-overview/properties.tsx +++ b/web/core/components/issues/peek-overview/properties.tsx @@ -27,6 +27,8 @@ import { cn } from "@/helpers/common.helper"; import { getDate, renderFormattedPayloadDate } from "@/helpers/date-time.helper"; import { shouldHighlightIssueDueDate } from "@/helpers/issue.helper"; import { useIssueDetail, useMember, useProject, useProjectState } from "@/hooks/store"; +// plane web components +import { IssueWorklogProperty } from "@/plane-web/components/issues"; interface IPeekOverviewProperties { workspaceSlug: string; @@ -279,6 +281,13 @@ export const PeekOverviewProperties: FC = observer((pro
+ + ); diff --git a/web/core/components/project/confirm-project-member-remove.tsx b/web/core/components/project/confirm-project-member-remove.tsx index a4a6f3d8e..d4a394e67 100644 --- a/web/core/components/project/confirm-project-member-remove.tsx +++ b/web/core/components/project/confirm-project-member-remove.tsx @@ -14,7 +14,7 @@ import { Button } from "@plane/ui"; import { useProject, useUser } from "@/hooks/store"; type Props = { - data: IUserLite; + data: Partial; onSubmit: () => Promise; isOpen: boolean; onClose: () => void; diff --git a/web/core/components/project/member-list-item.tsx b/web/core/components/project/member-list-item.tsx index 886b0776c..1e3259047 100644 --- a/web/core/components/project/member-list-item.tsx +++ b/web/core/components/project/member-list-item.tsx @@ -80,7 +80,7 @@ export const ProjectMemberListItem: React.FC = observer((props) => { )} member !== null) ?? []} + data={(memberDetails?.filter((member): member is IProjectMemberDetails => member !== null) ?? []) as any} keyExtractor={(rowData) => rowData?.member.id ?? ""} thClassName="text-left font-medium divide-x-0 border-b border-t divide-custom-border-200" tBodyClassName="divide-y-0" diff --git a/web/core/components/workspace/settings/members-list-item.tsx b/web/core/components/workspace/settings/members-list-item.tsx index e877eea59..683b39606 100644 --- a/web/core/components/workspace/settings/members-list-item.tsx +++ b/web/core/components/workspace/settings/members-list-item.tsx @@ -12,7 +12,6 @@ import { WORKSPACE_MEMBER_LEAVE } from "@/constants/event-tracker"; // hooks import { useEventTracker, useMember, useUser } from "@/hooks/store"; import { useAppRouter } from "@/hooks/use-app-router"; -import { usePlatformOS } from "@/hooks/use-platform-os"; import useMemberColumns from "@/plane-web/components/workspace/settings/useMemberColumns"; type Props = { @@ -33,7 +32,6 @@ export const WorkspaceMembersListItem: FC = observer((props) => { workspace: { removeMemberFromWorkspace }, } = useMember(); const { captureEvent } = useEventTracker(); - const { isMobile } = usePlatformOS(); // derived values const handleLeaveWorkspace = async () => { @@ -96,9 +94,10 @@ export const WorkspaceMembersListItem: FC = observer((props) => { )}
member !== null) ?? []} + data={(memberDetails?.filter((member): member is IWorkspaceMember => member !== null) ?? []) as any} keyExtractor={(rowData) => rowData?.member.id ?? ""} - thClassName="text-left font-medium divide-x-0 border-b border-t divide-custom-border-200" + tHeadClassName="border-b border-custom-border-100" + thClassName="text-left font-medium divide-x-0" tBodyClassName="divide-y-0" tBodyTrClassName="divide-x-0" tHeadTrClassName="divide-x-0" diff --git a/web/core/constants/issue.ts b/web/core/constants/issue.ts index fd31350c7..77f94a319 100644 --- a/web/core/constants/issue.ts +++ b/web/core/constants/issue.ts @@ -456,19 +456,3 @@ export const groupReactionEmojis = (reactions: any) => { return groupedEmojis; }; - -export enum EActivityFilterType { - COMMENT = "COMMENT", - ACTIVITY = "ACTIVITY", -} - -export const ACTIVITY_FILTER_TYPE_OPTIONS = [ - { - value: EActivityFilterType.COMMENT, - label: "Comments", - }, - { - value: EActivityFilterType.ACTIVITY, - label: "Updates", - }, -]; \ No newline at end of file diff --git a/web/core/constants/workspace.ts b/web/core/constants/workspace.ts index d5b1bb7b8..7345993f2 100644 --- a/web/core/constants/workspace.ts +++ b/web/core/constants/workspace.ts @@ -1,8 +1,5 @@ // types import { TStaticViewTypes } from "@plane/types"; -// icons -import { SettingIcon } from "@/components/icons/attachment"; -import { Props } from "@/components/icons/types"; // services images import CSVLogo from "@/public/services/csv.svg"; import ExcelLogo from "@/public/services/excel.svg"; @@ -135,61 +132,3 @@ export const RESTRICTED_URLS = [ "spaces", "workspace-invitations", ]; - -export const WORKSPACE_SETTINGS_LINKS: { - key: string; - label: string; - href: string; - access: EUserWorkspaceRoles; - highlight: (pathname: string, baseUrl: string) => boolean; - Icon: React.FC; -}[] = [ - { - key: "general", - label: "General", - href: `/settings`, - access: EUserWorkspaceRoles.GUEST, - highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/`, - Icon: SettingIcon, - }, - { - key: "members", - label: "Members", - href: `/settings/members`, - access: EUserWorkspaceRoles.GUEST, - highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/members/`, - Icon: SettingIcon, - }, - { - key: "billing-and-plans", - label: "Billing and plans", - href: `/settings/billing`, - access: EUserWorkspaceRoles.ADMIN, - highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/billing/`, - Icon: SettingIcon, - }, - { - key: "export", - label: "Exports", - href: `/settings/exports`, - access: EUserWorkspaceRoles.MEMBER, - highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/exports/`, - Icon: SettingIcon, - }, - { - key: "webhooks", - label: "Webhooks", - href: `/settings/webhooks`, - access: EUserWorkspaceRoles.ADMIN, - highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/webhooks/`, - Icon: SettingIcon, - }, - { - key: "api-tokens", - label: "API tokens", - href: `/settings/api-tokens`, - access: EUserWorkspaceRoles.ADMIN, - highlight: (pathname: string, baseUrl: string) => pathname === `${baseUrl}/settings/api-tokens/`, - Icon: SettingIcon, - }, -]; diff --git a/web/ee/components/issues/activity/index.ts b/web/ee/components/issues/activity/index.ts new file mode 100644 index 000000000..6060c4afc --- /dev/null +++ b/web/ee/components/issues/activity/index.ts @@ -0,0 +1,2 @@ +export * from "./root"; +export * from "./worklog-create-button"; diff --git a/web/ee/components/issues/activity/root.tsx b/web/ee/components/issues/activity/root.tsx new file mode 100644 index 000000000..0013dcb4b --- /dev/null +++ b/web/ee/components/issues/activity/root.tsx @@ -0,0 +1 @@ +export * from "@/plane-web/components/issues/worklog/activity/root"; diff --git a/web/ee/components/issues/activity/worklog-create-button.tsx b/web/ee/components/issues/activity/worklog-create-button.tsx new file mode 100644 index 000000000..1e5924433 --- /dev/null +++ b/web/ee/components/issues/activity/worklog-create-button.tsx @@ -0,0 +1 @@ +export * from "@/plane-web/components/issues/worklog/activity/worklog-create-button"; diff --git a/web/ee/components/issues/properties/index.ts b/web/ee/components/issues/properties/index.ts new file mode 100644 index 000000000..1efe34c51 --- /dev/null +++ b/web/ee/components/issues/properties/index.ts @@ -0,0 +1 @@ +export * from "./root"; diff --git a/web/ee/components/issues/properties/root.tsx b/web/ee/components/issues/properties/root.tsx new file mode 100644 index 000000000..eb0553613 --- /dev/null +++ b/web/ee/components/issues/properties/root.tsx @@ -0,0 +1 @@ +export * from "@/plane-web/components/issues/worklog/property/root"; diff --git a/web/ee/constants/issues.ts b/web/ee/constants/issues.ts new file mode 100644 index 000000000..7be9f72e7 --- /dev/null +++ b/web/ee/constants/issues.ts @@ -0,0 +1 @@ +export * from "ce/constants/issues"; diff --git a/web/ee/constants/workspace.ts b/web/ee/constants/workspace.ts new file mode 100644 index 000000000..b295d6e02 --- /dev/null +++ b/web/ee/constants/workspace.ts @@ -0,0 +1 @@ +export * from "ce/constants/workspace"; diff --git a/web/ee/issues/index.ts b/web/ee/issues/index.ts new file mode 100644 index 000000000..1aa924b41 --- /dev/null +++ b/web/ee/issues/index.ts @@ -0,0 +1,2 @@ +export * from "./worklog/activity"; +export * from "./worklog/property"; diff --git a/web/ee/issues/worklog/activity/index.ts b/web/ee/issues/worklog/activity/index.ts new file mode 100644 index 000000000..6060c4afc --- /dev/null +++ b/web/ee/issues/worklog/activity/index.ts @@ -0,0 +1,2 @@ +export * from "./root"; +export * from "./worklog-create-button"; diff --git a/web/ee/issues/worklog/activity/root.tsx b/web/ee/issues/worklog/activity/root.tsx new file mode 100644 index 000000000..0013dcb4b --- /dev/null +++ b/web/ee/issues/worklog/activity/root.tsx @@ -0,0 +1 @@ +export * from "@/plane-web/components/issues/worklog/activity/root"; diff --git a/web/ee/issues/worklog/activity/worklog-create-button.tsx b/web/ee/issues/worklog/activity/worklog-create-button.tsx new file mode 100644 index 000000000..1e5924433 --- /dev/null +++ b/web/ee/issues/worklog/activity/worklog-create-button.tsx @@ -0,0 +1 @@ +export * from "@/plane-web/components/issues/worklog/activity/worklog-create-button"; diff --git a/web/ee/issues/worklog/index.ts b/web/ee/issues/worklog/index.ts new file mode 100644 index 000000000..c0ed33ebf --- /dev/null +++ b/web/ee/issues/worklog/index.ts @@ -0,0 +1,2 @@ +export * from "./property"; +export * from "./activity"; diff --git a/web/ee/issues/worklog/property/index.ts b/web/ee/issues/worklog/property/index.ts new file mode 100644 index 000000000..1efe34c51 --- /dev/null +++ b/web/ee/issues/worklog/property/index.ts @@ -0,0 +1 @@ +export * from "./root"; diff --git a/web/ee/issues/worklog/property/root.tsx b/web/ee/issues/worklog/property/root.tsx new file mode 100644 index 000000000..eb0553613 --- /dev/null +++ b/web/ee/issues/worklog/property/root.tsx @@ -0,0 +1 @@ +export * from "@/plane-web/components/issues/worklog/property/root"; diff --git a/web/helpers/date-time.helper.ts b/web/helpers/date-time.helper.ts index b6ec11655..4053a961c 100644 --- a/web/helpers/date-time.helper.ts +++ b/web/helpers/date-time.helper.ts @@ -299,3 +299,38 @@ export const getCurrentDateTimeInISO = () => { const date = new Date(); return date.toISOString(); }; + +/** + * @description converts hours and minutes to minutes + * @param { number } hours + * @param { number } minutes + * @returns { number } minutes + * @example convertHoursMinutesToMinutes(2, 30) // Output: 150 + */ +export const convertHoursMinutesToMinutes = (hours: number, minutes: number): number => hours * 60 + minutes; + +/** + * @description converts minutes to hours and minutes + * @param { number } mins + * @returns { number, number } hours and minutes + * @example convertMinutesToHoursAndMinutes(150) // Output: { hours: 2, minutes: 30 } + */ +export const convertMinutesToHoursAndMinutes = (mins: number): { hours: number; minutes: number } => { + const hours = Math.floor(mins / 60); + const minutes = Math.floor(mins % 60); + + return { hours: hours, minutes: minutes }; +}; + +/** + * @description converts minutes to days, hours and minutes + * @param { number } totalMinutes + * @returns { string } days, hours and minutes + */ +export const convertMinutesToDaysHoursMinutes = (totalMinutes: number): string => { + const days = Math.floor(totalMinutes / (60 * 24)); + const hours = Math.floor((totalMinutes % (60 * 24)) / 60); + const minutes = totalMinutes % 60; + + return `${days ? `${days}d ` : ``}${hours ? `${hours}h ` : ``}${minutes ? `${minutes}m ` : ``} `; +};