Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2023-12 #52

Merged
merged 10 commits into from
Jan 7, 2024
9 changes: 9 additions & 0 deletions packages/example-app/src/ForwardRefPatch.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from "react";

// Redeclare forwardRef to fix the generic type removal problem.
// See more: https://fettblog.eu/typescript-react-generic-forward-refs/#option-3%3A-augment-forwardref
declare module "react" {
function forwardRef<T, P = {}>(
render: (props: P, ref: React.Ref<T>) => React.ReactElement | null
): (props: P & React.RefAttributes<T>) => React.ReactElement | null;
}
44 changes: 44 additions & 0 deletions packages/example-app/src/StatusBar/BranchPopupTrigger.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import {
ActionTooltip,
PlatformIcon,
StatusBarWidget,
TooltipTrigger,
} from "@intellij-platform/core";
import React from "react";

import { activeFileRepoHeadState } from "../VersionControl/active-file.state";
import { useLatestRecoilValue } from "../recoil-utils";

export function BranchPopupTrigger() {
const gitRepoHead = useLatestRecoilValue(activeFileRepoHeadState);

return (
gitRepoHead && (
<TooltipTrigger
tooltip={
<ActionTooltip
actionName={
gitRepoHead.detached
? "Git: Detached HEAD doesn't point to any branch"
: `Git Branch: ${gitRepoHead.head}`
}
/>
}
>
<StatusBarWidget
icon={
<PlatformIcon
icon={
gitRepoHead.detached ? "general/warning.svg" : "vcs/branch.svg"
}
/>
}
label={gitRepoHead.head.slice(
0,
gitRepoHead.detached ? 8 : undefined
)}
/>
</TooltipTrigger>
)
);
}
11 changes: 11 additions & 0 deletions packages/example-app/src/StatusBar/IdeStatusBar.state.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { atom } from "recoil";
import { Bounds } from "@intellij-platform/core";

export const showProgressPanelState = atom({
key: "ide.statusbar.showProgressPanel",
default: false,
});
export const tasksPopupBoundsState = atom<Bounds | null>({
key: "ide.statusbar.tasksPopup",
default: null,
});
107 changes: 4 additions & 103 deletions packages/example-app/src/StatusBar/IdeStatusBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,93 +2,28 @@ import React from "react";
import { useRecoilValue } from "recoil";
import styled from "styled-components";
import {
ActionTooltip,
Divider,
Item,
Link,
Menu,
MenuItemLayout,
MenuTrigger,
PlatformIcon,
PopupTrigger,
ProgressBar,
ProgressBarProps,
ProgressBarStopButton,
StatusBar,
StatusBarWidget,
TooltipTrigger,
} from "@intellij-platform/core";

import { editorCursorPositionState } from "../Editor/editor.state";
import { BranchesPopup } from "../VersionControl/Branches/BranchesPopup";
import { activeFileRepoHeadState } from "../VersionControl/active-file.state";
import { notImplemented } from "../Project/notImplemented";
import { useLatestRecoilValue } from "../recoil-utils";
import { firstTaskState, taskCountState, useCancelTask } from "../tasks";
import { useShowGitTipIfNeeded } from "../VersionControl/useShowGitTipIfNeeded";
import { StatusBarTaskProgressBar } from "./StatusBarTaskProgressBar";
import { BranchPopupTrigger } from "./BranchPopupTrigger";

const StyledLastMessage = styled.div`
margin-left: 0.75rem;
cursor: pointer;
`;

function StatusBarProgress(
props: Omit<ProgressBarProps, "dense" | "namePosition" | "width">
) {
return <ProgressBar dense namePosition="side" width={146} {...props} />;
}

const Spacer = styled.span`
width: 0.5rem;
`;

/**
* Intentionally, "processes" haven't been abstracted as an extension point for different features, since the focus
* here is not to create an IDE, but to demo UI components.
*/
const StatusBarProcess = () => {
const firstTask = useRecoilValue(firstTaskState);
const tasksCount = useRecoilValue(taskCountState);
const cancel = useCancelTask();

return (
<>
{firstTask && (
<StatusBarProgress
name={firstTask.progress.text || firstTask.title}
isIndeterminate={firstTask.progress.isIndeterminate}
value={firstTask.progress.fraction}
maxValue={1}
button={
<>
{/*
{task.canPause && (
<ProgressBarPauseButton
small
paused={false}
onPausedChange={() => {}}
/>
)}
*/}
{firstTask.isCancelable && (
<ProgressBarStopButton
small
onPress={() => cancel(firstTask.id)}
/>
)}
</>
}
/>
)}
{tasksCount > 1 && (
<>
<Spacer />
<Link onPress={notImplemented}>Show all ({tasksCount})</Link>
</>
)}
</>
);
};

