diff --git a/packages/types/src/common.d.ts b/packages/types/src/common.d.ts index 6a8c725a82d..5fe31ad0006 100644 --- a/packages/types/src/common.d.ts +++ b/packages/types/src/common.d.ts @@ -19,5 +19,6 @@ export type TLogoProps = { icon?: { name?: string; color?: string; + background_color?: string; }; }; diff --git a/packages/types/src/issues.d.ts b/packages/types/src/issues.d.ts index 0f2bb8af262..eff81f857b2 100644 --- a/packages/types/src/issues.d.ts +++ b/packages/types/src/issues.d.ts @@ -140,6 +140,7 @@ export interface IIssueActivity { name: string; priority: string | null; sequence_id: string; + type_id: string; } | null; new_identifier: string | null; new_value: string | null; diff --git a/packages/types/src/issues/activity/base.d.ts b/packages/types/src/issues/activity/base.d.ts index 4b3c9ebe868..82b881fd940 100644 --- a/packages/types/src/issues/activity/base.d.ts +++ b/packages/types/src/issues/activity/base.d.ts @@ -60,4 +60,9 @@ export type TIssueActivityComment = id: string; activity_type: "WORKLOG"; created_at?: string; + } + | { + id: string; + activity_type: "ISSUE_ADDITIONAL_PROPERTIES_ACTIVITY"; + created_at?: string; }; diff --git a/packages/types/src/project/projects.d.ts b/packages/types/src/project/projects.d.ts index c53d301c48f..76ea39ded7f 100644 --- a/packages/types/src/project/projects.d.ts +++ b/packages/types/src/project/projects.d.ts @@ -144,4 +144,5 @@ export interface ISearchIssueResponse { state__group: TStateGroups; state__name: string; workspace__slug: string; + type_id: string; } diff --git a/packages/types/src/workspace.d.ts b/packages/types/src/workspace.d.ts index f5cec8eadb4..d70dbcc8132 100644 --- a/packages/types/src/workspace.d.ts +++ b/packages/types/src/workspace.d.ts @@ -118,6 +118,7 @@ export interface IWorkspaceIssueSearchResult { project_id: string; sequence_id: number; workspace__slug: string; + type_id: string; } export interface IWorkspacePageSearchResult { diff --git a/packages/ui/src/emoji/emoji-icon-picker-new.tsx b/packages/ui/src/emoji/emoji-icon-picker-new.tsx index a8651b349e7..41ad6968208 100644 --- a/packages/ui/src/emoji/emoji-icon-picker-new.tsx +++ b/packages/ui/src/emoji/emoji-icon-picker-new.tsx @@ -101,7 +101,7 @@ export const EmojiIconPicker: React.FC = (props) => { type: EmojiIconPickerTypes.EMOJI, value: val, }); - if (closeOnSelect) close(); + if (closeOnSelect) handleToggle(false); }} height="20rem" width="100%" @@ -120,7 +120,7 @@ export const EmojiIconPicker: React.FC = (props) => { type: EmojiIconPickerTypes.ICON, value: val, }); - if (closeOnSelect) close(); + if (closeOnSelect) handleToggle(false); }} /> diff --git a/packages/ui/src/emoji/logo.tsx b/packages/ui/src/emoji/logo.tsx index a2a5dd6abc3..528e1604753 100644 --- a/packages/ui/src/emoji/logo.tsx +++ b/packages/ui/src/emoji/logo.tsx @@ -5,7 +5,6 @@ import useFontFaceObserver from "use-font-face-observer"; import { LUCIDE_ICONS_LIST } from "./icons"; // helpers import { emojiCodeToUnicode } from "./helpers"; -import { cn } from "../../helpers"; type TLogoProps = { in_use: "emoji" | "icon"; @@ -23,11 +22,10 @@ type Props = { logo: TLogoProps; size?: number; type?: "lucide" | "material"; - customColor?: string; }; export const Logo: FC = (props) => { - const { logo, size = 16, customColor, type = "material" } = props; + const { logo, size = 16, type = "material" } = props; // destructuring the logo object const { in_use, emoji, icon } = logo; @@ -74,20 +72,19 @@ export const Logo: FC = (props) => { {lucideIcon && ( )} ) : ( diff --git a/packages/ui/src/sortable/sortable.tsx b/packages/ui/src/sortable/sortable.tsx index 93603d173f5..b437f1df1cf 100644 --- a/packages/ui/src/sortable/sortable.tsx +++ b/packages/ui/src/sortable/sortable.tsx @@ -2,8 +2,10 @@ import React, { Fragment, useEffect, useMemo } from "react"; import { monitorForElements } from "@atlaskit/pragmatic-drag-and-drop/element/adapter"; import { Draggable } from "./draggable"; +type TEnhancedData = T & { __uuid__?: string }; + type Props = { - data: T[]; + data: TEnhancedData[]; render: (item: T, index: number) => React.ReactNode; onChange: (data: T[], movedItem?: T) => void; keyExtractor: (item: T, index: number) => string; @@ -12,9 +14,9 @@ type Props = { }; const moveItem = ( - data: T[], - source: T, - destination: T & Record, + data: TEnhancedData[], + source: TEnhancedData, + destination: TEnhancedData & Record, keyExtractor: (item: T, index: number) => string ): { newData: T[]; @@ -44,7 +46,16 @@ const moveItem = ( newData.splice(adjustedDestinationIndex, 0, movedItem); - return { newData, movedItem }; + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { __uuid__: movedItemId, ...movedItemData } = movedItem; + return { + newData: newData.map((item) => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { __uuid__: uuid, ...rest } = item; + return rest as T; + }), + movedItem: movedItemData as T, + }; }; export const Sortable = ({ data, render, onChange, keyExtractor, containerClassName, id }: Props) => { @@ -55,8 +66,8 @@ export const Sortable = ({ data, render, onChange, keyExtractor, containerCl if (!destination) return; const { newData, movedItem } = moveItem( data, - source.data as T, - destination.data as T & { closestEdge: string }, + source.data as TEnhancedData, + destination.data as TEnhancedData & { closestEdge: string }, keyExtractor ); onChange(newData, movedItem); @@ -76,9 +87,13 @@ export const Sortable = ({ data, render, onChange, keyExtractor, containerCl return ( <> - {enhancedData.map((item, index) => ( - - {render(item, index)} + {data.map((item, index) => ( + + {render(item, index)} ))} diff --git a/web/ce/components/issues/issue-details/index.ts b/web/ce/components/issues/issue-details/index.ts index 36386e658f8..a465ed4b3b5 100644 --- a/web/ce/components/issues/issue-details/index.ts +++ b/web/ce/components/issues/issue-details/index.ts @@ -1 +1,2 @@ export * from "./issue-identifier"; +export * from "./issue-properties-activity"; diff --git a/web/ce/components/issues/issue-details/issue-identifier.tsx b/web/ce/components/issues/issue-details/issue-identifier.tsx index 8b32a8d3218..019acbac575 100644 --- a/web/ce/components/issues/issue-details/issue-identifier.tsx +++ b/web/ce/components/issues/issue-details/issue-identifier.tsx @@ -1,27 +1,44 @@ import { observer } from "mobx-react"; +// helpers +import { cn } from "@/helpers/common.helper"; // hooks import { useIssueDetail, useProject } from "@/hooks/store"; -type TIssueIdentifierProps = { - issueId: string; +type TIssueIdentifierBaseProps = { projectId: string; + size?: "xs" | "sm" | "md" | "lg"; + textContainerClassName?: string; +}; + +type TIssueIdentifierFromStore = TIssueIdentifierBaseProps & { + issueId: string; +}; + +type TIssueIdentifierWithDetails = TIssueIdentifierBaseProps & { + issueTypeId?: string | null; + projectIdentifier: string; + issueSequenceId: string | number; }; +type TIssueIdentifierProps = TIssueIdentifierFromStore | TIssueIdentifierWithDetails; export const IssueIdentifier: React.FC = observer((props) => { - const { issueId, projectId } = props; + const { projectId, textContainerClassName } = props; // store hooks - const { getProjectById } = useProject(); + const { getProjectIdentifierById } = useProject(); const { issue: { getIssueById }, } = useIssueDetail(); + // Determine if the component is using store data or not + const isUsingStoreData = "issueId" in props; // derived values - const issue = getIssueById(issueId); - const projectDetails = getProjectById(projectId); + const issue = isUsingStoreData ? getIssueById(props.issueId) : null; + const projectIdentifier = isUsingStoreData ? getProjectIdentifierById(projectId) : props.projectIdentifier; + const issueSequenceId = isUsingStoreData ? issue?.sequence_id : props.issueSequenceId; return (
- - {projectDetails?.identifier}-{issue?.sequence_id} + + {projectIdentifier}-{issueSequenceId}
); diff --git a/web/ce/components/issues/issue-details/issue-properties-activity/index.ts b/web/ce/components/issues/issue-details/issue-properties-activity/index.ts new file mode 100644 index 00000000000..1efe34c51ec --- /dev/null +++ b/web/ce/components/issues/issue-details/issue-properties-activity/index.ts @@ -0,0 +1 @@ +export * from "./root"; diff --git a/web/ce/components/issues/issue-details/issue-properties-activity/root.tsx b/web/ce/components/issues/issue-details/issue-properties-activity/root.tsx new file mode 100644 index 00000000000..cac7556764e --- /dev/null +++ b/web/ce/components/issues/issue-details/issue-properties-activity/root.tsx @@ -0,0 +1,8 @@ +import { FC } from "react"; + +type TIssueAdditionalPropertiesActivity = { + activityId: string; + ends: "top" | "bottom" | undefined; +}; + +export const IssueAdditionalPropertiesActivity: FC = () => <>; diff --git a/web/core/components/command-palette/command-modal.tsx b/web/core/components/command-palette/command-modal.tsx index f0c779c55a5..e7b65b44903 100644 --- a/web/core/components/command-palette/command-modal.tsx +++ b/web/core/components/command-palette/command-modal.tsx @@ -7,10 +7,11 @@ import { useParams } from "next/navigation"; import useSWR from "swr"; import { FolderPlus, Search, Settings } from "lucide-react"; import { Dialog, Transition } from "@headlessui/react"; -// icons +// types import { IWorkspaceSearchResults } from "@plane/types"; -// hooks +// ui import { LayersIcon, Loader, ToggleSwitch, Tooltip } from "@plane/ui"; +// components import { ChangeIssueAssignee, ChangeIssuePriority, @@ -23,28 +24,28 @@ import { CommandPaletteWorkspaceSettingsActions, } from "@/components/command-palette"; import { EmptyState } from "@/components/empty-state"; +// constants import { EmptyStateType } from "@/constants/empty-state"; +// fetch-keys import { ISSUE_DETAILS } from "@/constants/fetch-keys"; +// hooks import { useCommandPalette, useEventTracker, useProject, useUser } from "@/hooks/store"; import { useAppRouter } from "@/hooks/use-app-router"; import useDebounce from "@/hooks/use-debounce"; import { usePlatformOS } from "@/hooks/use-platform-os"; -// services +// plane web components +import { IssueIdentifier } from "@/plane-web/components/issues"; +// plane web services import { WorkspaceService } from "@/plane-web/services"; +// services import { IssueService } from "@/services/issue"; -// ui -// components -// types -// fetch-keys -// constants - const workspaceService = new WorkspaceService(); const issueService = new IssueService(); export const CommandModal: React.FC = observer(() => { // hooks - const { getProjectById, workspaceProjectIds } = useProject(); + const { workspaceProjectIds } = useProject(); const { isMobile } = usePlatformOS(); const { canPerformAnyCreateAction } = useUser(); // states @@ -141,8 +142,6 @@ export const CommandModal: React.FC = observer(() => { [debouncedSearchTerm, isWorkspaceLevel, projectId, workspaceSlug] // Only call effect if debounced search term changes ); - const projectDetails = getProjectById(issueDetails?.project_id ?? ""); - return ( setSearchTerm("")} as={React.Fragment}> closePalette()}> @@ -198,8 +197,15 @@ export const CommandModal: React.FC = observer(() => { }`} > {issueDetails && ( -
- {projectDetails?.identifier}-{issueDetails.sequence_id} {issueDetails.name} +
+ {issueDetails.project_id && ( + + )} + {issueDetails.name}
)} {projectId && ( diff --git a/web/core/components/command-palette/helpers.tsx b/web/core/components/command-palette/helpers.tsx index cc3e80bb7ca..99c8c310e43 100644 --- a/web/core/components/command-palette/helpers.tsx +++ b/web/core/components/command-palette/helpers.tsx @@ -9,11 +9,14 @@ import { IWorkspaceProjectSearchResult, IWorkspaceSearchResult, } from "@plane/types"; -import { ContrastIcon, DiceIcon, LayersIcon } from "@plane/ui"; +// ui +import { ContrastIcon, DiceIcon } from "@plane/ui"; +// plane web components +import { IssueIdentifier } from "@/plane-web/components/issues"; export const commandGroups: { [key: string]: { - icon: JSX.Element; + icon: JSX.Element | null; itemName: (item: any) => React.ReactNode; path: (item: any, projectId: string | undefined) => string; title: string; @@ -31,14 +34,18 @@ export const commandGroups: { title: "Cycles", }, issue: { - icon: , + icon: null, itemName: (issue: IWorkspaceIssueSearchResult) => ( -
- - {issue.project__identifier}-{issue.sequence_id} - {" "} +
+ {" "} {issue.name} -
+
), path: (issue: IWorkspaceIssueSearchResult) => `/${issue?.workspace__slug}/projects/${issue?.project_id}/issues/${issue?.id}`, diff --git a/web/core/components/core/activity.tsx b/web/core/components/core/activity.tsx index 94273f4a9a3..9a06b336b4f 100644 --- a/web/core/components/core/activity.tsx +++ b/web/core/components/core/activity.tsx @@ -165,7 +165,7 @@ const activityDetails: { ); }, - icon: