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

fix(Scope/Workspace/Lanes UI): Override useLanes hook #6936

Merged
merged 10 commits into from
Jan 20, 2023
5 changes: 4 additions & 1 deletion scopes/component/component-drawer/component-drawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export type TransformTreeFn = (host?: WorkspaceModel | ScopeModel) => (rootNode:

export type ComponentsDrawerProps = Omit<DrawerType, 'render'> & {
useComponents: () => { components: ComponentModel[]; loading?: boolean };
useLanes?: () => { lanesModel?: LanesModel; loading?: boolean };
emptyMessage?: ReactNode;
plugins?: ComponentsDrawerPlugins;
transformTree?: TransformTreeFn;
Expand All @@ -54,6 +55,7 @@ export type ComponentsDrawerPlugins = {
export class ComponentsDrawer implements DrawerType {
readonly id: string;
readonly useComponents: () => { components: ComponentModel[]; loading?: boolean };
readonly useLanes: () => { lanesModel?: LanesModel; loading?: boolean };
name: ReactNode;
tooltip?: string;
order?: number;
Expand All @@ -68,6 +70,7 @@ export class ComponentsDrawer implements DrawerType {
constructor(props: ComponentsDrawerProps) {
Object.assign(this, props);
this.useComponents = props.useComponents;
this.useLanes = props.useLanes || useLanes;
this.emptyMessage = props.emptyMessage;
this.plugins = props.plugins || {};
this.setWidgets(props.plugins?.drawerWidgets);
Expand Down Expand Up @@ -144,7 +147,7 @@ export class ComponentsDrawer implements DrawerType {

render = () => {
const { loading, components } = this.useComponents();
const { lanesModel: lanes } = useLanes();
const { lanesModel: lanes } = this.useLanes();
const componentFiltersContext = useContext(ComponentFilterContext);

const filters = componentFiltersContext?.filters || [];
Expand Down
5 changes: 4 additions & 1 deletion scopes/lanes/hooks/use-lanes/lanes-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export type LanesProviderProps = {
children: ReactNode;
viewedLaneId?: LaneId;
targetLanes?: LanesModel;
skipNetworkCall?: boolean;
ignoreDerivingFromUrl?: IgnoreDerivingFromUrl[];
};

Expand All @@ -20,8 +21,10 @@ export function LanesProvider({
viewedLaneId: viewedIdFromProps,
targetLanes,
ignoreDerivingFromUrl: ignoreDerivingFromUrlFromProps,
skipNetworkCall,
}: LanesProviderProps) {
const { lanesModel, loading } = useLanes(targetLanes);
const { lanesModel, loading } = useLanes(targetLanes, skipNetworkCall);

const [lanesState, setLanesState] = useState<LanesModel | undefined>(lanesModel);
const [viewedLaneId, setViewedLaneId] = useState<LaneId | undefined>(viewedIdFromProps);

Expand Down
5 changes: 3 additions & 2 deletions scopes/lanes/hooks/use-lanes/use-lanes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,11 @@ const GET_LANES = gql`
`;

export function useLanes(
targetLanes?: LanesModel
targetLanes?: LanesModel,
skip?: boolean
): LanesContextModel & Omit<QueryResult<LanesQuery & { getHost: { id: string } }>, 'data'> {
const lanesContext = useLanesContext();
const shouldSkip = !!targetLanes || !!lanesContext;
const shouldSkip = skip || !!targetLanes || !!lanesContext;

const { data, loading, ...rest } = useDataQuery<LanesQuery & { getHost: { id: string } }>(GET_LANES, {
skip: shouldSkip,
Expand Down
2 changes: 2 additions & 0 deletions scopes/scope/scope/get-scope-options.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { DrawerType } from '@teambit/ui-foundation.ui.tree.drawer';
import { ComponentType, ReactNode } from 'react';
import { ScopeModel } from '.';

Expand All @@ -8,4 +9,5 @@ export type GetScopeOptions = {
scopeClassName?: string;
TargetScopeOverview?: ComponentType;
PaneWrapper?: ComponentType<{ children: ReactNode }>;
overrideDrawers?: DrawerType[];
};
11 changes: 8 additions & 3 deletions scopes/scope/scope/scope.ui.drawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import {
ScopeTreeNode,
} from '@teambit/ui-foundation.ui.side-bar';
import { TreeNode as TreeNodeType, TreeNodeProps } from '@teambit/design.ui.tree';
import { useLanes } from '@teambit/lanes.hooks.use-lanes';
import { useLanes as defaultUseLanesHook } from '@teambit/lanes.hooks.use-lanes';
import { useLaneComponents } from '@teambit/lanes.hooks.use-lane-components';
import { ComponentModel } from '@teambit/component';
import { useScope, ScopeContext } from '@teambit/scope.ui.hooks.scope-context';
// import { WorkspaceModel } from '@teambit/workspace';
import { LanesModel } from '@teambit/lanes.ui.models.lanes-model';
import { SidebarSlot } from './scope.ui.runtime';

export type ScopeDrawerProps = {
Expand All @@ -21,6 +21,7 @@ export type ScopeDrawerProps = {
drawerWidgetSlot: DrawerWidgetSlot;
assumeScopeInUrl?: boolean;
overrideUseComponents?: () => { components: ComponentModel[] };
overrideUseLanes?: () => { lanesModel?: LanesModel; loading?: boolean };
};

export const scopeDrawer = ({
Expand All @@ -29,12 +30,15 @@ export const scopeDrawer = ({
drawerWidgetSlot,
assumeScopeInUrl = false,
overrideUseComponents,
overrideUseLanes: useLanesFromProps,
}: ScopeDrawerProps) => {
const useLanes = useLanesFromProps || defaultUseLanesHook;

const customScopeTreeNodeRenderer = (treeNodeSlot, host?: any) =>
function TreeNode(props: TreeNodeProps<PayloadType>) {
const children = props.node.children;

if (!children) return <ComponentView {...props} treeNodeSlot={treeNodeSlot} />;
if (!children) return <ComponentView {...props} treeNodeSlot={treeNodeSlot} useLanes={useLanes} />;

// skip over scope node and render only children
if (props.node.payload instanceof ScopePayload) {
Expand Down Expand Up @@ -76,6 +80,7 @@ export const scopeDrawer = ({
drawerWidgets: drawerWidgetSlot,
},
useHost: () => useScope(),
useLanes,
emptyMessage: 'Scope is empty',
// TODO: create an interface for Component host.
transformTree: (host?: any) => {
Expand Down
34 changes: 23 additions & 11 deletions scopes/scope/scope/scope.ui.runtime.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { MenuLinkItem } from '@teambit/design.ui.surfaces.menu.link-item';
import CommandBarAspect, { CommandBarUI, CommandHandler } from '@teambit/command-bar';
import { ScopeModel } from '@teambit/scope.models.scope-model';
import { DrawerType } from '@teambit/ui-foundation.ui.tree.drawer';
import { LanesModel } from '@teambit/lanes.ui.models.lanes-model';
import {
DrawerWidgetSlot,
FilterWidget,
Expand Down Expand Up @@ -131,7 +132,7 @@ export class ScopeUI {
TargetCorner={options.Corner}
routeSlot={this.routeSlot}
menuSlot={this.menuSlot}
sidebar={<this.sidebar.render items={this.listSidebarLinks()} />}
sidebar={<this.sidebar.render items={this.listSidebarLinks()} overrideDrawerSlot={options.overrideDrawers} />}
scopeUi={this}
userUseScopeQuery={options.useScope}
badgeSlot={this.scopeBadgeSlot}
Expand Down Expand Up @@ -286,16 +287,27 @@ export class ScopeUI {
this.drawerWidgetSlot.register(widgets);
};

registerDefaultDrawers(assumeScopeInUrl = false, overrideUseComponents?: () => { components: ComponentModel[] }) {
this.sidebar.registerDrawer(
scopeDrawer({
treeWidgets: this.sidebarSlot,
filtersSlot: this.drawerComponentsFiltersSlot,
drawerWidgetSlot: this.drawerWidgetSlot,
assumeScopeInUrl,
overrideUseComponents,
})
);
registerDefaultDrawers(
assumeScopeInUrl = false,
overrideUseComponents?: () => { components: ComponentModel[] },
overrideUseLanes?: () => { lanesModel: LanesModel }
) {
this.sidebar.registerDrawer(this.getDefaultDrawer(assumeScopeInUrl, overrideUseComponents, overrideUseLanes));
}

getDefaultDrawer(
assumeScopeInUrl = false,
overrideUseComponents?: () => { components: ComponentModel[] },
overrideUseLanes?: () => { lanesModel: LanesModel }
) {
return scopeDrawer({
treeWidgets: this.sidebarSlot,
filtersSlot: this.drawerComponentsFiltersSlot,
drawerWidgetSlot: this.drawerWidgetSlot,
assumeScopeInUrl,
overrideUseComponents,
overrideUseLanes,
});
}

uiRoot(): UIRoot {
Expand Down
8 changes: 6 additions & 2 deletions scopes/ui-foundation/sidebar/ui/side-bar/side-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,17 @@ export type SideBarProps = {
* slot of registered items to the main section at the top.
*/
items?: ComponentType[];
/**
* override register drawers from the slot
*/
overrideDrawerSlot?: DrawerType[];
} & React.HTMLAttributes<HTMLDivElement>;

/**
* side bar component.
*/
export function SideBar({ drawerSlot, items = [], ...rest }: SideBarProps) {
const drawers = flatten(drawerSlot.values())
export function SideBar({ drawerSlot, items = [], overrideDrawerSlot, ...rest }: SideBarProps) {
const drawers = (overrideDrawerSlot || flatten(drawerSlot.values()))
.filter((drawer) => !drawer?.isHidden?.())
.sort(sortFn);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,23 @@ import { TreeContext } from '@teambit/base-ui.graph.tree.tree-context';
import { indentClass } from '@teambit/base-ui.graph.tree.indent';
import { TreeNodeProps } from '@teambit/base-ui.graph.tree.recursive-tree';
import { useLanes } from '@teambit/lanes.hooks.use-lanes';
import { LanesModel } from '@teambit/lanes.ui.models.lanes-model';
import { PayloadType } from '../payload-type';
import { getName } from '../utils/get-name';
import styles from './component-view.module.scss';

export type ComponentViewProps<Payload = any> = {
treeNodeSlot?: ComponentTreeSlot;
useLanes?: () => { lanesModel?: LanesModel };
} & TreeNodeProps<Payload>;

export function ComponentView(props: ComponentViewProps<PayloadType>) {
const { node } = props;
const component = node.payload;

const { onSelect } = useContext(TreeContext);
const { lanesModel } = useLanes();
const { lanesModel } = (props.useLanes || useLanes)();

const handleClick = useCallback(
(event: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {
onSelect && onSelect(node.id, event);
Expand Down
19 changes: 15 additions & 4 deletions scopes/workspace/workspace/workspace.ui.drawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,29 @@ import {
ScopePayload,
ScopeTreeNode,
} from '@teambit/ui-foundation.ui.side-bar';
import { useLanes } from '@teambit/lanes.hooks.use-lanes';
import { useLanes as defaultUseLanesHook } from '@teambit/lanes.hooks.use-lanes';
import { useLaneComponents } from '@teambit/lanes.hooks.use-lane-components';
import { TreeNodeProps } from '@teambit/design.ui.tree';
import { ComponentModel } from '@teambit/component';
import { LanesModel } from '@teambit/lanes.ui.models.lanes-model';
import { SidebarWidgetSlot } from './workspace.ui.runtime';

export type WorkspaceDrawerProps = {
treeWidgets: SidebarWidgetSlot;
filtersSlot: ComponentFiltersSlot;
drawerWidgetSlot: DrawerWidgetSlot;
overrideUseLanes?: () => { lanesModel?: LanesModel; loading?: boolean };
};

export const workspaceDrawer = ({ treeWidgets, filtersSlot, drawerWidgetSlot }: WorkspaceDrawerProps) =>
new ComponentsDrawer({
export const workspaceDrawer = ({
treeWidgets,
filtersSlot,
drawerWidgetSlot,
overrideUseLanes: useLanesFromProps,
}: WorkspaceDrawerProps) => {
const useLanes = useLanesFromProps || defaultUseLanesHook;

return new ComponentsDrawer({
order: 0,
id: 'workspace-components-drawer',
name: 'COMPONENTS',
Expand All @@ -31,7 +40,7 @@ export const workspaceDrawer = ({ treeWidgets, filtersSlot, drawerWidgetSlot }:
function TreeNode(props: TreeNodeProps<PayloadType>) {
const children = props.node.children;

if (!children) return <ComponentView {...props} treeNodeSlot={treeNodeSlot} />; // non collapse
if (!children) return <ComponentView {...props} treeNodeSlot={treeNodeSlot} useLanes={useLanes} />; // non collapse

if (props.node.payload instanceof ScopePayload) return <ScopeTreeNode {...props} />;

Expand All @@ -42,6 +51,7 @@ export const workspaceDrawer = ({ treeWidgets, filtersSlot, drawerWidgetSlot }:
drawerWidgets: drawerWidgetSlot,
},
emptyMessage: 'Workspace is empty',
useLanes,
useComponents: () => {
const { lanesModel, loading: lanesLoading } = useLanes();
const viewedLaneId = lanesModel?.viewedLane?.id;
Expand All @@ -62,6 +72,7 @@ export const workspaceDrawer = ({ treeWidgets, filtersSlot, drawerWidgetSlot }:
};
},
});
};

function mergeComponents(mainComponents: ComponentModel[], laneComponents: ComponentModel[]): ComponentModel[] {
const mainComponentsThatAreNotOnLane = mainComponents.filter((mainComponent) => {
Expand Down