Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,6 @@ export const actions = addPrefix(ACTION_PREFIX, {
SET_FROM_PERSISTENCE: "SET_FROM_PERSISTENCE",
OPEN_DASHBOARD: "OPEN_DASHBOARD",
OPEN_INSTALLATION_WIZARD: "OPEN_INSTALLATION_WIZARD",
SET_SCOPE: "SET_SCOPE"
SET_SCOPE: "SET_SCOPE",
SET_STATE: "SET_STATE"
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Meta, StoryObj } from "@storybook/react";

import { ScopeNavigation } from ".";

// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
const meta: Meta<typeof ScopeNavigation> = {
title: "Navigation/ScopeNavigation",
component: ScopeNavigation,
parameters: {
// More on how to position stories at: https://storybook.js.org/docs/react/configure/story-layout
layout: "fullscreen"
}
};

export default meta;

type Story = StoryObj<typeof meta>;

// More on writing stories with args: https://storybook.js.org/docs/react/writing-stories/args
export const Default: Story = {
args: {}
};

export const Disabled: Story = {
args: {}
};
109 changes: 109 additions & 0 deletions src/components/Navigation/ScopeNavigation/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { useContext, useEffect, useState } from "react";
import { actions } from "../../../actions";
import { dispatcher } from "../../../dispatcher";
import { usePrevious } from "../../../hooks/usePrevious";
import { HistoryManager, HistoryStep } from "../../../utils/historyManager";
import { ConfigContext } from "../../common/App/ConfigContext";
import { Scope } from "../../common/App/types";
import { HistoryNavigationPanel } from "../HistoryNavigationPanel";
import { ChangeEnvironmentPayload, ChangeViewPayload } from "../types";
import { actions as globalActions } from "./../actions";
import { ScopeNavigationProps } from "./types";

const sendMessage = (historyStep: HistoryStep) => {
if (historyStep.scope) {
window.sendMessageToDigma({
action: globalActions.CHANGE_SCOPE,
payload: {
...historyStep.scope
}
});
}
};

export const ScopeNavigation = (props: ScopeNavigationProps) => {
const [historyManager, setHistoryManager] = useState<HistoryManager>(
new HistoryManager()
);
const { environment } = useContext(ConfigContext);
const previousTabId = usePrevious(props.currentTabId);
const previousSate = usePrevious(historyManager.getCurrent());

useEffect(() => {
const currentStep = historyManager.getCurrent();
if (
previousSate?.scope.span?.spanCodeObjectId ===
currentStep?.scope.span?.spanCodeObjectId
) {
if (previousTabId !== props.currentTabId) {
historyManager.updateCurrent({ tabId: props.currentTabId });
}
}
}, [previousTabId, props.currentTabId, previousSate]);

useEffect(() => {
const handleSetScope = (data: unknown) => {
const newScope = data as Scope;
const currentScope = historyManager.getCurrent()?.scope;
if (
!currentScope ||
currentScope.span?.spanCodeObjectId !== newScope.span?.spanCodeObjectId
) {
historyManager.push({
environment: environment || null,
scope: newScope,
tabId: null
});
} else {
const historyStep = historyManager.getCurrent();

if (historyStep && historyStep.tabId) {
window.sendMessageToDigma<ChangeViewPayload>({
action: globalActions.CHANGE_VIEW,
payload: {
view: historyStep.tabId
}
});
}

if (historyStep && historyStep.environment) {
window.sendMessageToDigma<ChangeEnvironmentPayload>({
action: globalActions.CHANGE_ENVIRONMENT,
payload: {
environment: historyStep.environment
}
});
}
}
};

dispatcher.addActionListener(actions.SET_SCOPE, handleSetScope);

return () => {
dispatcher.removeActionListener(actions.SET_SCOPE, handleSetScope);
};
}, [environment, props.currentTabId, historyManager]);

const handleBackClick = () => {
const currentStep = historyManager.back();
if (currentStep) {
sendMessage(currentStep);
}
};

const handleNexClick = () => {
const currentStep = historyManager.forward();
if (currentStep) {
sendMessage(currentStep);
}
};

return (
<HistoryNavigationPanel
isBackDisabled={!historyManager.canMoveBack()}
isForwardDisabled={!historyManager.canMoveForward()}
onGoBack={handleBackClick}
onGoForward={handleNexClick}
/>
);
};
14 changes: 14 additions & 0 deletions src/components/Navigation/ScopeNavigation/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import styled from "styled-components";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove this file as not used


export const NavigationButton = styled.button`
height: 28px;
width: 28px;

&:not([disabled]) {
border: none;
}

&:disabled {
color: ${({ theme }) => theme.colors.v3.icon.disabled};
}
`;
3 changes: 3 additions & 0 deletions src/components/Navigation/ScopeNavigation/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface ScopeNavigationProps {
currentTabId: string;
}
18 changes: 9 additions & 9 deletions src/components/Navigation/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import { FourSquaresIcon } from "../common/icons/FourSquaresIcon";
import { ThreeDotsIcon } from "../common/icons/ThreeDotsIcon";
import { CodeButton } from "./CodeButton";
import { CodeButtonMenu } from "./CodeButtonMenu";
import { HistoryNavigationPanel } from "./HistoryNavigationPanel";
import { IconButton } from "./IconButton";
import { ScopeNavigation } from "./ScopeNavigation";
import { Tabs } from "./Tabs";
import { TargetButtonMenu } from "./TargetButtonMenu";
import { actions } from "./actions";
Expand Down Expand Up @@ -113,6 +113,7 @@ export const Navigation = () => {
const [isAutoFixing, setIsAutoFixing] = useState(false);
const [isAnnotationAdding, setIsAnnotationAdding] = useState(false);
const previousCodeContext = usePrevious(codeContext);
const [currentTab, setCurrentTab] = useState<string>();

const environments = config.environments || [];

Expand All @@ -124,6 +125,9 @@ export const Navigation = () => {
const handleViewData = (data: unknown) => {
const payload = data as SetViewsPayload;
setTabs(payload.views);

const selected = payload.views.find((x) => x.isSelected);
selected && setCurrentTab(selected.id);
};

const handleCodeContextData = (data: unknown) => {
Expand Down Expand Up @@ -319,7 +323,8 @@ export const Navigation = () => {
openURLInDefaultBrowser(SLACK_WORKSPACE_URL);
};

const handleTabClick = (tabId: string) => {
const changeTab = (tabId: string) => {
setCurrentTab(tabId);
window.sendMessageToDigma<ChangeViewPayload>({
action: actions.CHANGE_VIEW,
payload: {
Expand Down Expand Up @@ -400,12 +405,7 @@ export const Navigation = () => {
return (
<s.Container>
<s.Row>
<HistoryNavigationPanel
isBackDisabled={true}
isForwardDisabled={true}
onGoBack={handleGoBackInHistory}
onGoForward={handleGoForwardInHistory}
/>
<ScopeNavigation currentTabId={currentTab || ""} />
<s.ScopeBar $isActive={Boolean(config.scope?.span)}>
<s.ScopeBarButton
disabled={isNull(config.scope?.span)}
Expand Down Expand Up @@ -507,7 +507,7 @@ export const Navigation = () => {
</s.Row>
)}
<s.TabsContainer>
<Tabs tabs={tabs || []} onSelect={handleTabClick} />
<Tabs tabs={tabs || []} onSelect={changeTab} />
</s.TabsContainer>
</s.Container>
);
Expand Down
158 changes: 158 additions & 0 deletions src/utils/historyManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import { Environment, Scope } from "../components/common/App/types";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please rename this file with HistoryManager as it is a class


const MAX_STEPS = 15;

export interface HistoryStep {
scope: Scope;
environment?: Environment | null;
tabId: string | null;
}

export interface UpdateStepParams {
scope?: Scope;
environment?: Environment | null;
tabId?: string;
}

export interface HistoryData {
steps: HistoryStep[];
currentStepIndex: number;
}

interface Node<T> {
next: Node<T> | null;
previous: Node<T> | null;
value: T;
}

export class HistoryManager {
private head: Node<HistoryStep> | null = null;
private tail: Node<HistoryStep> | null = null;

private current: Node<HistoryStep> | null = null;
private itemsCount = 0;
private currentIndex = -1;

constructor(data?: HistoryData) {
if (data) {
this.init(data.steps, data.currentStepIndex);
}
}

push(step: HistoryStep) {
const newNode: Node<HistoryStep> = {
value: step,
previous: null,
next: null
};

if (this.current != this.tail) {
this.tail = this.current;
this.itemsCount = this.itemsCount - (this.itemsCount - this.currentIndex);
}

if (this.tail) {
this.tail.next = newNode;
newNode.previous = this.tail;
}

if (!this.head) {
this.head = newNode;
}

this.tail = newNode;
this.current = newNode;
this.currentIndex++;

if (this.itemsCount === MAX_STEPS && this.head?.next) {
this.head = this.head.next;
} else {
this.itemsCount++;
}
}

canMoveBack() {
if (!this.current?.previous) {
return false;
}
return true;
}

back() {
if (!this.current?.previous) {
return null;
}

this.current = this.current.previous;
this.currentIndex--;
return this.getCurrent();
}

canMoveForward() {
if (!this.current?.next) {
return false;
}
return true;
}

forward() {
if (!this.current?.next) {
return null;
}

this.current = this.current.next;
this.currentIndex++;
return this.getCurrent();
}

getLast() {
return this.tail?.value;
}

getCurrent() {
return this.current?.value;
}

updateCurrent(newValue: UpdateStepParams) {
if (this.current) {
this.current.value = { ...this.current.value, ...newValue };
}
}

getHistoryData() {
const steps = [];
let step = this.head;
while (step) {
steps.push(step.value);
step = step.next;
}

return {
steps,
currentStepIndex: this.currentIndex
};
}

private init(steps: HistoryStep[], selectedStep: number) {
if (!steps.length) {
return;
}

let currentIndex = 0;

let localCurrent = null;
do {
this.push(steps[currentIndex]);

if (selectedStep === currentIndex) {
localCurrent = this.current;
}

currentIndex++;
} while (currentIndex < steps.length);

this.itemsCount = steps.length;
this.currentIndex = selectedStep;
this.current = localCurrent;
}
}