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): Add cloud ExecutionsUsage and API blocking using licenses #6159

Merged
merged 57 commits into from
May 15, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
a87b0b6
Add ExecutionsUsage component
RicardoE105 May 3, 2023
1d8955c
set $sidebar-expanded-width back to 200px
RicardoE105 May 3, 2023
399060c
add days using interpolation
RicardoE105 May 3, 2023
f57d085
Rename PlanData type to CloudPlanData
RicardoE105 May 3, 2023
43209c9
Rename Metadata type to PlanMetadata
RicardoE105 May 3, 2023
0ceaf34
Make prop block in the update button
RicardoE105 May 3, 2023
a67feae
Use variable in line-height
RicardoE105 May 3, 2023
835292a
Remove progressBarSection class
RicardoE105 May 3, 2023
1db1f3f
fix trial expiration calculation
RicardoE105 May 3, 2023
0d6729c
mock expirationDate and fix issue with days left
RicardoE105 May 3, 2023
d834ec3
Remove unnecesary property from class .container
RicardoE105 May 4, 2023
0429314
inject component data via props
RicardoE105 May 4, 2023
bcfd76c
Check for plan data during app mounting and keep data in the store
RicardoE105 May 4, 2023
b48adc6
Remove mounted hook
RicardoE105 May 4, 2023
78424c9
redirect when upgrade plan is clicked
RicardoE105 May 4, 2023
0148832
Remove computed properties
RicardoE105 May 4, 2023
efb615b
Remove instance property as it's not needed anymore
RicardoE105 May 4, 2023
c8a2fb4
Flatten plan object
RicardoE105 May 4, 2023
d624c71
remove console.log
RicardoE105 May 4, 2023
17294c8
Add all cloud types within its own namespace
RicardoE105 May 6, 2023
6eef985
keep redirection inside component
RicardoE105 May 6, 2023
3d0d2ba
get computed properties back
RicardoE105 May 6, 2023
90c8556
Improve polling logic
RicardoE105 May 6, 2023
2fbb1e7
Move cloudData to its own store
RicardoE105 May 6, 2023
b765867
Remove commented interfaces
RicardoE105 May 6, 2023
807a797
remove cloudPlan from user store
RicardoE105 May 6, 2023
95f1a2e
Sync master
RicardoE105 May 6, 2023
b782e0e
fix imports
RicardoE105 May 6, 2023
cfb921d
update logic for userIsTrialing method
RicardoE105 May 9, 2023
ae0949c
centralize userIsTrialing method
RicardoE105 May 9, 2023
e1353b4
redirect to production change plan page always
RicardoE105 May 9, 2023
be626dc
Call staging or production cloud api depending on base URL
RicardoE105 May 9, 2023
34fee42
remove setting store form ExecutionUsage.vue
RicardoE105 May 9, 2023
dee8651
fix linting issue
RicardoE105 May 9, 2023
48191cd
Add trial group to PlanMetadata group
RicardoE105 May 9, 2023
bb22b9c
Move helpers into the store
RicardoE105 May 9, 2023
f8cc32a
make staging url check more specific
RicardoE105 May 9, 2023
99c51b0
make cloud state nullable
RicardoE105 May 9, 2023
4a4aa83
fix linting issue
RicardoE105 May 9, 2023
903557a
swap mockup date for endpoint
RicardoE105 May 10, 2023
aefa08a
Merge branch 'master' into ado-638-in-app-build-ui-for-upgrade-path
RicardoE105 May 10, 2023
6b48ad5
Make getCurrentPlan async
RicardoE105 May 10, 2023
fabd05c
asas
RicardoE105 May 11, 2023
765dd60
Improvements
RicardoE105 May 12, 2023
1f1ff74
small improvements
RicardoE105 May 12, 2023
4766591
chore: resolve conflicts
mutdmour May 12, 2023
b09bcdc
chore: resolve conflicts
mutdmour May 12, 2023
9b5fbba
make sure there is data before calculating trial expiration
RicardoE105 May 12, 2023
454659f
Fix issue with component not loading on first page load
RicardoE105 May 12, 2023
25b6f91
type safety improvements
RicardoE105 May 13, 2023
827e1dd
Sync master
RicardoE105 May 13, 2023
5b9c5e8
apply component ui feedback
RicardoE105 May 14, 2023
d30632e
fix linting issue
RicardoE105 May 14, 2023
d3a64a1
chore: clean up unnecessary change from merge conflict
mutdmour May 15, 2023
d2a77ab
feat: Block api feature using licenses, show notice page for trial cl…
mutdmour May 15, 2023
a745424
add pluralization to days left text
RicardoE105 May 15, 2023
9c8f61e
sync master
RicardoE105 May 15, 2023
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 packages/design-system/src/components/N8nMenu/Menu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
</el-menu>
</div>
<div :class="[$style.lowerContent, 'pb-2xs']">
<slot name="beforeLowerMenu"></slot>
<el-menu :defaultActive="defaultActive" :collapse="collapsed" v-on="$listeners">
<n8n-menu-item
v-for="item in lowerMenuItems"
Expand Down
33 changes: 33 additions & 0 deletions packages/editor-ui/src/Interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1443,3 +1443,36 @@ export type VersionControlPreferences = {
branchColor: string;
publicKey?: string;
};

