Skip to content

Commit

Permalink
feat(editor): Update Usage and plan page (#4842)
Browse files Browse the repository at this point in the history
* feat(editor): usage and plan store

* feat(editor): usage and plan page updates

* feat(editor): usage and plan add buttons and alert

* tes(editor): usage and plan store

* tes(editor): usage remove refresh button and add link to view plans

* tes(editor): usage use info tip

* tes(editor): usage info style
  • Loading branch information
cstuncsik authored Dec 8, 2022
1 parent f042f76 commit c3efdce
Show file tree
Hide file tree
Showing 11 changed files with 204 additions and 62 deletions.
10 changes: 8 additions & 2 deletions packages/design-system/src/components/N8nAlert/Alert.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@
<div v-if="$slots.title || title" :class="$style.title">
<slot name="title">{{ title }}</slot>
</div>
<div v-if="$slots.default || description" :class="$style.description">
<div
v-if="$slots.default || description"
:class="{ [$style.description]: true, [$style.hasTitle]: $slots.title || title }"
>
<slot>{{ description }}</slot>
</div>
</div>
Expand Down Expand Up @@ -231,7 +234,10 @@ const alertBoxClassNames = computed(() => {
.description {
font-size: $alert-description-font-size;
margin: 5px 0 0 0;
&.hasTitle {
margin: 5px 0 0 0;
}
}
.aside {
Expand Down
6 changes: 3 additions & 3 deletions packages/editor-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@
"@codemirror/state": "^6.1.4",
"@codemirror/view": "^6.5.1",
"@fontsource/open-sans": "^4.5.0",
"@fortawesome/fontawesome-svg-core": "^6.2.1",
"@fortawesome/free-regular-svg-icons": "^6.2.1",
"@fortawesome/free-solid-svg-icons": "^6.2.1",
"@fortawesome/fontawesome-svg-core": "^1.2.35",
"@fortawesome/free-regular-svg-icons": "^6.1.1",
"@fortawesome/free-solid-svg-icons": "^5.15.3",
"@fortawesome/vue-fontawesome": "^2.0.2",
"axios": "^0.21.1",
"dateformat": "^3.0.3",
Expand Down
10 changes: 5 additions & 5 deletions packages/editor-ui/src/components/SettingsSidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,11 @@ export default mixins(
menuItems.push(
{
id: 'settings-usage-and-plan',
icon: 'chart-simple',
icon: 'chart-bar',
label: this.$locale.baseText('settings.usageAndPlan.title'),
position: 'top',
available: this.canAccessUsageAndPlan(),
activateOnRouteNames: [ VIEWS.USAGE_AND_PLAN ],
activateOnRouteNames: [ VIEWS.USAGE ],
},
);
Expand All @@ -131,7 +131,7 @@ export default mixins(
return this.canUserAccessRouteByName(VIEWS.API_SETTINGS);
},
canAccessUsageAndPlan(): boolean {
return this.canUserAccessRouteByName(VIEWS.USAGE_AND_PLAN);
return this.canUserAccessRouteByName(VIEWS.USAGE);
},
onVersionClick() {
this.uiStore.openModal(ABOUT_MODAL_KEY);
Expand Down Expand Up @@ -167,8 +167,8 @@ export default mixins(
}
break;
case 'settings-usage-and-plan':
if (this.$router.currentRoute.name !== VIEWS.USAGE_AND_PLAN) {
this.$router.push({ name: VIEWS.USAGE_AND_PLAN });
if (this.$router.currentRoute.name !== VIEWS.USAGE) {
this.$router.push({ name: VIEWS.USAGE });
}
break;
default:
Expand Down
2 changes: 1 addition & 1 deletion packages/editor-ui/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ export enum VIEWS {
FAKE_DOOR = "ComingSoon",
COMMUNITY_NODES = "CommunityNodes",
WORKFLOWS = "WorkflowsView",
USAGE_AND_PLAN = "UsageAndPlan",
USAGE = "Usage",
}

export enum FAKE_DOOR_FEATURES {
Expand Down
7 changes: 7 additions & 0 deletions packages/editor-ui/src/plugins/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"_reusableDynamicText.moreInfo": "More info",
"_reusableDynamicText.oauth2.clientId": "Client ID",
"_reusableDynamicText.oauth2.clientSecret": "Client Secret",
"_reusableBaseText.unlimited": "Unlimited",
"generic.any": "Any",
"generic.cancel": "Cancel",
"generic.confirm": "Confirm",
Expand Down Expand Up @@ -1114,6 +1115,12 @@
"settings.api.view.error": "Could not check if an api key already exists.",
"settings.version": "Version",
"settings.usageAndPlan.title": "Usage and plan",
"settings.usageAndPlan.plan": "You’re on the {plan} plan",
"settings.usageAndPlan.activeWorkflows": "Active workflows",
"settings.usageAndPlan.activeWorkflows.count": "{count} of {limit}",
"settings.usageAndPlan.activeWorkflows.hint": "If an active workflow contains multiple triggers, each will count as an active workflow. For example, 1 active workflow with 3 triggers will count as 3 active workflows.",
"settings.usageAndPlan.button.activation": "Add activation key",
"settings.usageAndPlan.button.plans": "View plans",
"showMessage.cancel": "@:_reusableBaseText.cancel",
"showMessage.ok": "OK",
"showMessage.showDetails": "Show Details",
Expand Down
4 changes: 2 additions & 2 deletions packages/editor-ui/src/plugins/icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
faBug,
faCalculator,
faCalendar,
faChartSimple,
faChartBar,
faCheck,
faCheckCircle,
faCheckSquare,
Expand Down Expand Up @@ -145,7 +145,7 @@ addIcon(faBoxOpen);
addIcon(faBug);
addIcon(faCalculator);
addIcon(faCalendar);
addIcon(faChartSimple);
addIcon(faChartBar);
addIcon(faCheck);
addIcon(faCheckCircle);
addIcon(faCheckSquare);
Expand Down
9 changes: 3 additions & 6 deletions packages/editor-ui/src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -557,8 +557,8 @@ const router = new Router({
},
},
{
path: 'usage-and-plan',
name: VIEWS.USAGE_AND_PLAN,
path: 'usage',
name: VIEWS.USAGE,
components: {
settingsView: settingsUsageAndPlanView,
},
Expand All @@ -567,17 +567,14 @@ const router = new Router({
pageCategory: 'settings',
getProperties(route: Route) {
return {
feature: 'usage-and-plan',
feature: 'usage',
};
},
},
permissions: {
allow: {
loginStatus: [LOGIN_STATUS.LoggedIn],
},
deny: {
role: [ROLE.Default],
},
},
},
},
Expand Down
36 changes: 36 additions & 0 deletions packages/editor-ui/src/stores/usageAndPlan.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { createPinia, setActivePinia } from "pinia";
import { useUsageAndPlanStore } from "@/stores/usageAndPlan";


describe('Usage and plan store', () => {
beforeEach(() => {
setActivePinia(createPinia());
});

test.each([
[5, 3, .8, false],
[5, 4, .8, true],
[5, 4, .9, false],
[10, 5, .8, false],
[10, 8, .8, true],
[10, 9, .8, true],
[-1, 99, .8, false],
[-1, 99, .1, false],
])('should check if workflow usage is close to limit', (limit, value, warningThreshold, expectation) => {
const store = useUsageAndPlanStore();
store.setData({
usage: {
executions: {
limit,
value,
warningThreshold,
},
},
license: {
planId: '',
planName: '',
},
});
expect(store.isCloseToLimit).toBe(expectation);
});
});
52 changes: 52 additions & 0 deletions packages/editor-ui/src/stores/usageAndPlan.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import {computed, reactive} from "vue";
import {defineStore} from "pinia";

export type UsageAndPlanState = {
loading: boolean;
error: Error | null;
data: {
usage: {
executions: {
limit: number, // -1 for unlimited, from license
value: number,
warningThreshold: number, // hardcoded value in BE
},
},
license: {
planId: string, // community
planName: string, // defaults to Community
},
}
};

export const useUsageAndPlanStore = defineStore('usageAndPlan', () => {
const state = reactive<UsageAndPlanState>({
loading: true,
error: null,
data: {
usage: {
executions: {
limit: -1,
value: 0,
warningThreshold: .8,
},
},
license: {
planId: 'community',
planName: 'Community',
},
},
});

const setData = (data: UsageAndPlanState['data']) => {
state.data = data;
};

return {
setData,
planName: computed(() => state.data.license.planName),
executionLimit: computed(() => state.data.usage.executions.limit),
executionCount: computed(() => state.data.usage.executions.value),
isCloseToLimit: computed(() => state.data.usage.executions.limit < 0 ? false : state.data.usage.executions.value / state.data.usage.executions.limit >= state.data.usage.executions.warningThreshold),
};
});
78 changes: 75 additions & 3 deletions packages/editor-ui/src/views/SettingsUsageAndPlan.vue
Original file line number Diff line number Diff line change
@@ -1,13 +1,85 @@
<template>
<div :class="$style.container">
<div>
<n8n-heading size="2xlarge">{{ $locale.baseText('settings.usageAndPlan.title') }}</n8n-heading>
<n8n-heading :class="$style.title" size="large">
{{ $locale.baseText('settings.usageAndPlan.plan', { interpolate: { plan: usageAndPlanStore.planName } }) }}
</n8n-heading>
<div :class="$style.quota">
<n8n-text size="medium" color="text-light">{{ $locale.baseText('settings.usageAndPlan.activeWorkflows') }}</n8n-text>
<i18n :class="$style.count" path="settings.usageAndPlan.activeWorkflows.count">
<template #count>{{ usageAndPlanStore.executionCount }}</template>
<template #limit>
<span v-if="usageAndPlanStore.executionLimit < 0">{{ $locale.baseText('_reusableBaseText.unlimited') }}</span>
<span v-else>{{ usageAndPlanStore.executionLimit }}</span>
</template>
</i18n>
</div>
<n8n-info-tip>
{{ $locale.baseText('settings.usageAndPlan.activeWorkflows.hint') }}
</n8n-info-tip>
<div :class="$style.buttons">
<n8n-button type="secondary" size="large">{{ $locale.baseText('settings.usageAndPlan.button.activation') }}</n8n-button>
<n8n-button size="large">
<a href="#">{{ $locale.baseText('settings.usageAndPlan.button.plans') }}</a>
</n8n-button>
</div>
</div>
</template>
<script lang="ts" setup>
import { useUsageAndPlanStore } from "@/stores/usageAndPlan";
const usageAndPlanStore = useUsageAndPlanStore();
</script>

<style lang="scss" module>
.container {
}
.spacedFlex {
display: flex;
justify-content: space-between;
align-items: center;
}
.title {
display: block;
padding: var(--spacing-2xl) 0 var(--spacing-m);
}
.quota {
display: flex;
justify-content: space-between;
align-items: center;
height: 54px;
padding: 0 var(--spacing-s);
margin: 0 0 var(--spacing-xs);
background: var(--color-background-xlight);
border-radius: var(--border-radius-large);
border: 1px solid var(--color-light-grey);
.count {
text-transform: lowercase;
font-size: var(--font-size-s);
}
}
.buttons {
display: flex;
justify-content: flex-end;
padding: var(--spacing-xl) 0 0;
button {
margin-left: var(--spacing-xs);
a {
display: inline-block;
color: inherit;
text-decoration: none;
padding: var(--spacing-xs) var(--spacing-m);
margin: calc(var(--spacing-xs) * -1) calc(var(--spacing-m) * -1);
}
}
}
div[class*="info"] span {
line-height: 1.4;
}
</style>
Loading

0 comments on commit c3efdce

Please sign in to comment.