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(editor): header tab navigation (no-changelog) #4244

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
1580fcd
✨ Adding current workflow execution list to the Vuex store
MiloradFilipovic Sep 28, 2022
eab2c31
✨ Updating current workflow executions after running a workflow from …
MiloradFilipovic Sep 28, 2022
fbf9b91
✨ Keeping the tab view content alive when switching tabs in main header
MiloradFilipovic Sep 28, 2022
2caa934
✨ Updating main header controls to work with current workflow regardl…
MiloradFilipovic Sep 28, 2022
d534e7c
🐛 Fixing a bug with previous WF executions still visible after creati…
MiloradFilipovic Sep 28, 2022
3a4fe34
⚡ Updating saved status when new WF is created
MiloradFilipovic Sep 28, 2022
5e52308
✨ Implemented initial version of execution perview
MiloradFilipovic Sep 29, 2022
79abcdf
✨ Keeping the WF view alive when switching to executions tab in new n…
MiloradFilipovic Sep 29, 2022
cd6a288
✨ Implemented executions landing page
MiloradFilipovic Sep 30, 2022
e6957ec
✨ Simplifying node view navigation
MiloradFilipovic Sep 30, 2022
c71c429
✨ Updating executions view zoom and selection to work with the new la…
MiloradFilipovic Sep 30, 2022
99b2116
✨ Using N8nRadioButtons component for main header tabs
MiloradFilipovic Sep 30, 2022
e531e03
💄 Implementing executions page states. Minor refactoring.
MiloradFilipovic Sep 30, 2022
c67f743
Merge branch 'feature/workflows-executions-navigation-redesign' into …
MiloradFilipovic Sep 30, 2022
633f494
⚡ Merge conflict fixes and pieces of code that were left behind
MiloradFilipovic Sep 30, 2022
33cd60d
⚡ Fixing layout and scrolling changes introduced after sync with mast…
MiloradFilipovic Sep 30, 2022
7033200
⚡ Removing keep-alive from node view which broke template opening and…
MiloradFilipovic Sep 30, 2022
2090dd6
✔️ Fixing linting errors
MiloradFilipovic Sep 30, 2022
c704f3a
One more lint error
MiloradFilipovic Sep 30, 2022
c8acded
Merge branch 'feature/workflows-executions-navigation-redesign' into …
MiloradFilipovic Oct 4, 2022
81b17d5
⚡ Implemented executions preview using iframes
MiloradFilipovic Oct 4, 2022
457478b
⚡ Fixing zoom menu positioning in iframe and adding different loading…
MiloradFilipovic Oct 5, 2022
b7bb511
⚡ Fixing navigation to and from WF templates and template loading
MiloradFilipovic Oct 5, 2022
c0dfb1d
⚡ Updating and fixing navigation to and from node view
MiloradFilipovic Oct 5, 2022
95a84fc
👌 Addressing previous PR comments
MiloradFilipovic Oct 5, 2022
b67d306
🐛 Fixing infinite loading when saving a new workflow
MiloradFilipovic Oct 6, 2022
82fb4ad
🐛 Handling opening already opened WF when not on Node view
MiloradFilipovic Oct 6, 2022
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
131 changes: 87 additions & 44 deletions package-lock.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export default Vue.extend({
color: var(--color-text-base);
transition: background-color 0.2s ease;
cursor: pointer;
user-select: none;
}

.disabled {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
v-bind="option"
:active="value === option.value"
:size="size"
:disabled="disabled"
@click="(e) => onClick(option.value, e)"
:disabled="disabled || option.disabled"
@click="(e) => onClick(option, e)"
/>
</div>
</template>
Expand Down Expand Up @@ -36,11 +36,11 @@ export default Vue.extend({
RadioButton,
},
methods: {
onClick(value: unknown) {
if (this.disabled) {
onClick(option: {label: string, value: string, disabled?: boolean}) {
if (this.disabled || option.disabled) {
return;
}
this.$emit('input', value);
this.$emit('input', option.value);
},
},
});
Expand Down
12 changes: 7 additions & 5 deletions packages/editor-ui/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@
[$style.sidebarCollapsed]: sidebarMenuCollapsed
}"
>
<div id="header" :class="$style['header']">
<div id="header" :class="$style.header">
<router-view name="header"></router-view>
</div>
<div id="sidebar" :class="$style['sidebar']">
<div id="sidebar" :class="$style.sidebar">
<router-view name="sidebar"></router-view>
</div>
<div id="content" :class="$style['content']">
<router-view />
<div id="content" :class="$style.content">
<keep-alive include="NodeView" :max="1">
<router-view />
</keep-alive>
</div>
<Modals />
<Telemetry />
Expand All @@ -35,7 +37,7 @@ import { showMessage } from './components/mixins/showMessage';
import { IUser } from './Interface';
import { mapGetters } from 'vuex';
import { userHelpers } from './components/mixins/userHelpers';
import { addHeaders, loadLanguage } from './plugins/i18n';
import { loadLanguage } from './plugins/i18n';
import { restApi } from '@/components/mixins/restApi';
import { globalLinkActions } from '@/components/mixins/globalLinkActions';

Expand Down
10 changes: 5 additions & 5 deletions packages/editor-ui/src/Interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1034,6 +1034,7 @@ export interface IUsersState {
}

export interface IWorkflowsState {
currentWorkflowExecutions: IExecutionsSummary[];
}

export interface ICommunityNodesState {
Expand Down Expand Up @@ -1088,11 +1089,10 @@ export interface ITab {
}

export interface ITabBarItem {
id: string,
label: string,
notifications?: number,
disabled?: boolean,
};
value: string;
label: string;
disabled?: boolean;
}

export interface IResourceLocatorReqParams {
nodeTypeAndVersion: INodeTypeNameVersion;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<template>
<div :class="$style.previewContainer">
<workflow-preview mode="execution" loaderType="spinner" :executionId="executionId"/>
</div>
</template>

<script lang="ts">
import mixins from 'vue-typed-mixins';
import { restApi } from '@/components/mixins/restApi';
import { showMessage } from '../mixins/showMessage';
import WorkflowPreview from '@/components/WorkflowPreview.vue';

export default mixins(restApi, showMessage).extend({
name: 'execution-preview',
components: {
WorkflowPreview,
},
data() {
return {
};
},
computed: {
executionId(): string {
return this.$route.params.executionId;
},
},
});
</script>

<style module lang="scss">

.previewContainer {
height: 100%;
overflow: hidden;
}

</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<template>
<div :class="['workflow-executions-container', $style.container]">
<div v-if="executionCount === 0" :class="[$style.messageContainer, $style.noExecutionsMessage]">
<n8n-heading tag="h2" size="large" color="text-dark">
{{ $locale.baseText('executionsLandingPage.emptyState.heading') }}
</n8n-heading>
<n8n-text>
{{ $locale.baseText('executionsLandingPage.emptyState.message') }}
</n8n-text>
<n8n-button class="mt-l" type="tertiary">
{{ $locale.baseText('nodeView.runButtonText.executeWorkflow') }}
</n8n-button>
</div>
<div v-else :class="[$style.messageContainer, $style.executionListMessage]">
<p :class="$style.icon">
<font-awesome-icon icon="hand-point-left" />
</p>
<p :class="$style.message">
{{ $locale.baseText('executionsLandingPage.clickExecutionMessage') }}
</p>
</div>
</div>
</template>

<script lang="ts">
import { IExecutionsSummary } from '@/Interface';
import Vue from 'vue';

export default Vue.extend({
name: 'executions-landing-page',
computed: {
executionCount(): number {
return (this.$store.getters['workflows/currentWorkflowExecutions'] as IExecutionsSummary[]).length;
},
},
});
</script>

<style module lang="scss">

.container {
width: 100%;
height: 100%;
flex: 1;
background-color: var(--color-background-light);
display: flex;
flex-direction: column;
align-items: center;
}

.messageContainer {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
margin-top: 20%;
color: var(--color-text-base);
}

.icon {
font-size: 24px;
color: var(--color-foreground-dark);
}

</style>
136 changes: 136 additions & 0 deletions packages/editor-ui/src/components/ExecutionsView/ExecutionsSidebar.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
<template>
<div v-if="executions.length > 0" :class="['executions-sidebar', $style.container]">
<n8n-heading tag="h2" size="medium" color="text-dark">
{{ $locale.baseText('generic.executions') }}
</n8n-heading>
<div :class="$style.executionList">
<div v-if="loading" :class="$style.loadingContainer">
<n8n-loading :class="$style.loader" variant="p" :rows="1" />
<n8n-loading :class="$style.loader" variant="p" :rows="1" />
</div>
<div v-else :class="$style.executionCard" v-for="execution in executions" :key="execution.id">
<n8n-icon v-if="getExecutionStatus(execution) === 'unknown'" :class="['mr-2xs', $style.icon, $style.unknown]" icon="exclamation-triangle" />
<n8n-icon v-else :class="['mr-2xs', $style.icon, $style[getExecutionStatus(execution)]]" icon="dot-circle" />
<router-link :class="$style.executionLink" :to="{ name: VIEWS.EXECUTION_PREVIEW, params: { workflowId: currentWorkflow, executionId: execution.id }}">
{{ $locale.baseText('executionSidebar.executionName', { interpolate: { id: execution.id } }) }}
</router-link>
</div>
</div>
</div>
</template>

<script lang="ts">
import { PLACEHOLDER_EMPTY_WORKFLOW_ID } from '@/constants';
import { IExecutionsSummary } from '@/Interface';
import mixins from 'vue-typed-mixins';
import { workflowHelpers } from '../mixins/workflowHelpers';
import { VIEWS } from '../../constants';

export default mixins(workflowHelpers).extend({
name: 'executions-sidebar',
data() {
return {
VIEWS,
loading: false,
};
},
computed: {
workflowName (): string {
return this.$store.getters.workflowName;
},
currentWorkflow (): string {
return this.$route.params.name || this.$store.getters.workflowId;
},
executions(): IExecutionsSummary[] {
return this.$store.getters['workflows/currentWorkflowExecutions'];
},
},
async mounted() {
if (!this.currentWorkflow || this.currentWorkflow === PLACEHOLDER_EMPTY_WORKFLOW_ID) {
this.$store.commit('workflows/setCurrentWorkflowExecutions', []);
} else {
await this.loadExecutions();
}
},
methods: {
async loadExecutions (): Promise<void> {
if (!this.currentWorkflow) {
this.loading = false;
return;
}
try {
this.loading = true;
await this.$store.dispatch('workflows/loadCurrentWorkflowExecutions');
} catch (error) {
this.$showError(
error,
this.$locale.baseText('executionsList.showError.refreshData.title'),
);
} finally {
this.loading = false;
}
},
getExecutionStatus(execution: IExecutionsSummary): string {
let status = 'unknown';

if (execution.waitTill) {
status = 'waiting';
} else if (execution.stoppedAt === undefined) {
status = 'running';
} else if (execution.finished) {
status = 'success';
} else if (execution.stoppedAt !== null) {
status === 'error';
}

return status;
},
},
});
</script>

<style module lang="scss">
.container {
flex: 310px 0 0;
height: 100%;
background-color: var(--color-background-xlight);
border-right: var(--border-base);
padding: var(--spacing-l) var(--spacing-2xs) var(--spacing-2xs) var(--spacing-l);
z-index: 1;
overflow: hidden;
}

.executionList {
height: 93%;
overflow: auto;
margin: var(--spacing-m) 0;
}

.executionCard {
display: flex;
padding: var(--spacing-2xs);
border-radius: var(--border-radius-base);
cursor: pointer;

&:hover {
background-color: var(--color-foreground-base);

.executionLink {
color: var(--color-text-dark)
}
}
}

.icon {
&.unknown, &.waiting, &.running { color: var(--color-warning); }
&.success { color: var(--color-success); }
&.error { color: var(--color-error); }
}

.executionLink {
display: block;
color: var(--color-text-base);
font-size: var(--font-size-xs);
}

</style>
Loading