export interface PlanData {
RicardoE105 marked this conversation as resolved.
Show resolved Hide resolved
planSpec: PlanSpec;
instance: Instance;
usage: Usage;
}

export interface PlanSpec {
planId: number;
monthlyExecutionsLimit: number;
activeWorkflowsLimit: number;
credentialsLimit: number;
isActive: boolean;
displayName: string;
metadata: Metadata;
}
export interface Metadata {
RicardoE105 marked this conversation as resolved.
Show resolved Hide resolved
version: string;
group: string;
slug: string;
trial: Trial;
}
export interface Trial {
length: number;
gracePeriod: number;
}
export interface Instance {
createdAt: string;
}
export interface Usage {
executions: number;
activeWorkflows: number;
}
184 changes: 184 additions & 0 deletions packages/editor-ui/src/components/ExecutionsUsage.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
<template>
<div v-if="userIsTrialing" :class="$style.container">
<div v-if="!isTrialExpired && trialHasExecutionsLeft" :class="$style.usageText">
<i18n path="executionUsage.currentUsage">
<template #text>
<n8n-text size="xsmall" color="text-dark">
{{ locale.baseText('executionUsage.currentUsage.text') }}
</n8n-text>
</template>
<template #count>
<n8n-text size="xsmall" :bold="true" color="warning">
{{ daysLeftOnTrial }} {{ locale.baseText('executionUsage.currentUsage.count') }}
RicardoE105 marked this conversation as resolved.
Show resolved Hide resolved
</n8n-text>
</template>
</i18n>
</div>
<div v-if="isTrialExpired" :class="$style.usageText">
<n8n-text size="xsmall" color="danger">
{{ locale.baseText('executionUsage.expired.text') }}
</n8n-text>
</div>
<div v-if="!trialHasExecutionsLeft" :class="$style.usageText">
<n8n-text size="xsmall">
{{ locale.baseText('executionUsage.ranOutOfExecutions.text') }}
</n8n-text>
</div>
<div v-if="!isTrialExpired" :class="$style.usageCounter">
<div :class="$style.progressBarSection">
<progress
:class="[
trialHasExecutionsLeft ? $style.progressBarSuccess : $style.progressBarDanger,
$style.progressBar,
]"
:value="currentExecutions"
:max="maxExecutions"
></progress>
</div>
<div :class="$style.executionsCountSection">
<n8n-text size="xsmall" :color="trialHasExecutionsLeft ? 'text-dark' : 'danger'">
{{ currentExecutions }}/{{ maxExecutions }}
</n8n-text>
<n8n-text size="xsmall" :color="trialHasExecutionsLeft ? 'text-dark' : 'danger'">{{
locale.baseText('executionUsage.label.executions')
}}</n8n-text>
</div>
</div>

<div :class="$style.upgradeButtonSection">
<n8n-button
:label="locale.baseText('executionUsage.button.upgrade')"
size="mini"
icon="gem"
type="success"
@click="onUpgradeClicked"
/>
</div>
</div>
</template>

<script setup lang="ts">
import { onMounted, ref, computed } from 'vue';
import { i18n as locale } from '@/plugins/i18n';
import type { PlanData } from '@/Interface';
import { DateTime } from 'luxon';

const currentPlan = ref<PlanData>({
RicardoE105 marked this conversation as resolved.
Show resolved Hide resolved
planSpec: {
planId: 43039,
monthlyExecutionsLimit: 200,
activeWorkflowsLimit: 10,
credentialsLimit: 100,
isActive: false,
displayName: 'Trial',
metadata: {
version: 'v1',
group: 'trial',
slug: 'trial-1',
trial: {
length: 7,
gracePeriod: 3,
},
},
},
instance: {
createdAt: '2023-05-01T01:47:47Z',
},
usage: {
executions: 100,
activeWorkflows: 10,
},
});

const now = DateTime.utc();

onMounted(async () => {});

const daysLeftOnTrial = computed(() => {
const { days = 0 } = now.diff(getPlanStartingDate(), ['days']).toObject();
return Math.trunc(days);
});

const isTrialExpired = computed(() => {
const trialEndsAt = getPlanStartingDate()
.plus({ days: currentPlan.value.planSpec.metadata.trial.length })
.endOf('day');
RicardoE105 marked this conversation as resolved.
Show resolved Hide resolved
return now.toMillis() > trialEndsAt.toMillis();
});

const getPlanStartingDate = () =>
DateTime.fromISO(currentPlan.value.instance.createdAt).startOf('day');

const trialHasExecutionsLeft = computed(
() => currentPlan.value.usage.executions < currentPlan.value.planSpec.monthlyExecutionsLimit,
);

