Skip to content

Commit

Permalink
feat(editor): Implement loading and error states for dynamically load…
Browse files Browse the repository at this point in the history
…ed components in node parameter list (#8477)
  • Loading branch information
MiloradFilipovic authored Jan 30, 2024
1 parent 121a55b commit e643a12
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 32 deletions.
5 changes: 1 addition & 4 deletions packages/editor-ui/src/components/CollectionParameter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
</template>

<script lang="ts" setup>
import { ref, computed, defineAsyncComponent } from 'vue';
import { ref, computed } from 'vue';
import type { IUpdateInformation } from '@/Interface';
import type {
Expand All @@ -65,9 +65,6 @@ import { get } from 'lodash-es';
import { useNDVStore } from '@/stores/ndv.store';
import { useNodeHelpers } from '@/composables/useNodeHelpers';
import { useI18n } from '@/composables/useI18n';
const ParameterInputList = defineAsyncComponent(
async () => await import('./ParameterInputList.vue'),
);
const selectedOption = ref<string | undefined>(undefined);
export interface Props {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@
</template>

<script lang="ts">
import { defineAsyncComponent, defineComponent } from 'vue';
import { defineComponent } from 'vue';
import type { PropType } from 'vue';
import type { IUpdateInformation } from '@/Interface';
Expand All @@ -136,15 +136,8 @@ import { deepCopy, isINodePropertyCollectionList } from 'n8n-workflow';
import { get } from 'lodash-es';
const ParameterInputList = defineAsyncComponent(
async () => await import('./ParameterInputList.vue'),
);
export default defineComponent({
name: 'FixedCollectionParameter',
components: {
ParameterInputList,
},
props: {
nodeValues: {
type: Object as PropType<Record<string, INodeParameters[]>>,
Expand Down
79 changes: 59 additions & 20 deletions packages/editor-ui/src/components/ParameterInputList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -65,26 +65,38 @@
:underline="true"
color="text-dark"
/>
<Suspense>
<CollectionParameter
v-if="parameter.type === 'collection'"
:parameter="parameter"
:values="nodeHelpers.getParameterValue(nodeValues, parameter.name, path)"
:node-values="nodeValues"
:path="getPath(parameter.name)"
:is-read-only="isReadOnly"
@valueChanged="valueChanged"
/>
<FixedCollectionParameter
v-else-if="parameter.type === 'fixedCollection'"
:parameter="parameter"
:values="nodeHelpers.getParameterValue(nodeValues, parameter.name, path)"
:node-values="nodeValues"
:path="getPath(parameter.name)"
:is-read-only="isReadOnly"
@valueChanged="valueChanged"
/>
<Suspense v-if="!asyncLoadingError">
<template #default>
<CollectionParameter
v-if="parameter.type === 'collection'"
:parameter="parameter"
:values="nodeHelpers.getParameterValue(nodeValues, parameter.name, path)"
:node-values="nodeValues"
:path="getPath(parameter.name)"
:is-read-only="isReadOnly"
@valueChanged="valueChanged"
/>
<FixedCollectionParameter
v-else-if="parameter.type === 'fixedCollection'"
:parameter="parameter"
:values="nodeHelpers.getParameterValue(nodeValues, parameter.name, path)"
:node-values="nodeValues"
:path="getPath(parameter.name)"
:is-read-only="isReadOnly"
@valueChanged="valueChanged"
/>
</template>
<template #fallback>
<n8n-text size="small" class="async-notice">
<n8n-icon icon="sync-alt" size="xsmall" :spin="true" />
{{ $locale.baseText('parameterInputList.loadingFields') }}
</n8n-text>
</template>
</Suspense>
<n8n-text v-else size="small" color="danger" class="async-notice">
<n8n-icon icon="exclamation-triangle" size="xsmall" />
{{ $locale.baseText('parameterInputList.loadingError') }}
</n8n-text>
</div>
<ResourceMapper
v-else-if="parameter.type === 'resourceMapper'"
Expand Down Expand Up @@ -150,7 +162,7 @@ import type {
import { deepCopy } from 'n8n-workflow';
import { mapStores } from 'pinia';
import type { PropType } from 'vue';
import { defineAsyncComponent, defineComponent } from 'vue';
import { defineAsyncComponent, defineComponent, onErrorCaptured, ref } from 'vue';
import type { INodeUi, IUpdateInformation } from '@/Interface';
Expand Down Expand Up @@ -226,9 +238,31 @@ export default defineComponent({
},
setup() {
const nodeHelpers = useNodeHelpers();
const asyncLoadingError = ref(false);
// This will catch errors in async components
onErrorCaptured((e, component) => {
if (
!['FixedCollectionParameter', 'CollectionParameter'].includes(
component?.$options.name as string,
)
) {
return;
}
asyncLoadingError.value = true;
console.error(e);
window?.Sentry?.captureException(e, {
tags: {
asyncLoadingError: true,
},
});
// Don't propagate the error further
return false;
});
return {
nodeHelpers,
asyncLoadingError,
};
},
computed: {
Expand Down Expand Up @@ -572,5 +606,10 @@ export default defineComponent({
font-weight: var(--font-weight-bold);
}
}
.async-notice {
display: block;
padding: var(--spacing-3xs) 0;
}
}
</style>
2 changes: 2 additions & 0 deletions packages/editor-ui/src/plugins/components.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ import { N8nPlugin } from 'n8n-design-system';
import { useMessage } from '@/composables/useMessage';
import EnterpriseEdition from '@/components/EnterpriseEdition.ee.vue';
import RBAC from '@/components/RBAC.vue';
import ParameterInputList from '@/components/ParameterInputList.vue';

export const GlobalComponentsPlugin: Plugin<{}> = {
install(app) {
const messageService = useMessage();

app.component('EnterpriseEdition', EnterpriseEdition);
app.component('RBAC', RBAC);
app.component('ParameterInputList', ParameterInputList);

app.use(ElementPlus);
app.use(N8nPlugin);
Expand Down
2 changes: 2 additions & 0 deletions packages/editor-ui/src/plugins/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1181,6 +1181,8 @@
"parameterInputList.delete": "Delete",
"parameterInputList.deleteParameter": "Delete Parameter",
"parameterInputList.parameterOptions": "Parameter Options",
"parameterInputList.loadingFields": "Loading fields...",
"parameterInputList.loadingError": "Error loading fields. Refresh you page and try again.",
"personalizationModal.businessOwner": "Business Owner",
"personalizationModal.continue": "Continue",
"personalizationModal.cicd": "CI/CD",
Expand Down

0 comments on commit e643a12

Please sign in to comment.