feat(editor): Add cloud ExecutionsUsage and API blocking using licenses (#6159)
* Add ExecutionsUsage component * set $sidebar-expanded-width back to 200px * add days using interpolation * Rename PlanData type to CloudPlanData * Rename Metadata type to PlanMetadata * Make prop block in the update button * Use variable in line-height * Remove progressBarSection class * fix trial expiration calculation * mock expirationDate and fix issue with days left * Remove unnecesary property from class .container * inject component data via props * Check for plan data during app mounting and keep data in the store * Remove mounted hook * redirect when upgrade plan is clicked * Remove computed properties * Remove instance property as it's not needed anymore * Flatten plan object * remove console.log * Add all cloud types within its own namespace * keep redirection inside component * get computed properties back * Improve polling logic * Move cloudData to its own store * Remove commented interfaces * remove cloudPlan from user store * fix imports * update logic for userIsTrialing method * centralize userIsTrialing method * redirect to production change plan page always * Call staging or production cloud api depending on base URL * remove setting store form ExecutionUsage.vue * fix linting issue * Add trial group to PlanMetadata group * Move helpers into the store * make staging url check more specific * make cloud state nullable * fix linting issue * swap mockup date for endpoint * Make getCurrentPlan async * asas * Improvements * small improvements * chore: resolve conflicts * make sure there is data before calculating trial expiration * Fix issue with component not loading on first page load * type safety improvements * apply component ui feedback * fix linting issue * chore: clean up unnecessary change from merge conflict * feat: Block api feature using licenses, show notice page for trial cloud users (#6187) * rename planSpec to plan * Remove instance property as it's not needed anymore * Flatten plan object * remove console.log * feat: disable api using license * feat: add api page * chore: resolve conflicts * chore: resolve conflicts * feat: update and refactor a bit * fix: update endpoints * fix: update endpoints * fix: use host * feat: update copy * fix linting issues --------- Co-authored-by: ricardo <ricardoespinoza105@gmail.com> * add pluralization to days left text --------- Co-authored-by: Mutasem <mutdmour@gmail.com> Co-authored-by: Mutasem Aldmour <4711238+mutdmour@users.noreply.github.com>
This commit is contained in:
83
packages/editor-ui/src/stores/cloudPlan.store.ts
Normal file
83
packages/editor-ui/src/stores/cloudPlan.store.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import { computed, reactive } from 'vue';
|
||||
import { defineStore } from 'pinia';
|
||||
import type { CloudPlanState } from '@/Interface';
|
||||
import { useRootStore } from '@/stores/n8nRoot.store';
|
||||
import { useSettingsStore } from '@/stores/settings.store';
|
||||
import { useUsersStore } from '@/stores/users.store';
|
||||
import { getCurrentPlan, getCurrentUsage } from '@/api/cloudPlans';
|
||||
import { DateTime } from 'luxon';
|
||||
|
||||
const DEFAULT_STATE: CloudPlanState = {
|
||||
data: null,
|
||||
usage: null,
|
||||
loadingPlan: false,
|
||||
};
|
||||
|
||||
export const useCloudPlanStore = defineStore('cloudPlan', () => {
|
||||
const rootStore = useRootStore();
|
||||
const settingsStore = useSettingsStore();
|
||||
const usersStore = useUsersStore();
|
||||
|
||||
const state = reactive<CloudPlanState>(DEFAULT_STATE);
|
||||
|
||||
const setData = (data: CloudPlanState['data']) => {
|
||||
state.data = data;
|
||||
};
|
||||
|
||||
const setUsage = (data: CloudPlanState['usage']) => {
|
||||
state.usage = data;
|
||||
};
|
||||
|
||||
const userIsTrialing = computed(() => state.data?.metadata?.group === 'trial');
|
||||
|
||||
const currentPlanData = computed(() => state.data);
|
||||
|
||||
const currentUsageData = computed(() => state.usage);
|
||||
|
||||
const trialExpired = computed(
|
||||
() =>
|
||||
state.data?.metadata?.group === 'trial' &&
|
||||
DateTime.now().toMillis() >= DateTime.fromISO(state.data?.expirationDate).toMillis(),
|
||||
);
|
||||
|
||||
const allExecutionsUsed = computed(() => {
|
||||
if (!state.usage?.executions || !state.data?.monthlyExecutionsLimit) return false;
|
||||
return state.usage?.executions >= state.data?.monthlyExecutionsLimit;
|
||||
});
|
||||
|
||||
const getOwnerCurrentPLan = async () => {
|
||||
const cloudUserId = settingsStore.settings.n8nMetadata?.userId;
|
||||
const hasCloudPlan =
|
||||
usersStore.currentUser?.isOwner && settingsStore.isCloudDeployment && cloudUserId;
|
||||
if (!hasCloudPlan) throw new Error('User does not have a cloud plan');
|
||||
state.loadingPlan = true;
|
||||
let plan;
|
||||
try {
|
||||
plan = await getCurrentPlan(rootStore.getRestCloudApiContext, `${cloudUserId}`);
|
||||
state.data = plan;
|
||||
state.loadingPlan = false;
|
||||
} catch (error) {
|
||||
state.loadingPlan = false;
|
||||
throw new Error(error);
|
||||
}
|
||||
|
||||
return plan;
|
||||
};
|
||||
|
||||
const getInstanceCurrentUsage = async () => {
|
||||
const usage = await getCurrentUsage({ baseUrl: rootStore.getBaseUrl, sessionId: '' });
|
||||
state.usage = usage;
|
||||
return usage;
|
||||
};
|
||||
|
||||
return {
|
||||
state,
|
||||
getOwnerCurrentPLan,
|
||||
getInstanceCurrentUsage,
|
||||
userIsTrialing,
|
||||
currentPlanData,
|
||||
currentUsageData,
|
||||
trialExpired,
|
||||
allExecutionsUsed,
|
||||
};
|
||||
});
|
||||
@@ -21,3 +21,4 @@ export * from './versions.store';
|
||||
export * from './webhooks.store';
|
||||
export * from './workflows.ee.store';
|
||||
export * from './workflows.store';
|
||||
export * from './cloudPlan.store';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { STORES } from '@/constants';
|
||||
import { CLOUD_BASE_URL_PRODUCTION, CLOUD_BASE_URL_STAGING, STORES } from '@/constants';
|
||||
import type { IRestApiContext, RootState } from '@/Interface';
|
||||
import type { IDataObject } from 'n8n-workflow';
|
||||
import { defineStore } from 'pinia';
|
||||
@@ -48,6 +48,15 @@ export const useRootStore = defineStore(STORES.ROOT, {
|
||||
return `${this.baseUrl}${this.restEndpoint}`;
|
||||
},
|
||||
|
||||
getRestCloudApiContext(): IRestApiContext {
|
||||
return {
|
||||
baseUrl: window.location.host.includes('stage-app.n8n.cloud')
|
||||
? CLOUD_BASE_URL_STAGING
|
||||
: CLOUD_BASE_URL_PRODUCTION,
|
||||
sessionId: '',
|
||||
};
|
||||
},
|
||||
|
||||
getRestApiContext(): IRestApiContext {
|
||||
return {
|
||||
baseUrl: this.getRestUrl,
|
||||
|
||||
Reference in New Issue
Block a user