const userIsTrialing = computed(() => currentPlan.value.planSpec.metadata.group === 'trial');

const currentExecutions = computed(() => currentPlan.value.usage.executions);

const maxExecutions = computed(() => currentPlan.value.planSpec.monthlyExecutionsLimit);
RicardoE105 marked this conversation as resolved.
Show resolved Hide resolved

const onUpgradeClicked = () => {};
RicardoE105 marked this conversation as resolved.
Show resolved Hide resolved
</script>

<style module lang="scss">
.container {
display: flex;
flex-direction: column;
background-color: var(--color-background-light);
border-radius: 0px;
margin: 0;
border: var(--border-base);
border-right: 0;
RicardoE105 marked this conversation as resolved.
Show resolved Hide resolved
}

.progressBar {
width: 62.4px;
}

.progressBarSuccess {
accent-color: var(--color-foreground-xdark);
}

.progressBarDanger {
accent-color: var(--color-danger);
}

.usageText {
margin-left: var(--spacing-s);
margin-right: var(--spacing-s);
margin-top: var(--spacing-xs);
line-height: 12.5px;
RicardoE105 marked this conversation as resolved.
Show resolved Hide resolved
}

.usageCounter {
display: flex;
flex-direction: row;
align-items: center;
margin-left: var(--spacing-s);
margin-top: var(--spacing-2xs);
font-size: var(--font-size-3xs);
}
.progressBarSection {
width: 62.4px;
justify-content: center;
margin-right: 0px;
}
RicardoE105 marked this conversation as resolved.
Show resolved Hide resolved

.danger {
color: var(--color-danger);
}

.executionsCountSection {
margin-left: var(--spacing-xs);
}

.upgradeButtonSection {
margin: var(--spacing-s);
}

.upgradeButtonSection > * {
width: 100%;
RicardoE105 marked this conversation as resolved.
Show resolved Hide resolved
}
</style>
4 changes: 4 additions & 0 deletions packages/editor-ui/src/components/MainSidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
/>
</div>
</template>

<template #beforeLowerMenu> <ExecutionsUsage v-if="!isCollapsed" /></template>
<template #menuSuffix>
<div v-if="hasVersionUpdates || versionControlStore.state.currentBranch">
<div v-if="hasVersionUpdates" :class="$style.updates" @click="openUpdatesPanel">
Expand Down Expand Up @@ -134,6 +136,7 @@ import { useRootStore } from '@/stores/n8nRootStore';
import { useVersionsStore } from '@/stores/versions';
import { isNavigationFailure } from 'vue-router';
import { useVersionControlStore } from '@/stores/versionControl';
import ExecutionsUsage from '@/components/ExecutionsUsage.vue';

export default mixins(
genericHelpers,
Expand All @@ -147,6 +150,7 @@ export default mixins(
components: {
GiftNotificationIcon,
WorkflowSettings,
ExecutionsUsage,
},
data() {
return {
Expand Down
2 changes: 1 addition & 1 deletion packages/editor-ui/src/n8n-theme-variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ $header-height: 65px;

// sidebar
$sidebar-width: 65px;
$sidebar-expanded-width: 200px;
$sidebar-expanded-width: 202px;
RicardoE105 marked this conversation as resolved.
Show resolved Hide resolved
$sidebar-inactive-color: var(--color-foreground-xdark);
$sidebar-active-color: $color-primary;

Expand Down
9 changes: 8 additions & 1 deletion packages/editor-ui/src/plugins/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1811,5 +1811,12 @@
"userActivationSurveyModal.sharedFeedback.success": "Thanks for your feedback",
"userActivationSurveyModal.sharedFeedback.error": "Problem sharing feedback, try again",
"sso.login.divider": "or",
"sso.login.button": "Continue with SSO"
"sso.login.button": "Continue with SSO",
"executionUsage.currentUsage": "{text} {count}",
"executionUsage.currentUsage.text": "You are in a free trial with limited executions. You have",
"executionUsage.currentUsage.count": "days left.",
"executionUsage.label.executions": "Executions",
"executionUsage.button.upgrade": "Upgrade plan",
"executionUsage.expired.text": "You're trial is over. Upgrade now to keep your automation data",
"executionUsage.ranOutOfExecutions.text": "You’re out of executions. Upgrade your plan to keep automating."
}
2 changes: 2 additions & 0 deletions packages/editor-ui/src/plugins/icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ import {
faTree,
faStickyNote as faSolidStickyNote,
faUserLock,
faGem,
} from '@fortawesome/free-solid-svg-icons';
import { faVariable } from './custom';
import { faStickyNote } from '@fortawesome/free-regular-svg-icons';
Expand Down Expand Up @@ -264,5 +265,6 @@ addIcon(faVariable);
addIcon(faVideo);
addIcon(faTree);
addIcon(faUserLock);
addIcon(faGem);

Vue.component('font-awesome-icon', FontAwesomeIcon);