diff --git a/app/javascript/dashboard/composables/spec/useIntegrationHook.spec.js b/app/javascript/dashboard/composables/spec/useIntegrationHook.spec.js new file mode 100644 index 000000000..1837cf1dd --- /dev/null +++ b/app/javascript/dashboard/composables/spec/useIntegrationHook.spec.js @@ -0,0 +1,56 @@ +import { useIntegrationHook } from '../useIntegrationHook'; +import { useMapGetter } from 'dashboard/composables/store'; +import { nextTick } from 'vue'; + +vi.mock('dashboard/composables/store'); + +describe('useIntegrationHook', () => { + let integrationGetter; + + beforeEach(() => { + integrationGetter = vi.fn(); + useMapGetter.mockReturnValue({ value: integrationGetter }); + }); + + it('should return the correct computed properties', async () => { + const mockIntegration = { + id: 1, + hook_type: 'inbox', + hooks: ['hook1', 'hook2'], + allow_multiple_hooks: true, + }; + integrationGetter.mockReturnValue(mockIntegration); + + const hook = useIntegrationHook(1); + + await nextTick(); + + expect(hook.integration.value).toEqual(mockIntegration); + expect(hook.integrationType.value).toBe('multiple'); + expect(hook.isIntegrationMultiple.value).toBe(true); + expect(hook.isIntegrationSingle.value).toBe(false); + expect(hook.isHookTypeInbox.value).toBe(true); + expect(hook.hasConnectedHooks.value).toBe(true); + }); + + it('should handle single integration type correctly', async () => { + const mockIntegration = { + id: 2, + hook_type: 'channel', + hooks: [], + allow_multiple_hooks: false, + }; + integrationGetter.mockReturnValue(mockIntegration); + + const hook = useIntegrationHook(2); + + await nextTick(); + + expect(hook.integration.value).toEqual(mockIntegration); + expect(hook.integrationType.value).toBe('single'); + expect(hook.isIntegrationMultiple.value).toBe(false); + expect(hook.isIntegrationSingle.value).toBe(true); + expect(hook.isHookTypeInbox.value).toBe(false); + expect(hook.hasConnectedHooks.value).toBe(false); + }); +}); diff --git a/app/javascript/dashboard/composables/useIntegrationHook.js b/app/javascript/dashboard/composables/useIntegrationHook.js new file mode 100644 index 000000000..42546cceb --- /dev/null +++ b/app/javascript/dashboard/composables/useIntegrationHook.js @@ -0,0 +1,68 @@ +import { computed } from 'vue'; +import { useMapGetter } from 'dashboard/composables/store'; + +/** + * Composable for managing integration hooks + * @param {string|number} integrationId - The ID of the integration + * @returns {Object} An object containing computed properties for the integration + */ +export const useIntegrationHook = integrationId => { + const integrationGetter = useMapGetter('integrations/getIntegration'); + + /** + * The integration object + * @type {import('vue').ComputedRef} + */ + const integration = computed(() => { + return integrationGetter.value(integrationId); + }); + + /** + * Whether the integration hook type is 'inbox' + * @type {import('vue').ComputedRef} + */ + const isHookTypeInbox = computed(() => { + return integration.value.hook_type === 'inbox'; + }); + + /** + * Whether the integration has any connected hooks + * @type {import('vue').ComputedRef} + */ + const hasConnectedHooks = computed(() => { + return !!integration.value.hooks.length; + }); + + /** + * The type of integration: 'multiple' or 'single' + * @type {import('vue').ComputedRef} + */ + const integrationType = computed(() => { + return integration.value.allow_multiple_hooks ? 'multiple' : 'single'; + }); + + /** + * Whether the integration allows multiple hooks + * @type {import('vue').ComputedRef} + */ + const isIntegrationMultiple = computed(() => { + return integrationType.value === 'multiple'; + }); + + /** + * Whether the integration allows only a single hook + * @type {import('vue').ComputedRef} + */ + const isIntegrationSingle = computed(() => { + return integrationType.value === 'single'; + }); + + return { + integration, + integrationType, + isIntegrationMultiple, + isIntegrationSingle, + isHookTypeInbox, + hasConnectedHooks, + }; +}; diff --git a/app/javascript/dashboard/routes/dashboard/settings/integrations/IntegrationHooks.vue b/app/javascript/dashboard/routes/dashboard/settings/integrations/IntegrationHooks.vue index ad2daa5f3..0f8b9155e 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/integrations/IntegrationHooks.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/integrations/IntegrationHooks.vue @@ -2,7 +2,7 @@ import { isEmptyObject } from '../../../../helper/commons'; import { mapGetters } from 'vuex'; import { useAlert } from 'dashboard/composables'; -import hookMixin from './hookMixin'; +import { useIntegrationHook } from 'dashboard/composables/useIntegrationHook'; import NewHook from './NewHook.vue'; import SingleIntegrationHooks from './SingleIntegrationHooks.vue'; import MultipleIntegrationHooks from './MultipleIntegrationHooks.vue'; @@ -13,13 +13,28 @@ export default { SingleIntegrationHooks, MultipleIntegrationHooks, }, - mixins: [hookMixin], props: { integrationId: { type: [String, Number], required: true, }, }, + setup(props) { + const { integrationId } = props; + + const { + integration, + isIntegrationMultiple, + isIntegrationSingle, + isHookTypeInbox, + } = useIntegrationHook(integrationId); + return { + integration, + isIntegrationMultiple, + isIntegrationSingle, + isHookTypeInbox, + }; + }, data() { return { loading: {}, @@ -31,23 +46,9 @@ export default { }, computed: { ...mapGetters({ uiFlags: 'integrations/getUIFlags' }), - integration() { - return this.$store.getters['integrations/getIntegration']( - this.integrationId - ); - }, showIntegrationHooks() { return !this.uiFlags.isFetching && !isEmptyObject(this.integration); }, - integrationType() { - return this.integration.allow_multiple_hooks ? 'multiple' : 'single'; - }, - isIntegrationMultiple() { - return this.integrationType === 'multiple'; - }, - isIntegrationSingle() { - return this.integrationType === 'single'; - }, showAddButton() { return this.showIntegrationHooks && this.isIntegrationMultiple; }, @@ -120,14 +121,14 @@ export default {
@@ -135,7 +136,7 @@ export default {
- + import { mapGetters } from 'vuex'; -import hookMixin from './hookMixin'; +import { useIntegrationHook } from 'dashboard/composables/useIntegrationHook'; export default { - mixins: [hookMixin], props: { - integration: { - type: Object, - default: () => ({}), + integrationId: { + type: String, + required: true, }, }, + setup(props) { + const { integration, isHookTypeInbox, hasConnectedHooks } = + useIntegrationHook(props.integrationId); + return { integration, isHookTypeInbox, hasConnectedHooks }; + }, computed: { ...mapGetters({ globalConfig: 'globalConfig/get', diff --git a/app/javascript/dashboard/routes/dashboard/settings/integrations/NewHook.vue b/app/javascript/dashboard/routes/dashboard/settings/integrations/NewHook.vue index afaf059a6..935268592 100644 --- a/app/javascript/dashboard/routes/dashboard/settings/integrations/NewHook.vue +++ b/app/javascript/dashboard/routes/dashboard/settings/integrations/NewHook.vue @@ -2,16 +2,22 @@