export const IdeStatusBar = () => {
const cursorPosition = useRecoilValue(editorCursorPositionState);
const maybeShowGitCloneTip = useShowGitTipIfNeeded();
Expand All @@ -109,7 +44,7 @@ export const IdeStatusBar = () => {
}
right={
<>
{<StatusBarProcess />}
{<StatusBarTaskProgressBar />}
<StatusBarWidget onPress={notImplemented} label="LF" />
<StatusBarWidget
onPress={notImplemented}
Expand Down Expand Up @@ -176,37 +111,3 @@ export const IdeStatusBar = () => {
/>
);
};

function BranchPopupTrigger() {
const gitRepoHead = useLatestRecoilValue(activeFileRepoHeadState);

return (
gitRepoHead && (
<TooltipTrigger
tooltip={
<ActionTooltip
actionName={
gitRepoHead.detached
? "Git: Detached HEAD doesn't point to any branch"
: `Git Branch: ${gitRepoHead.head}`
}
/>
}
>
<StatusBarWidget
icon={
<PlatformIcon
icon={
gitRepoHead.detached ? "general/warning.svg" : "vcs/branch.svg"
}
/>
}
label={gitRepoHead.head.slice(
0,
gitRepoHead.detached ? 8 : undefined
)}
/>
</TooltipTrigger>
)
);
}
111 changes: 111 additions & 0 deletions packages/example-app/src/StatusBar/StatusBarTaskProgressBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import styled from "styled-components";
import {
BareButton,
Link,
ProgressBar,
ProgressBarProps,
ProgressBarStopButton,
Tooltip,
TooltipTrigger,
} from "@intellij-platform/core";
import { useRecoilState, useRecoilValue } from "recoil";
import { firstTaskState, taskCountState, useCancelTask } from "../tasks";
import { showProgressPanelState } from "./IdeStatusBar.state";
import React, { useEffect } from "react";
import { TasksPopup } from "./TasksPopup";

function StatusBarProgress(
props: Omit<ProgressBarProps, "dense" | "namePosition" | "width">
) {
return <ProgressBar dense namePosition="side" width={146} {...props} />;
}

const Spacer = styled.span`
width: 0.5rem;
`;
const StyledProgressBarButton = styled.span`
cursor: pointer;

${ProgressBar.Container} {
cursor: unset;
}
`;
/**
* Intentionally, "processes" haven't been abstracted as an extension point for different features, since the focus
* here is not to create an IDE, but to demo UI components.
*/
export const StatusBarTaskProgressBar = () => {
const firstTask = useRecoilValue(firstTaskState);
const tasksCount = useRecoilValue(taskCountState);
const cancel = useCancelTask();
const [showProgressPanel, setShowProgressPanel] = useRecoilState(
showProgressPanelState
);

// When there is no tasks, switch back to not showing the panel.
useEffect(() => {
if (tasksCount === 0) {
setShowProgressPanel(false);
}
}, [tasksCount]);

return (
<>
{firstTask && !showProgressPanel && (
<TooltipTrigger
tooltip={
<Tooltip>{`${firstTask.title}. Click to see all running background tasks.`}</Tooltip>
}
>
<BareButton
preventFocusOnPress
onPress={() => {
setShowProgressPanel(true);
}}
>
<StyledProgressBarButton>
<StatusBarProgress
name={firstTask.progress.text || firstTask.title}
isIndeterminate={firstTask.progress.isIndeterminate}
value={firstTask.progress.fraction}
maxValue={1}
button={
<>
{/* {task.canPause && (
<ProgressBarPauseButton
small
paused={false}
onPausedChange={() => {}}
/>
)}*/}
{firstTask.isCancelable && (
<TooltipTrigger tooltip={<Tooltip>Cancel</Tooltip>}>
<ProgressBarStopButton
small
onPress={() => cancel(firstTask.id)}
/>
</TooltipTrigger>
)}
</>
}
/>
</StyledProgressBarButton>
</BareButton>
</TooltipTrigger>
)}
{(tasksCount > 1 || showProgressPanel) && (
<>
<Spacer />
<Link
onPress={() =>
setShowProgressPanel((currentValue) => !currentValue)
}
>
{showProgressPanel ? "Hide processes" : "Show all"} ({tasksCount})
</Link>
</>
)}
{showProgressPanel && tasksCount > 0 && <TasksPopup />}
</>
);
};
Loading