mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-21 11:49:59 +00:00
refactor(editor): Move editor-ui and design-system to frontend dir (no-changelog) (#13564)
This commit is contained in:
@@ -0,0 +1,209 @@
|
||||
<script setup lang="ts">
|
||||
import {
|
||||
COMMUNITY_PACKAGE_INSTALL_MODAL_KEY,
|
||||
COMMUNITY_NODES_INSTALLATION_DOCS_URL,
|
||||
} from '@/constants';
|
||||
import CommunityPackageCard from '@/components/CommunityPackageCard.vue';
|
||||
import { useToast } from '@/composables/useToast';
|
||||
import { useDocumentTitle } from '@/composables/useDocumentTitle';
|
||||
import type { PublicInstalledPackage } from 'n8n-workflow';
|
||||
|
||||
import { useCommunityNodesStore } from '@/stores/communityNodes.store';
|
||||
import { useUIStore } from '@/stores/ui.store';
|
||||
import { onBeforeUnmount, ref } from 'vue';
|
||||
import { useExternalHooks } from '@/composables/useExternalHooks';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { usePushConnection } from '@/composables/usePushConnection';
|
||||
import { usePushConnectionStore } from '@/stores/pushConnection.store';
|
||||
import { computed } from 'vue';
|
||||
import { useI18n } from '@/composables/useI18n';
|
||||
import { onBeforeMount } from 'vue';
|
||||
import { onMounted } from 'vue';
|
||||
import { useTelemetry } from '@/composables/useTelemetry';
|
||||
|
||||
const PACKAGE_COUNT_THRESHOLD = 31;
|
||||
|
||||
const loading = ref(false);
|
||||
|
||||
const router = useRouter();
|
||||
const pushConnection = usePushConnection({ router });
|
||||
const pushStore = usePushConnectionStore();
|
||||
const externalHooks = useExternalHooks();
|
||||
const i18n = useI18n();
|
||||
const telemetry = useTelemetry();
|
||||
const toast = useToast();
|
||||
const documentTitle = useDocumentTitle();
|
||||
|
||||
const communityNodesStore = useCommunityNodesStore();
|
||||
const uiStore = useUIStore();
|
||||
|
||||
const getEmptyStateDescription = computed(() => {
|
||||
const packageCount = communityNodesStore.availablePackageCount;
|
||||
|
||||
return packageCount < PACKAGE_COUNT_THRESHOLD
|
||||
? i18n.baseText('settings.communityNodes.empty.description.no-packages', {
|
||||
interpolate: {
|
||||
docURL: COMMUNITY_NODES_INSTALLATION_DOCS_URL,
|
||||
},
|
||||
})
|
||||
: i18n.baseText('settings.communityNodes.empty.description', {
|
||||
interpolate: {
|
||||
docURL: COMMUNITY_NODES_INSTALLATION_DOCS_URL,
|
||||
count: (Math.floor(packageCount / 10) * 10).toString(),
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
const getEmptyStateButtonText = computed(() =>
|
||||
i18n.baseText('settings.communityNodes.empty.installPackageLabel'),
|
||||
);
|
||||
|
||||
const actionBoxConfig = computed(() => {
|
||||
return {
|
||||
calloutText: '',
|
||||
calloutTheme: '',
|
||||
hideButton: false,
|
||||
};
|
||||
});
|
||||
|
||||
const onClickEmptyStateButton = () => {
|
||||
openInstallModal();
|
||||
};
|
||||
|
||||
const openInstallModal = () => {
|
||||
const telemetryPayload = {
|
||||
is_empty_state: communityNodesStore.getInstalledPackages.length === 0,
|
||||
};
|
||||
telemetry.track('user clicked cnr install button', telemetryPayload);
|
||||
|
||||
void externalHooks.run('settingsCommunityNodesView.openInstallModal', telemetryPayload);
|
||||
uiStore.openModal(COMMUNITY_PACKAGE_INSTALL_MODAL_KEY);
|
||||
};
|
||||
|
||||
onBeforeMount(() => {
|
||||
pushConnection.initialize();
|
||||
// The push connection is needed here to receive `reloadNodeType` and `removeNodeType` events when community nodes are installed, updated, or removed.
|
||||
pushStore.pushConnect();
|
||||
});
|
||||
|
||||
onMounted(async () => {
|
||||
documentTitle.set(i18n.baseText('settings.communityNodes'));
|
||||
try {
|
||||
loading.value = true;
|
||||
await communityNodesStore.fetchInstalledPackages();
|
||||
|
||||
const installedPackages: PublicInstalledPackage[] = communityNodesStore.getInstalledPackages;
|
||||
const packagesToUpdate: PublicInstalledPackage[] = installedPackages.filter(
|
||||
(p) => p.updateAvailable,
|
||||
);
|
||||
telemetry.track('user viewed cnr settings page', {
|
||||
num_of_packages_installed: installedPackages.length,
|
||||
installed_packages: installedPackages.map((p) => {
|
||||
return {
|
||||
package_name: p.packageName,
|
||||
package_version: p.installedVersion,
|
||||
package_nodes: p.installedNodes.map((node) => `${node.name}-v${node.latestVersion}`),
|
||||
is_update_available: p.updateAvailable !== undefined,
|
||||
};
|
||||
}),
|
||||
packages_to_update: packagesToUpdate.map((p) => {
|
||||
return {
|
||||
package_name: p.packageName,
|
||||
package_version_current: p.installedVersion,
|
||||
package_version_available: p.updateAvailable,
|
||||
};
|
||||
}),
|
||||
number_of_updates_available: packagesToUpdate.length,
|
||||
});
|
||||
} catch (error) {
|
||||
toast.showError(
|
||||
error,
|
||||
i18n.baseText('settings.communityNodes.fetchError.title'),
|
||||
i18n.baseText('settings.communityNodes.fetchError.message'),
|
||||
);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
try {
|
||||
await communityNodesStore.fetchAvailableCommunityPackageCount();
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
pushStore.pushDisconnect();
|
||||
pushConnection.terminate();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="$style.container">
|
||||
<div :class="$style.headingContainer">
|
||||
<n8n-heading size="2xlarge">{{ i18n.baseText('settings.communityNodes') }}</n8n-heading>
|
||||
<n8n-button
|
||||
v-if="communityNodesStore.getInstalledPackages.length > 0 && !loading"
|
||||
:label="i18n.baseText('settings.communityNodes.installModal.installButton.label')"
|
||||
size="large"
|
||||
@click="openInstallModal"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="loading" :class="$style.cardsContainer">
|
||||
<CommunityPackageCard
|
||||
v-for="n in 2"
|
||||
:key="'index-' + n"
|
||||
:loading="true"
|
||||
></CommunityPackageCard>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="communityNodesStore.getInstalledPackages.length === 0"
|
||||
:class="$style.actionBoxContainer"
|
||||
>
|
||||
<n8n-action-box
|
||||
:heading="i18n.baseText('settings.communityNodes.empty.title')"
|
||||
:description="getEmptyStateDescription"
|
||||
:button-text="getEmptyStateButtonText"
|
||||
:callout-text="actionBoxConfig.calloutText"
|
||||
:callout-theme="actionBoxConfig.calloutTheme"
|
||||
@click:button="onClickEmptyStateButton"
|
||||
/>
|
||||
</div>
|
||||
<div v-else :class="$style.cardsContainer">
|
||||
<CommunityPackageCard
|
||||
v-for="communityPackage in communityNodesStore.getInstalledPackages"
|
||||
:key="communityPackage.packageName"
|
||||
:community-package="communityPackage"
|
||||
></CommunityPackageCard>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" module>
|
||||
.container {
|
||||
height: 100%;
|
||||
padding-right: var(--spacing-2xs);
|
||||
> * {
|
||||
margin-bottom: var(--spacing-2xl);
|
||||
}
|
||||
}
|
||||
|
||||
.headingContainer {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.loadingContainer {
|
||||
display: flex;
|
||||
gap: var(--spacing-xs);
|
||||
}
|
||||
|
||||
.actionBoxContainer {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.cardsContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--spacing-2xs);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user