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

feat: eda plot view #1161

Merged
merged 88 commits into from
May 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
7250d2b
fix: eda -> runner comms to own API file & no more undefined eda vars
SmiteDeluxe Feb 29, 2024
217cc3f
fix: undefined state on reveal panel
SmiteDeluxe Feb 29, 2024
bc1ac24
fix: waitForUpdateHtmlDone now not part of constructCurrentState anymore
SmiteDeluxe Feb 29, 2024
5afb4df
fix: small things & feat: first runnerApi methods that append pipeline
SmiteDeluxe Feb 29, 2024
00a491d
fix: properly show "0" values in table
SmiteDeluxe Mar 1, 2024
4709cc3
feat: get and set basic profiling for new table
SmiteDeluxe Mar 1, 2024
7a0481b
Merge remote-tracking branch 'origin/main' into 929-eda-append-code-t…
SmiteDeluxe Mar 1, 2024
926d79c
fix: col/row deselection if click row/col again and only one
SmiteDeluxe Mar 1, 2024
0b368f7
fix: profiling minimal better styling
SmiteDeluxe Mar 1, 2024
f220bf5
feat: optionally pass table to getProfiling for performance
SmiteDeluxe Mar 1, 2024
e953262
feat: more profiling info & profiling styling
SmiteDeluxe Mar 1, 2024
cebbda6
fix: ProfilingInfo own comp & better profiling height calc
SmiteDeluxe Mar 5, 2024
2789859
fix: profiling fetch also if state existing but no profiling info
SmiteDeluxe Mar 5, 2024
2cb1da6
fix: icon colors & profiling height bug & warn icon if missing vals
SmiteDeluxe Mar 5, 2024
6ee653e
feat: filter and sort icons in col headers
SmiteDeluxe Mar 5, 2024
d9ba845
feat: filter context menu start & fix: row/col select clear
SmiteDeluxe Mar 6, 2024
0d476f8
Merge remote-tracking branch 'origin/main' into 929-eda-append-code-t…
SmiteDeluxe Mar 7, 2024
6237bfc
fix: multiple pipeline support & refactoring
SmiteDeluxe Mar 7, 2024
8350e3c
feat: CODEGEN_PREFIX in front of generated placeholders
SmiteDeluxe Mar 7, 2024
5a532c9
fix: rename current warn to error & no color in state, decided in svelte
SmiteDeluxe Mar 7, 2024
18a24e0
fix: updateTableSpace column names trimmed & minor things
SmiteDeluxe Mar 8, 2024
95734a4
fix: webview reload and profiling semantic
SmiteDeluxe Mar 29, 2024
44b3850
fix: no manual updateTableSpace & colWidths svelte store & head has bg
SmiteDeluxe Mar 29, 2024
8126561
fix: change state profiling semantics
SmiteDeluxe Mar 29, 2024
608cce2
fix: placeholder generation now incr number
SmiteDeluxe Mar 29, 2024
a4fd31c
feat: profiling histograms
SmiteDeluxe Mar 29, 2024
d27a4de
Merge remote-tracking branch 'origin/main' into 929-eda-append-code-t…
SmiteDeluxe Mar 30, 2024
7306942
refactor: some comments and code, more readable
SmiteDeluxe Mar 30, 2024
6e3ab4f
fix: image in top of profiling
SmiteDeluxe Mar 30, 2024
5e951a6
Merge remote-tracking branch 'origin/main' into 929-eda-append-code-t…
SmiteDeluxe Mar 30, 2024
6c6259b
refactor: comments for readability and future
SmiteDeluxe Mar 30, 2024
e8e792a
fix: mega-linter issues
SmiteDeluxe Mar 30, 2024
ff8e14e
fix: small annoying megalinter fix
SmiteDeluxe Mar 30, 2024
c6630f7
fix: types fixed and adapted for history plans
SmiteDeluxe Mar 30, 2024
7fac042
fix: other file fixes after previous state type changes
SmiteDeluxe Mar 30, 2024
22e2cb5
fix: Svelte ARIA warnings
SmiteDeluxe Mar 30, 2024
0bac77d
fix: pr comments
SmiteDeluxe Apr 2, 2024
4b27452
Merge remote-tracking branch 'origin/main' into 929-eda-append-code-t…
SmiteDeluxe Apr 2, 2024
4d37f5f
fix: megalinter
SmiteDeluxe Apr 2, 2024
6fca1ac
prep merge
SmiteDeluxe Apr 2, 2024
0f0dea9
Merge branch '929-eda-append-code-to-pipelines' into 955-eda-plot-view
SmiteDeluxe Apr 2, 2024
139fbc3
fix: after merge fixes
SmiteDeluxe Apr 2, 2024
3d1924e
fix: Column sort type
SmiteDeluxe Apr 2, 2024
f990503
fix: refreshTab history entry and how it works
SmiteDeluxe Apr 2, 2024
131aab7
Merge remote-tracking branch 'origin/main' into 929-eda-append-code-t…
SmiteDeluxe Apr 3, 2024
5784f35
Merge remote-tracking branch 'origin/main' into 929-eda-append-code-t…
SmiteDeluxe Apr 3, 2024
cf64b65
Merge branch 'main' into 929-eda-append-code-to-pipelines
lars-reimann Apr 3, 2024
7f5b64b
Merge branch 'main' into 929-eda-append-code-to-pipelines
WinPlay02 Apr 3, 2024
7427d6d
fix: pr comments & pipeline execute reject in runnerApi
SmiteDeluxe Apr 4, 2024
43ff883
style: apply automated linter fixes
megalinter-bot Apr 4, 2024
1d98097
Merge branch 'main' into 929-eda-append-code-to-pipelines
WinPlay02 Apr 4, 2024
254a24d
Merge branch '929-eda-append-code-to-pipelines' into 955-eda-plot-view
SmiteDeluxe Apr 4, 2024
505446a
fix: remove states older than 7 days
SmiteDeluxe Apr 4, 2024
98c113d
Merge remote-tracking branch 'origin/main' into 929-eda-append-code-t…
SmiteDeluxe Apr 5, 2024
12e8fd6
Merge remote-tracking branch 'origin/main' into 929-eda-append-code-t…
SmiteDeluxe Apr 5, 2024
32be1f1
refactor: new vscode region comments & code reordering
SmiteDeluxe Apr 5, 2024
e76d1b7
Merge branch '929-eda-append-code-to-pipelines' into 955-eda-plot-view
SmiteDeluxe Apr 5, 2024
a8549c7
fix: fullHeadBackground full width
SmiteDeluxe Apr 5, 2024
6aa555b
feat: add code after placeholder and ignore rest of pipeline
SmiteDeluxe Apr 5, 2024
307360c
fix: forgot in prev commit
SmiteDeluxe Apr 5, 2024
184686e
fix: don't get idNess, all by counting myself & more ...
SmiteDeluxe Apr 5, 2024
5dc2dc3
Merge branch 'main' into 955-eda-plot-view
SmiteDeluxe Apr 10, 2024
8d6ab96
fix: after merge changes
SmiteDeluxe Apr 10, 2024
4ec6692
fix: placholder suffix cleanup
SmiteDeluxe Apr 10, 2024
08d49ac
Merge remote-tracking branch 'origin/main' into 955-eda-plot-view
SmiteDeluxe Apr 23, 2024
4a3d260
Merge branch 'main' into 955-eda-plot-view
SmiteDeluxe Apr 24, 2024
44712b2
fix: loggings with new system
SmiteDeluxe Apr 24, 2024
241e5a6
Merge remote-tracking branch 'origin/main' into 955-eda-plot-view
SmiteDeluxe Apr 24, 2024
e9c00ed
Merge remote-tracking branch 'origin/main' into 955-eda-plot-view
SmiteDeluxe Apr 30, 2024
8c1830a
feat: init history setup & zoom for histograms
SmiteDeluxe May 1, 2024
870155c
Merge remote-tracking branch 'origin/main' into 955-eda-plot-view
SmiteDeluxe May 1, 2024
9446322
fix: Tab states retained & profile border improv & refactors
SmiteDeluxe May 2, 2024
38468ea
feat: TabContent improvements
SmiteDeluxe May 2, 2024
f90cd4b
feat: isGenerating for Tabs in sidebar
SmiteDeluxe May 2, 2024
2759541
Merge remote-tracking branch 'origin/main' into 955-eda-plot-view
SmiteDeluxe May 7, 2024
3f5b3aa
feat: plot generation from plot panel form
SmiteDeluxe May 7, 2024
09e279f
feat: hover/click image in profiling to zoom too
SmiteDeluxe May 8, 2024
ec2a342
fix: profiling zoom icon tied to left so work with bigger col
SmiteDeluxe May 8, 2024
f445de9
feat: plotting by col selection
SmiteDeluxe May 8, 2024
1d43a9a
feat: guidedMenu for tabs
SmiteDeluxe May 8, 2024
265ea17
fix: icons & newTabBtn instead of guided menu
SmiteDeluxe May 9, 2024
6f37fe6
fix: logging
SmiteDeluxe May 9, 2024
4bfa017
fix: linter
SmiteDeluxe May 9, 2024
9dc38e1
fix: weird linter issue
SmiteDeluxe May 9, 2024
ecf91b5
style: apply automated linter fixes
megalinter-bot May 9, 2024
8142983
feat: scroll in dropdown
SmiteDeluxe May 9, 2024
efed9eb
Merge remote-tracking branch 'origin/main' into 955-eda-plot-view
SmiteDeluxe May 9, 2024
7364077
feat: keep column names if rebuilding started with type change
SmiteDeluxe May 9, 2024
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
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@
# Configuration
/vitest.config.ts
/packages/safe-ds-eda/svelte.config.js
/packages/safe-ds-eda/consts.config.ts
/packages/safe-ds-eda/vite.config.ts
/packages/safe-ds-eda/types/*.d.ts
1 change: 1 addition & 0 deletions packages/safe-ds-eda/consts.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const imageWidthToHeightRatio = 1 + 1 / 3;
33 changes: 25 additions & 8 deletions packages/safe-ds-eda/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import TableView from './components/TableView.svelte';
import Sidebar from './components/Sidebar.svelte';
import { throttle } from 'lodash';
import { currentTabIndex, currentState } from './webviewState';
import TabContent from './components/tabs/TabContent.svelte';

let sidebarWidth = 307; // Initial width of the sidebar in pixels

Expand Down Expand Up @@ -37,12 +39,21 @@
</script>

<main>
<div class="sidebarWrapper" style:width="{sidebarWidth}px" class:white-bg={sidebarWidth < 100}>
<div class="sidebarWrapper" style:width="{sidebarWidth}px">
<Sidebar width={sidebarWidth} />
<button class="resizer" on:mousedown={handleDrag}></button>
</div>
<div class="tableWrapper">
<TableView {sidebarWidth} />
<div class="contentWrapper">
<div class:hide={$currentTabIndex !== undefined}>
<TableView {sidebarWidth} />
</div>
{#if $currentState.tabs}
{#each $currentState.tabs as tab, index}
<div class:hide={index !== $currentTabIndex}>
<TabContent {tab} {sidebarWidth} />
</div>
{/each}
{/if}
</div>
</main>

Expand All @@ -59,15 +70,17 @@
flex-shrink: 0;
overflow: hidden;
position: relative;
background-color: var(--bg-bright);
background-color: var(--bg-dark);
}

.white-bg {
background-color: var(--bg-bright);
.contentWrapper {
flex: 1;
width: 100%;
}

.tableWrapper {
flex: 1;
.contentWrapper * {
height: 100%;
width: 100%;
}

.resizer {
Expand All @@ -79,4 +92,8 @@
cursor: ew-resize;
background-color: transparent;
}

.hide {
display: none;
}
</style>
20 changes: 5 additions & 15 deletions packages/safe-ds-eda/src/apis/extensionApi.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,4 @@
import type { State } from '../../types/state';

export const setCurrentGlobalState = function (state: State) {
window.injVscode.postMessage({
command: 'setCurrentGlobalState',
value: state,
});
};

export const resetGlobalState = function () {
window.injVscode.postMessage({
command: 'resetGlobalState',
value: null,
});
};
import type { HistoryEntry } from '../../types/state';

export const createInfoToast = function (message: string) {
window.injVscode.postMessage({ command: 'setInfo', value: message });
Expand All @@ -21,3 +7,7 @@ export const createInfoToast = function (message: string) {
export const createErrorToast = function (message: string) {
window.injVscode.postMessage({ command: 'setError', value: message });
};

export const executeRunner = function (pastEntries: HistoryEntry[], newEntry: HistoryEntry) {
window.injVscode.postMessage({ command: 'executeRunner', value: { pastEntries, newEntry } });
};
245 changes: 245 additions & 0 deletions packages/safe-ds-eda/src/apis/historyApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
import { get } from 'svelte/store';
import type { FromExtensionMessage, RunnerExecutionResultMessage } from '../../types/messaging';
import type {
EmptyTab,
ExternalHistoryEntry,
HistoryEntry,
InteralEmptyTabHistoryEntry,
InternalHistoryEntry,
RealTab,
Tab,
TabHistoryEntry,
} from '../../types/state';
import { cancelTabIdsWaiting, currentState, currentTabIndex } from '../webviewState';
import { executeRunner } from './extensionApi';

// Wait for results to return from the server
const asyncQueue: (ExternalHistoryEntry & { id: number })[] = [];
let messagesWaitingForTurn: RunnerExecutionResultMessage[] = [];
let entryIdCounter = 0;

export const getAndIncrementEntryId = function (): number {
return entryIdCounter++;
};

window.addEventListener('message', (event) => {
const message = event.data as FromExtensionMessage;

if (message.command === 'runnerExecutionResult') {
if (asyncQueue.length === 0) {
throw new Error('No entries in asyncQueue');
}
const asyncQueueEntryIndex = asyncQueue.findIndex((entry) => entry.id === message.value.historyId);
if (asyncQueueEntryIndex === -1) return;
if (asyncQueueEntryIndex !== 0) {
// eslint-disable-next-line no-console
console.log('Message not in turn, waiting for turn');
messagesWaitingForTurn.push(message);
return;
}

deployResult(message);
asyncQueue.shift();
evaluateMessagesWaitingForTurn();
} else if (message.command === 'cancelRunnerExecution') {
cancelExecuteExternalHistoryEntry(message.value);
}
});

export const addInternalToHistory = function (entry: InternalHistoryEntry): void {
currentState.update((state) => {
const entryWithId: HistoryEntry = {
...entry,
id: getAndIncrementEntryId(),
};
const newHistory = [...state.history, entryWithId];
return {
...state,
history: newHistory,
};
});
};

export const executeExternalHistoryEntry = function (entry: ExternalHistoryEntry): void {
currentState.update((state) => {
const entryWithId: HistoryEntry = {
...entry,
id: getAndIncrementEntryId(),
};
const newHistory = [...state.history, entryWithId];

asyncQueue.push(entryWithId);
executeRunner(state.history, entryWithId); // Is this good in here? Otherwise risk of empty array idk

return {
...state,
history: newHistory,
};
});
};

export const addAndDeployTabHistoryEntry = function (entry: TabHistoryEntry & { id: number }, tab: Tab): void {
// Search if already exists and is up to date
const existingTab = get(currentState).tabs?.find(
(et) =>
et.type !== 'empty' &&
et.type === tab.type &&
et.tabComment === tab.tabComment &&
tab.type &&
!et.content.outdated &&
!et.isInGeneration,
);
if (existingTab) {
currentTabIndex.set(get(currentState).tabs!.indexOf(existingTab));
return;
}

currentState.update((state) => {
const newHistory = [...state.history, entry];

return {
...state,
history: newHistory,
tabs: (state.tabs ?? []).concat([tab]),
};
});
currentTabIndex.set(get(currentState).tabs!.indexOf(tab));
};

export const addEmptyTabHistoryEntry = function (): void {
const entry: InteralEmptyTabHistoryEntry & { id: number } = {
action: 'emptyTab',
type: 'internal',
alias: 'New empty tab',
id: getAndIncrementEntryId(),
};
const tab: EmptyTab = {
type: 'empty',
id: crypto.randomUUID(),
isInGeneration: true,
};

currentState.update((state) => {
const newHistory = [...state.history, entry];

return {
...state,
history: newHistory,
tabs: (state.tabs ?? []).concat([tab]),
};
});
currentTabIndex.set(get(currentState).tabs!.indexOf(tab));
};

export const cancelExecuteExternalHistoryEntry = function (entry: HistoryEntry): void {
const index = asyncQueue.findIndex((queueEntry) => queueEntry.id === entry.id);
if (index !== -1) {
asyncQueue.splice(index, 1);
if (entry.type === 'external-visualizing' && entry.existingTabId) {
cancelTabIdsWaiting.update((ids) => {
return ids.concat([entry.existingTabId!]);
});
const tab: RealTab = get(currentState).tabs!.find(
(t) => t.type !== 'empty' && t.id === entry.existingTabId,
)! as RealTab;
unsetTabAsGenerating(tab);
}
} else {
throw new Error('Entry already fully executed');
}
};

export const setTabAsGenerating = function (tab: RealTab): void {
currentState.update((state) => {
const newTabs = state.tabs?.map((t) => {
if (t === tab) {
return {
...t,
isInGeneration: true,
};
} else {
return t;
}
});

return {
...state,
tabs: newTabs,
};
});
};

export const unsetTabAsGenerating = function (tab: RealTab): void {
currentState.update((state) => {
const newTabs = state.tabs?.map((t) => {
if (t === tab) {
return {
...t,
isInGeneration: false,
};
} else {
return t;
}
});

return {
...state,
tabs: newTabs,
};
});
};

const deployResult = function (result: RunnerExecutionResultMessage) {
const resultContent = result.value;
if (resultContent.type === 'tab') {
if (resultContent.content.id) {
const existingTab = get(currentState).tabs?.find((et) => et.id === resultContent.content.id);
if (existingTab) {
const tabIndex = get(currentState).tabs!.indexOf(existingTab);
currentState.update((state) => {
return {
...state,
tabs: state.tabs?.map((t) => {
if (t.id === resultContent.content.id) {
return resultContent.content;
} else {
return t;
}
}),
};
});
currentTabIndex.set(tabIndex);
return;
}
}
const tab = resultContent.content;
tab.id = crypto.randomUUID();
currentState.update((state) => {
return {
...state,
tabs: (state.tabs ?? []).concat(tab),
};
});
currentTabIndex.set(get(currentState).tabs!.indexOf(tab));
}
};

const evaluateMessagesWaitingForTurn = function () {
const newMessagesWaitingForTurn: RunnerExecutionResultMessage[] = [];
let firstItemQueueChanged = false;

for (const entry of messagesWaitingForTurn) {
if (asyncQueue[0].id === entry.value.historyId) {
// eslint-disable-next-line no-console
console.log(`Deploying message from waiting queue: ${entry}`);
deployResult(entry);
asyncQueue.shift();
firstItemQueueChanged = true;
} else if (asyncQueue.findIndex((queueEntry) => queueEntry.id === entry.value.historyId) !== -1) {
newMessagesWaitingForTurn.push(entry); // Only those that still exist in asyncqueue and were not the first item still have to be waited for
}
}

messagesWaitingForTurn = newMessagesWaitingForTurn;
if (firstItemQueueChanged) evaluateMessagesWaitingForTurn(); // Only if first element was deployed we have to scan again, as this is only deployment condition
};
25 changes: 25 additions & 0 deletions packages/safe-ds-eda/src/components/NewTabButton.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<script lang="ts">
import { addEmptyTabHistoryEntry } from '../apis/historyApi';
import PlusIcon from '../icons/Plus.svelte';
import { preventClicks } from '../webviewState';

const createEmptyTab = function () {
if ($preventClicks) return;
addEmptyTabHistoryEntry();
};
</script>

<div class="wrapper">
<div role="none" class="iconWrapper" on:click={createEmptyTab}>
<PlusIcon />
</div>
</div>

<style>
.wrapper {
width: 35px;
height: 35px;
cursor: pointer;
position: relative;
}
</style>
Loading