From 384cccf542dbd71108be3ca563fbeac45049aefb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20=C3=96hlerking?= Date: Thu, 12 Oct 2023 16:26:13 +0200 Subject: [PATCH 01/13] implement configuration dialog --- ...ernalToolElementDisplayState.composable.ts | 74 + ...ToolElementDisplayState.composable.unit.ts | 142 + .../data-board-external-tool-element/index.ts | 1 + .../data-board/BoardApi.composable.ts | 15 +- .../ContextExternalToolApi.composable.ts | 31 + .../ContextExternalToolApi.composable.unit.ts | 75 + src/components/data-external-tool/index.ts | 1 + .../ExternalToolConfigurator.vue | 9 +- .../ExternalToolElement.unit.ts | 240 +- .../ExternalToolElement.vue | 75 +- ...ExternalToolElementConfigurationDialog.vue | 211 + .../feature-board/card/CardHost.unit.ts | 25 + .../feature-board/card/CardHost.vue | 38 +- .../card/ContentElementList.unit.ts | 4 + .../feature-board/card/ContentElementList.vue | 5 + src/locales/de.json | 3 +- src/locales/en.json | 3 +- src/locales/es.json | 3 +- src/locales/uk.json | 3 +- ...ntextExternalToolConfigurator.page.unit.ts | 26 +- .../ContextExternalToolConfigurator.page.vue | 30 +- .../rooms/tools/RoomExternalToolsOverview.vue | 8 +- .../rooms/tools/RoomExternalToolsSection.vue | 20 +- src/router/routes.ts | 2 +- src/serverApi/v3/api.ts | 37687 +++++++++------- src/store/context-external-tools.ts | 58 +- src/store/context-external-tools.unit.ts | 26 +- .../external-tool/context-external-tool.ts | 2 +- src/store/external-tool/index.ts | 1 - .../mapper/context-external-tool.mapper.ts | 6 +- .../context-external-tool.mapper.unit.ts | 8 +- .../external-tool/tool-context-type.enum.ts | 4 - .../factory/contextExternalToolFactory.ts | 6 +- .../factory/contextExternalToolSaveFactory.ts | 4 +- tests/test-utils/factory/index.ts | 1 + tsconfig.json | 2 + vue.config.js | 4 + 37 files changed, 23203 insertions(+), 15650 deletions(-) create mode 100644 src/components/data-board-external-tool-element/SharedExternalToolElementDisplayState.composable.ts create mode 100644 src/components/data-board-external-tool-element/SharedExternalToolElementDisplayState.composable.unit.ts create mode 100644 src/components/data-board-external-tool-element/index.ts create mode 100644 src/components/data-external-tool/ContextExternalToolApi.composable.ts create mode 100644 src/components/data-external-tool/ContextExternalToolApi.composable.unit.ts create mode 100644 src/components/data-external-tool/index.ts create mode 100644 src/components/feature-board-external-tool-element/ExternalToolElementConfigurationDialog.vue delete mode 100644 src/store/external-tool/tool-context-type.enum.ts diff --git a/src/components/data-board-external-tool-element/SharedExternalToolElementDisplayState.composable.ts b/src/components/data-board-external-tool-element/SharedExternalToolElementDisplayState.composable.ts new file mode 100644 index 0000000000..1d9757d166 --- /dev/null +++ b/src/components/data-board-external-tool-element/SharedExternalToolElementDisplayState.composable.ts @@ -0,0 +1,74 @@ +import { useErrorHandler } from "@/components/error-handling/ErrorHandler.composable"; +import { ToolContextType } from "@/serverApi/v3"; +import { ExternalToolDisplayData } from "@/store/external-tool"; +import { createTestableSharedComposable } from "@/utils/create-shared-composable"; +import { useContextExternalToolApi } from "@data-external-tool"; +import { ref, Ref } from "vue"; + +export const useSharedExternalToolElementDisplayState = + createTestableSharedComposable(() => { + const { handleError } = useErrorHandler(); + const { fetchDisplayDataCall } = useContextExternalToolApi(); + const displayDataMap: Map> = new Map< + string, + Ref + >(); + const isLoading: Ref = ref(false); + + const getDisplayDataList = ( + cardId: string + ): Ref | undefined => { + const displayDataList: Ref | undefined = + displayDataMap.get(cardId); + + return displayDataList; + }; + + const fetchDisplayData = async (cardId: string): Promise => { + isLoading.value = true; + + try { + let displayDataList: Ref | undefined = + getDisplayDataList(cardId); + + if (!displayDataList?.value) { + displayDataList = ref([]); + + displayDataMap.set(cardId, displayDataList); + } + + displayDataList.value = await fetchDisplayDataCall( + cardId, + ToolContextType.BoardCard + ); + } catch (error) { + handleError(error); + } + + isLoading.value = false; + }; + + const findDisplayData = ( + cardId: string, + contextExternalToolId: string + ): ExternalToolDisplayData | undefined => { + const displayDataList: Ref | undefined = + getDisplayDataList(cardId); + + const displayData: ExternalToolDisplayData | undefined = + displayDataList?.value.find( + (externalToolDisplayData: ExternalToolDisplayData) => + externalToolDisplayData.contextExternalToolId === + contextExternalToolId + ); + + return displayData; + }; + + return { + isLoading, + getDisplayDataList, + fetchDisplayData, + findDisplayData, + }; + }); diff --git a/src/components/data-board-external-tool-element/SharedExternalToolElementDisplayState.composable.unit.ts b/src/components/data-board-external-tool-element/SharedExternalToolElementDisplayState.composable.unit.ts new file mode 100644 index 0000000000..f2472fa4f9 --- /dev/null +++ b/src/components/data-board-external-tool-element/SharedExternalToolElementDisplayState.composable.unit.ts @@ -0,0 +1,142 @@ +import { useErrorHandler } from "@/components/error-handling/ErrorHandler.composable"; +import { ToolContextType } from "@/serverApi/v3"; +import { ExternalToolDisplayData } from "@/store/external-tool"; +import { externalToolDisplayDataFactory } from "@@/tests/test-utils"; +import { useContextExternalToolApi } from "@data-external-tool"; +import { createMock, DeepMocked } from "@golevelup/ts-jest"; +import { Ref } from "vue"; +import { useSharedExternalToolElementDisplayState } from "./SharedExternalToolElementDisplayState.composable"; + +jest.mock("@data-external-tool"); +jest.mock("@/components/error-handling/ErrorHandler.composable"); +jest.mock( + "@/utils/create-shared-composable", + () => ({ + createTestableSharedComposable: (composable) => composable, + }) +); + +describe("SharedExternalToolElementDisplayState.composable", () => { + let useContextExternalToolApiMock: DeepMocked< + ReturnType + >; + let useErrorHandlerMock: DeepMocked>; + + beforeEach(() => { + useContextExternalToolApiMock = + createMock>(); + useErrorHandlerMock = createMock>(); + + jest + .mocked(useContextExternalToolApi) + .mockReturnValue(useContextExternalToolApiMock); + jest.mocked(useErrorHandler).mockReturnValue(useErrorHandlerMock); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + describe("when no data is loaded", () => { + it("should have no data lists", async () => { + const displayDataState = useSharedExternalToolElementDisplayState(); + + const result: Ref | undefined = + displayDataState.getDisplayDataList("cardId"); + + expect(result).toBeUndefined(); + }); + + it("should not find data", async () => { + const displayDataState = useSharedExternalToolElementDisplayState(); + + const result: ExternalToolDisplayData | undefined = + displayDataState.findDisplayData("cardId", "contextExternalToolId"); + + expect(result).toBeUndefined(); + }); + }); + + describe("when data is loaded", () => { + const setup = () => { + const displayData: ExternalToolDisplayData = + externalToolDisplayDataFactory.build(); + + useContextExternalToolApiMock.fetchDisplayDataCall.mockResolvedValue([ + displayData, + ]); + + return { + displayData, + ...useSharedExternalToolElementDisplayState(), + }; + }; + + it("should call the api for display data of the card", async () => { + const { fetchDisplayData } = setup(); + + await fetchDisplayData("cardId"); + + expect( + useContextExternalToolApiMock.fetchDisplayDataCall + ).toHaveBeenCalledWith("cardId", ToolContextType.BoardCard); + }); + + it("should set the display data in the state", async () => { + const { fetchDisplayData, getDisplayDataList, displayData } = setup(); + + await fetchDisplayData("cardId"); + const result: Ref | undefined = + getDisplayDataList("cardId"); + + expect(result?.value).toEqual([displayData]); + }); + + it("should find the display data for a specific tool", async () => { + const { fetchDisplayData, findDisplayData, displayData } = setup(); + + await fetchDisplayData("cardId"); + const result: ExternalToolDisplayData | undefined = findDisplayData( + "cardId", + displayData.contextExternalToolId + ); + + expect(result).toEqual(displayData); + }); + + it("should not find data for non-existing tools", async () => { + const { fetchDisplayData, findDisplayData } = setup(); + + await fetchDisplayData("cardId"); + const result: ExternalToolDisplayData | undefined = findDisplayData( + "cardId", + "otherId" + ); + + expect(result).toBeUndefined(); + }); + }); + + describe("when an error occurs during loading", () => { + const setup = () => { + const error = new Error("unable to load"); + + useContextExternalToolApiMock.fetchDisplayDataCall.mockRejectedValue( + error + ); + + return { + error, + ...useSharedExternalToolElementDisplayState(), + }; + }; + + it("should handle the error", async () => { + const { fetchDisplayData, error } = setup(); + + await fetchDisplayData("cardId"); + + expect(useErrorHandlerMock.handleError).toHaveBeenCalledWith(error); + }); + }); +}); diff --git a/src/components/data-board-external-tool-element/index.ts b/src/components/data-board-external-tool-element/index.ts new file mode 100644 index 0000000000..a19823e3ff --- /dev/null +++ b/src/components/data-board-external-tool-element/index.ts @@ -0,0 +1 @@ +export * from "./SharedExternalToolElementDisplayState.composable"; diff --git a/src/components/data-board/BoardApi.composable.ts b/src/components/data-board/BoardApi.composable.ts index 33951e8215..7307663df3 100644 --- a/src/components/data-board/BoardApi.composable.ts +++ b/src/components/data-board/BoardApi.composable.ts @@ -9,7 +9,7 @@ import { ContentElementType, CreateCardBodyParamsRequiredEmptyElementsEnum, CreateContentElementBodyParams, - ExternalToolElementContent, + ExternalToolElementResponse, FileElementContent, RichTextElementContent, RoomsApiFactory, @@ -91,9 +91,12 @@ export const useBoardApi = () => { }; } - if (element.type === ContentElementType.ExternalTool) { + if (isExternalToolElement(element)) { return { - content: element.content as ExternalToolElementContent, + content: { + contextExternalToolId: + element.content.contextExternalToolId ?? undefined, + }, type: ContentElementType.ExternalTool, }; } @@ -101,6 +104,12 @@ export const useBoardApi = () => { throw new Error("element.type mapping is undefined for updateElementCall"); }; + const isExternalToolElement = ( + element: AnyContentElement + ): element is ExternalToolElementResponse => { + return element.type === ContentElementType.ExternalTool; + }; + const createElementCall = async ( cardId: string, params: CreateContentElementBodyParams diff --git a/src/components/data-external-tool/ContextExternalToolApi.composable.ts b/src/components/data-external-tool/ContextExternalToolApi.composable.ts new file mode 100644 index 0000000000..236e124826 --- /dev/null +++ b/src/components/data-external-tool/ContextExternalToolApi.composable.ts @@ -0,0 +1,31 @@ +import { + ToolApiFactory, + ToolApiInterface, + ToolContextType, + ToolReferenceListResponse, +} from "@/serverApi/v3"; +import { ExternalToolDisplayData } from "@/store/external-tool"; +import { ExternalToolMapper } from "@/store/external-tool/mapper"; +import { $axios } from "@/utils/api"; +import { AxiosResponse } from "axios"; + +export const useContextExternalToolApi = () => { + const toolApi: ToolApiInterface = ToolApiFactory(undefined, "/v3", $axios); + + const fetchDisplayDataCall = async ( + contextId: string, + contextType: ToolContextType + ): Promise => { + const response: AxiosResponse = + await toolApi.toolControllerGetToolReferences(contextId, contextType); + + const mapped: ExternalToolDisplayData[] = + ExternalToolMapper.mapToExternalToolDisplayData(response.data); + + return mapped; + }; + + return { + fetchDisplayDataCall, + }; +}; diff --git a/src/components/data-external-tool/ContextExternalToolApi.composable.unit.ts b/src/components/data-external-tool/ContextExternalToolApi.composable.unit.ts new file mode 100644 index 0000000000..9d72d794cd --- /dev/null +++ b/src/components/data-external-tool/ContextExternalToolApi.composable.unit.ts @@ -0,0 +1,75 @@ +import * as serverApi from "@/serverApi/v3/api"; +import { ToolContextType, ToolReferenceResponse } from "@/serverApi/v3/api"; +import { + ExternalToolDisplayData, + ToolConfigurationStatus, +} from "@/store/external-tool"; +import { + mockApiResponse, + toolReferenceResponseFactory, +} from "@@/tests/test-utils"; +import { createMock, DeepMocked } from "@golevelup/ts-jest"; +import { useContextExternalToolApi } from "./ContextExternalToolApi.composable"; + +describe("ContextExternalToolApi.composable", () => { + let toolApi: DeepMocked; + + beforeEach(() => { + toolApi = createMock(); + + jest.spyOn(serverApi, "ToolApiFactory").mockReturnValue(toolApi); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + describe("fetchDisplayDataCall", () => { + const setup = () => { + const displayData: ToolReferenceResponse = + toolReferenceResponseFactory.build({ logoUrl: "mockLogoUrl" }); + + toolApi.toolControllerGetToolReferences.mockResolvedValue( + mockApiResponse({ data: { data: [displayData] } }) + ); + + return { + displayData, + }; + }; + + it("should call the api for tool references", async () => { + setup(); + + await useContextExternalToolApi().fetchDisplayDataCall( + "cardId", + ToolContextType.BoardCard + ); + + expect(toolApi.toolControllerGetToolReferences).toHaveBeenCalledWith( + "cardId", + ToolContextType.BoardCard + ); + }); + + it("should return an array of display data", async () => { + const { displayData } = setup(); + + const result: ExternalToolDisplayData[] = + await useContextExternalToolApi().fetchDisplayDataCall( + "courseId", + ToolContextType.Course + ); + + expect(result).toEqual([ + { + contextExternalToolId: displayData.contextToolId, + name: displayData.displayName, + logoUrl: displayData.logoUrl, + status: ToolConfigurationStatus.Latest, + openInNewTab: displayData.openInNewTab, + }, + ]); + }); + }); +}); diff --git a/src/components/data-external-tool/index.ts b/src/components/data-external-tool/index.ts new file mode 100644 index 0000000000..a86cde4ed7 --- /dev/null +++ b/src/components/data-external-tool/index.ts @@ -0,0 +1 @@ +export * from "./ContextExternalToolApi.composable"; diff --git a/src/components/external-tools/configuration/ExternalToolConfigurator.vue b/src/components/external-tools/configuration/ExternalToolConfigurator.vue index e66283404f..7f09314e6d 100644 --- a/src/components/external-tools/configuration/ExternalToolConfigurator.vue +++ b/src/components/external-tools/configuration/ExternalToolConfigurator.vue @@ -29,6 +29,7 @@

import ExternalToolConfigSettings from "@/components/external-tools/configuration/ExternalToolConfigSettings.vue"; import { useExternalToolMappings } from "@/composables/external-tool-mappings.composable"; +import { useI18n } from "@/composables/i18n.composable"; import { ExternalToolConfigurationTemplate, SchoolExternalTool, } from "@/store/external-tool"; +import { ContextExternalTool } from "@/store/external-tool/context-external-tool"; import { BusinessError } from "@/store/types/commons"; import { computed, @@ -91,9 +94,7 @@ import { useSlots, watch, } from "vue"; -import { useI18n } from "@/composables/i18n.composable"; import ExternalToolSelectionRow from "./ExternalToolSelectionRow.vue"; -import { ContextExternalTool } from "@/store/external-tool/context-external-tool"; type ConfigurationTypes = SchoolExternalTool | ContextExternalTool; @@ -117,6 +118,10 @@ export default defineComponent({ loading: { type: Boolean, }, + displaySettingsTitle: { + type: Boolean, + default: true, + }, }, setup(props, { emit }) { const { t } = useI18n(); diff --git a/src/components/feature-board-external-tool-element/ExternalToolElement.unit.ts b/src/components/feature-board-external-tool-element/ExternalToolElement.unit.ts index 82e7ecc6c5..cb892f96e2 100644 --- a/src/components/feature-board-external-tool-element/ExternalToolElement.unit.ts +++ b/src/components/feature-board-external-tool-element/ExternalToolElement.unit.ts @@ -2,60 +2,90 @@ import { ContentElementType, ExternalToolElementResponse, } from "@/serverApi/v3"; -import ContextExternalToolsModule from "@/store/context-external-tools"; import { ExternalToolDisplayData } from "@/store/external-tool"; -import { CONTEXT_EXTERNAL_TOOLS_MODULE_KEY, I18N_KEY } from "@/utils/inject"; -import { createModuleMocks } from "@/utils/mock-store-module"; +import { ContextExternalTool } from "@/store/external-tool/context-external-tool"; +import { I18N_KEY } from "@/utils/inject"; import { + contextExternalToolFactory, externalToolDisplayDataFactory, i18nMock, timestampsResponseFactory, } from "@@/tests/test-utils"; import createComponentMocks from "@@/tests/test-utils/componentMocks"; -import { createMock } from "@golevelup/ts-jest"; +import { useBoardFocusHandler, useContentElementState } from "@data-board"; +import { useSharedExternalToolElementDisplayState } from "@data-board-external-tool-element"; +import { createMock, DeepMocked } from "@golevelup/ts-jest"; import { mdiPuzzleOutline } from "@mdi/js"; import { useDeleteConfirmationDialog } from "@ui-confirmation-dialog"; import { MountOptions, shallowMount, Wrapper } from "@vue/test-utils"; -import Vue from "vue"; +import Vue, { ref } from "vue"; import ExternalToolElement from "./ExternalToolElement.vue"; -jest.mock("@data-board", () => { - return { - useBoardFocusHandler: jest.fn(), - }; -}); +jest.mock("@data-board"); +jest.mock("@data-board-external-tool-element"); jest.mock("@ui-confirmation-dialog"); -const TEST_ELEMENT: ExternalToolElementResponse = { +const EMPTY_TEST_ELEMENT: ExternalToolElementResponse = { id: "external-tool-element-id", - content: {}, + content: { + contextExternalToolId: null, + }, type: ContentElementType.ExternalTool, timestamps: timestampsResponseFactory.build(), }; describe("ExternalToolElement", () => { + let useContentElementStateMock: DeepMocked< + ReturnType + >; + let useBoardFocusHandlerMock: DeepMocked< + ReturnType + >; + let useSharedExternalToolElementDisplayStateMock: DeepMocked< + ReturnType + >; + + beforeEach(() => { + useContentElementStateMock = + createMock>(); + useBoardFocusHandlerMock = + createMock>(); + useSharedExternalToolElementDisplayStateMock = + createMock>(); + + jest + .mocked(useContentElementState) + .mockReturnValue(useContentElementStateMock); + jest.mocked(useBoardFocusHandler).mockReturnValue(useBoardFocusHandlerMock); + jest + .mocked(useSharedExternalToolElementDisplayState) + .mockReturnValue(useSharedExternalToolElementDisplayStateMock); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + const getWrapper = ( props: { element: ExternalToolElementResponse; isEditMode: boolean; }, - displayData: ExternalToolDisplayData[] = [] + displayData?: ExternalToolDisplayData ) => { document.body.setAttribute("data-app", "true"); - const contextExternalToolsModule = createModuleMocks( - ContextExternalToolsModule, - { - getExternalToolDisplayDataList: displayData, - } - ); - const useDeleteConfirmationDialogReturnValue = createMock>(); jest .mocked(useDeleteConfirmationDialog) .mockReturnValue(useDeleteConfirmationDialogReturnValue); + useContentElementStateMock.modelValue = ref(props.element.content); + useSharedExternalToolElementDisplayStateMock.findDisplayData.mockReturnValue( + displayData + ); + const wrapper: Wrapper = shallowMount( ExternalToolElement as MountOptions, { @@ -66,19 +96,20 @@ describe("ExternalToolElement", () => { isFirstElement: false, isLastElement: false, hasMultipleElements: false, + cardId: "cardId", ...props, }, provide: { [I18N_KEY.valueOf()]: i18nMock, - [CONTEXT_EXTERNAL_TOOLS_MODULE_KEY.valueOf()]: - contextExternalToolsModule, + }, + stubs: { + ExternalToolElementConfigurationDialog: true, }, } ); return { wrapper, - contextExternalToolsModule, useDeleteConfirmationDialogReturnValue, }; }; @@ -91,7 +122,7 @@ describe("ExternalToolElement", () => { describe("when not in edit mode", () => { const setup = () => { const { wrapper } = getWrapper({ - element: TEST_ELEMENT, + element: EMPTY_TEST_ELEMENT, isEditMode: false, }); @@ -112,7 +143,7 @@ describe("ExternalToolElement", () => { describe("when in edit mode", () => { const setup = () => { const { wrapper } = getWrapper({ - element: TEST_ELEMENT, + element: EMPTY_TEST_ELEMENT, isEditMode: true, }); @@ -139,17 +170,15 @@ describe("ExternalToolElement", () => { const { wrapper } = getWrapper( { element: { - ...TEST_ELEMENT, + ...EMPTY_TEST_ELEMENT, content: { contextExternalToolId }, }, isEditMode: false, }, - [ - externalToolDisplayDataFactory.build({ - contextExternalToolId, - logoUrl: undefined, - }), - ] + externalToolDisplayDataFactory.build({ + contextExternalToolId, + logoUrl: undefined, + }) ); return { @@ -175,17 +204,15 @@ describe("ExternalToolElement", () => { const { wrapper } = getWrapper( { element: { - ...TEST_ELEMENT, + ...EMPTY_TEST_ELEMENT, content: { contextExternalToolId }, }, isEditMode: false, }, - [ - externalToolDisplayDataFactory.build({ - contextExternalToolId, - logoUrl: "logo-url", - }), - ] + externalToolDisplayDataFactory.build({ + contextExternalToolId, + logoUrl: "logo-url", + }) ); return { @@ -209,7 +236,7 @@ describe("ExternalToolElement", () => { describe("when no tool is selected", () => { const setup = () => { const { wrapper } = getWrapper({ - element: TEST_ELEMENT, + element: EMPTY_TEST_ELEMENT, isEditMode: true, }); @@ -235,16 +262,13 @@ describe("ExternalToolElement", () => { const setup = () => { const contextExternalToolId = "context-external-tool-id"; - const { wrapper } = getWrapper( - { - element: { - ...TEST_ELEMENT, - content: { contextExternalToolId }, - }, - isEditMode: false, + const { wrapper } = getWrapper({ + element: { + ...EMPTY_TEST_ELEMENT, + content: { contextExternalToolId }, }, - [] - ); + isEditMode: false, + }); return { wrapper, @@ -273,12 +297,12 @@ describe("ExternalToolElement", () => { const { wrapper } = getWrapper( { element: { - ...TEST_ELEMENT, + ...EMPTY_TEST_ELEMENT, content: { contextExternalToolId }, }, isEditMode: false, }, - [toolDisplayData] + toolDisplayData ); return { @@ -304,16 +328,15 @@ describe("ExternalToolElement", () => { const setup = () => { const contextExternalToolId = "context-external-tool-id"; - const { wrapper } = getWrapper( - { - element: { - ...TEST_ELEMENT, - content: { contextExternalToolId }, - }, - isEditMode: false, + useSharedExternalToolElementDisplayStateMock.isLoading = ref(true); + + const { wrapper } = getWrapper({ + element: { + ...EMPTY_TEST_ELEMENT, + content: { contextExternalToolId }, }, - [] - ); + isEditMode: false, + }); return { wrapper, @@ -323,9 +346,9 @@ describe("ExternalToolElement", () => { it("should display a loading state", () => { const { wrapper } = setup(); - const title = wrapper.findComponent({ ref: "externalToolElement" }); + const card = wrapper.findComponent({ ref: "externalToolElement" }); - expect(title.attributes("loading")).toEqual("true"); + expect(card.attributes("loading")).toEqual("true"); }); }); @@ -333,15 +356,17 @@ describe("ExternalToolElement", () => { const setup = () => { const contextExternalToolId = "context-external-tool-id"; + useSharedExternalToolElementDisplayStateMock.isLoading = ref(false); + const { wrapper } = getWrapper( { element: { - ...TEST_ELEMENT, + ...EMPTY_TEST_ELEMENT, content: { contextExternalToolId }, }, isEditMode: false, }, - [externalToolDisplayDataFactory.build({ contextExternalToolId })] + externalToolDisplayDataFactory.build({ contextExternalToolId }) ); return { @@ -363,7 +388,7 @@ describe("ExternalToolElement", () => { describe("when in edit mode", () => { const setup = () => { const { wrapper } = getWrapper({ - element: TEST_ELEMENT, + element: EMPTY_TEST_ELEMENT, isEditMode: true, }); @@ -384,7 +409,7 @@ describe("ExternalToolElement", () => { describe("when in display mode", () => { const setup = () => { const { wrapper } = getWrapper({ - element: TEST_ELEMENT, + element: EMPTY_TEST_ELEMENT, isEditMode: false, }); @@ -413,12 +438,12 @@ describe("ExternalToolElement", () => { const { wrapper, useDeleteConfirmationDialogReturnValue } = getWrapper( { element: { - ...TEST_ELEMENT, + ...EMPTY_TEST_ELEMENT, content: { contextExternalToolId }, }, isEditMode: true, }, - [toolDisplayData] + toolDisplayData ); return { @@ -445,4 +470,83 @@ describe("ExternalToolElement", () => { }); }); }); + + describe("Dialog", () => { + describe("when clicking on a un-configured tool card in edit mode", () => { + const setup = () => { + const { wrapper } = getWrapper({ + element: EMPTY_TEST_ELEMENT, + isEditMode: true, + }); + + return { + wrapper, + }; + }; + + it("should display the configuration dialog", async () => { + const { wrapper } = setup(); + + const card = wrapper.findComponent({ + ref: "externalToolElement", + }); + + card.vm.$emit("click"); + await Vue.nextTick(); + + const dialog = wrapper.findComponent({ + ref: "board-external-tool-element-configuration-dialog", + }); + + expect(dialog.props("isOpen")).toEqual(true); + }); + }); + + describe("when the dialog is saving a tool", () => { + const setup = () => { + const savedTool: ContextExternalTool = + contextExternalToolFactory.build(); + + const { wrapper } = getWrapper({ + element: EMPTY_TEST_ELEMENT, + isEditMode: true, + }); + + return { + wrapper, + savedTool, + }; + }; + + it("should update the elements content", async () => { + const { wrapper, savedTool } = setup(); + + const dialog = wrapper.findComponent({ + ref: "board-external-tool-element-configuration-dialog", + }); + + dialog.vm.$emit("save", savedTool); + await Vue.nextTick(); + + expect(useContentElementStateMock.modelValue.value).toEqual({ + contextExternalToolId: savedTool.id, + }); + }); + + it("should fetch the display data", async () => { + const { wrapper, savedTool } = setup(); + + const dialog = wrapper.findComponent({ + ref: "board-external-tool-element-configuration-dialog", + }); + + dialog.vm.$emit("save", savedTool); + await Vue.nextTick(); + + expect( + useSharedExternalToolElementDisplayStateMock.fetchDisplayData + ).toHaveBeenCalledWith("cardId"); + }); + }); + }); }); diff --git a/src/components/feature-board-external-tool-element/ExternalToolElement.vue b/src/components/feature-board-external-tool-element/ExternalToolElement.vue index a966f4caa6..a5cc60b991 100644 --- a/src/components/feature-board-external-tool-element/ExternalToolElement.vue +++ b/src/components/feature-board-external-tool-element/ExternalToolElement.vue @@ -39,19 +39,25 @@ @edit:element="onEditElement" > + + diff --git a/src/components/feature-board/card/CardHost.unit.ts b/src/components/feature-board/card/CardHost.unit.ts index ad17f97855..10edfd0d45 100644 --- a/src/components/feature-board/card/CardHost.unit.ts +++ b/src/components/feature-board/card/CardHost.unit.ts @@ -16,8 +16,11 @@ import { useCardState, useEditMode, } from "@data-board"; +import { useSharedExternalToolElementDisplayState } from "@data-board-external-tool-element"; +import { createMock, DeepMocked } from "@golevelup/ts-jest"; import { useDeleteConfirmationDialog } from "@ui-confirmation-dialog"; import { MountOptions, shallowMount, Wrapper } from "@vue/test-utils"; +import flushPromises from "flush-promises"; import Vue, { computed, ref } from "vue"; import { setupAddElementDialogMock } from "../test-utils/AddElementDialogMock"; import CardHost from "./CardHost.vue"; @@ -28,6 +31,7 @@ jest.mock("@data-board/BoardPermissions.composable"); jest.mock("../shared/AddElementDialog.composable"); jest.mock("@ui-confirmation-dialog"); jest.mock("@data-board"); +jest.mock("@data-board-external-tool-element"); const mockedBoardFocusHandler = jest.mocked(useBoardFocusHandler); const mockedUserPermissions = jest.mocked(useBoardPermissions); @@ -52,6 +56,10 @@ const CARD_WITH_FILE_ELEMENT: BoardCard = boardCardFactory.build({ describe("CardHost", () => { let wrapper: Wrapper; + let useSharedExternalToolElementDisplayStateMock: DeepMocked< + ReturnType + >; + const setup = (options?: { card: BoardCard; isLoading?: boolean; @@ -111,6 +119,13 @@ describe("CardHost", () => { isDeleteDialogOpen: ref(false), }); + useSharedExternalToolElementDisplayStateMock = + createMock>(); + + jest + .mocked(useSharedExternalToolElementDisplayState) + .mockReturnValue(useSharedExternalToolElementDisplayStateMock); + wrapper = shallowMount(CardHost as MountOptions, { ...createComponentMocks({}), propsData: CARD_SKELETON, @@ -128,6 +143,16 @@ describe("CardHost", () => { expect(wrapper.findComponent(CardHost).exists()).toBe(true); }); + it("should fetch all external tool display data for the card", async () => { + setup({ card: CARD_WITHOUT_ELEMENTS }); + + await flushPromises(); + + expect( + useSharedExternalToolElementDisplayStateMock.fetchDisplayData + ).toHaveBeenCalledWith(CARD_SKELETON.cardId); + }); + describe("'CardSkeleton' component", () => { it("should be rendered if loading is set 'true'", () => { setup({ card: CARD_WITHOUT_ELEMENTS, isLoading: true }); diff --git a/src/components/feature-board/card/CardHost.vue b/src/components/feature-board/card/CardHost.vue index 5162e3371b..35bf381818 100644 --- a/src/components/feature-board/card/CardHost.vue +++ b/src/components/feature-board/card/CardHost.vue @@ -56,6 +56,7 @@ diff --git a/src/components/feature-board-external-tool-element/ExternalToolElementConfigurationDialog.vue b/src/components/feature-board-external-tool-element/ExternalToolElementConfigurationDialog.vue index b5d627fa2b..5cf7f301e8 100644 --- a/src/components/feature-board-external-tool-element/ExternalToolElementConfigurationDialog.vue +++ b/src/components/feature-board-external-tool-element/ExternalToolElementConfigurationDialog.vue @@ -2,7 +2,6 @@

From 8f0f298702b34d0536069f518f462b7ca526cb0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20=C3=96hlerking?= Date: Mon, 16 Oct 2023 10:13:29 +0200 Subject: [PATCH 08/13] deprecate --- src/store/context-external-tools.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/store/context-external-tools.ts b/src/store/context-external-tools.ts index 3493ae4100..4afeb08ec3 100644 --- a/src/store/context-external-tools.ts +++ b/src/store/context-external-tools.ts @@ -190,6 +190,9 @@ export default class ContextExternalToolsModule extends VuexModule { return null; } + /** + * @deprecated useContextExternalToolApi.fetchDisplayDataCall + */ @Action async loadExternalToolDisplayData(payload: { contextId: string; From 6161518cd29de89300d8a0775eec26205adf269a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20=C3=96hlerking?= Date: Mon, 16 Oct 2023 11:00:45 +0200 Subject: [PATCH 09/13] rename style class --- .../ExternalToolElement.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/feature-board-external-tool-element/ExternalToolElement.vue b/src/components/feature-board-external-tool-element/ExternalToolElement.vue index f3ce8e4761..2c893b219f 100644 --- a/src/components/feature-board-external-tool-element/ExternalToolElement.vue +++ b/src/components/feature-board-external-tool-element/ExternalToolElement.vue @@ -13,7 +13,7 @@ @keydown.up.down="onKeydownArrow" @click="onClickElement" > -
+
Date: Tue, 17 Oct 2023 11:13:47 +0200 Subject: [PATCH 10/13] change external tool element context to the element --- ...ernalToolElementDisplayState.composable.ts | 31 ++ ...oolElementDisplayState.composable.unit.ts} | 75 +---- ...ernalToolElementDisplayState.composable.ts | 74 ----- .../data-board-external-tool-element/index.ts | 2 +- .../data-board/BoardApi.composable.unit.ts | 11 +- .../ContextExternalToolApi.composable.ts | 16 +- .../ContextExternalToolApi.composable.unit.ts | 37 ++- .../ExternalToolElement.unit.ts | 52 +++- .../ExternalToolElement.vue | 43 ++- ...rnalToolElementConfigurationDialog.unit.ts | 16 +- ...ExternalToolElementConfigurationDialog.vue | 24 +- .../feature-board/card/CardHost.unit.ts | 25 -- .../feature-board/card/CardHost.vue | 12 +- .../feature-board/card/ContentElementList.vue | 9 +- src/serverApi/v3/api.ts | 269 ++++++++++++------ src/store/context-external-tools.ts | 10 +- src/store/context-external-tools.unit.ts | 13 +- .../mapper/common-tool.mapper.ts | 12 +- .../mapper/context-external-tool.mapper.ts | 4 +- .../mapper/external-tool.mapper.ts | 28 +- .../factory/toolReferenceResponseFactory.ts | 4 +- 21 files changed, 388 insertions(+), 379 deletions(-) create mode 100644 src/components/data-board-external-tool-element/ExternalToolElementDisplayState.composable.ts rename src/components/data-board-external-tool-element/{SharedExternalToolElementDisplayState.composable.unit.ts => ExternalToolElementDisplayState.composable.unit.ts} (50%) delete mode 100644 src/components/data-board-external-tool-element/SharedExternalToolElementDisplayState.composable.ts diff --git a/src/components/data-board-external-tool-element/ExternalToolElementDisplayState.composable.ts b/src/components/data-board-external-tool-element/ExternalToolElementDisplayState.composable.ts new file mode 100644 index 0000000000..77a6ac100c --- /dev/null +++ b/src/components/data-board-external-tool-element/ExternalToolElementDisplayState.composable.ts @@ -0,0 +1,31 @@ +import { useErrorHandler } from "@/components/error-handling/ErrorHandler.composable"; +import { ExternalToolDisplayData } from "@/store/external-tool"; +import { useContextExternalToolApi } from "@data-external-tool"; +import { ref, Ref } from "vue"; + +export const useExternalToolElementDisplayState = () => { + const { handleError } = useErrorHandler(); + const { fetchDisplayDataCall } = useContextExternalToolApi(); + const displayData: Ref = ref(); + const isLoading: Ref = ref(false); + + const fetchDisplayData = async ( + contextExternalToolId: string + ): Promise => { + isLoading.value = true; + + try { + displayData.value = await fetchDisplayDataCall(contextExternalToolId); + } catch (error) { + handleError(error); + } + + isLoading.value = false; + }; + + return { + isLoading, + displayData, + fetchDisplayData, + }; +}; diff --git a/src/components/data-board-external-tool-element/SharedExternalToolElementDisplayState.composable.unit.ts b/src/components/data-board-external-tool-element/ExternalToolElementDisplayState.composable.unit.ts similarity index 50% rename from src/components/data-board-external-tool-element/SharedExternalToolElementDisplayState.composable.unit.ts rename to src/components/data-board-external-tool-element/ExternalToolElementDisplayState.composable.unit.ts index f2472fa4f9..e0b0637d08 100644 --- a/src/components/data-board-external-tool-element/SharedExternalToolElementDisplayState.composable.unit.ts +++ b/src/components/data-board-external-tool-element/ExternalToolElementDisplayState.composable.unit.ts @@ -4,17 +4,10 @@ import { ExternalToolDisplayData } from "@/store/external-tool"; import { externalToolDisplayDataFactory } from "@@/tests/test-utils"; import { useContextExternalToolApi } from "@data-external-tool"; import { createMock, DeepMocked } from "@golevelup/ts-jest"; -import { Ref } from "vue"; -import { useSharedExternalToolElementDisplayState } from "./SharedExternalToolElementDisplayState.composable"; +import { useExternalToolElementDisplayState } from "./ExternalToolElementDisplayState.composable"; jest.mock("@data-external-tool"); jest.mock("@/components/error-handling/ErrorHandler.composable"); -jest.mock( - "@/utils/create-shared-composable", - () => ({ - createTestableSharedComposable: (composable) => composable, - }) -); describe("SharedExternalToolElementDisplayState.composable", () => { let useContextExternalToolApiMock: DeepMocked< @@ -38,82 +31,44 @@ describe("SharedExternalToolElementDisplayState.composable", () => { }); describe("when no data is loaded", () => { - it("should have no data lists", async () => { - const displayDataState = useSharedExternalToolElementDisplayState(); + it("should not have data", async () => { + const { displayData } = useExternalToolElementDisplayState(); - const result: Ref | undefined = - displayDataState.getDisplayDataList("cardId"); - - expect(result).toBeUndefined(); - }); - - it("should not find data", async () => { - const displayDataState = useSharedExternalToolElementDisplayState(); - - const result: ExternalToolDisplayData | undefined = - displayDataState.findDisplayData("cardId", "contextExternalToolId"); - - expect(result).toBeUndefined(); + expect(displayData.value).toBeUndefined(); }); }); describe("when data is loaded", () => { const setup = () => { - const displayData: ExternalToolDisplayData = + const displayDataMock: ExternalToolDisplayData = externalToolDisplayDataFactory.build(); useContextExternalToolApiMock.fetchDisplayDataCall.mockResolvedValue([ - displayData, + displayDataMock, ]); return { - displayData, - ...useSharedExternalToolElementDisplayState(), + displayDataMock, + ...useExternalToolElementDisplayState(), }; }; it("should call the api for display data of the card", async () => { const { fetchDisplayData } = setup(); - await fetchDisplayData("cardId"); + await fetchDisplayData("contextId"); expect( useContextExternalToolApiMock.fetchDisplayDataCall - ).toHaveBeenCalledWith("cardId", ToolContextType.BoardCard); + ).toHaveBeenCalledWith("contextId", ToolContextType.BoardElement); }); it("should set the display data in the state", async () => { - const { fetchDisplayData, getDisplayDataList, displayData } = setup(); - - await fetchDisplayData("cardId"); - const result: Ref | undefined = - getDisplayDataList("cardId"); - - expect(result?.value).toEqual([displayData]); - }); + const { fetchDisplayData, displayData, displayDataMock } = setup(); - it("should find the display data for a specific tool", async () => { - const { fetchDisplayData, findDisplayData, displayData } = setup(); - - await fetchDisplayData("cardId"); - const result: ExternalToolDisplayData | undefined = findDisplayData( - "cardId", - displayData.contextExternalToolId - ); - - expect(result).toEqual(displayData); - }); - - it("should not find data for non-existing tools", async () => { - const { fetchDisplayData, findDisplayData } = setup(); - - await fetchDisplayData("cardId"); - const result: ExternalToolDisplayData | undefined = findDisplayData( - "cardId", - "otherId" - ); + await fetchDisplayData("contextId"); - expect(result).toBeUndefined(); + expect(displayData.value).toEqual(displayDataMock); }); }); @@ -127,14 +82,14 @@ describe("SharedExternalToolElementDisplayState.composable", () => { return { error, - ...useSharedExternalToolElementDisplayState(), + ...useExternalToolElementDisplayState(), }; }; it("should handle the error", async () => { const { fetchDisplayData, error } = setup(); - await fetchDisplayData("cardId"); + await fetchDisplayData("contextId"); expect(useErrorHandlerMock.handleError).toHaveBeenCalledWith(error); }); diff --git a/src/components/data-board-external-tool-element/SharedExternalToolElementDisplayState.composable.ts b/src/components/data-board-external-tool-element/SharedExternalToolElementDisplayState.composable.ts deleted file mode 100644 index 1d9757d166..0000000000 --- a/src/components/data-board-external-tool-element/SharedExternalToolElementDisplayState.composable.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { useErrorHandler } from "@/components/error-handling/ErrorHandler.composable"; -import { ToolContextType } from "@/serverApi/v3"; -import { ExternalToolDisplayData } from "@/store/external-tool"; -import { createTestableSharedComposable } from "@/utils/create-shared-composable"; -import { useContextExternalToolApi } from "@data-external-tool"; -import { ref, Ref } from "vue"; - -export const useSharedExternalToolElementDisplayState = - createTestableSharedComposable(() => { - const { handleError } = useErrorHandler(); - const { fetchDisplayDataCall } = useContextExternalToolApi(); - const displayDataMap: Map> = new Map< - string, - Ref - >(); - const isLoading: Ref = ref(false); - - const getDisplayDataList = ( - cardId: string - ): Ref | undefined => { - const displayDataList: Ref | undefined = - displayDataMap.get(cardId); - - return displayDataList; - }; - - const fetchDisplayData = async (cardId: string): Promise => { - isLoading.value = true; - - try { - let displayDataList: Ref | undefined = - getDisplayDataList(cardId); - - if (!displayDataList?.value) { - displayDataList = ref([]); - - displayDataMap.set(cardId, displayDataList); - } - - displayDataList.value = await fetchDisplayDataCall( - cardId, - ToolContextType.BoardCard - ); - } catch (error) { - handleError(error); - } - - isLoading.value = false; - }; - - const findDisplayData = ( - cardId: string, - contextExternalToolId: string - ): ExternalToolDisplayData | undefined => { - const displayDataList: Ref | undefined = - getDisplayDataList(cardId); - - const displayData: ExternalToolDisplayData | undefined = - displayDataList?.value.find( - (externalToolDisplayData: ExternalToolDisplayData) => - externalToolDisplayData.contextExternalToolId === - contextExternalToolId - ); - - return displayData; - }; - - return { - isLoading, - getDisplayDataList, - fetchDisplayData, - findDisplayData, - }; - }); diff --git a/src/components/data-board-external-tool-element/index.ts b/src/components/data-board-external-tool-element/index.ts index a19823e3ff..7203a1a816 100644 --- a/src/components/data-board-external-tool-element/index.ts +++ b/src/components/data-board-external-tool-element/index.ts @@ -1 +1 @@ -export * from "./SharedExternalToolElementDisplayState.composable"; +export * from "./ExternalToolElementDisplayState.composable"; diff --git a/src/components/data-board/BoardApi.composable.unit.ts b/src/components/data-board/BoardApi.composable.unit.ts index 3edc48d1ff..951c25652c 100644 --- a/src/components/data-board/BoardApi.composable.unit.ts +++ b/src/components/data-board/BoardApi.composable.unit.ts @@ -1,4 +1,7 @@ -import { ContentElementType } from "@/serverApi/v3"; +import { + ContentElementType, + ExternalToolElementResponse, +} from "@/serverApi/v3"; import * as serverApi from "@/serverApi/v3/api"; import { CardResponse } from "@/serverApi/v3/api"; import { ApplicationError } from "@/store/types/application-error"; @@ -187,11 +190,15 @@ describe("BoardApi.composable", () => { it("should call elementControllerUpdateElement api with ExternalToolElement", async () => { const { updateElementCall } = useBoardApi(); - const payload = { + const payload: ExternalToolElementResponse = { id: "external-tool-element-id", type: ContentElementType.ExternalTool, content: { contextExternalToolId: "context-external-tool-id", + displayData: { + name: "name", + logoUrl: "logoUrl", + }, }, timestamps: timestampsResponseFactory.build(), }; diff --git a/src/components/data-external-tool/ContextExternalToolApi.composable.ts b/src/components/data-external-tool/ContextExternalToolApi.composable.ts index 236e124826..b3caf443a3 100644 --- a/src/components/data-external-tool/ContextExternalToolApi.composable.ts +++ b/src/components/data-external-tool/ContextExternalToolApi.composable.ts @@ -1,8 +1,7 @@ import { ToolApiFactory, ToolApiInterface, - ToolContextType, - ToolReferenceListResponse, + ToolReferenceResponse, } from "@/serverApi/v3"; import { ExternalToolDisplayData } from "@/store/external-tool"; import { ExternalToolMapper } from "@/store/external-tool/mapper"; @@ -13,13 +12,14 @@ export const useContextExternalToolApi = () => { const toolApi: ToolApiInterface = ToolApiFactory(undefined, "/v3", $axios); const fetchDisplayDataCall = async ( - contextId: string, - contextType: ToolContextType - ): Promise => { - const response: AxiosResponse = - await toolApi.toolControllerGetToolReferences(contextId, contextType); + contextExternalToolId: string + ): Promise => { + const response: AxiosResponse = + await toolApi.toolReferenceControllerGetToolReference( + contextExternalToolId + ); - const mapped: ExternalToolDisplayData[] = + const mapped: ExternalToolDisplayData = ExternalToolMapper.mapToExternalToolDisplayData(response.data); return mapped; diff --git a/src/components/data-external-tool/ContextExternalToolApi.composable.unit.ts b/src/components/data-external-tool/ContextExternalToolApi.composable.unit.ts index 9d72d794cd..6001dd377c 100644 --- a/src/components/data-external-tool/ContextExternalToolApi.composable.unit.ts +++ b/src/components/data-external-tool/ContextExternalToolApi.composable.unit.ts @@ -1,5 +1,5 @@ import * as serverApi from "@/serverApi/v3/api"; -import { ToolContextType, ToolReferenceResponse } from "@/serverApi/v3/api"; +import { ToolReferenceResponse } from "@/serverApi/v3/api"; import { ExternalToolDisplayData, ToolConfigurationStatus, @@ -29,8 +29,8 @@ describe("ContextExternalToolApi.composable", () => { const displayData: ToolReferenceResponse = toolReferenceResponseFactory.build({ logoUrl: "mockLogoUrl" }); - toolApi.toolControllerGetToolReferences.mockResolvedValue( - mockApiResponse({ data: { data: [displayData] } }) + toolApi.toolReferenceControllerGetToolReference.mockResolvedValue( + mockApiResponse({ data: displayData }) ); return { @@ -42,34 +42,29 @@ describe("ContextExternalToolApi.composable", () => { setup(); await useContextExternalToolApi().fetchDisplayDataCall( - "cardId", - ToolContextType.BoardCard + "contextExternalToolId" ); - expect(toolApi.toolControllerGetToolReferences).toHaveBeenCalledWith( - "cardId", - ToolContextType.BoardCard - ); + expect( + toolApi.toolReferenceControllerGetToolReference + ).toHaveBeenCalledWith("contextExternalToolId"); }); it("should return an array of display data", async () => { const { displayData } = setup(); - const result: ExternalToolDisplayData[] = + const result: ExternalToolDisplayData = await useContextExternalToolApi().fetchDisplayDataCall( - "courseId", - ToolContextType.Course + "contextExternalToolId" ); - expect(result).toEqual([ - { - contextExternalToolId: displayData.contextToolId, - name: displayData.displayName, - logoUrl: displayData.logoUrl, - status: ToolConfigurationStatus.Latest, - openInNewTab: displayData.openInNewTab, - }, - ]); + expect(result).toEqual({ + contextExternalToolId: displayData.contextToolId, + name: displayData.displayName, + logoUrl: displayData.logoUrl, + status: ToolConfigurationStatus.Latest, + openInNewTab: displayData.openInNewTab, + }); }); }); }); diff --git a/src/components/feature-board-external-tool-element/ExternalToolElement.unit.ts b/src/components/feature-board-external-tool-element/ExternalToolElement.unit.ts index 35589562db..7bc7a6f274 100644 --- a/src/components/feature-board-external-tool-element/ExternalToolElement.unit.ts +++ b/src/components/feature-board-external-tool-element/ExternalToolElement.unit.ts @@ -13,7 +13,7 @@ import { } from "@@/tests/test-utils"; import createComponentMocks from "@@/tests/test-utils/componentMocks"; import { useBoardFocusHandler, useContentElementState } from "@data-board"; -import { useSharedExternalToolElementDisplayState } from "@data-board-external-tool-element"; +import { useExternalToolElementDisplayState } from "@data-board-external-tool-element"; import { createMock, DeepMocked } from "@golevelup/ts-jest"; import { mdiPuzzleOutline } from "@mdi/js"; import { useDeleteConfirmationDialog } from "@ui-confirmation-dialog"; @@ -42,7 +42,7 @@ describe("ExternalToolElement", () => { ReturnType >; let useSharedExternalToolElementDisplayStateMock: DeepMocked< - ReturnType + ReturnType >; beforeEach(() => { @@ -51,14 +51,14 @@ describe("ExternalToolElement", () => { useBoardFocusHandlerMock = createMock>(); useSharedExternalToolElementDisplayStateMock = - createMock>(); + createMock>(); jest .mocked(useContentElementState) .mockReturnValue(useContentElementStateMock); jest.mocked(useBoardFocusHandler).mockReturnValue(useBoardFocusHandlerMock); jest - .mocked(useSharedExternalToolElementDisplayState) + .mocked(useExternalToolElementDisplayState) .mockReturnValue(useSharedExternalToolElementDisplayStateMock); }); @@ -82,9 +82,7 @@ describe("ExternalToolElement", () => { .mockReturnValue(useDeleteConfirmationDialogReturnValue); useContentElementStateMock.modelValue = ref(props.element.content); - useSharedExternalToolElementDisplayStateMock.findDisplayData.mockReturnValue( - displayData - ); + useSharedExternalToolElementDisplayStateMock.displayData = ref(displayData); const wrapper: Wrapper = shallowMount( ExternalToolElement as MountOptions, @@ -118,6 +116,37 @@ describe("ExternalToolElement", () => { jest.resetAllMocks(); }); + describe("when the element is mounted", () => { + describe("when the element has a tool attached", () => { + it("should load the display data", () => { + getWrapper({ + element: { + ...EMPTY_TEST_ELEMENT, + content: { contextExternalToolId: "contextExternalToolId" }, + }, + isEditMode: false, + }); + + expect( + useSharedExternalToolElementDisplayStateMock.fetchDisplayData + ).toHaveBeenCalledWith("contextExternalToolId"); + }); + }); + + describe("when the element deos not have a tool attached", () => { + it("should not load the display data", () => { + getWrapper({ + element: EMPTY_TEST_ELEMENT, + isEditMode: false, + }); + + expect( + useSharedExternalToolElementDisplayStateMock.fetchDisplayData + ).not.toHaveBeenCalled(); + }); + }); + }); + describe("when no tool is selected", () => { describe("when not in edit mode", () => { const setup = () => { @@ -461,8 +490,11 @@ describe("ExternalToolElement", () => { describe("when the dialog is saving a tool", () => { const setup = () => { - const savedTool: ContextExternalTool = - contextExternalToolFactory.build(); + const savedTool: ContextExternalTool = contextExternalToolFactory.build( + { + id: "contextExternalToolId", + } + ); const { wrapper } = getWrapper({ element: EMPTY_TEST_ELEMENT, @@ -502,7 +534,7 @@ describe("ExternalToolElement", () => { expect( useSharedExternalToolElementDisplayStateMock.fetchDisplayData - ).toHaveBeenCalledWith("cardId"); + ).toHaveBeenCalledWith(savedTool.id); }); }); }); diff --git a/src/components/feature-board-external-tool-element/ExternalToolElement.vue b/src/components/feature-board-external-tool-element/ExternalToolElement.vue index 2c893b219f..a81a89ed7f 100644 --- a/src/components/feature-board-external-tool-element/ExternalToolElement.vue +++ b/src/components/feature-board-external-tool-element/ExternalToolElement.vue @@ -15,13 +15,13 @@ >
@@ -44,7 +44,7 @@
import { useI18n } from "@/composables/i18n.composable"; import { ExternalToolElementResponse } from "@/serverApi/v3"; -import { ExternalToolDisplayData } from "@/store/external-tool"; import { ContextExternalTool } from "@/store/external-tool/context-external-tool"; import { useBoardFocusHandler, useContentElementState } from "@data-board"; -import { useSharedExternalToolElementDisplayState } from "@data-board-external-tool-element"; +import { useExternalToolElementDisplayState } from "@data-board-external-tool-element"; import { mdiPuzzleOutline } from "@mdi/js"; import { computed, ComputedRef, defineComponent, + onMounted, PropType, Ref, ref, @@ -84,7 +84,6 @@ export default defineComponent({ type: Object as PropType, required: true, }, - cardId: { type: String, required: true }, isEditMode: { type: Boolean, required: true }, }, emits: [ @@ -98,7 +97,11 @@ export default defineComponent({ const { modelValue } = useContentElementState(props, { autoSaveDebounce: 0, }); - const displayState = useSharedExternalToolElementDisplayState(); + const { + fetchDisplayData, + displayData, + isLoading: isDisplayDataLoading, + } = useExternalToolElementDisplayState(); const autofocus: Ref = ref(false); const element: Ref = toRef(props, "element"); @@ -110,25 +113,13 @@ export default defineComponent({ () => !!modelValue.value.contextExternalToolId ); - const toolDisplayData: Ref = computed( - () => - modelValue.value.contextExternalToolId - ? displayState.findDisplayData( - props.cardId, - modelValue.value.contextExternalToolId - ) - : undefined - ); - const toolDisplayName: ComputedRef = computed( - () => toolDisplayData.value?.name ?? "..." + () => displayData.value?.name ?? "..." ); const isLoading = computed( () => - hasLinkedTool.value && - !toolDisplayData.value && - displayState.isLoading.value + hasLinkedTool.value && !displayData.value && isDisplayDataLoading.value ); const isConfigurationDialogOpen: Ref = ref(false); @@ -171,14 +162,20 @@ export default defineComponent({ const onConfigurationDialogSave = async (tool: ContextExternalTool) => { modelValue.value.contextExternalToolId = tool.id; - await displayState.fetchDisplayData(props.cardId); + await fetchDisplayData(modelValue.value.contextExternalToolId); }; + onMounted(async () => { + if (modelValue.value.contextExternalToolId) { + await fetchDisplayData(modelValue.value.contextExternalToolId); + } + }); + return { t, hasLinkedTool, - toolDisplayData, toolDisplayName, + displayData, isLoading, isConfigurationDialogOpen, mdiPuzzleOutline, diff --git a/src/components/feature-board-external-tool-element/ExternalToolElementConfigurationDialog.unit.ts b/src/components/feature-board-external-tool-element/ExternalToolElementConfigurationDialog.unit.ts index 21c75cc156..4e5acefa34 100644 --- a/src/components/feature-board-external-tool-element/ExternalToolElementConfigurationDialog.unit.ts +++ b/src/components/feature-board-external-tool-element/ExternalToolElementConfigurationDialog.unit.ts @@ -54,7 +54,7 @@ describe("ExternalToolElementConfigurationDialog", () => { const propsData = { isOpen: false, - cardId: "cardId", + contextId: "contextId", ...props, }; @@ -117,8 +117,8 @@ describe("ExternalToolElementConfigurationDialog", () => { expect( contextExternalToolsModule.loadAvailableToolsForContext ).toHaveBeenCalledWith({ - contextId: "cardId", - contextType: ToolContextType.BoardCard, + contextId: "contextId", + contextType: ToolContextType.BoardElement, }); }); }); @@ -127,7 +127,7 @@ describe("ExternalToolElementConfigurationDialog", () => { const setup = async () => { const contextExternalTool = contextExternalToolFactory.build({ displayName: "testName", - contextType: ToolContextType.BoardCard, + contextType: ToolContextType.BoardElement, }); const { contextExternalToolsModule, wrapper } = await getWrapper({ @@ -208,8 +208,8 @@ describe("ExternalToolElementConfigurationDialog", () => { expect( contextExternalToolsModule.createContextExternalTool ).toHaveBeenCalledWith<[ContextExternalToolSave]>({ - contextId: "cardId", - contextType: ToolContextType.BoardCard, + contextId: "contextId", + contextType: ToolContextType.BoardElement, displayName: template.name, schoolToolId: template.schoolExternalToolId, toolVersion: template.version, @@ -302,8 +302,8 @@ describe("ExternalToolElementConfigurationDialog", () => { >({ contextExternalToolId: contextExternalToolId, contextExternalTool: { - contextId: "cardId", - contextType: ToolContextType.BoardCard, + contextId: "contextId", + contextType: ToolContextType.BoardElement, displayName: template.name, parameters: [], toolVersion: template.version, diff --git a/src/components/feature-board-external-tool-element/ExternalToolElementConfigurationDialog.vue b/src/components/feature-board-external-tool-element/ExternalToolElementConfigurationDialog.vue index 5cf7f301e8..0ac2469682 100644 --- a/src/components/feature-board-external-tool-element/ExternalToolElementConfigurationDialog.vue +++ b/src/components/feature-board-external-tool-element/ExternalToolElementConfigurationDialog.vue @@ -51,7 +51,15 @@ import { injectStrict, } from "@/utils/inject"; import { useBoardNotifier } from "@util-board"; -import { computed, ComputedRef, defineComponent, ref, Ref, watch } from "vue"; +import { + computed, + ComputedRef, + defineComponent, + PropType, + ref, + Ref, + watch, +} from "vue"; import ExternalToolConfigurator from "../external-tools/configuration/ExternalToolConfigurator.vue"; import VCustomDialog from "../organisms/vCustomDialog.vue"; @@ -63,10 +71,14 @@ export default defineComponent({ type: Boolean, required: true, }, - cardId: { + contextId: { type: String, required: true, }, + contextType: { + type: String as PropType, + default: ToolContextType.BoardElement, + }, configId: { type: String, }, @@ -122,8 +134,8 @@ export default defineComponent({ ContextExternalToolMapper.mapTemplateToContextExternalToolSave( template, configuredParameterValues, - props.cardId, - ToolContextType.BoardCard, + props.contextId, + props.contextType, displayName.value ); @@ -182,8 +194,8 @@ export default defineComponent({ displayName.value = configuration.value?.displayName; } else { await contextExternalToolsModule.loadAvailableToolsForContext({ - contextId: props.cardId, - contextType: ToolContextType.BoardCard, + contextId: props.contextId, + contextType: props.contextType, }); } diff --git a/src/components/feature-board/card/CardHost.unit.ts b/src/components/feature-board/card/CardHost.unit.ts index a649647e9a..a5e2e830fe 100644 --- a/src/components/feature-board/card/CardHost.unit.ts +++ b/src/components/feature-board/card/CardHost.unit.ts @@ -17,11 +17,8 @@ import { useEditMode, } from "@data-board"; import { BoardMenuActionDelete } from "@ui-board"; -import { useSharedExternalToolElementDisplayState } from "@data-board-external-tool-element"; -import { createMock, DeepMocked } from "@golevelup/ts-jest"; import { useDeleteConfirmationDialog } from "@ui-confirmation-dialog"; import { MountOptions, shallowMount, Wrapper } from "@vue/test-utils"; -import flushPromises from "flush-promises"; import Vue, { computed, ref } from "vue"; import { setupAddElementDialogMock } from "../test-utils/AddElementDialogMock"; import CardHost from "./CardHost.vue"; @@ -32,7 +29,6 @@ jest.mock("@data-board/BoardPermissions.composable"); jest.mock("../shared/AddElementDialog.composable"); jest.mock("@ui-confirmation-dialog"); jest.mock("@data-board"); -jest.mock("@data-board-external-tool-element"); const mockedBoardFocusHandler = jest.mocked(useBoardFocusHandler); const mockedUserPermissions = jest.mocked(useBoardPermissions); @@ -57,10 +53,6 @@ const CARD_WITH_FILE_ELEMENT: BoardCard = boardCardFactory.build({ describe("CardHost", () => { let wrapper: Wrapper; - let useSharedExternalToolElementDisplayStateMock: DeepMocked< - ReturnType - >; - const setup = (options?: { card: BoardCard; isLoading?: boolean; @@ -120,13 +112,6 @@ describe("CardHost", () => { isDeleteDialogOpen: ref(false), }); - useSharedExternalToolElementDisplayStateMock = - createMock>(); - - jest - .mocked(useSharedExternalToolElementDisplayState) - .mockReturnValue(useSharedExternalToolElementDisplayStateMock); - wrapper = shallowMount(CardHost as MountOptions, { ...createComponentMocks({}), propsData: CARD_SKELETON, @@ -144,16 +129,6 @@ describe("CardHost", () => { expect(wrapper.findComponent(CardHost).exists()).toBe(true); }); - it("should fetch all external tool display data for the card", async () => { - setup({ card: CARD_WITHOUT_ELEMENTS }); - - await flushPromises(); - - expect( - useSharedExternalToolElementDisplayStateMock.fetchDisplayData - ).toHaveBeenCalledWith(CARD_SKELETON.cardId); - }); - describe("'CardSkeleton' component", () => { it("should be rendered if loading is set 'true'", () => { setup({ card: CARD_WITHOUT_ELEMENTS, isLoading: true }); diff --git a/src/components/feature-board/card/CardHost.vue b/src/components/feature-board/card/CardHost.vue index 8e4c22c8e8..46f6d7d91d 100644 --- a/src/components/feature-board/card/CardHost.vue +++ b/src/components/feature-board/card/CardHost.vue @@ -44,7 +44,6 @@
{ - const { fetchDisplayData } = useSharedExternalToolElementDisplayState(); - - await fetchDisplayData(props.cardId); - }); - return { boardMenuClasses, isLoading, diff --git a/src/components/feature-board/card/ContentElementList.vue b/src/components/feature-board/card/ContentElementList.vue index 6c92a65d06..43dcd4fae9 100644 --- a/src/components/feature-board/card/ContentElementList.vue +++ b/src/components/feature-board/card/ContentElementList.vue @@ -46,7 +46,6 @@ v-else-if="showExternalToolElement(element)" :element="element" :isEditMode="isEditMode" - :card-id="cardId" @move-keyboard:edit="onMoveElementKeyboard(index, element, $event)" @move-down:edit="onMoveElementDown(index, element)" @move-up:edit="onMoveElementUp(index, element)" @@ -62,19 +61,19 @@ import { ContentElementType, ExternalToolElementResponse, FileElementResponse, + LinkElementResponse, RichTextElementResponse, SubmissionContainerElementResponse, - LinkElementResponse, } from "@/serverApi/v3"; import { AnyContentElement } from "@/types/board/ContentElement"; import { ElementMove } from "@/types/board/DragAndDrop"; import { ENV_CONFIG_MODULE_KEY, injectStrict } from "@/utils/inject"; import { ExternalToolElement } from "@feature-board-external-tool-element"; import { FileContentElement } from "@feature-board-file-element"; +import { LinkContentElement } from "@feature-board-link-element"; import { SubmissionContentElement } from "@feature-board-submission-element"; import { RichTextContentElement } from "@feature-board-text-element"; import { computed, defineComponent, PropType } from "vue"; -import { LinkContentElement } from "@feature-board-link-element"; import ContentElement from "./ContentElement.vue"; export default defineComponent({ @@ -88,10 +87,6 @@ export default defineComponent({ LinkContentElement, }, props: { - cardId: { - type: String, - required: true, - }, elements: { type: Array as PropType, required: true, diff --git a/src/serverApi/v3/api.ts b/src/serverApi/v3/api.ts index bc212b5033..6dfd5e29f6 100644 --- a/src/serverApi/v3/api.ts +++ b/src/serverApi/v3/api.ts @@ -785,7 +785,7 @@ export interface ContextExternalToolResponse { */ export enum ContextExternalToolResponseContextTypeEnum { Course = 'course', - BoardCard = 'boardCard' + BoardElement = 'board-element' } /** @@ -4513,6 +4513,17 @@ export interface TimestampsResponse { */ deletedAt?: string; } +/** + * + * @export + * @enum {string} + */ +export enum ToolConfigurationStatusResponse { + Latest = 'Latest', + Outdated = 'Outdated', + Unknown = 'Unknown' +} + /** * * @export @@ -4520,7 +4531,7 @@ export interface TimestampsResponse { */ export enum ToolContextType { Course = 'course', - BoardCard = 'boardCard' + BoardElement = 'board-element' } /** @@ -4608,23 +4619,12 @@ export interface ToolReferenceResponse { */ openInNewTab: boolean; /** - * The status of the tool - * @type {string} + * + * @type {ToolConfigurationStatusResponse} * @memberof ToolReferenceResponse */ - status: ToolReferenceResponseStatusEnum; -} - -/** - * @export - * @enum {string} - */ -export enum ToolReferenceResponseStatusEnum { - Latest = 'Latest', - Outdated = 'Outdated', - Unknown = 'Unknown' + status: ToolConfigurationStatusResponse; } - /** * * @export @@ -13863,20 +13863,19 @@ export const ToolApiAxiosParamCreator = function (configuration?: Configuration) }, /** * - * @summary Get ExternalTool References for a given context - * @param {string} contextId - * @param {ToolContextType} contextType + * @summary Updates an ExternalTool + * @param {string} externalToolId + * @param {ExternalToolUpdateParams} externalToolUpdateParams * @param {*} [options] Override http request option. * @throws {RequiredError} */ - toolControllerGetToolReferences: async (contextId: string, contextType: ToolContextType, options: any = {}): Promise => { - // verify required parameter 'contextId' is not null or undefined - assertParamExists('toolControllerGetToolReferences', 'contextId', contextId) - // verify required parameter 'contextType' is not null or undefined - assertParamExists('toolControllerGetToolReferences', 'contextType', contextType) - const localVarPath = `/tools/external-tools/{contextType}/{contextId}/references` - .replace(`{${"contextId"}}`, encodeURIComponent(String(contextId))) - .replace(`{${"contextType"}}`, encodeURIComponent(String(contextType))); + toolControllerUpdateExternalTool: async (externalToolId: string, externalToolUpdateParams: ExternalToolUpdateParams, options: any = {}): Promise => { + // verify required parameter 'externalToolId' is not null or undefined + assertParamExists('toolControllerUpdateExternalTool', 'externalToolId', externalToolId) + // verify required parameter 'externalToolUpdateParams' is not null or undefined + assertParamExists('toolControllerUpdateExternalTool', 'externalToolUpdateParams', externalToolUpdateParams) + const localVarPath = `/tools/external-tools/{externalToolId}` + .replace(`{${"externalToolId"}}`, encodeURIComponent(String(externalToolId))); // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); let baseOptions; @@ -13884,7 +13883,7 @@ export const ToolApiAxiosParamCreator = function (configuration?: Configuration) baseOptions = configuration.baseOptions; } - const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; const localVarHeaderParameter = {} as any; const localVarQueryParameter = {} as any; @@ -13894,9 +13893,12 @@ export const ToolApiAxiosParamCreator = function (configuration?: Configuration) + localVarHeaderParameter['Content-Type'] = 'application/json'; + setSearchParams(localVarUrlObj, localVarQueryParameter, options.query); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(externalToolUpdateParams, localVarRequestOptions, configuration) return { url: toPathString(localVarUrlObj), @@ -13905,19 +13907,16 @@ export const ToolApiAxiosParamCreator = function (configuration?: Configuration) }, /** * - * @summary Updates an ExternalTool - * @param {string} externalToolId - * @param {ExternalToolUpdateParams} externalToolUpdateParams + * @summary Get tool launch request for a context external tool id + * @param {string} contextExternalToolId The id of the context external tool * @param {*} [options] Override http request option. * @throws {RequiredError} */ - toolControllerUpdateExternalTool: async (externalToolId: string, externalToolUpdateParams: ExternalToolUpdateParams, options: any = {}): Promise => { - // verify required parameter 'externalToolId' is not null or undefined - assertParamExists('toolControllerUpdateExternalTool', 'externalToolId', externalToolId) - // verify required parameter 'externalToolUpdateParams' is not null or undefined - assertParamExists('toolControllerUpdateExternalTool', 'externalToolUpdateParams', externalToolUpdateParams) - const localVarPath = `/tools/external-tools/{externalToolId}` - .replace(`{${"externalToolId"}}`, encodeURIComponent(String(externalToolId))); + toolLaunchControllerGetToolLaunchRequest: async (contextExternalToolId: string, options: any = {}): Promise => { + // verify required parameter 'contextExternalToolId' is not null or undefined + assertParamExists('toolLaunchControllerGetToolLaunchRequest', 'contextExternalToolId', contextExternalToolId) + const localVarPath = `/tools/context/{contextExternalToolId}/launch` + .replace(`{${"contextExternalToolId"}}`, encodeURIComponent(String(contextExternalToolId))); // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); let baseOptions; @@ -13925,7 +13924,7 @@ export const ToolApiAxiosParamCreator = function (configuration?: Configuration) baseOptions = configuration.baseOptions; } - const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; const localVarHeaderParameter = {} as any; const localVarQueryParameter = {} as any; @@ -13935,12 +13934,9 @@ export const ToolApiAxiosParamCreator = function (configuration?: Configuration) - localVarHeaderParameter['Content-Type'] = 'application/json'; - setSearchParams(localVarUrlObj, localVarQueryParameter, options.query); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; - localVarRequestOptions.data = serializeDataIfNeeded(externalToolUpdateParams, localVarRequestOptions, configuration) return { url: toPathString(localVarUrlObj), @@ -13949,15 +13945,15 @@ export const ToolApiAxiosParamCreator = function (configuration?: Configuration) }, /** * - * @summary Get tool launch request for a context external tool id - * @param {string} contextExternalToolId The id of the context external tool + * @summary Get ExternalTool Reference for a given context external tool + * @param {string} contextExternalToolId * @param {*} [options] Override http request option. * @throws {RequiredError} */ - toolLaunchControllerGetToolLaunchRequest: async (contextExternalToolId: string, options: any = {}): Promise => { + toolReferenceControllerGetToolReference: async (contextExternalToolId: string, options: any = {}): Promise => { // verify required parameter 'contextExternalToolId' is not null or undefined - assertParamExists('toolLaunchControllerGetToolLaunchRequest', 'contextExternalToolId', contextExternalToolId) - const localVarPath = `/tools/context/{contextExternalToolId}/launch` + assertParamExists('toolReferenceControllerGetToolReference', 'contextExternalToolId', contextExternalToolId) + const localVarPath = `/tools/tool-references/context-external-tools/{contextExternalToolId}` .replace(`{${"contextExternalToolId"}}`, encodeURIComponent(String(contextExternalToolId))); // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -13976,6 +13972,48 @@ export const ToolApiAxiosParamCreator = function (configuration?: Configuration) + setSearchParams(localVarUrlObj, localVarQueryParameter, options.query); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, + /** + * + * @summary Get ExternalTool References for a given context + * @param {string} contextId + * @param {ToolContextType} contextType + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + toolReferenceControllerGetToolReferencesForContext: async (contextId: string, contextType: ToolContextType, options: any = {}): Promise => { + // verify required parameter 'contextId' is not null or undefined + assertParamExists('toolReferenceControllerGetToolReferencesForContext', 'contextId', contextId) + // verify required parameter 'contextType' is not null or undefined + assertParamExists('toolReferenceControllerGetToolReferencesForContext', 'contextType', contextType) + const localVarPath = `/tools/tool-references/{contextType}/{contextId}` + .replace(`{${"contextId"}}`, encodeURIComponent(String(contextId))) + .replace(`{${"contextType"}}`, encodeURIComponent(String(contextType))); + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication bearer required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + + setSearchParams(localVarUrlObj, localVarQueryParameter, options.query); let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; @@ -14358,18 +14396,6 @@ export const ToolApiFp = function(configuration?: Configuration) { const localVarAxiosArgs = await localVarAxiosParamCreator.toolControllerGetExternalToolLogo(externalToolId, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, - /** - * - * @summary Get ExternalTool References for a given context - * @param {string} contextId - * @param {ToolContextType} contextType - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - async toolControllerGetToolReferences(contextId: string, contextType: ToolContextType, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.toolControllerGetToolReferences(contextId, contextType, options); - return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); - }, /** * * @summary Updates an ExternalTool @@ -14393,6 +14419,29 @@ export const ToolApiFp = function(configuration?: Configuration) { const localVarAxiosArgs = await localVarAxiosParamCreator.toolLaunchControllerGetToolLaunchRequest(contextExternalToolId, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, + /** + * + * @summary Get ExternalTool Reference for a given context external tool + * @param {string} contextExternalToolId + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async toolReferenceControllerGetToolReference(contextExternalToolId: string, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.toolReferenceControllerGetToolReference(contextExternalToolId, options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, + /** + * + * @summary Get ExternalTool References for a given context + * @param {string} contextId + * @param {ToolContextType} contextType + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async toolReferenceControllerGetToolReferencesForContext(contextId: string, contextType: ToolContextType, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.toolReferenceControllerGetToolReferencesForContext(contextId, contextType, options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, /** * * @summary Creates a SchoolExternalTool @@ -14607,17 +14656,6 @@ export const ToolApiFactory = function (configuration?: Configuration, basePath? toolControllerGetExternalToolLogo(externalToolId: string, options?: any): AxiosPromise { return localVarFp.toolControllerGetExternalToolLogo(externalToolId, options).then((request) => request(axios, basePath)); }, - /** - * - * @summary Get ExternalTool References for a given context - * @param {string} contextId - * @param {ToolContextType} contextType - * @param {*} [options] Override http request option. - * @throws {RequiredError} - */ - toolControllerGetToolReferences(contextId: string, contextType: ToolContextType, options?: any): AxiosPromise { - return localVarFp.toolControllerGetToolReferences(contextId, contextType, options).then((request) => request(axios, basePath)); - }, /** * * @summary Updates an ExternalTool @@ -14639,6 +14677,27 @@ export const ToolApiFactory = function (configuration?: Configuration, basePath? toolLaunchControllerGetToolLaunchRequest(contextExternalToolId: string, options?: any): AxiosPromise { return localVarFp.toolLaunchControllerGetToolLaunchRequest(contextExternalToolId, options).then((request) => request(axios, basePath)); }, + /** + * + * @summary Get ExternalTool Reference for a given context external tool + * @param {string} contextExternalToolId + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + toolReferenceControllerGetToolReference(contextExternalToolId: string, options?: any): AxiosPromise { + return localVarFp.toolReferenceControllerGetToolReference(contextExternalToolId, options).then((request) => request(axios, basePath)); + }, + /** + * + * @summary Get ExternalTool References for a given context + * @param {string} contextId + * @param {ToolContextType} contextType + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + toolReferenceControllerGetToolReferencesForContext(contextId: string, contextType: ToolContextType, options?: any): AxiosPromise { + return localVarFp.toolReferenceControllerGetToolReferencesForContext(contextId, contextType, options).then((request) => request(axios, basePath)); + }, /** * * @summary Creates a SchoolExternalTool @@ -14847,17 +14906,6 @@ export interface ToolApiInterface { */ toolControllerGetExternalToolLogo(externalToolId: string, options?: any): AxiosPromise; - /** - * - * @summary Get ExternalTool References for a given context - * @param {string} contextId - * @param {ToolContextType} contextType - * @param {*} [options] Override http request option. - * @throws {RequiredError} - * @memberof ToolApiInterface - */ - toolControllerGetToolReferences(contextId: string, contextType: ToolContextType, options?: any): AxiosPromise; - /** * * @summary Updates an ExternalTool @@ -14879,6 +14927,27 @@ export interface ToolApiInterface { */ toolLaunchControllerGetToolLaunchRequest(contextExternalToolId: string, options?: any): AxiosPromise; + /** + * + * @summary Get ExternalTool Reference for a given context external tool + * @param {string} contextExternalToolId + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ToolApiInterface + */ + toolReferenceControllerGetToolReference(contextExternalToolId: string, options?: any): AxiosPromise; + + /** + * + * @summary Get ExternalTool References for a given context + * @param {string} contextId + * @param {ToolContextType} contextType + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ToolApiInterface + */ + toolReferenceControllerGetToolReferencesForContext(contextId: string, contextType: ToolContextType, options?: any): AxiosPromise; + /** * * @summary Creates a SchoolExternalTool @@ -15115,19 +15184,6 @@ export class ToolApi extends BaseAPI implements ToolApiInterface { return ToolApiFp(this.configuration).toolControllerGetExternalToolLogo(externalToolId, options).then((request) => request(this.axios, this.basePath)); } - /** - * - * @summary Get ExternalTool References for a given context - * @param {string} contextId - * @param {ToolContextType} contextType - * @param {*} [options] Override http request option. - * @throws {RequiredError} - * @memberof ToolApi - */ - public toolControllerGetToolReferences(contextId: string, contextType: ToolContextType, options?: any) { - return ToolApiFp(this.configuration).toolControllerGetToolReferences(contextId, contextType, options).then((request) => request(this.axios, this.basePath)); - } - /** * * @summary Updates an ExternalTool @@ -15153,6 +15209,31 @@ export class ToolApi extends BaseAPI implements ToolApiInterface { return ToolApiFp(this.configuration).toolLaunchControllerGetToolLaunchRequest(contextExternalToolId, options).then((request) => request(this.axios, this.basePath)); } + /** + * + * @summary Get ExternalTool Reference for a given context external tool + * @param {string} contextExternalToolId + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ToolApi + */ + public toolReferenceControllerGetToolReference(contextExternalToolId: string, options?: any) { + return ToolApiFp(this.configuration).toolReferenceControllerGetToolReference(contextExternalToolId, options).then((request) => request(this.axios, this.basePath)); + } + + /** + * + * @summary Get ExternalTool References for a given context + * @param {string} contextId + * @param {ToolContextType} contextType + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof ToolApi + */ + public toolReferenceControllerGetToolReferencesForContext(contextId: string, contextType: ToolContextType, options?: any) { + return ToolApiFp(this.configuration).toolReferenceControllerGetToolReferencesForContext(contextId, contextType, options).then((request) => request(this.axios, this.basePath)); + } + /** * * @summary Creates a SchoolExternalTool diff --git a/src/store/context-external-tools.ts b/src/store/context-external-tools.ts index 4afeb08ec3..3b3793ccfa 100644 --- a/src/store/context-external-tools.ts +++ b/src/store/context-external-tools.ts @@ -25,6 +25,9 @@ import { } from "./external-tool/mapper"; import { BusinessError } from "./types/commons"; +/** + * @deprecated prefer using useContextExternalToolApi + */ @Module({ name: "contextExternalToolsModule", namespaced: true, @@ -190,9 +193,6 @@ export default class ContextExternalToolsModule extends VuexModule { return null; } - /** - * @deprecated useContextExternalToolApi.fetchDisplayDataCall - */ @Action async loadExternalToolDisplayData(payload: { contextId: string; @@ -203,13 +203,13 @@ export default class ContextExternalToolsModule extends VuexModule { try { const response: AxiosResponse = - await this.toolApi.toolControllerGetToolReferences( + await this.toolApi.toolReferenceControllerGetToolReferencesForContext( payload.contextId, payload.contextType ); const mapped: ExternalToolDisplayData[] = - ExternalToolMapper.mapToExternalToolDisplayData(response.data); + ExternalToolMapper.mapToExternalToolDisplayDataList(response.data); this.setExternalToolDisplayDataList(mapped); } catch (error: unknown) { diff --git a/src/store/context-external-tools.unit.ts b/src/store/context-external-tools.unit.ts index e1bb31d107..cbfe224e98 100644 --- a/src/store/context-external-tools.unit.ts +++ b/src/store/context-external-tools.unit.ts @@ -249,7 +249,7 @@ describe("ContextExternalToolsModule", () => { const displayData: ToolReferenceResponse = toolReferenceResponseFactory.build({ logoUrl: "logoUrl" }); - apiMock.toolControllerGetToolReferences.mockResolvedValue( + apiMock.toolReferenceControllerGetToolReferencesForContext.mockResolvedValue( mockApiResponse({ data: { data: [displayData] } }) ); @@ -265,10 +265,9 @@ describe("ContextExternalToolsModule", () => { await module.loadExternalToolDisplayData({ contextId, contextType }); - expect(apiMock.toolControllerGetToolReferences).toHaveBeenCalledWith( - contextId, - contextType - ); + expect( + apiMock.toolReferenceControllerGetToolReferencesForContext + ).toHaveBeenCalledWith(contextId, contextType); }); it("should set the state", async () => { @@ -298,7 +297,9 @@ describe("ContextExternalToolsModule", () => { const error = axiosErrorFactory.build(); const apiError = mapAxiosErrorToResponseError(error); - apiMock.toolControllerGetToolReferences.mockRejectedValue(error); + apiMock.toolReferenceControllerGetToolReferencesForContext.mockRejectedValue( + error + ); return { apiError, diff --git a/src/store/external-tool/mapper/common-tool.mapper.ts b/src/store/external-tool/mapper/common-tool.mapper.ts index 7d1d06034e..28bb899bd1 100644 --- a/src/store/external-tool/mapper/common-tool.mapper.ts +++ b/src/store/external-tool/mapper/common-tool.mapper.ts @@ -4,15 +4,15 @@ import { CustomParameterResponseLocationEnum, CustomParameterResponseScopeEnum, CustomParameterResponseTypeEnum, + ToolConfigurationStatusResponse, ToolLaunchRequestResponseMethodEnum, - ToolReferenceResponseStatusEnum, } from "@/serverApi/v3"; +import { ToolLaunchRequestMethodEnum } from "@/store/external-tool"; import { ToolConfigurationStatus } from "../tool-configuration-status.enum"; import { ToolParameterEntry } from "../tool-parameter-entry"; import { ToolParameterLocation } from "../tool-parameter-location.enum"; import { ToolParameterScope } from "../tool-parameter-scope.enum"; import { ToolParameterType } from "../tool-parameter.enum"; -import { ToolLaunchRequestMethodEnum } from "@/store/external-tool"; export const ToolParamLocationMapping: Record< CustomParameterResponseLocationEnum, @@ -50,12 +50,12 @@ export const ToolParamScopeMapping: Record< }; export const ToolConfigurationStatusMapping: Record< - ToolReferenceResponseStatusEnum, + ToolConfigurationStatusResponse, ToolConfigurationStatus > = { - [ToolReferenceResponseStatusEnum.Latest]: ToolConfigurationStatus.Latest, - [ToolReferenceResponseStatusEnum.Outdated]: ToolConfigurationStatus.Outdated, - [ToolReferenceResponseStatusEnum.Unknown]: ToolConfigurationStatus.Unknown, + [ToolConfigurationStatusResponse.Latest]: ToolConfigurationStatus.Latest, + [ToolConfigurationStatusResponse.Outdated]: ToolConfigurationStatus.Outdated, + [ToolConfigurationStatusResponse.Unknown]: ToolConfigurationStatus.Unknown, }; export const ToolLaunchRequestMethodMapping: Record< diff --git a/src/store/external-tool/mapper/context-external-tool.mapper.ts b/src/store/external-tool/mapper/context-external-tool.mapper.ts index 0d91ad1eb3..e8de488da7 100644 --- a/src/store/external-tool/mapper/context-external-tool.mapper.ts +++ b/src/store/external-tool/mapper/context-external-tool.mapper.ts @@ -22,8 +22,8 @@ export const ToolContextMapping: Record< ToolContextType > = { [ContextExternalToolResponseContextTypeEnum.Course]: ToolContextType.Course, - [ContextExternalToolResponseContextTypeEnum.BoardCard]: - ToolContextType.BoardCard, + [ContextExternalToolResponseContextTypeEnum.BoardElement]: + ToolContextType.BoardElement, }; export class ContextExternalToolMapper { diff --git a/src/store/external-tool/mapper/external-tool.mapper.ts b/src/store/external-tool/mapper/external-tool.mapper.ts index 863e9179a6..1b87d4532b 100644 --- a/src/store/external-tool/mapper/external-tool.mapper.ts +++ b/src/store/external-tool/mapper/external-tool.mapper.ts @@ -2,8 +2,10 @@ import { CustomParameterResponse, ToolLaunchRequestResponse, ToolReferenceListResponse, + ToolReferenceResponse, } from "@/serverApi/v3"; import { ExternalToolDisplayData } from "../external-tool-display-data"; +import { ToolLaunchRequest } from "../tool-launch-request"; import { ToolParameter } from "../tool-parameter"; import { ToolConfigurationStatusMapping, @@ -12,7 +14,6 @@ import { ToolParamScopeMapping, ToolParamTypeMapping, } from "./common-tool.mapper"; -import { ToolLaunchRequest } from "../tool-launch-request"; export class ExternalToolMapper { static mapToToolParameter(response: CustomParameterResponse): ToolParameter { @@ -32,22 +33,31 @@ export class ExternalToolMapper { return mapped; } - static mapToExternalToolDisplayData( + static mapToExternalToolDisplayDataList( response: ToolReferenceListResponse ): ExternalToolDisplayData[] { const mapped: ExternalToolDisplayData[] = response.data.map( - (tool): ExternalToolDisplayData => ({ - contextExternalToolId: tool.contextToolId, - name: tool.displayName, - status: ToolConfigurationStatusMapping[tool.status], - logoUrl: tool.logoUrl, - openInNewTab: tool.openInNewTab, - }) + (tool): ExternalToolDisplayData => + ExternalToolMapper.mapToExternalToolDisplayData(tool) ); return mapped; } + static mapToExternalToolDisplayData( + response: ToolReferenceResponse + ): ExternalToolDisplayData { + const mapped: ExternalToolDisplayData = { + contextExternalToolId: response.contextToolId, + name: response.displayName, + status: ToolConfigurationStatusMapping[response.status], + logoUrl: response.logoUrl, + openInNewTab: response.openInNewTab, + }; + + return mapped; + } + static mapToToolLaunchRequest( response: ToolLaunchRequestResponse ): ToolLaunchRequest { diff --git a/tests/test-utils/factory/toolReferenceResponseFactory.ts b/tests/test-utils/factory/toolReferenceResponseFactory.ts index 82b58ec9f6..55bc580624 100644 --- a/tests/test-utils/factory/toolReferenceResponseFactory.ts +++ b/tests/test-utils/factory/toolReferenceResponseFactory.ts @@ -1,13 +1,13 @@ import { + ToolConfigurationStatusResponse, ToolReferenceResponse, - ToolReferenceResponseStatusEnum, } from "@/serverApi/v3"; import { Factory } from "fishery"; export const toolReferenceResponseFactory = Factory.define(({ sequence }) => ({ contextToolId: `context-external-tool-${sequence}`, - status: ToolReferenceResponseStatusEnum.Latest, + status: ToolConfigurationStatusResponse.Latest, openInNewTab: true, displayName: `Tool ${sequence}`, })); From bb9583198e99adf80caee523b01d33cabe6b4fad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20=C3=96hlerking?= Date: Tue, 17 Oct 2023 14:49:31 +0200 Subject: [PATCH 11/13] fix test --- .../ExternalToolElementDisplayState.composable.unit.ts | 6 +++--- src/components/data-board/BoardApi.composable.unit.ts | 4 ---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/components/data-board-external-tool-element/ExternalToolElementDisplayState.composable.unit.ts b/src/components/data-board-external-tool-element/ExternalToolElementDisplayState.composable.unit.ts index e0b0637d08..f8461888ae 100644 --- a/src/components/data-board-external-tool-element/ExternalToolElementDisplayState.composable.unit.ts +++ b/src/components/data-board-external-tool-element/ExternalToolElementDisplayState.composable.unit.ts @@ -43,9 +43,9 @@ describe("SharedExternalToolElementDisplayState.composable", () => { const displayDataMock: ExternalToolDisplayData = externalToolDisplayDataFactory.build(); - useContextExternalToolApiMock.fetchDisplayDataCall.mockResolvedValue([ - displayDataMock, - ]); + useContextExternalToolApiMock.fetchDisplayDataCall.mockResolvedValue( + displayDataMock + ); return { displayDataMock, diff --git a/src/components/data-board/BoardApi.composable.unit.ts b/src/components/data-board/BoardApi.composable.unit.ts index 951c25652c..a46025e86a 100644 --- a/src/components/data-board/BoardApi.composable.unit.ts +++ b/src/components/data-board/BoardApi.composable.unit.ts @@ -195,10 +195,6 @@ describe("BoardApi.composable", () => { type: ContentElementType.ExternalTool, content: { contextExternalToolId: "context-external-tool-id", - displayData: { - name: "name", - logoUrl: "logoUrl", - }, }, timestamps: timestampsResponseFactory.build(), }; From ca7dcf29a3b4169d46c83063fee0c2c64bfd6583 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20=C3=96hlerking?= Date: Tue, 17 Oct 2023 15:27:13 +0200 Subject: [PATCH 12/13] fix test --- .../ExternalToolElementDisplayState.composable.unit.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/data-board-external-tool-element/ExternalToolElementDisplayState.composable.unit.ts b/src/components/data-board-external-tool-element/ExternalToolElementDisplayState.composable.unit.ts index f8461888ae..53db87a5ac 100644 --- a/src/components/data-board-external-tool-element/ExternalToolElementDisplayState.composable.unit.ts +++ b/src/components/data-board-external-tool-element/ExternalToolElementDisplayState.composable.unit.ts @@ -1,5 +1,4 @@ import { useErrorHandler } from "@/components/error-handling/ErrorHandler.composable"; -import { ToolContextType } from "@/serverApi/v3"; import { ExternalToolDisplayData } from "@/store/external-tool"; import { externalToolDisplayDataFactory } from "@@/tests/test-utils"; import { useContextExternalToolApi } from "@data-external-tool"; @@ -9,7 +8,7 @@ import { useExternalToolElementDisplayState } from "./ExternalToolElementDisplay jest.mock("@data-external-tool"); jest.mock("@/components/error-handling/ErrorHandler.composable"); -describe("SharedExternalToolElementDisplayState.composable", () => { +describe("ExternalToolElementDisplayState.composable", () => { let useContextExternalToolApiMock: DeepMocked< ReturnType >; @@ -60,7 +59,7 @@ describe("SharedExternalToolElementDisplayState.composable", () => { expect( useContextExternalToolApiMock.fetchDisplayDataCall - ).toHaveBeenCalledWith("contextId", ToolContextType.BoardElement); + ).toHaveBeenCalledWith("contextId"); }); it("should set the display data in the state", async () => { From d9e83739d2df10e7961ff1f32c4136fb9ab38b1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20=C3=96hlerking?= Date: Thu, 19 Oct 2023 09:39:11 +0200 Subject: [PATCH 13/13] move ExternalToolElementDisplayState.composable.ts to @data-external-tool --- src/components/data-board-external-tool-element/index.ts | 1 - .../ExternalToolElementDisplayState.composable.ts | 6 +++--- .../ExternalToolElementDisplayState.composable.unit.ts | 4 ++-- src/components/data-external-tool/index.ts | 1 + .../ExternalToolElement.unit.ts | 4 ++-- .../ExternalToolElement.vue | 2 +- tsconfig.json | 1 - vue.config.js | 3 --- 8 files changed, 9 insertions(+), 13 deletions(-) delete mode 100644 src/components/data-board-external-tool-element/index.ts rename src/components/{data-board-external-tool-element => data-external-tool}/ExternalToolElementDisplayState.composable.ts (75%) rename src/components/{data-board-external-tool-element => data-external-tool}/ExternalToolElementDisplayState.composable.unit.ts (94%) diff --git a/src/components/data-board-external-tool-element/index.ts b/src/components/data-board-external-tool-element/index.ts deleted file mode 100644 index 7203a1a816..0000000000 --- a/src/components/data-board-external-tool-element/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./ExternalToolElementDisplayState.composable"; diff --git a/src/components/data-board-external-tool-element/ExternalToolElementDisplayState.composable.ts b/src/components/data-external-tool/ExternalToolElementDisplayState.composable.ts similarity index 75% rename from src/components/data-board-external-tool-element/ExternalToolElementDisplayState.composable.ts rename to src/components/data-external-tool/ExternalToolElementDisplayState.composable.ts index 77a6ac100c..c96fb9423c 100644 --- a/src/components/data-board-external-tool-element/ExternalToolElementDisplayState.composable.ts +++ b/src/components/data-external-tool/ExternalToolElementDisplayState.composable.ts @@ -1,7 +1,7 @@ -import { useErrorHandler } from "@/components/error-handling/ErrorHandler.composable"; -import { ExternalToolDisplayData } from "@/store/external-tool"; -import { useContextExternalToolApi } from "@data-external-tool"; import { ref, Ref } from "vue"; +import { ExternalToolDisplayData } from "../../store/external-tool"; +import { useErrorHandler } from "../error-handling/ErrorHandler.composable"; +import { useContextExternalToolApi } from "./index"; export const useExternalToolElementDisplayState = () => { const { handleError } = useErrorHandler(); diff --git a/src/components/data-board-external-tool-element/ExternalToolElementDisplayState.composable.unit.ts b/src/components/data-external-tool/ExternalToolElementDisplayState.composable.unit.ts similarity index 94% rename from src/components/data-board-external-tool-element/ExternalToolElementDisplayState.composable.unit.ts rename to src/components/data-external-tool/ExternalToolElementDisplayState.composable.unit.ts index 53db87a5ac..1fe5ff37ed 100644 --- a/src/components/data-board-external-tool-element/ExternalToolElementDisplayState.composable.unit.ts +++ b/src/components/data-external-tool/ExternalToolElementDisplayState.composable.unit.ts @@ -1,9 +1,9 @@ -import { useErrorHandler } from "@/components/error-handling/ErrorHandler.composable"; import { ExternalToolDisplayData } from "@/store/external-tool"; import { externalToolDisplayDataFactory } from "@@/tests/test-utils"; -import { useContextExternalToolApi } from "@data-external-tool"; import { createMock, DeepMocked } from "@golevelup/ts-jest"; +import { useErrorHandler } from "../error-handling/ErrorHandler.composable"; import { useExternalToolElementDisplayState } from "./ExternalToolElementDisplayState.composable"; +import { useContextExternalToolApi } from "./index"; jest.mock("@data-external-tool"); jest.mock("@/components/error-handling/ErrorHandler.composable"); diff --git a/src/components/data-external-tool/index.ts b/src/components/data-external-tool/index.ts index a86cde4ed7..f64b0c1f8f 100644 --- a/src/components/data-external-tool/index.ts +++ b/src/components/data-external-tool/index.ts @@ -1 +1,2 @@ export * from "./ContextExternalToolApi.composable"; +export * from "./ExternalToolElementDisplayState.composable"; diff --git a/src/components/feature-board-external-tool-element/ExternalToolElement.unit.ts b/src/components/feature-board-external-tool-element/ExternalToolElement.unit.ts index 7bc7a6f274..54651ab219 100644 --- a/src/components/feature-board-external-tool-element/ExternalToolElement.unit.ts +++ b/src/components/feature-board-external-tool-element/ExternalToolElement.unit.ts @@ -13,7 +13,7 @@ import { } from "@@/tests/test-utils"; import createComponentMocks from "@@/tests/test-utils/componentMocks"; import { useBoardFocusHandler, useContentElementState } from "@data-board"; -import { useExternalToolElementDisplayState } from "@data-board-external-tool-element"; +import { useExternalToolElementDisplayState } from "@data-external-tool"; import { createMock, DeepMocked } from "@golevelup/ts-jest"; import { mdiPuzzleOutline } from "@mdi/js"; import { useDeleteConfirmationDialog } from "@ui-confirmation-dialog"; @@ -22,7 +22,7 @@ import Vue, { ref } from "vue"; import ExternalToolElement from "./ExternalToolElement.vue"; jest.mock("@data-board"); -jest.mock("@data-board-external-tool-element"); +jest.mock("@data-external-tool"); jest.mock("@ui-confirmation-dialog"); const EMPTY_TEST_ELEMENT: ExternalToolElementResponse = { diff --git a/src/components/feature-board-external-tool-element/ExternalToolElement.vue b/src/components/feature-board-external-tool-element/ExternalToolElement.vue index a81a89ed7f..39b7fa00f4 100644 --- a/src/components/feature-board-external-tool-element/ExternalToolElement.vue +++ b/src/components/feature-board-external-tool-element/ExternalToolElement.vue @@ -59,7 +59,7 @@ import { useI18n } from "@/composables/i18n.composable"; import { ExternalToolElementResponse } from "@/serverApi/v3"; import { ContextExternalTool } from "@/store/external-tool/context-external-tool"; import { useBoardFocusHandler, useContentElementState } from "@data-board"; -import { useExternalToolElementDisplayState } from "@data-board-external-tool-element"; +import { useExternalToolElementDisplayState } from "@data-external-tool"; import { mdiPuzzleOutline } from "@mdi/js"; import { computed, diff --git a/tsconfig.json b/tsconfig.json index 872d8998ee..1b7c928128 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,7 +19,6 @@ "paths": { "@data-board": ["src/components/data-board"], "@data-external-tool": ["src/components/data-external-tool"], - "@data-board-external-tool-element": ["src/components/data-board-external-tool-element"], "@feature-board-file-element": [ "src/components/feature-board-file-element" ], diff --git a/vue.config.js b/vue.config.js index 3a742e265c..ab7b9116e2 100644 --- a/vue.config.js +++ b/vue.config.js @@ -22,9 +22,6 @@ module.exports = defineConfig({ alias: { "@data-board": getDir("src/components/data-board"), "@data-external-tool": getDir("src/components/data-external-tool"), - "@data-board-external-tool-element": getDir( - "src/components/data-board-external-tool-element" - ), "@feature-board-file-element": getDir( "src/components/feature-board-file-element" ),