From 664dbffd446effb71ebacf48d6d20c2555a5d4aa Mon Sep 17 00:00:00 2001 From: "chengzhe.lcz" Date: Tue, 21 Jan 2025 17:36:53 +0800 Subject: [PATCH 01/12] feat: layout service add moveContainerTo api --- .../ai-native/src/browser/layout/tabbar.view.tsx | 16 +++++++++------- .../main-layout/src/browser/layout.service.ts | 14 ++++++++++++++ .../src/browser/tabbar/tabbar.service.ts | 13 +++++++++++++ .../src/common/main-layout.definition.ts | 1 + .../src/browser/component/terminal.module.less | 6 ++++++ .../src/browser/component/terminal.widget.tsx | 11 ++++++++--- 6 files changed, 51 insertions(+), 10 deletions(-) diff --git a/packages/ai-native/src/browser/layout/tabbar.view.tsx b/packages/ai-native/src/browser/layout/tabbar.view.tsx index 46b26c504f..3c4cdf3da0 100644 --- a/packages/ai-native/src/browser/layout/tabbar.view.tsx +++ b/packages/ai-native/src/browser/layout/tabbar.view.tsx @@ -176,14 +176,16 @@ export const AIRightTabRenderer = ({ {...props} renderContainerWrap={({ children }) => (
-
- {options && options.title} -
- - - + {!options?.titleComponent && ( +
+ {options && options.title} +
+ + + +
-
+ )}
{children}
)} diff --git a/packages/main-layout/src/browser/layout.service.ts b/packages/main-layout/src/browser/layout.service.ts index efecee634a..c508a99d60 100644 --- a/packages/main-layout/src/browser/layout.service.ts +++ b/packages/main-layout/src/browser/layout.service.ts @@ -224,6 +224,20 @@ export class LayoutService extends WithEventBus implements IMainLayoutService { } }; + moveContainerTo(containerId: string, from: string, to: string): void { + const fromTabbar = this.getTabbarService(from); + const toTabbar = this.getTabbarService(to); + const container = fromTabbar.getContainer(containerId); + if (!container) { + throw new Error(`container: ${containerId} does not exist on tabbar: ${from}`); + } + fromTabbar.removeContainer(containerId); + if (!fromTabbar.visibleContainers.length || fromTabbar.currentContainerId.get() === containerId) { + this.toggleSlot(from, false); + } + toTabbar.dynamicAddContainer(containerId, container); + } + isVisible(location: string) { const tabbarService = this.getTabbarService(location); return !!tabbarService.currentContainerId.get(); diff --git a/packages/main-layout/src/browser/tabbar/tabbar.service.ts b/packages/main-layout/src/browser/tabbar/tabbar.service.ts index f58ad4fdc7..1edb53001a 100644 --- a/packages/main-layout/src/browser/tabbar/tabbar.service.ts +++ b/packages/main-layout/src/browser/tabbar/tabbar.service.ts @@ -691,6 +691,19 @@ export class TabbarService extends WithEventBus { }); } + removeContainer(containerId: string) { + const disposable = this.disposableMap.get(containerId); + disposable?.dispose(); + this.updateCurrentContainerId(''); + this.doChangeViewEmitter.fire(); + } + + dynamicAddContainer(containerId: string, options: ComponentRegistryInfo) { + this.registerContainer(containerId, options); + this.updateCurrentContainerId(containerId); + this.doChangeViewEmitter.fire(); + } + protected doInsertTab(containers: ComponentRegistryInfo[], sourceIndex: number, targetIndex: number) { const targetPriority = this.getContainerState(containers[targetIndex].options!.containerId).priority; const changePriority = (sourceIndex: number, targetIndex: number) => { diff --git a/packages/main-layout/src/common/main-layout.definition.ts b/packages/main-layout/src/common/main-layout.definition.ts index a8c7551120..11b5cb6f92 100644 --- a/packages/main-layout/src/common/main-layout.definition.ts +++ b/packages/main-layout/src/common/main-layout.definition.ts @@ -86,6 +86,7 @@ export interface IMainLayoutService { getExtraTopMenu(): IContextMenu; getExtraMenu(): IContextMenu; getAllAccordionService(): Map; + moveContainerTo(containerId: string, from: string, to: string): void; } export const MainLayoutContribution = Symbol('MainLayoutContribution'); diff --git a/packages/terminal-next/src/browser/component/terminal.module.less b/packages/terminal-next/src/browser/component/terminal.module.less index 8de088bceb..6747e5e08f 100644 --- a/packages/terminal-next/src/browser/component/terminal.module.less +++ b/packages/terminal-next/src/browser/component/terminal.module.less @@ -39,6 +39,11 @@ width: 100%; } +.terminalContentWrapper { + height: 100%; + width: 100%; +} + .terminalSearch { display: flex; justify-content: center; @@ -62,6 +67,7 @@ border-color: var(--focusBorder); } } + .closeBtn { padding: 0px 6px; cursor: pointer; diff --git a/packages/terminal-next/src/browser/component/terminal.widget.tsx b/packages/terminal-next/src/browser/component/terminal.widget.tsx index 27d67eb480..5821f7072b 100644 --- a/packages/terminal-next/src/browser/component/terminal.widget.tsx +++ b/packages/terminal-next/src/browser/component/terminal.widget.tsx @@ -68,8 +68,13 @@ export default ({ widget, error, show }: IProps) => { const view = useInjectable(ITerminalGroupViewService); React.useEffect(() => { - if (content.current) { - widget.element = content.current; + if (content.current && widget.element) { + content.current.appendChild(widget.element); + } else if (content.current && !widget.element) { + const ele = document.createElement('div'); + content.current.appendChild(ele); + ele.className = styles.terminalContent; + widget.element = ele; } }, []); @@ -91,7 +96,7 @@ export default ({ widget, error, show }: IProps) => {
From 01a1af2e3ad142ff2baaff81c858542f07e01e2e Mon Sep 17 00:00:00 2001 From: "chengzhe.lcz" Date: Wed, 22 Jan 2025 10:56:00 +0800 Subject: [PATCH 02/12] chore: need right container to move to show --- packages/ai-native/src/browser/DropRight.tsx | 3 +++ packages/ai-native/src/browser/ai-core.contribution.ts | 5 +++++ packages/main-layout/src/browser/default-config.ts | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 packages/ai-native/src/browser/DropRight.tsx diff --git a/packages/ai-native/src/browser/DropRight.tsx b/packages/ai-native/src/browser/DropRight.tsx new file mode 100644 index 0000000000..580b320df3 --- /dev/null +++ b/packages/ai-native/src/browser/DropRight.tsx @@ -0,0 +1,3 @@ +import React from 'react'; + +export const DropRight = () =>
drop here
; diff --git a/packages/ai-native/src/browser/ai-core.contribution.ts b/packages/ai-native/src/browser/ai-core.contribution.ts index 21faba52ec..efcc855463 100644 --- a/packages/ai-native/src/browser/ai-core.contribution.ts +++ b/packages/ai-native/src/browser/ai-core.contribution.ts @@ -82,6 +82,7 @@ import { IntelligentCompletionsController } from './contrib/intelligent-completi import { ProblemFixController } from './contrib/problem-fix/problem-fix.controller'; import { RenameSingleHandler } from './contrib/rename/rename.handler'; import { AIRunToolbar } from './contrib/run-toolbar/run-toolbar'; +import { DropRight } from './DropRight'; import { AIChatTabRenderer, AIChatTabRendererWithTab, @@ -493,6 +494,10 @@ export class AINativeBrowserContribution id: AI_CHAT_LOGO_AVATAR_ID, component: AIChatLogoAvatar, }); + registry.register('drop-right', [], { + component: DropRight, + containerId: 'drop-right', + }); } registerKeybindings(keybindings: KeybindingRegistry): void { diff --git a/packages/main-layout/src/browser/default-config.ts b/packages/main-layout/src/browser/default-config.ts index b26b9e0ae9..77c20aa3ab 100644 --- a/packages/main-layout/src/browser/default-config.ts +++ b/packages/main-layout/src/browser/default-config.ts @@ -19,7 +19,7 @@ export const defaultConfig: LayoutConfig = { ], }, [SlotLocation.right]: { - modules: [], + modules: ['drop-right'], }, [SlotLocation.main]: { modules: ['@opensumi/ide-editor'], From 91a86cc3c9693a14476d1e99d25a036dcc57308d Mon Sep 17 00:00:00 2001 From: "chengzhe.lcz" Date: Wed, 22 Jan 2025 16:52:14 +0800 Subject: [PATCH 03/12] feat: register drop area in main-layout pkg --- packages/ai-native/src/browser/DropRight.tsx | 3 -- .../src/browser/ai-core.contribution.ts | 5 -- .../main-layout/src/browser/default-config.ts | 8 +++- .../src/browser/drop-area/drop-area.tsx | 34 +++++++++++++ .../src/browser/drop-area/styles.module.less | 7 +++ .../main-layout/src/browser/layout.service.ts | 48 +++++++++++++++++-- .../src/browser/main-layout.contribution.ts | 22 ++++++++- .../src/common/main-layout.definition.ts | 4 +- 8 files changed, 115 insertions(+), 16 deletions(-) delete mode 100644 packages/ai-native/src/browser/DropRight.tsx create mode 100644 packages/main-layout/src/browser/drop-area/drop-area.tsx create mode 100644 packages/main-layout/src/browser/drop-area/styles.module.less diff --git a/packages/ai-native/src/browser/DropRight.tsx b/packages/ai-native/src/browser/DropRight.tsx deleted file mode 100644 index 580b320df3..0000000000 --- a/packages/ai-native/src/browser/DropRight.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import React from 'react'; - -export const DropRight = () =>
drop here
; diff --git a/packages/ai-native/src/browser/ai-core.contribution.ts b/packages/ai-native/src/browser/ai-core.contribution.ts index efcc855463..21faba52ec 100644 --- a/packages/ai-native/src/browser/ai-core.contribution.ts +++ b/packages/ai-native/src/browser/ai-core.contribution.ts @@ -82,7 +82,6 @@ import { IntelligentCompletionsController } from './contrib/intelligent-completi import { ProblemFixController } from './contrib/problem-fix/problem-fix.controller'; import { RenameSingleHandler } from './contrib/rename/rename.handler'; import { AIRunToolbar } from './contrib/run-toolbar/run-toolbar'; -import { DropRight } from './DropRight'; import { AIChatTabRenderer, AIChatTabRendererWithTab, @@ -494,10 +493,6 @@ export class AINativeBrowserContribution id: AI_CHAT_LOGO_AVATAR_ID, component: AIChatLogoAvatar, }); - registry.register('drop-right', [], { - component: DropRight, - containerId: 'drop-right', - }); } registerKeybindings(keybindings: KeybindingRegistry): void { diff --git a/packages/main-layout/src/browser/default-config.ts b/packages/main-layout/src/browser/default-config.ts index 77c20aa3ab..cb749c62df 100644 --- a/packages/main-layout/src/browser/default-config.ts +++ b/packages/main-layout/src/browser/default-config.ts @@ -25,7 +25,13 @@ export const defaultConfig: LayoutConfig = { modules: ['@opensumi/ide-editor'], }, [SlotLocation.bottom]: { - modules: ['@opensumi/ide-terminal-next', '@opensumi/ide-output', 'debug-console', '@opensumi/ide-markers'], + modules: [ + 'drop-bottom', + '@opensumi/ide-terminal-next', + '@opensumi/ide-output', + 'debug-console', + '@opensumi/ide-markers', + ], }, [SlotLocation.statusBar]: { modules: ['@opensumi/ide-status-bar'], diff --git a/packages/main-layout/src/browser/drop-area/drop-area.tsx b/packages/main-layout/src/browser/drop-area/drop-area.tsx new file mode 100644 index 0000000000..aca8b436f1 --- /dev/null +++ b/packages/main-layout/src/browser/drop-area/drop-area.tsx @@ -0,0 +1,34 @@ +import React from 'react'; + +import { useInjectable } from '@opensumi/ide-core-browser'; +import { IMainLayoutService } from '@opensumi/ide-main-layout'; + +import styles from './styles.module.less'; + +interface IDropAreaProps { + location: string; +} + +const DropArea: React.FC = (props) => { + const { location } = props; + const layoutService = useInjectable(IMainLayoutService); + + return ( +
{ + const containerId = e.dataTransfer?.getData('containerId'); + layoutService.moveContainerTo(containerId, location); + }} + onDragOver={(e) => { + e.preventDefault(); + }} + > + drop here +
+ ); +}; + +export const RightDropArea = () => ; + +export const BottomDropArea = () => ; diff --git a/packages/main-layout/src/browser/drop-area/styles.module.less b/packages/main-layout/src/browser/drop-area/styles.module.less new file mode 100644 index 0000000000..e6c4b88c00 --- /dev/null +++ b/packages/main-layout/src/browser/drop-area/styles.module.less @@ -0,0 +1,7 @@ +.drop_area { + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; +} diff --git a/packages/main-layout/src/browser/layout.service.ts b/packages/main-layout/src/browser/layout.service.ts index c508a99d60..d74f42d7dc 100644 --- a/packages/main-layout/src/browser/layout.service.ts +++ b/packages/main-layout/src/browser/layout.service.ts @@ -224,20 +224,58 @@ export class LayoutService extends WithEventBus implements IMainLayoutService { } }; - moveContainerTo(containerId: string, from: string, to: string): void { - const fromTabbar = this.getTabbarService(from); - const toTabbar = this.getTabbarService(to); + findTabbarServiceByContainerId(containerId: string): TabbarService | undefined { + let tabbarService: undefined | TabbarService; + for (const [key, value] of this.tabbarServices.entries()) { + if (value.containersMap.has(containerId)) { + tabbarService = value; + break; + } + } + + return tabbarService; + } + + moveContainerTo(containerId: string, to: string): void { + const fromTabbar = this.findTabbarServiceByContainerId(containerId); + + if (!fromTabbar) { + this.logger.error(`cannot find container: ${containerId}`); + return; + } const container = fromTabbar.getContainer(containerId); if (!container) { - throw new Error(`container: ${containerId} does not exist on tabbar: ${from}`); + this.logger.error(`cannot find container: ${containerId}`); + return; } + + const toTabbar = this.getTabbarService(to); + fromTabbar.removeContainer(containerId); if (!fromTabbar.visibleContainers.length || fromTabbar.currentContainerId.get() === containerId) { - this.toggleSlot(from, false); + this.toggleSlot(fromTabbar.location, false); } toTabbar.dynamicAddContainer(containerId, container); } + handleDragContainerStart(containerId: string): void { + const tabbarService = this.findTabbarServiceByContainerId(containerId); + const bottomService = this.tabbarServices.get('bottom'); + const rightService = this.tabbarServices.get('right'); + if (!tabbarService) { + this.logger.error(`cannot find container: ${containerId}`); + return; + } + if (tabbarService?.location === 'right') { + bottomService?.updateCurrentContainerId('drop-bottom'); + this.toggleSlot('bottom', true); + } + if (tabbarService?.location === 'bottom') { + rightService?.updateCurrentContainerId('drop-right'); + this.toggleSlot('right', true); + } + } + isVisible(location: string) { const tabbarService = this.getTabbarService(location); return !!tabbarService.currentContainerId.get(); diff --git a/packages/main-layout/src/browser/main-layout.contribution.ts b/packages/main-layout/src/browser/main-layout.contribution.ts index 32eb92faf3..de70d75152 100644 --- a/packages/main-layout/src/browser/main-layout.contribution.ts +++ b/packages/main-layout/src/browser/main-layout.contribution.ts @@ -43,6 +43,7 @@ import { Command, CommandContribution, CommandRegistry, CommandService } from '@ import { IMainLayoutService } from '../common'; +import { BottomDropArea, RightDropArea } from './drop-area/drop-area'; import { ViewQuickOpenHandler } from './quick-open-view'; import { BottomTabRenderer, LeftTabRenderer, RightTabRenderer } from './tabbar/renderer.view'; @@ -117,7 +118,14 @@ export const RETRACT_BOTTOM_PANEL: Command = { iconClass: getIcon('shrink'), }; -@Domain(CommandContribution, ClientAppContribution, SlotRendererContribution, MenuContribution, QuickOpenContribution) +@Domain( + CommandContribution, + ClientAppContribution, + SlotRendererContribution, + MenuContribution, + QuickOpenContribution, + ComponentContribution, +) export class MainLayoutModuleContribution extends WithEventBus implements @@ -125,6 +133,7 @@ export class MainLayoutModuleContribution ClientAppContribution, SlotRendererContribution, MenuContribution, + ComponentContribution, QuickOpenContribution { @Autowired(IMainLayoutService) @@ -186,6 +195,17 @@ export class MainLayoutModuleContribution } } + registerComponent(registry: ComponentRegistry): void { + registry.register('drop-right', [], { + component: RightDropArea, + containerId: 'drop-right', + }); + registry.register('drop-bottom', [], { + component: BottomDropArea, + containerId: 'drop-bottom', + }); + } + async onStart() { this.registerSideToggleKey(); } diff --git a/packages/main-layout/src/common/main-layout.definition.ts b/packages/main-layout/src/common/main-layout.definition.ts index 11b5cb6f92..d5b8a88e37 100644 --- a/packages/main-layout/src/common/main-layout.definition.ts +++ b/packages/main-layout/src/common/main-layout.definition.ts @@ -86,7 +86,9 @@ export interface IMainLayoutService { getExtraTopMenu(): IContextMenu; getExtraMenu(): IContextMenu; getAllAccordionService(): Map; - moveContainerTo(containerId: string, from: string, to: string): void; + moveContainerTo(containerId: string, to: string): void; + handleDragContainerStart(containerId: string): void; + findTabbarServiceByContainerId(containerId: string): TabbarService | undefined; } export const MainLayoutContribution = Symbol('MainLayoutContribution'); From dbd52e98ce582c02883e6f85f4a5f1e541d67ead Mon Sep 17 00:00:00 2001 From: "chengzhe.lcz" Date: Thu, 23 Jan 2025 10:13:46 +0800 Subject: [PATCH 04/12] feat: complete drag behavior --- .../src/browser/layout/tabbar.view.tsx | 2 +- .../src/layout/layout.interface.ts | 1 + .../src/browser/accordion/titlebar.view.tsx | 25 +++++++++++++++++-- .../main-layout/src/browser/layout.service.ts | 13 +++++++++- .../src/browser/tabbar/bar.view.tsx | 3 +++ .../src/browser/tabbar/panel.view.tsx | 5 +++- .../src/browser/tabbar/tabbar.service.ts | 5 ++++ .../src/common/main-layout.definition.ts | 3 ++- .../src/browser/contribution/terminal.view.ts | 1 + 9 files changed, 52 insertions(+), 6 deletions(-) diff --git a/packages/ai-native/src/browser/layout/tabbar.view.tsx b/packages/ai-native/src/browser/layout/tabbar.view.tsx index 3c4cdf3da0..e4c6b5cfbb 100644 --- a/packages/ai-native/src/browser/layout/tabbar.view.tsx +++ b/packages/ai-native/src/browser/layout/tabbar.view.tsx @@ -176,7 +176,7 @@ export const AIRightTabRenderer = ({ {...props} renderContainerWrap={({ children }) => (
- {!options?.titleComponent && ( + {!options?.title && (
{options && options.title}
diff --git a/packages/core-browser/src/layout/layout.interface.ts b/packages/core-browser/src/layout/layout.interface.ts index 0b5ebe90dc..a8bdc67222 100644 --- a/packages/core-browser/src/layout/layout.interface.ts +++ b/packages/core-browser/src/layout/layout.interface.ts @@ -79,6 +79,7 @@ export interface ExtViewContainerOptions { // viewContainer 最小高度,默认 120 miniSize?: number; alignment?: Layout.alignment; + draggable?: boolean; } export const ComponentRegistry = Symbol('ComponentRegistry'); diff --git a/packages/main-layout/src/browser/accordion/titlebar.view.tsx b/packages/main-layout/src/browser/accordion/titlebar.view.tsx index 00c07f158e..e67aa326d6 100644 --- a/packages/main-layout/src/browser/accordion/titlebar.view.tsx +++ b/packages/main-layout/src/browser/accordion/titlebar.view.tsx @@ -1,6 +1,8 @@ import React from 'react'; -import { useDesignStyles } from '@opensumi/ide-core-browser'; +import { useDesignStyles, useInjectable } from '@opensumi/ide-core-browser'; + +import { TabbarService, TabbarServiceFactory } from '../tabbar/tabbar.service'; import styles from './styles.module.less'; @@ -8,11 +10,30 @@ export const TitleBar: React.FC<{ title: string; menubar?: React.ReactNode; height?: number; + draggable?: boolean; + side: string; + containerId: string; }> = React.memo((props) => { const styles_titlebar = useDesignStyles(styles.titlebar, 'titlebar'); + const tabbarService: TabbarService = useInjectable(TabbarServiceFactory)(props.side); + return (
-

{props.title}

+ {!props.draggable &&

{props.title}

} + {!!props.draggable && ( +

{ + tabbarService.handleDragStart(e, props.containerId); + }} + onDragEnd={(e) => { + tabbarService.handleDragEnd(e); + }} + > + {props.title} +

+ )} {props.menubar || null}
); diff --git a/packages/main-layout/src/browser/layout.service.ts b/packages/main-layout/src/browser/layout.service.ts index d74f42d7dc..bf976edcd2 100644 --- a/packages/main-layout/src/browser/layout.service.ts +++ b/packages/main-layout/src/browser/layout.service.ts @@ -258,7 +258,7 @@ export class LayoutService extends WithEventBus implements IMainLayoutService { toTabbar.dynamicAddContainer(containerId, container); } - handleDragContainerStart(containerId: string): void { + showDropAreaForContainer(containerId: string): void { const tabbarService = this.findTabbarServiceByContainerId(containerId); const bottomService = this.tabbarServices.get('bottom'); const rightService = this.tabbarServices.get('right'); @@ -276,6 +276,17 @@ export class LayoutService extends WithEventBus implements IMainLayoutService { } } + hideDropArea(): void { + const bottomService = this.tabbarServices.get('bottom'); + const rightService = this.tabbarServices.get('right'); + if (bottomService?.currentContainerId.get() === 'drop-bottom') { + bottomService.updateCurrentContainerId(bottomService.previousContainerId || ''); + } + if (rightService?.currentContainerId.get() === 'drop-right') { + rightService.updateCurrentContainerId(rightService.previousContainerId || ''); + } + } + isVisible(location: string) { const tabbarService = this.getTabbarService(location); return !!tabbarService.currentContainerId.get(); diff --git a/packages/main-layout/src/browser/tabbar/bar.view.tsx b/packages/main-layout/src/browser/tabbar/bar.view.tsx index 6fe7334178..21e61a9824 100644 --- a/packages/main-layout/src/browser/tabbar/bar.view.tsx +++ b/packages/main-layout/src/browser/tabbar/bar.view.tsx @@ -168,6 +168,9 @@ export const TabbarViewBase: React.FC = (props) => { } tabbarService.handleDrop(e, containerId); }} + onDragEnd={(e) => { + tabbarService.handleDragEnd(e); + }} key={containerId} id={containerId} onContextMenu={(e) => tabbarService.handleContextMenu(e, containerId)} diff --git a/packages/main-layout/src/browser/tabbar/panel.view.tsx b/packages/main-layout/src/browser/tabbar/panel.view.tsx index 7d2346d664..26a07806cf 100644 --- a/packages/main-layout/src/browser/tabbar/panel.view.tsx +++ b/packages/main-layout/src/browser/tabbar/panel.view.tsx @@ -105,7 +105,7 @@ export const ContainerView: React.FC<{ const ref = React.useRef(); const containerRef = React.useRef(null); const appConfig = useInjectable(AppConfig); - const { title, titleComponent, component: CustomComponent, containerId } = component.options || {}; + const { title, titleComponent, component: CustomComponent, containerId, draggable } = component.options || {}; const injector: Injector = useInjectable(INJECTOR_TOKEN); const layoutViewSize = useInjectable(LayoutViewSizeConfig); @@ -144,7 +144,10 @@ export const ContainerView: React.FC<{
{!title ? null : ( } /> diff --git a/packages/main-layout/src/browser/tabbar/tabbar.service.ts b/packages/main-layout/src/browser/tabbar/tabbar.service.ts index 1edb53001a..4f24692501 100644 --- a/packages/main-layout/src/browser/tabbar/tabbar.service.ts +++ b/packages/main-layout/src/browser/tabbar/tabbar.service.ts @@ -664,6 +664,7 @@ export class TabbarService extends WithEventBus { // drag & drop handleDragStart(e: React.DragEvent, containerId: string) { e.dataTransfer.setData('containerId', containerId); + this.layoutService.showDropAreaForContainer(containerId); } handleDrop(e: React.DragEvent, target: string) { @@ -677,6 +678,10 @@ export class TabbarService extends WithEventBus { } } + handleDragEnd(e: React.DragEvent) { + this.layoutService.hideDropArea(); + } + restoreState() { this.storedState = this.layoutState.getState(LAYOUT_STATE.getTabbarSpace(this.location), {}); for (const containerId of this.state.keys()) { diff --git a/packages/main-layout/src/common/main-layout.definition.ts b/packages/main-layout/src/common/main-layout.definition.ts index d5b8a88e37..d319617d1e 100644 --- a/packages/main-layout/src/common/main-layout.definition.ts +++ b/packages/main-layout/src/common/main-layout.definition.ts @@ -87,7 +87,8 @@ export interface IMainLayoutService { getExtraMenu(): IContextMenu; getAllAccordionService(): Map; moveContainerTo(containerId: string, to: string): void; - handleDragContainerStart(containerId: string): void; + showDropAreaForContainer(containerId: string): void; + hideDropArea(): void; findTabbarServiceByContainerId(containerId: string): TabbarService | undefined; } diff --git a/packages/terminal-next/src/browser/contribution/terminal.view.ts b/packages/terminal-next/src/browser/contribution/terminal.view.ts index 6623103426..c3a0976c4c 100644 --- a/packages/terminal-next/src/browser/contribution/terminal.view.ts +++ b/packages/terminal-next/src/browser/contribution/terminal.view.ts @@ -56,6 +56,7 @@ export class TerminalRenderContribution implements ComponentContribution, TabBar activateKeyBinding: 'ctrl+`', containerId: TerminalRenderContribution.viewId, titleComponent: TerminalTabs, + draggable: true, }, ); } From e2d81842ea0de5650396faea0d3abcee513fd43a Mon Sep 17 00:00:00 2001 From: "chengzhe.lcz" Date: Thu, 23 Jan 2025 10:52:38 +0800 Subject: [PATCH 05/12] feat: tabbarHandler should change --- .../src/browser/layout/layout.module.less | 18 ++++++++--------- .../src/browser/layout/tabbar.view.tsx | 20 +++++++++---------- .../main-layout/src/browser/layout.service.ts | 5 ++++- .../src/browser/tabbar/panel.view.tsx | 4 +++- .../src/browser/terminal.controller.ts | 7 ++++--- 5 files changed, 30 insertions(+), 24 deletions(-) diff --git a/packages/ai-native/src/browser/layout/layout.module.less b/packages/ai-native/src/browser/layout/layout.module.less index b7bd8ace83..044724f506 100644 --- a/packages/ai-native/src/browser/layout/layout.module.less +++ b/packages/ai-native/src/browser/layout/layout.module.less @@ -119,20 +119,20 @@ border: none; } +.header { + height: 36px; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0 10px; + background-color: var(--editorGroupHeader-tabsBackground); +} + .right_slot_container_wrap { height: 100%; display: flex; flex-direction: column; - .header { - height: 36px; - display: flex; - align-items: center; - justify-content: space-between; - padding: 0 10px; - background-color: var(--editorGroupHeader-tabsBackground); - } - .container { flex: 1; } diff --git a/packages/ai-native/src/browser/layout/tabbar.view.tsx b/packages/ai-native/src/browser/layout/tabbar.view.tsx index e4c6b5cfbb..9e758b32d2 100644 --- a/packages/ai-native/src/browser/layout/tabbar.view.tsx +++ b/packages/ai-native/src/browser/layout/tabbar.view.tsx @@ -174,18 +174,18 @@ export const AIRightTabRenderer = ({ return ( + {options && options.title} +
+ + + +
+
+ } renderContainerWrap={({ children }) => (
- {!options?.title && ( -
- {options && options.title} -
- - - -
-
- )}
{children}
)} diff --git a/packages/main-layout/src/browser/layout.service.ts b/packages/main-layout/src/browser/layout.service.ts index bf976edcd2..75fd0caa0b 100644 --- a/packages/main-layout/src/browser/layout.service.ts +++ b/packages/main-layout/src/browser/layout.service.ts @@ -226,7 +226,7 @@ export class LayoutService extends WithEventBus implements IMainLayoutService { findTabbarServiceByContainerId(containerId: string): TabbarService | undefined { let tabbarService: undefined | TabbarService; - for (const [key, value] of this.tabbarServices.entries()) { + for (const value of this.tabbarServices.values()) { if (value.containersMap.has(containerId)) { tabbarService = value; break; @@ -252,10 +252,13 @@ export class LayoutService extends WithEventBus implements IMainLayoutService { const toTabbar = this.getTabbarService(to); fromTabbar.removeContainer(containerId); + if (!fromTabbar.visibleContainers.length || fromTabbar.currentContainerId.get() === containerId) { this.toggleSlot(fromTabbar.location, false); } toTabbar.dynamicAddContainer(containerId, container); + const newHandler = this.injector.get(TabBarHandler, [containerId, this.getTabbarService(toTabbar.location)]); + this.handleMap.set(containerId, newHandler!); } showDropAreaForContainer(containerId: string): void { diff --git a/packages/main-layout/src/browser/tabbar/panel.view.tsx b/packages/main-layout/src/browser/tabbar/panel.view.tsx index 26a07806cf..321aced0d3 100644 --- a/packages/main-layout/src/browser/tabbar/panel.view.tsx +++ b/packages/main-layout/src/browser/tabbar/panel.view.tsx @@ -100,8 +100,9 @@ export const ContainerView: React.FC<{ renderContainerWrap?: React.FC<{ children: React.ReactNode; }>; + customTitleBar?: React.ReactNode; className?: string; -}> = ({ component, titleMenu, side, renderContainerWrap, className }) => { +}> = ({ component, titleMenu, side, renderContainerWrap, className, customTitleBar }) => { const ref = React.useRef(); const containerRef = React.useRef(null); const appConfig = useInjectable(AppConfig); @@ -140,6 +141,7 @@ export const ContainerView: React.FC<{ return (
+ {!!customTitleBar && customTitleBar} {!CustomComponent && (
{!title ? null : ( diff --git a/packages/terminal-next/src/browser/terminal.controller.ts b/packages/terminal-next/src/browser/terminal.controller.ts index 2e05889616..a2662a8806 100644 --- a/packages/terminal-next/src/browser/terminal.controller.ts +++ b/packages/terminal-next/src/browser/terminal.controller.ts @@ -23,7 +23,6 @@ import { } from '@opensumi/ide-core-common'; import { WorkbenchEditorService } from '@opensumi/ide-editor'; import { IMainLayoutService } from '@opensumi/ide-main-layout'; -import { TabBarHandler } from '@opensumi/ide-main-layout/lib/browser/tabbar-handler'; import { IThemeService } from '@opensumi/ide-theme'; import { @@ -62,7 +61,6 @@ import { TerminalGroupViewService } from './terminal.view'; @Injectable() export class TerminalController extends WithEventBus implements ITerminalController { protected _focus: boolean; - protected _tabBarHandler: TabBarHandler | undefined; protected _clients: Map; protected _onDidOpenTerminal = new Emitter(); protected _onDidCloseTerminal = new Emitter(); @@ -199,6 +197,10 @@ export class TerminalController extends WithEventBus implements ITerminalControl return this._clientId; } + get _tabBarHandler() { + return this.layoutService.getTabbarHandler(TERMINAL_CONTAINER_ID); + } + private async _createClientOrIgnore(widget: IWidget) { if (this._clients.has(widget.id)) { return this._clients.get(widget.id)!; @@ -418,7 +420,6 @@ export class TerminalController extends WithEventBus implements ITerminalControl }), ]); - this._tabBarHandler = this.layoutService.getTabbarHandler(TERMINAL_CONTAINER_ID); this.themeBackground = this.terminalTheme.terminalTheme.background || ''; this.addDispose( From 13ec70c793b12d8172a8fba5079f8b831f93e04d Mon Sep 17 00:00:00 2001 From: "chengzhe.lcz" Date: Wed, 5 Feb 2025 15:11:37 +0800 Subject: [PATCH 06/12] feat: toggle slot ignore drop container --- .../main-layout/src/browser/default-config.ts | 6 ++- .../main-layout/src/browser/layout.service.ts | 40 +++++++++++++------ .../src/browser/main-layout.contribution.ts | 12 +++--- .../src/common/main-layout.definition.ts | 3 ++ 4 files changed, 42 insertions(+), 19 deletions(-) diff --git a/packages/main-layout/src/browser/default-config.ts b/packages/main-layout/src/browser/default-config.ts index cb749c62df..d60cb1b618 100644 --- a/packages/main-layout/src/browser/default-config.ts +++ b/packages/main-layout/src/browser/default-config.ts @@ -1,6 +1,8 @@ /* istanbul ignore file */ import { LayoutConfig, SlotLocation } from '@opensumi/ide-core-browser'; +import { DROP_BOTTOM_CONTAINER, DROP_RIGHT_CONTAINER } from '../common'; + export const defaultConfig: LayoutConfig = { [SlotLocation.top]: { modules: ['@opensumi/ide-menu-bar'], @@ -19,14 +21,14 @@ export const defaultConfig: LayoutConfig = { ], }, [SlotLocation.right]: { - modules: ['drop-right'], + modules: [DROP_RIGHT_CONTAINER], }, [SlotLocation.main]: { modules: ['@opensumi/ide-editor'], }, [SlotLocation.bottom]: { modules: [ - 'drop-bottom', + DROP_BOTTOM_CONTAINER, '@opensumi/ide-terminal-next', '@opensumi/ide-output', 'debug-console', diff --git a/packages/main-layout/src/browser/layout.service.ts b/packages/main-layout/src/browser/layout.service.ts index 75fd0caa0b..ad0404911b 100644 --- a/packages/main-layout/src/browser/layout.service.ts +++ b/packages/main-layout/src/browser/layout.service.ts @@ -32,6 +32,8 @@ import { Deferred, getDebugLogger, isUndefined } from '@opensumi/ide-core-common import { ThemeChangedEvent } from '@opensumi/ide-theme'; import { + DROP_BOTTOM_CONTAINER, + DROP_RIGHT_CONTAINER, IMainLayoutService, MainLayoutContribution, SUPPORT_ACCORDION_LOCATION, @@ -271,21 +273,19 @@ export class LayoutService extends WithEventBus implements IMainLayoutService { } if (tabbarService?.location === 'right') { bottomService?.updateCurrentContainerId('drop-bottom'); - this.toggleSlot('bottom', true); } if (tabbarService?.location === 'bottom') { rightService?.updateCurrentContainerId('drop-right'); - this.toggleSlot('right', true); } } hideDropArea(): void { const bottomService = this.tabbarServices.get('bottom'); const rightService = this.tabbarServices.get('right'); - if (bottomService?.currentContainerId.get() === 'drop-bottom') { + if (bottomService?.currentContainerId.get() === DROP_BOTTOM_CONTAINER) { bottomService.updateCurrentContainerId(bottomService.previousContainerId || ''); } - if (rightService?.currentContainerId.get() === 'drop-right') { + if (rightService?.currentContainerId.get() === DROP_RIGHT_CONTAINER) { rightService.updateCurrentContainerId(rightService.previousContainerId || ''); } } @@ -311,18 +311,13 @@ export class LayoutService extends WithEventBus implements IMainLayoutService { return; } if (show === true) { - tabbarService.updateCurrentContainerId( - tabbarService.currentContainerId.get() || - tabbarService.previousContainerId || - tabbarService.containersMap.keys().next().value!, - ); + // 不允许通过该api展示drop面板 + tabbarService.updateCurrentContainerId(this.findNonDropContainerId(tabbarService)); } else if (show === false) { tabbarService.updateCurrentContainerId(''); } else { tabbarService.updateCurrentContainerId( - tabbarService.currentContainerId.get() - ? '' - : tabbarService.previousContainerId || tabbarService.containersMap.keys().next().value!, + tabbarService.currentContainerId.get() ? '' : this.findNonDropContainerId(tabbarService), ); } if (tabbarService.currentContainerId.get() && size) { @@ -330,6 +325,27 @@ export class LayoutService extends WithEventBus implements IMainLayoutService { } } + private findNonDropContainerId(tabbarService: TabbarService): string { + const currentContainerId = tabbarService.currentContainerId.get(); + if (currentContainerId && ![DROP_BOTTOM_CONTAINER, DROP_RIGHT_CONTAINER].includes(currentContainerId as string)) { + return currentContainerId; + } + if ( + tabbarService.previousContainerId && + ![DROP_BOTTOM_CONTAINER, DROP_RIGHT_CONTAINER].includes(tabbarService.previousContainerId as string) + ) { + return tabbarService.previousContainerId; + } + + for (const key of tabbarService.containersMap.keys()) { + if (![DROP_BOTTOM_CONTAINER, DROP_RIGHT_CONTAINER].includes(key as string)) { + return key; + } + } + + return ''; + } + getTabbarService(location: string) { const service = this.tabbarServices.get(location) || this.injector.get(TabbarService, [location]); if (!this.tabbarServices.get(location)) { diff --git a/packages/main-layout/src/browser/main-layout.contribution.ts b/packages/main-layout/src/browser/main-layout.contribution.ts index de70d75152..599885771d 100644 --- a/packages/main-layout/src/browser/main-layout.contribution.ts +++ b/packages/main-layout/src/browser/main-layout.contribution.ts @@ -41,7 +41,7 @@ import { import { ContributionProvider, Domain, IEventBus, WithEventBus, localize } from '@opensumi/ide-core-common'; import { Command, CommandContribution, CommandRegistry, CommandService } from '@opensumi/ide-core-common/lib/command'; -import { IMainLayoutService } from '../common'; +import { DROP_BOTTOM_CONTAINER, DROP_RIGHT_CONTAINER, IMainLayoutService } from '../common'; import { BottomDropArea, RightDropArea } from './drop-area/drop-area'; import { ViewQuickOpenHandler } from './quick-open-view'; @@ -196,13 +196,15 @@ export class MainLayoutModuleContribution } registerComponent(registry: ComponentRegistry): void { - registry.register('drop-right', [], { + registry.register(DROP_RIGHT_CONTAINER, [], { component: RightDropArea, - containerId: 'drop-right', + hideTab: true, + containerId: DROP_RIGHT_CONTAINER, }); - registry.register('drop-bottom', [], { + registry.register(DROP_BOTTOM_CONTAINER, [], { component: BottomDropArea, - containerId: 'drop-bottom', + hideTab: true, + containerId: DROP_BOTTOM_CONTAINER, }); } diff --git a/packages/main-layout/src/common/main-layout.definition.ts b/packages/main-layout/src/common/main-layout.definition.ts index d319617d1e..81b69e91f7 100644 --- a/packages/main-layout/src/common/main-layout.definition.ts +++ b/packages/main-layout/src/common/main-layout.definition.ts @@ -132,3 +132,6 @@ export class ViewCollapseChangedEvent extends BasicEvent<{ }> {} export const SUPPORT_ACCORDION_LOCATION = new Set([SlotLocation.left, SlotLocation.right]); + +export const DROP_BOTTOM_CONTAINER = 'drop-bottom'; +export const DROP_RIGHT_CONTAINER = 'drop-right'; From 5baa83907784e02a3cb1249773dd5210c9e14afa Mon Sep 17 00:00:00 2001 From: "chengzhe.lcz" Date: Thu, 6 Feb 2025 16:56:18 +0800 Subject: [PATCH 07/12] fix: optimize code and fix initial layout storage --- .../src/browser/style/design.module.less | 20 +++++++++++ .../src/browser/accordion/titlebar.view.tsx | 25 +++++++------ .../main-layout/src/browser/layout.service.ts | 35 +++++++++++-------- 3 files changed, 56 insertions(+), 24 deletions(-) diff --git a/packages/design/src/browser/style/design.module.less b/packages/design/src/browser/style/design.module.less index 5660a995ff..7530292a71 100644 --- a/packages/design/src/browser/style/design.module.less +++ b/packages/design/src/browser/style/design.module.less @@ -601,6 +601,7 @@ &::-webkit-scrollbar { width: 4px; + &:hover { width: 10px; } @@ -716,6 +717,25 @@ .design-extension_item { border-radius: 8px; } + + .design-tab_item_wrapper { + > div { + display: flex; + align-items: center; + justify-content: center; + width: 22px; + height: 22px; + line-height: 22px; + padding: 0; + border-radius: 4px; + font-size: 16px; + + &:hover { + color: var(--design-text-hoverForeground); + background-color: var(--kt-icon-hoverBackground); + } + } + } } .design-tab_panel { diff --git a/packages/main-layout/src/browser/accordion/titlebar.view.tsx b/packages/main-layout/src/browser/accordion/titlebar.view.tsx index e67aa326d6..de984351dd 100644 --- a/packages/main-layout/src/browser/accordion/titlebar.view.tsx +++ b/packages/main-layout/src/browser/accordion/titlebar.view.tsx @@ -17,20 +17,25 @@ export const TitleBar: React.FC<{ const styles_titlebar = useDesignStyles(styles.titlebar, 'titlebar'); const tabbarService: TabbarService = useInjectable(TabbarServiceFactory)(props.side); + const handleDragStart = React.useCallback( + (e: React.DragEvent) => { + tabbarService.handleDragStart(e, props.containerId); + }, + [tabbarService], + ); + + const handleDragEnd = React.useCallback( + (e: React.DragEvent) => { + tabbarService.handleDragEnd(e); + }, + [tabbarService], + ); + return (
{!props.draggable &&

{props.title}

} {!!props.draggable && ( -

{ - tabbarService.handleDragStart(e, props.containerId); - }} - onDragEnd={(e) => { - tabbarService.handleDragEnd(e); - }} - > +

{props.title}

)} diff --git a/packages/main-layout/src/browser/layout.service.ts b/packages/main-layout/src/browser/layout.service.ts index ad0404911b..62332ca961 100644 --- a/packages/main-layout/src/browser/layout.service.ts +++ b/packages/main-layout/src/browser/layout.service.ts @@ -203,7 +203,7 @@ export class LayoutService extends WithEventBus implements IMainLayoutService { /** * ContainerId 存在三种值类型,对应的处理模式如下: * 1. undefined: 采用首个注册的容器作为当前 containerId - * 2. string: 直接使用该 containerId 作为当前 containerId + * 2. string: 非drop container 直接使用该 containerId 作为当前 containerId * 3. '': 直接清空当前 containerId,不展开相应的 viewContainer */ if (isUndefined(currentId)) { @@ -213,15 +213,21 @@ export class LayoutService extends WithEventBus implements IMainLayoutService { } else { service.updateCurrentContainerId(defaultContainer); } - } else if (currentId) { + } else if (currentId && !this.isDropContainer(currentId)) { if (service.containersMap.has(currentId)) { service.updateCurrentContainerId(currentId); } else { - service.updateCurrentContainerId(defaultContainer); - // 等待后续新容器注册时,更新当前的 containerId - service.updateNextContainerId(currentId); + // 如果在别的 tabbar 中存在该 containerId,则将其移动到当前 tabbar + if (this.findTabbarServiceByContainerId(currentId)) { + this.moveContainerTo(currentId, service.location); + service.updateCurrentContainerId(currentId); + } else { + service.updateCurrentContainerId(defaultContainer); + // 等待后续新容器注册时,更新当前的 containerId + service.updateNextContainerId(currentId); + } } - } else if (currentId === '') { + } else if (currentId === '' || this.isDropContainer(currentId)) { service.updateCurrentContainerId(''); } }; @@ -272,10 +278,10 @@ export class LayoutService extends WithEventBus implements IMainLayoutService { return; } if (tabbarService?.location === 'right') { - bottomService?.updateCurrentContainerId('drop-bottom'); + bottomService?.updateCurrentContainerId(DROP_BOTTOM_CONTAINER); } if (tabbarService?.location === 'bottom') { - rightService?.updateCurrentContainerId('drop-right'); + rightService?.updateCurrentContainerId(DROP_RIGHT_CONTAINER); } } @@ -325,20 +331,21 @@ export class LayoutService extends WithEventBus implements IMainLayoutService { } } + private isDropContainer(containerId: string): boolean { + return [DROP_BOTTOM_CONTAINER, DROP_RIGHT_CONTAINER].includes(containerId); + } + private findNonDropContainerId(tabbarService: TabbarService): string { const currentContainerId = tabbarService.currentContainerId.get(); - if (currentContainerId && ![DROP_BOTTOM_CONTAINER, DROP_RIGHT_CONTAINER].includes(currentContainerId as string)) { + if (currentContainerId && !this.isDropContainer(currentContainerId)) { return currentContainerId; } - if ( - tabbarService.previousContainerId && - ![DROP_BOTTOM_CONTAINER, DROP_RIGHT_CONTAINER].includes(tabbarService.previousContainerId as string) - ) { + if (tabbarService.previousContainerId && !this.isDropContainer(tabbarService.previousContainerId)) { return tabbarService.previousContainerId; } for (const key of tabbarService.containersMap.keys()) { - if (![DROP_BOTTOM_CONTAINER, DROP_RIGHT_CONTAINER].includes(key as string)) { + if (!this.isDropContainer(key)) { return key; } } From 8e4dcebebc76a14f32c2f8e64a119fbbe4221cdc Mon Sep 17 00:00:00 2001 From: "chengzhe.lcz" Date: Fri, 7 Feb 2025 11:34:06 +0800 Subject: [PATCH 08/12] chore: add i18n and fix ci problem --- packages/i18n/src/common/en-US.lang.ts | 1 + packages/i18n/src/common/zh-CN.lang.ts | 1 + .../src/browser/accordion/titlebar.view.tsx | 13 ++++++------ .../src/browser/drop-area/drop-area.tsx | 20 ++++++++++++------- 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/packages/i18n/src/common/en-US.lang.ts b/packages/i18n/src/common/en-US.lang.ts index da843c1c80..627f683f65 100644 --- a/packages/i18n/src/common/en-US.lang.ts +++ b/packages/i18n/src/common/en-US.lang.ts @@ -1326,6 +1326,7 @@ export const localizationBundle = { 'main-layout.bottom-panel.toggle': 'Toggle Bottom Side Bar', 'main-layout.bottom-panel.show': 'Show Bottom Side Bar', 'main-layout.bottom-panel.hide': 'Hide Bottom Side Bar', + 'main-layout.drop-area.tip': 'drop here', 'refactor-preview.title': 'REFACTOR PREVIEW', 'refactor-preview.title.clear': 'Discard Refactoring', diff --git a/packages/i18n/src/common/zh-CN.lang.ts b/packages/i18n/src/common/zh-CN.lang.ts index 6172104a0f..b4172f1f38 100644 --- a/packages/i18n/src/common/zh-CN.lang.ts +++ b/packages/i18n/src/common/zh-CN.lang.ts @@ -924,6 +924,7 @@ export const localizationBundle = { 'main-layout.bottom-panel.toggle': '切换底部面板', 'main-layout.bottom-panel.show': '显示底部面板', 'main-layout.bottom-panel.hide': '隐藏底部面板', + 'main-layout.drop-area.tip': '放置此处', 'refactor-preview.title': '重构预览', 'refactor-preview.title.clear': '放弃重构', diff --git a/packages/main-layout/src/browser/accordion/titlebar.view.tsx b/packages/main-layout/src/browser/accordion/titlebar.view.tsx index de984351dd..7d023f98ed 100644 --- a/packages/main-layout/src/browser/accordion/titlebar.view.tsx +++ b/packages/main-layout/src/browser/accordion/titlebar.view.tsx @@ -11,18 +11,17 @@ export const TitleBar: React.FC<{ menubar?: React.ReactNode; height?: number; draggable?: boolean; - side: string; - containerId: string; + side?: string; + containerId?: string; }> = React.memo((props) => { const styles_titlebar = useDesignStyles(styles.titlebar, 'titlebar'); const tabbarService: TabbarService = useInjectable(TabbarServiceFactory)(props.side); - const handleDragStart = React.useCallback( - (e: React.DragEvent) => { + const handleDragStart = (e: React.DragEvent) => { + if (props.containerId && props.side) { tabbarService.handleDragStart(e, props.containerId); - }, - [tabbarService], - ); + } + }; const handleDragEnd = React.useCallback( (e: React.DragEvent) => { diff --git a/packages/main-layout/src/browser/drop-area/drop-area.tsx b/packages/main-layout/src/browser/drop-area/drop-area.tsx index aca8b436f1..18e35cf735 100644 --- a/packages/main-layout/src/browser/drop-area/drop-area.tsx +++ b/packages/main-layout/src/browser/drop-area/drop-area.tsx @@ -1,7 +1,8 @@ import React from 'react'; -import { useInjectable } from '@opensumi/ide-core-browser'; -import { IMainLayoutService } from '@opensumi/ide-main-layout'; +import { localize, useInjectable } from '@opensumi/ide-core-browser'; + +import { IMainLayoutService } from '../../common'; import styles from './styles.module.less'; @@ -13,18 +14,23 @@ const DropArea: React.FC = (props) => { const { location } = props; const layoutService = useInjectable(IMainLayoutService); + const handleDrop = React.useCallback( + (e: React.DragEvent) => { + const containerId = e.dataTransfer?.getData('containerId'); + layoutService.moveContainerTo(containerId, location); + }, + [layoutService, location], + ); + return (
{ - const containerId = e.dataTransfer?.getData('containerId'); - layoutService.moveContainerTo(containerId, location); - }} + onDrop={handleDrop} onDragOver={(e) => { e.preventDefault(); }} > - drop here + {localize('main-layout.drop-area.tip')}
); }; From f84098b7088e194ef5d76cbec8e72e7c1828b4e0 Mon Sep 17 00:00:00 2001 From: "chengzhe.lcz" Date: Fri, 7 Feb 2025 17:40:31 +0800 Subject: [PATCH 09/12] feat: hide terminal right tab icon --- packages/core-browser/src/layout/layout.interface.ts | 2 ++ packages/main-layout/src/browser/layout.service.ts | 4 ++++ packages/main-layout/src/browser/tabbar/bar.view.tsx | 8 ++++++-- .../src/browser/contribution/terminal.view.ts | 1 + 4 files changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/core-browser/src/layout/layout.interface.ts b/packages/core-browser/src/layout/layout.interface.ts index a8bdc67222..1f759b4ac1 100644 --- a/packages/core-browser/src/layout/layout.interface.ts +++ b/packages/core-browser/src/layout/layout.interface.ts @@ -74,6 +74,8 @@ export interface ExtViewContainerOptions { hideIfEmpty?: boolean; // 隐藏tab图标,仅挂载视图,视图切换交给其他逻辑控制 hideTab?: boolean; + // 隐藏指定位置的图标 + hideLocationTab?: SlotLocation[]; noResize?: boolean; fromExtension?: boolean; // viewContainer 最小高度,默认 120 diff --git a/packages/main-layout/src/browser/layout.service.ts b/packages/main-layout/src/browser/layout.service.ts index 62332ca961..8a4f54c7c6 100644 --- a/packages/main-layout/src/browser/layout.service.ts +++ b/packages/main-layout/src/browser/layout.service.ts @@ -256,6 +256,10 @@ export class LayoutService extends WithEventBus implements IMainLayoutService { this.logger.error(`cannot find container: ${containerId}`); return; } + if (!container.options?.draggable) { + this.logger.warn(`container: ${containerId} is not draggable`); + return; + } const toTabbar = this.getTabbarService(to); diff --git a/packages/main-layout/src/browser/tabbar/bar.view.tsx b/packages/main-layout/src/browser/tabbar/bar.view.tsx index 21e61a9824..4755586924 100644 --- a/packages/main-layout/src/browser/tabbar/bar.view.tsx +++ b/packages/main-layout/src/browser/tabbar/bar.view.tsx @@ -125,11 +125,15 @@ export const TabbarViewBase: React.FC = (props) => { }); const renderContainers = React.useCallback( - (component: ComponentRegistryInfo, tabbarService: TabbarService, currentContainerId?: string) => { + (component: ComponentRegistryInfo, tabbarService: TabbarService, currentContainerId?: string, side?: string) => { const containerId = component.options?.containerId; if (!containerId) { return null; } + if (side && component.options?.hideLocationTab?.includes(side)) { + return null; + } + tabbarService.updateTabInMoreKey(containerId, false); let ref: HTMLLIElement | null; return ( @@ -189,7 +193,7 @@ export const TabbarViewBase: React.FC = (props) => { return (
- {visibleContainers.map((component) => renderContainers(component, tabbarService, currentContainerId))} + {visibleContainers.map((component) => renderContainers(component, tabbarService, currentContainerId, side))} {renderOtherVisibleContainers({ props, renderContainers })} {hideContainers.length ? (
  • Date: Thu, 13 Feb 2025 10:56:00 +0800 Subject: [PATCH 10/12] chore: add a space char in comment line --- packages/main-layout/src/browser/layout.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/main-layout/src/browser/layout.service.ts b/packages/main-layout/src/browser/layout.service.ts index 8a4f54c7c6..37a79602b7 100644 --- a/packages/main-layout/src/browser/layout.service.ts +++ b/packages/main-layout/src/browser/layout.service.ts @@ -203,7 +203,7 @@ export class LayoutService extends WithEventBus implements IMainLayoutService { /** * ContainerId 存在三种值类型,对应的处理模式如下: * 1. undefined: 采用首个注册的容器作为当前 containerId - * 2. string: 非drop container 直接使用该 containerId 作为当前 containerId + * 2. string: 非 drop container 直接使用该 containerId 作为当前 containerId * 3. '': 直接清空当前 containerId,不展开相应的 viewContainer */ if (isUndefined(currentId)) { From e1b75e551bd530c46114caaa00d0f9180a080f61 Mon Sep 17 00:00:00 2001 From: "chengzhe.lcz" Date: Thu, 13 Feb 2025 11:07:41 +0800 Subject: [PATCH 11/12] chore: useCallback in titlebar.view --- .../src/browser/accordion/titlebar.view.tsx | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/main-layout/src/browser/accordion/titlebar.view.tsx b/packages/main-layout/src/browser/accordion/titlebar.view.tsx index 7d023f98ed..32f7b8cea7 100644 --- a/packages/main-layout/src/browser/accordion/titlebar.view.tsx +++ b/packages/main-layout/src/browser/accordion/titlebar.view.tsx @@ -17,11 +17,14 @@ export const TitleBar: React.FC<{ const styles_titlebar = useDesignStyles(styles.titlebar, 'titlebar'); const tabbarService: TabbarService = useInjectable(TabbarServiceFactory)(props.side); - const handleDragStart = (e: React.DragEvent) => { - if (props.containerId && props.side) { - tabbarService.handleDragStart(e, props.containerId); - } - }; + const handleDragStart = React.useCallback( + (e: React.DragEvent) => { + if (props.containerId && props.side) { + tabbarService.handleDragStart(e, props.containerId); + } + }, + [props.containerId, props.side, tabbarService], + ); const handleDragEnd = React.useCallback( (e: React.DragEvent) => { From d2494ff57e60c4da393378932d8d0f53fa3f875f Mon Sep 17 00:00:00 2001 From: "chengzhe.lcz" Date: Fri, 14 Feb 2025 14:14:19 +0800 Subject: [PATCH 12/12] fix: keybinding re-initial --- packages/terminal-next/src/browser/terminal.controller.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/terminal-next/src/browser/terminal.controller.ts b/packages/terminal-next/src/browser/terminal.controller.ts index a2662a8806..5eeb5d2c9a 100644 --- a/packages/terminal-next/src/browser/terminal.controller.ts +++ b/packages/terminal-next/src/browser/terminal.controller.ts @@ -399,11 +399,9 @@ export class TerminalController extends WithEventBus implements ITerminalControl } initContextKey(dom: HTMLDivElement) { - if (!this.terminalContextKey) { - this.terminalContextKey = this.injector.get(TerminalContextKey, [dom]); - this.terminalContextKey.isTerminalFocused.set(this._focus); - this.terminalContextKey.isTerminalViewInitialized.set(true); - } + this.terminalContextKey = this.injector.get(TerminalContextKey, [dom]); + this.terminalContextKey.isTerminalFocused.set(this._focus); + this.terminalContextKey.isTerminalViewInitialized.set(true); } async firstInitialize() {