diff --git a/src/components/rooms/RoomExternalToolCard.vue b/src/components/rooms/RoomExternalToolCard.vue
index b73ed359e6..ff973dabee 100644
--- a/src/components/rooms/RoomExternalToolCard.vue
+++ b/src/components/rooms/RoomExternalToolCard.vue
@@ -1,6 +1,7 @@
emit("refresh"));
const { isTeacher } = useContextExternalToolConfigurationStatus();
@@ -122,6 +123,28 @@ const menuItems = [
},
];
+const isDeepLinkingTool: ComputedRef = computed(
+ () => !!props.tool.isLtiDeepLinkingTool
+);
+
+const hasDeepLink: ComputedRef = computed(() => !!props.tool.ltiDeepLink);
+
+const toolName: ComputedRef = computed(() => {
+ if (isDeepLinkingTool.value) {
+ return hasDeepLink.value
+ ? props.tool.name
+ : t("feature-board-external-tool-element.placeholder.selectContent", {
+ toolName: props.tool.name,
+ });
+ }
+
+ return props.tool.name;
+});
+
+const showTool: ComputedRef = computed(
+ () => !(isDeepLinkingTool.value && !hasDeepLink.value && !isTeacher())
+);
+
const isToolOutdated: ComputedRef = computed(
() =>
props.tool.status.isOutdatedOnScopeSchool ||
diff --git a/src/modules/data/external-tool/ExternalToolApi.composable.unit.ts b/src/modules/data/external-tool/ExternalToolApi.composable.unit.ts
index 55d0e62c39..002795c80c 100644
--- a/src/modules/data/external-tool/ExternalToolApi.composable.unit.ts
+++ b/src/modules/data/external-tool/ExternalToolApi.composable.unit.ts
@@ -1,6 +1,7 @@
import * as serverApi from "@/serverApi/v3/api";
import {
ContextExternalToolBodyParams,
+ LaunchType,
ToolContextType,
ToolLaunchRequestResponse,
} from "@/serverApi/v3/api";
@@ -67,7 +68,7 @@ describe("ExternalToolApi.composable", () => {
payload: launchRequest.payload,
method: ToolLaunchRequestMethodEnum.Get,
openNewTab: launchRequest.openNewTab,
- isDeepLink: false,
+ launchType: LaunchType.Basic,
});
});
});
@@ -119,7 +120,7 @@ describe("ExternalToolApi.composable", () => {
payload: launchRequest.payload,
method: ToolLaunchRequestMethodEnum.Get,
openNewTab: launchRequest.openNewTab,
- isDeepLink: false,
+ launchType: LaunchType.Basic,
});
});
});
diff --git a/src/modules/data/external-tool/ExternalToolLaunchState.composable.ts b/src/modules/data/external-tool/ExternalToolLaunchState.composable.ts
index 9b1e8658fe..0bed810dab 100644
--- a/src/modules/data/external-tool/ExternalToolLaunchState.composable.ts
+++ b/src/modules/data/external-tool/ExternalToolLaunchState.composable.ts
@@ -1,4 +1,4 @@
-import { ContextExternalToolBodyParams } from "@/serverApi/v3";
+import { ContextExternalToolBodyParams, LaunchType } from "@/serverApi/v3";
import {
ToolLaunchRequest,
ToolLaunchRequestMethodEnum,
@@ -6,10 +6,13 @@ import {
import { BusinessError } from "@/store/types/commons";
import { HttpStatusCode } from "@/store/types/http-status-code.enum";
import { mapAxiosErrorToResponseError } from "@/utils/api";
-import { ref, Ref } from "vue";
+import { uniqueId } from "lodash";
+import { onUnmounted, ref, Ref } from "vue";
import { useExternalToolApi } from "./ExternalToolApi.composable";
-export const useExternalToolLaunchState = () => {
+export const useExternalToolLaunchState = (
+ refreshCallback?: () => Promise | void
+) => {
const { fetchContextLaunchDataCall, fetchSchoolLaunchDataCall } =
useExternalToolApi();
@@ -17,6 +20,9 @@ export const useExternalToolLaunchState = () => {
const error: Ref = ref();
const toolLaunchRequest: Ref = ref();
+ const windowRef: Ref = ref(null);
+ const windowIntervalHandle: Ref = ref();
+
const fetchContextLaunchRequest = async (
contextExternalToolId: string
): Promise => {
@@ -103,9 +109,11 @@ export const useExternalToolLaunchState = () => {
const form: HTMLFormElement = document.createElement("form");
form.method = "POST";
form.action = toolLaunch.url;
- form.target = toolLaunch.openNewTab ? "_blank" : "_self";
form.id = "launch-form";
+ const target = uniqueId();
+ form.target = toolLaunch.openNewTab ? target : "_self";
+
const payload = JSON.parse(toolLaunch.payload || "{}");
for (const key in payload) {
@@ -121,9 +129,26 @@ export const useExternalToolLaunchState = () => {
document.body.appendChild(form);
+ windowRef.value = window.open(undefined, form.target);
+
form.submit();
+
+ if (toolLaunch.launchType === LaunchType.Lti11ContentItemSelection) {
+ windowIntervalHandle.value = setInterval(async () => {
+ if (windowRef.value?.closed) {
+ await refreshCallback?.();
+
+ windowRef.value = null;
+ clearInterval(windowIntervalHandle.value);
+ }
+ }, 1000);
+ }
};
+ onUnmounted(() => {
+ clearInterval(windowIntervalHandle.value);
+ });
+
return {
toolLaunchRequest,
error,
diff --git a/src/modules/data/external-tool/ExternalToolLaunchState.composable.unit.ts b/src/modules/data/external-tool/ExternalToolLaunchState.composable.unit.ts
index 7c2c45dcbc..8428dc2f47 100644
--- a/src/modules/data/external-tool/ExternalToolLaunchState.composable.unit.ts
+++ b/src/modules/data/external-tool/ExternalToolLaunchState.composable.unit.ts
@@ -1,4 +1,8 @@
-import { ContextExternalToolBodyParams, ToolContextType } from "@/serverApi/v3";
+import {
+ ContextExternalToolBodyParams,
+ LaunchType,
+ ToolContextType,
+} from "@/serverApi/v3";
import {
ToolLaunchRequest,
ToolLaunchRequestMethodEnum,
@@ -11,6 +15,7 @@ import { toolLaunchRequestFactory } from "@@/tests/test-utils/factory/toolLaunch
import { createMock, DeepMocked } from "@golevelup/ts-jest";
import { useExternalToolApi } from "./ExternalToolApi.composable";
import { useExternalToolLaunchState } from "./ExternalToolLaunchState.composable";
+import { nextTick } from "vue";
jest.mock("@data-external-tool/ExternalToolApi.composable");
@@ -64,7 +69,7 @@ describe("ExternalToolLaunchState.composable", () => {
url: response.url,
payload: response.payload,
openNewTab: response.openNewTab,
- isDeepLink: false,
+ launchType: LaunchType.Basic,
});
});
@@ -152,7 +157,7 @@ describe("ExternalToolLaunchState.composable", () => {
url: response.url,
payload: response.payload,
openNewTab: response.openNewTab,
- isDeepLink: false,
+ launchType: response.launchType,
});
});
@@ -279,11 +284,12 @@ describe("ExternalToolLaunchState.composable", () => {
});
describe("when launching a tool with post method", () => {
- describe("when opening in the same tab", () => {
+ describe("when opening in a new tab", () => {
const setup = () => {
const launchRequest = toolLaunchRequestFactory.build({
method: ToolLaunchRequestMethodEnum.Post,
- openNewTab: false,
+ openNewTab: true,
+ payload: "",
});
const composable = useExternalToolLaunchState();
@@ -295,7 +301,7 @@ describe("ExternalToolLaunchState.composable", () => {
};
};
- it("should create a launch form with target _self", () => {
+ it("should create a launch form with a number as the target ", () => {
const { launchRequest, launchTool } = setup();
launchTool();
@@ -303,17 +309,16 @@ describe("ExternalToolLaunchState.composable", () => {
const form = document.getElementById("launch-form");
expect(form?.outerHTML).toEqual(
- ``
+ ``
);
});
});
- describe("when opening in a new tab", () => {
+ describe("when opening in the same tab", () => {
const setup = () => {
const launchRequest = toolLaunchRequestFactory.build({
method: ToolLaunchRequestMethodEnum.Post,
- openNewTab: true,
- payload: "",
+ openNewTab: false,
});
const composable = useExternalToolLaunchState();
@@ -325,7 +330,7 @@ describe("ExternalToolLaunchState.composable", () => {
};
};
- it("should create a launch form with target _blank", () => {
+ it("should create a launch form with target _self", () => {
const { launchRequest, launchTool } = setup();
launchTool();
@@ -333,7 +338,7 @@ describe("ExternalToolLaunchState.composable", () => {
const form = document.getElementById("launch-form");
expect(form?.outerHTML).toEqual(
- ``
+ ``
);
});
});
@@ -403,5 +408,84 @@ describe("ExternalToolLaunchState.composable", () => {
expect(window.open).not.toHaveBeenCalled();
});
});
+
+ describe("when the launch is with launchType Lti11ContentItemSelection", () => {
+ const setup = () => {
+ const refreshCallback = jest.fn();
+ const launchRequest = toolLaunchRequestFactory.build({
+ method: ToolLaunchRequestMethodEnum.Post,
+ openNewTab: true,
+ launchType: LaunchType.Lti11ContentItemSelection,
+ });
+
+ const composable = useExternalToolLaunchState(refreshCallback);
+ composable.toolLaunchRequest.value = launchRequest;
+
+ const mockWindow = {
+ closed: false,
+ };
+
+ jest
+ .spyOn(window, "open")
+ .mockReturnValue(mockWindow as unknown as Window);
+
+ const setInterval = jest.spyOn(window, "setInterval");
+ const clearInterval = jest.spyOn(window, "clearInterval");
+
+ return {
+ ...composable,
+ refreshCallback,
+ setInterval,
+ clearInterval,
+ mockWindow,
+ };
+ };
+
+ afterEach(() => {
+ jest.useRealTimers();
+ jest.restoreAllMocks();
+ });
+
+ it("should call refreshCallback", async () => {
+ jest.useFakeTimers();
+ const {
+ launchTool,
+ refreshCallback,
+ mockWindow,
+ setInterval,
+ clearInterval,
+ } = setup();
+
+ launchTool();
+
+ expect(setInterval).toHaveBeenCalled();
+ expect(mockWindow.closed).toBe(false);
+
+ mockWindow.closed = true;
+
+ jest.advanceTimersByTime(1000);
+ await nextTick();
+
+ expect(refreshCallback).toHaveBeenCalled();
+ expect(clearInterval).toHaveBeenCalled();
+ });
+
+ it("should not call refreshCallback", async () => {
+ jest.useFakeTimers();
+ const { launchTool, refreshCallback, mockWindow } = setup();
+
+ launchTool();
+
+ expect(setInterval).toHaveBeenCalled();
+
+ mockWindow.closed = false;
+
+ jest.advanceTimersByTime(1000);
+ await nextTick();
+
+ expect(refreshCallback).not.toHaveBeenCalled();
+ expect(clearInterval).not.toHaveBeenCalled();
+ });
+ });
});
});
diff --git a/src/modules/data/external-tool/externalToolReferenceApi.composable.unit.ts b/src/modules/data/external-tool/externalToolReferenceApi.composable.unit.ts
index ca726747ec..0950a903af 100644
--- a/src/modules/data/external-tool/externalToolReferenceApi.composable.unit.ts
+++ b/src/modules/data/external-tool/externalToolReferenceApi.composable.unit.ts
@@ -62,6 +62,7 @@ describe("externalToolReferenceApi.composable", () => {
logoUrl: displayData.logoUrl,
status: contextExternalToolConfigurationStatusFactory.build(),
openInNewTab: displayData.openInNewTab,
+ isLtiDeepLinkingTool: displayData.isLtiDeepLinkingTool,
});
});
});
@@ -109,6 +110,7 @@ describe("externalToolReferenceApi.composable", () => {
logoUrl: displayData.logoUrl,
status: contextExternalToolConfigurationStatusFactory.build(),
openInNewTab: displayData.openInNewTab,
+ isLtiDeepLinkingTool: displayData.isLtiDeepLinkingTool,
},
]);
});
diff --git a/src/modules/data/external-tool/types/external-tool-display-data.ts b/src/modules/data/external-tool/types/external-tool-display-data.ts
index b60703e06b..c19d436ec0 100644
--- a/src/modules/data/external-tool/types/external-tool-display-data.ts
+++ b/src/modules/data/external-tool/types/external-tool-display-data.ts
@@ -1,3 +1,4 @@
+import { LtiDeepLinkResponse } from "@/serverApi/v3";
import { ContextExternalToolConfigurationStatus } from "./context-external-tool-configuration-status";
export type ExternalToolDisplayData = {
@@ -14,4 +15,8 @@ export type ExternalToolDisplayData = {
openInNewTab: boolean;
status: ContextExternalToolConfigurationStatus;
+
+ isLtiDeepLinkingTool: boolean;
+
+ ltiDeepLink?: LtiDeepLinkResponse;
};
diff --git a/src/modules/feature/board-external-tool-element/ExternalToolElement.unit.ts b/src/modules/feature/board-external-tool-element/ExternalToolElement.unit.ts
index 6251585991..2600daa23f 100644
--- a/src/modules/feature/board-external-tool-element/ExternalToolElement.unit.ts
+++ b/src/modules/feature/board-external-tool-element/ExternalToolElement.unit.ts
@@ -8,6 +8,7 @@ import {
contextExternalToolFactory,
externalToolDisplayDataFactory,
externalToolElementResponseFactory,
+ ltiDeepLinkResponseFactory,
schoolToolConfigurationStatusFactory,
} from "@@/tests/test-utils";
import {
@@ -22,8 +23,6 @@ import {
useExternalToolDisplayState,
useExternalToolLaunchState,
} from "@data-external-tool";
-import { ToolLaunchRequest } from "@/store/external-tool";
-import { toolLaunchRequestFactory } from "@@/tests/test-utils/factory/toolLaunchRequestFactory";
import { createMock, DeepMocked } from "@golevelup/ts-jest";
import { mdiPuzzleOutline } from "@icons/material";
import { useSharedLastCreatedElement } from "@util-board";
@@ -104,12 +103,10 @@ describe("ExternalToolElement", () => {
element: ExternalToolElementResponse;
isEditMode: boolean;
},
- displayData?: ExternalToolDisplayData,
- toolLaunchRequest?: ToolLaunchRequest
+ displayData?: ExternalToolDisplayData
) => {
useContentElementStateMock.modelValue = ref(propsData.element.content);
useExternalToolElementDisplayStateMock.displayData.value = displayData;
- useExternalToolLaunchStateMock.toolLaunchRequest.value = toolLaunchRequest;
const refreshTime = 299000;
const envConfigModuleMock = createModuleMocks(EnvConfigModule, {
@@ -155,6 +152,7 @@ describe("ExternalToolElement", () => {
},
externalToolDisplayDataFactory.build({
status: schoolToolConfigurationStatusFactory.build(),
+ isLtiDeepLinkingTool: false,
})
);
@@ -399,16 +397,19 @@ describe("ExternalToolElement", () => {
});
});
- describe("when deeplinking tool is selected", () => {
+ describe("when a deeplinking tool without a deeplink is selected", () => {
describe("when not in edit mode", () => {
const setup = () => {
const { wrapper } = getWrapper(
{
- element: externalToolElementResponseFactory.build(),
+ element: externalToolElementResponseFactory.build({
+ content: { contextExternalToolId: "contextExternalToolId" },
+ }),
isEditMode: false,
},
- undefined,
- toolLaunchRequestFactory.build({ isDeepLink: true })
+ externalToolDisplayDataFactory.build({
+ isLtiDeepLinkingTool: true,
+ })
);
return {
@@ -436,8 +437,8 @@ describe("ExternalToolElement", () => {
},
externalToolDisplayDataFactory.build({
status: schoolToolConfigurationStatusFactory.build(),
- }),
- toolLaunchRequestFactory.build({ isDeepLink: true })
+ isLtiDeepLinkingTool: true,
+ })
);
return {
@@ -452,15 +453,65 @@ describe("ExternalToolElement", () => {
expect(element.isVisible()).toEqual(true);
});
+ });
+ });
- it("should load the launch request", async () => {
- setup();
+ describe("when a deeplinking tool with a deeplink is selected", () => {
+ describe("when not in edit mode", () => {
+ const setup = () => {
+ const { wrapper } = getWrapper(
+ {
+ element: externalToolElementResponseFactory.build({
+ content: { contextExternalToolId: "contextExternalToolId" },
+ }),
+ isEditMode: false,
+ },
+ externalToolDisplayDataFactory.build({
+ isLtiDeepLinkingTool: true,
+ ltiDeepLink: ltiDeepLinkResponseFactory.build(),
+ })
+ );
- await nextTick();
+ return {
+ wrapper,
+ };
+ };
- expect(
- useExternalToolLaunchStateMock.fetchContextLaunchRequest
- ).toHaveBeenCalledWith("contextExternalToolId");
+ it("should show the element", () => {
+ const { wrapper } = setup();
+
+ const element = wrapper.findComponent({ ref: "externalToolElement" });
+
+ expect(element.isVisible()).toEqual(true);
+ });
+ });
+
+ describe("when in edit mode", () => {
+ const setup = () => {
+ const { wrapper } = getWrapper(
+ {
+ element: externalToolElementResponseFactory.build({
+ content: { contextExternalToolId: "contextExternalToolId" },
+ }),
+ isEditMode: true,
+ },
+ externalToolDisplayDataFactory.build({
+ isLtiDeepLinkingTool: true,
+ ltiDeepLink: ltiDeepLinkResponseFactory.build(),
+ })
+ );
+
+ return {
+ wrapper,
+ };
+ };
+
+ it("should show the element", () => {
+ const { wrapper } = setup();
+
+ const element = wrapper.findComponent({ ref: "externalToolElement" });
+
+ expect(element.isVisible()).toEqual(true);
});
});
});
@@ -562,6 +613,11 @@ describe("ExternalToolElement", () => {
describe("when the component has finished loading", () => {
const setup = () => {
const contextExternalToolId = "context-external-tool-id";
+ const displayData = externalToolDisplayDataFactory.build({
+ contextExternalToolId,
+ isLtiDeepLinkingTool: true,
+ ltiDeepLink: ltiDeepLinkResponseFactory.build(),
+ });
useExternalToolElementDisplayStateMock.isLoading = ref(false);
@@ -572,7 +628,7 @@ describe("ExternalToolElement", () => {
}),
isEditMode: false,
},
- externalToolDisplayDataFactory.build({ contextExternalToolId })
+ displayData
);
return {
@@ -725,8 +781,9 @@ describe("ExternalToolElement", () => {
}),
isEditMode: true,
},
- undefined,
- toolLaunchRequestFactory.build({ isDeepLink: true })
+ externalToolDisplayDataFactory.build({
+ isLtiDeepLinkingTool: true,
+ })
);
return {
diff --git a/src/modules/feature/board-external-tool-element/ExternalToolElement.vue b/src/modules/feature/board-external-tool-element/ExternalToolElement.vue
index 714be5b7c0..b7504cf429 100644
--- a/src/modules/feature/board-external-tool-element/ExternalToolElement.vue
+++ b/src/modules/feature/board-external-tool-element/ExternalToolElement.vue
@@ -117,8 +117,7 @@ const {
launchTool,
fetchContextLaunchRequest,
error: launchError,
- toolLaunchRequest,
-} = useExternalToolLaunchState();
+} = useExternalToolLaunchState(() => loadCardData());
const autofocus: Ref = ref(false);
const element: Ref = toRef(props, "element");
@@ -141,16 +140,20 @@ const hasLinkedTool: ComputedRef = computed(
() => !!modelValue.value.contextExternalToolId
);
-const isDeepLinkingTool: ComputedRef = computed(
- () => toolLaunchRequest.value?.isDeepLink
+const isDeepLinkingTool: ComputedRef = computed(
+ () => !!displayData.value?.isLtiDeepLinkingTool
+);
+
+const hasDeepLink: ComputedRef = computed(
+ () => !!displayData.value?.ltiDeepLink
);
const showTool: ComputedRef = computed(() => {
- if (!toolLaunchRequest.value) {
+ if (!displayData.value || !hasLinkedTool.value) {
return false;
}
- return toolLaunchRequest.value.isDeepLink ? false : hasLinkedTool.value;
+ return isDeepLinkingTool.value ? hasDeepLink.value : true;
});
const toolDisplayName: ComputedRef = computed(
@@ -187,20 +190,19 @@ const isLoading = computed(
const isConfigurationDialogOpen: Ref = ref(false);
const toolTitle: ComputedRef = computed(() => {
- if (hasLinkedTool.value) {
- if (isDeepLinkingTool.value) {
- return t(
- "feature-board-external-tool-element.placeholder.selectContent",
- {
- toolName: toolDisplayName.value,
- }
- );
- }
+ if (!hasLinkedTool.value) {
+ return t("feature-board-external-tool-element.placeholder.selectTool");
+ }
- return toolDisplayName.value;
+ if (isDeepLinkingTool.value) {
+ return hasDeepLink.value
+ ? toolDisplayName.value
+ : t("feature-board-external-tool-element.placeholder.selectContent", {
+ toolName: toolDisplayName.value,
+ });
}
- return t("feature-board-external-tool-element.placeholder.selectTool");
+ return toolDisplayName.value;
});
const onKeydownArrow = (event: KeyboardEvent) => {
diff --git a/src/pages/course-rooms/tools/RoomExternalToolsErrorDialog.unit.ts b/src/pages/course-rooms/tools/RoomExternalToolsErrorDialog.unit.ts
index 7e81a7ed2f..6e895d2657 100644
--- a/src/pages/course-rooms/tools/RoomExternalToolsErrorDialog.unit.ts
+++ b/src/pages/course-rooms/tools/RoomExternalToolsErrorDialog.unit.ts
@@ -58,6 +58,7 @@ describe("RoomExternalToolsErrorDialog", () => {
name: "Test Tool",
openInNewTab: false,
contextExternalToolId: "contextExternalToolId",
+ isLtiDeepLinkingTool: false,
};
};
diff --git a/src/pages/course-rooms/tools/RoomExternalToolsOverview.unit.ts b/src/pages/course-rooms/tools/RoomExternalToolsOverview.unit.ts
index 0843ab31e7..b79d48d754 100644
--- a/src/pages/course-rooms/tools/RoomExternalToolsOverview.unit.ts
+++ b/src/pages/course-rooms/tools/RoomExternalToolsOverview.unit.ts
@@ -240,4 +240,25 @@ describe("RoomExternalToolOverview", () => {
).toHaveBeenCalledWith(displayData.contextExternalToolId);
});
});
+
+ describe("when emit refresh", () => {
+ const setup = () => {
+ const { wrapper } = getWrapper();
+
+ return {
+ wrapper,
+ };
+ };
+
+ it("should call tool reference endpoint again", () => {
+ const { wrapper } = setup();
+
+ const section = wrapper.findComponent(RoomExternalToolsSection);
+ section.vm.$emit("refresh");
+
+ expect(
+ useExternalToolDisplayListStateMock.fetchDisplayData
+ ).toHaveBeenCalledTimes(2);
+ });
+ });
});
diff --git a/src/pages/course-rooms/tools/RoomExternalToolsOverview.vue b/src/pages/course-rooms/tools/RoomExternalToolsOverview.vue
index c95636ce51..96c7a8e716 100644
--- a/src/pages/course-rooms/tools/RoomExternalToolsOverview.vue
+++ b/src/pages/course-rooms/tools/RoomExternalToolsOverview.vue
@@ -38,6 +38,7 @@
:room-id="roomId"
data-testid="room-external-tool-section"
@delete="onDeleteTool"
+ @refresh="() => fetchDisplayData(props.roomId, ToolContextType.Course)"
/>
diff --git a/src/pages/course-rooms/tools/RoomExternalToolsSection.vue b/src/pages/course-rooms/tools/RoomExternalToolsSection.vue
index 04c26d979f..353ce3d945 100644
--- a/src/pages/course-rooms/tools/RoomExternalToolsSection.vue
+++ b/src/pages/course-rooms/tools/RoomExternalToolsSection.vue
@@ -10,6 +10,7 @@
@delete="onOpenDeleteDialog"
@edit="onEditTool"
@error="onError"
+ @refresh="$emit('refresh')"
:data-testid="`external-tool-card-${index}`"
/>
@@ -77,6 +78,7 @@ const props = defineProps({
const emit = defineEmits<{
(e: "delete", value: ExternalToolDisplayData): void;
+ (e: "refresh"): void;
}>();
const authModule: AuthModule = injectStrict(AUTH_MODULE_KEY);
diff --git a/src/serverApi/v3/api.ts b/src/serverApi/v3/api.ts
index 4fe75fa025..f05cbabad7 100644
--- a/src/serverApi/v3/api.ts
+++ b/src/serverApi/v3/api.ts
@@ -2014,12 +2014,6 @@ export interface ContextExternalToolResponse {
* @memberof ContextExternalToolResponse
*/
parameters: Array;
- /**
- *
- * @type {string}
- * @memberof ContextExternalToolResponse
- */
- logoUrl?: string;
}
/**
@@ -4102,6 +4096,18 @@ export enum LanguageType {
Uk = 'uk'
}
+/**
+ *
+ * @export
+ * @enum {string}
+ */
+export enum LaunchType {
+ Basic = 'basic',
+ Oauth2 = 'oauth2',
+ Lti11BasicLaunch = 'lti11BasicLaunch',
+ Lti11ContentItemSelection = 'lti11ContentItemSelection'
+}
+
/**
*
* @export
@@ -4625,6 +4631,171 @@ export interface LoginResponse {
*/
accessToken: string;
}
+/**
+ *
+ * @export
+ * @interface Lti11DeepLinkContentItemListParams
+ */
+export interface Lti11DeepLinkContentItemListParams {
+ /**
+ *
+ * @type {string}
+ * @memberof Lti11DeepLinkContentItemListParams
+ */
+ context: string;
+ /**
+ *
+ * @type {Array}
+ * @memberof Lti11DeepLinkContentItemListParams
+ */
+ graph: Array;
+}
+/**
+ *
+ * @export
+ * @interface Lti11DeepLinkParams
+ */
+export interface Lti11DeepLinkParams {
+ /**
+ *
+ * @type {string}
+ * @memberof Lti11DeepLinkParams
+ */
+ lti_message_type: string;
+ /**
+ *
+ * @type {string}
+ * @memberof Lti11DeepLinkParams
+ */
+ lti_version: string;
+ /**
+ *
+ * @type {Lti11DeepLinkContentItemListParams}
+ * @memberof Lti11DeepLinkParams
+ */
+ content_items?: Lti11DeepLinkContentItemListParams;
+ /**
+ *
+ * @type {string}
+ * @memberof Lti11DeepLinkParams
+ */
+ data: string;
+ /**
+ *
+ * @type {string}
+ * @memberof Lti11DeepLinkParams
+ */
+ oauth_version: string;
+ /**
+ *
+ * @type {string}
+ * @memberof Lti11DeepLinkParams
+ */
+ oauth_nonce: string;
+ /**
+ *
+ * @type {number}
+ * @memberof Lti11DeepLinkParams
+ */
+ oauth_timestamp: number;
+ /**
+ *
+ * @type {string}
+ * @memberof Lti11DeepLinkParams
+ */
+ oauth_signature_method: string;
+ /**
+ *
+ * @type {string}
+ * @memberof Lti11DeepLinkParams
+ */
+ oauth_consumer_key: string;
+ /**
+ *
+ * @type {string}
+ * @memberof Lti11DeepLinkParams
+ */
+ oauth_signature: string;
+ /**
+ *
+ * @type {string}
+ * @memberof Lti11DeepLinkParams
+ */
+ oauth_callback?: string;
+}
+/**
+ *
+ * @export
+ * @interface Lti11DeepLinkParamsRaw
+ */
+export interface Lti11DeepLinkParamsRaw {
+ /**
+ *
+ * @type {string}
+ * @memberof Lti11DeepLinkParamsRaw
+ */
+ lti_message_type: string;
+ /**
+ *
+ * @type {string}
+ * @memberof Lti11DeepLinkParamsRaw
+ */
+ lti_version: string;
+ /**
+ *
+ * @type {string}
+ * @memberof Lti11DeepLinkParamsRaw
+ */
+ content_items?: string;
+ /**
+ *
+ * @type {string}
+ * @memberof Lti11DeepLinkParamsRaw
+ */
+ data: string;
+ /**
+ *
+ * @type {string}
+ * @memberof Lti11DeepLinkParamsRaw
+ */
+ oauth_version: string;
+ /**
+ *
+ * @type {string}
+ * @memberof Lti11DeepLinkParamsRaw
+ */
+ oauth_nonce: string;
+ /**
+ *
+ * @type {number}
+ * @memberof Lti11DeepLinkParamsRaw
+ */
+ oauth_timestamp: number;
+ /**
+ *
+ * @type {string}
+ * @memberof Lti11DeepLinkParamsRaw
+ */
+ oauth_signature_method: string;
+ /**
+ *
+ * @type {string}
+ * @memberof Lti11DeepLinkParamsRaw
+ */
+ oauth_consumer_key: string;
+ /**
+ *
+ * @type {string}
+ * @memberof Lti11DeepLinkParamsRaw
+ */
+ oauth_signature: string;
+ /**
+ *
+ * @type {string}
+ * @memberof Lti11DeepLinkParamsRaw
+ */
+ oauth_callback?: string;
+}
/**
*
* @export
@@ -4723,6 +4894,55 @@ export interface Lti11ToolConfigUpdateParams {
*/
launch_presentation_locale: string;
}
+/**
+ *
+ * @export
+ * @interface LtiDeepLinkResponse
+ */
+export interface LtiDeepLinkResponse {
+ /**
+ *
+ * @type {string}
+ * @memberof LtiDeepLinkResponse
+ */
+ mediaType: string;
+ /**
+ *
+ * @type {string}
+ * @memberof LtiDeepLinkResponse
+ */
+ title?: string;
+ /**
+ *
+ * @type {string}
+ * @memberof LtiDeepLinkResponse
+ */
+ text?: string;
+ /**
+ *
+ * @type {string}
+ * @memberof LtiDeepLinkResponse
+ */
+ availableFrom?: string;
+ /**
+ *
+ * @type {string}
+ * @memberof LtiDeepLinkResponse
+ */
+ availableUntil?: string;
+ /**
+ *
+ * @type {string}
+ * @memberof LtiDeepLinkResponse
+ */
+ submissionFrom?: string;
+ /**
+ *
+ * @type {string}
+ * @memberof LtiDeepLinkResponse
+ */
+ submissionUntil?: string;
+}
/**
*
* @export
@@ -6384,6 +6604,19 @@ export interface OidcContextResponse {
*/
ui_locales: Array;
}
+/**
+ *
+ * @export
+ * @interface OidcLogoutBodyParams
+ */
+export interface OidcLogoutBodyParams {
+ /**
+ *
+ * @type {string}
+ * @memberof OidcLogoutBodyParams
+ */
+ logout_token: string;
+}
/**
*
* @export
@@ -8753,11 +8986,11 @@ export interface ToolLaunchRequestResponse {
*/
openNewTab?: boolean;
/**
- * Specifies whether the request is an LTI Deep linking content item selection request
- * @type {boolean}
+ *
+ * @type {LaunchType}
* @memberof ToolLaunchRequestResponse
*/
- isDeepLink: boolean;
+ launchType: LaunchType;
}
/**
@@ -8830,6 +9063,18 @@ export interface ToolReferenceResponse {
* @memberof ToolReferenceResponse
*/
status: ContextExternalToolConfigurationStatusResponse;
+ /**
+ * Whether the tool is a lti deep linking tool
+ * @type {boolean}
+ * @memberof ToolReferenceResponse
+ */
+ isLtiDeepLinkingTool: boolean;
+ /**
+ *
+ * @type {LtiDeepLinkResponse}
+ * @memberof ToolReferenceResponse
+ */
+ ltiDeepLink?: LtiDeepLinkResponse;
}
/**
*
@@ -10970,6 +11215,42 @@ export const AuthenticationApiAxiosParamCreator = function (configuration?: Conf
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
+ return {
+ url: toPathString(localVarUrlObj),
+ options: localVarRequestOptions,
+ };
+ },
+ /**
+ *
+ * @summary Logs out a user for a given logout token from an external oidc system.
+ * @param {OidcLogoutBodyParams} oidcLogoutBodyParams
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ */
+ logoutControllerLogoutOidc: async (oidcLogoutBodyParams: OidcLogoutBodyParams, options: any = {}): Promise => {
+ // verify required parameter 'oidcLogoutBodyParams' is not null or undefined
+ assertParamExists('logoutControllerLogoutOidc', 'oidcLogoutBodyParams', oidcLogoutBodyParams)
+ const localVarPath = `/logout/oidc`;
+ // 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: 'POST', ...baseOptions, ...options};
+ const localVarHeaderParameter = {} as any;
+ const localVarQueryParameter = {} as any;
+
+
+
+ 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(oidcLogoutBodyParams, localVarRequestOptions, configuration)
+
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
@@ -11038,6 +11319,17 @@ export const AuthenticationApiFp = function(configuration?: Configuration) {
const localVarAxiosArgs = await localVarAxiosParamCreator.logoutControllerLogout(options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
+ /**
+ *
+ * @summary Logs out a user for a given logout token from an external oidc system.
+ * @param {OidcLogoutBodyParams} oidcLogoutBodyParams
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ */
+ async logoutControllerLogoutOidc(oidcLogoutBodyParams: OidcLogoutBodyParams, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> {
+ const localVarAxiosArgs = await localVarAxiosParamCreator.logoutControllerLogoutOidc(oidcLogoutBodyParams, options);
+ return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
+ },
}
};
@@ -11096,6 +11388,16 @@ export const AuthenticationApiFactory = function (configuration?: Configuration,
logoutControllerLogout(options?: any): AxiosPromise {
return localVarFp.logoutControllerLogout(options).then((request) => request(axios, basePath));
},
+ /**
+ *
+ * @summary Logs out a user for a given logout token from an external oidc system.
+ * @param {OidcLogoutBodyParams} oidcLogoutBodyParams
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ */
+ logoutControllerLogoutOidc(oidcLogoutBodyParams: OidcLogoutBodyParams, options?: any): AxiosPromise {
+ return localVarFp.logoutControllerLogoutOidc(oidcLogoutBodyParams, options).then((request) => request(axios, basePath));
+ },
};
};
@@ -11153,6 +11455,16 @@ export interface AuthenticationApiInterface {
*/
logoutControllerLogout(options?: any): AxiosPromise;
+ /**
+ *
+ * @summary Logs out a user for a given logout token from an external oidc system.
+ * @param {OidcLogoutBodyParams} oidcLogoutBodyParams
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ * @memberof AuthenticationApiInterface
+ */
+ logoutControllerLogoutOidc(oidcLogoutBodyParams: OidcLogoutBodyParams, options?: any): AxiosPromise;
+
}
/**
@@ -11219,6 +11531,18 @@ export class AuthenticationApi extends BaseAPI implements AuthenticationApiInter
public logoutControllerLogout(options?: any) {
return AuthenticationApiFp(this.configuration).logoutControllerLogout(options).then((request) => request(this.axios, this.basePath));
}
+
+ /**
+ *
+ * @summary Logs out a user for a given logout token from an external oidc system.
+ * @param {OidcLogoutBodyParams} oidcLogoutBodyParams
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ * @memberof AuthenticationApi
+ */
+ public logoutControllerLogoutOidc(oidcLogoutBodyParams: OidcLogoutBodyParams, options?: any) {
+ return AuthenticationApiFp(this.configuration).logoutControllerLogoutOidc(oidcLogoutBodyParams, options).then((request) => request(this.axios, this.basePath));
+ }
}
@@ -24294,6 +24618,45 @@ export const ToolApiAxiosParamCreator = function (configuration?: Configuration)
options: localVarRequestOptions,
};
},
+ /**
+ *
+ * @param {string} contextExternalToolId
+ * @param {Lti11DeepLinkParamsRaw} lti11DeepLinkParamsRaw
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ */
+ toolDeepLinkControllerDeepLink: async (contextExternalToolId: string, lti11DeepLinkParamsRaw: Lti11DeepLinkParamsRaw, options: any = {}): Promise => {
+ // verify required parameter 'contextExternalToolId' is not null or undefined
+ assertParamExists('toolDeepLinkControllerDeepLink', 'contextExternalToolId', contextExternalToolId)
+ // verify required parameter 'lti11DeepLinkParamsRaw' is not null or undefined
+ assertParamExists('toolDeepLinkControllerDeepLink', 'lti11DeepLinkParamsRaw', lti11DeepLinkParamsRaw)
+ const localVarPath = `/tools/context-external-tools/{contextExternalToolId}/lti11-deep-link-callback`
+ .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;
+ if (configuration) {
+ baseOptions = configuration.baseOptions;
+ }
+
+ const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
+ const localVarHeaderParameter = {} as any;
+ const localVarQueryParameter = {} as any;
+
+
+
+ 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(lti11DeepLinkParamsRaw, localVarRequestOptions, configuration)
+
+ return {
+ url: toPathString(localVarUrlObj),
+ options: localVarRequestOptions,
+ };
+ },
/**
*
* @summary Get tool launch request for a context external tool id
@@ -24933,6 +25296,17 @@ export const ToolApiFp = function(configuration?: Configuration) {
const localVarAxiosArgs = await localVarAxiosParamCreator.toolControllerUpdateExternalTool(externalToolId, externalToolUpdateParams, options);
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
},
+ /**
+ *
+ * @param {string} contextExternalToolId
+ * @param {Lti11DeepLinkParamsRaw} lti11DeepLinkParamsRaw
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ */
+ async toolDeepLinkControllerDeepLink(contextExternalToolId: string, lti11DeepLinkParamsRaw: Lti11DeepLinkParamsRaw, options?: any): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> {
+ const localVarAxiosArgs = await localVarAxiosParamCreator.toolDeepLinkControllerDeepLink(contextExternalToolId, lti11DeepLinkParamsRaw, options);
+ return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
+ },
/**
*
* @summary Get tool launch request for a context external tool id
@@ -25264,6 +25638,16 @@ export const ToolApiFactory = function (configuration?: Configuration, basePath?
toolControllerUpdateExternalTool(externalToolId: string, externalToolUpdateParams: ExternalToolUpdateParams, options?: any): AxiosPromise {
return localVarFp.toolControllerUpdateExternalTool(externalToolId, externalToolUpdateParams, options).then((request) => request(axios, basePath));
},
+ /**
+ *
+ * @param {string} contextExternalToolId
+ * @param {Lti11DeepLinkParamsRaw} lti11DeepLinkParamsRaw
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ */
+ toolDeepLinkControllerDeepLink(contextExternalToolId: string, lti11DeepLinkParamsRaw: Lti11DeepLinkParamsRaw, options?: any): AxiosPromise {
+ return localVarFp.toolDeepLinkControllerDeepLink(contextExternalToolId, lti11DeepLinkParamsRaw, options).then((request) => request(axios, basePath));
+ },
/**
*
* @summary Get tool launch request for a context external tool id
@@ -25584,6 +25968,16 @@ export interface ToolApiInterface {
*/
toolControllerUpdateExternalTool(externalToolId: string, externalToolUpdateParams: ExternalToolUpdateParams, options?: any): AxiosPromise;
+ /**
+ *
+ * @param {string} contextExternalToolId
+ * @param {Lti11DeepLinkParamsRaw} lti11DeepLinkParamsRaw
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ * @memberof ToolApiInterface
+ */
+ toolDeepLinkControllerDeepLink(contextExternalToolId: string, lti11DeepLinkParamsRaw: Lti11DeepLinkParamsRaw, options?: any): AxiosPromise;
+
/**
*
* @summary Get tool launch request for a context external tool id
@@ -25944,6 +26338,18 @@ export class ToolApi extends BaseAPI implements ToolApiInterface {
return ToolApiFp(this.configuration).toolControllerUpdateExternalTool(externalToolId, externalToolUpdateParams, options).then((request) => request(this.axios, this.basePath));
}
+ /**
+ *
+ * @param {string} contextExternalToolId
+ * @param {Lti11DeepLinkParamsRaw} lti11DeepLinkParamsRaw
+ * @param {*} [options] Override http request option.
+ * @throws {RequiredError}
+ * @memberof ToolApi
+ */
+ public toolDeepLinkControllerDeepLink(contextExternalToolId: string, lti11DeepLinkParamsRaw: Lti11DeepLinkParamsRaw, options?: any) {
+ return ToolApiFp(this.configuration).toolDeepLinkControllerDeepLink(contextExternalToolId, lti11DeepLinkParamsRaw, options).then((request) => request(this.axios, this.basePath));
+ }
+
/**
*
* @summary Get tool launch request for a context external tool id
diff --git a/src/store/external-tool/mapper/external-tool.mapper.ts b/src/store/external-tool/mapper/external-tool.mapper.ts
index 88b80e81a0..771cc0620a 100644
--- a/src/store/external-tool/mapper/external-tool.mapper.ts
+++ b/src/store/external-tool/mapper/external-tool.mapper.ts
@@ -58,6 +58,8 @@ export class ExternalToolMapper {
logoUrl: response.logoUrl,
thumbnailUrl: response.thumbnailUrl,
openInNewTab: response.openInNewTab,
+ isLtiDeepLinkingTool: response.isLtiDeepLinkingTool,
+ ltiDeepLink: response.ltiDeepLink,
};
return mapped;
@@ -71,7 +73,7 @@ export class ExternalToolMapper {
url: response.url,
payload: response.payload,
openNewTab: response.openNewTab,
- isDeepLink: response.isDeepLink,
+ launchType: response.launchType,
};
return mapped;
diff --git a/src/store/external-tool/tool-launch-request.ts b/src/store/external-tool/tool-launch-request.ts
index b5deddb91c..f0f3d5d1d7 100644
--- a/src/store/external-tool/tool-launch-request.ts
+++ b/src/store/external-tool/tool-launch-request.ts
@@ -1,3 +1,4 @@
+import { LaunchType } from "@/serverApi/v3";
import { ToolLaunchRequestMethodEnum } from "@/store/external-tool/tool-launch-request-method.enum";
export type ToolLaunchRequest = {
@@ -5,5 +6,5 @@ export type ToolLaunchRequest = {
url: string;
payload?: string;
openNewTab?: boolean;
- isDeepLink: boolean;
+ launchType: LaunchType;
};
diff --git a/tests/test-utils/factory/externalToolDisplayDataFactory.ts b/tests/test-utils/factory/externalToolDisplayDataFactory.ts
index e1abd328d8..7f6a3c2c59 100644
--- a/tests/test-utils/factory/externalToolDisplayDataFactory.ts
+++ b/tests/test-utils/factory/externalToolDisplayDataFactory.ts
@@ -10,4 +10,5 @@ export const externalToolDisplayDataFactory =
openInNewTab: false,
status: contextExternalToolConfigurationStatusFactory.build(),
logoUrl: "https://example.com/logo.png",
+ isLtiDeepLinkingTool: false,
}));
diff --git a/tests/test-utils/factory/index.ts b/tests/test-utils/factory/index.ts
index 1817284e48..8230f77e4e 100644
--- a/tests/test-utils/factory/index.ts
+++ b/tests/test-utils/factory/index.ts
@@ -64,6 +64,7 @@ export * from "./videoConferenceJoinResponseFactory";
export * from "./envsFactory";
export * from "./media-board";
export * from "./contextExternalToolResponseFactory";
+export * from "./ltiDeepLinkResponseFactory";
export * from "./courseInfoDataResponseFactory";
export * from "./deletedElementResponseFactory";
export * from "./room";
diff --git a/tests/test-utils/factory/ltiDeepLinkResponseFactory.ts b/tests/test-utils/factory/ltiDeepLinkResponseFactory.ts
new file mode 100644
index 0000000000..4ea0cf1883
--- /dev/null
+++ b/tests/test-utils/factory/ltiDeepLinkResponseFactory.ts
@@ -0,0 +1,8 @@
+import { Factory } from "fishery";
+import { LtiDeepLinkResponse } from "@/serverApi/v3";
+
+export const ltiDeepLinkResponseFactory = Factory.define(
+ () => ({
+ mediaType: "mediaType",
+ })
+);
diff --git a/tests/test-utils/factory/toolLaunchRequestFactory.ts b/tests/test-utils/factory/toolLaunchRequestFactory.ts
index f6cced0a4c..c9d1217ed8 100644
--- a/tests/test-utils/factory/toolLaunchRequestFactory.ts
+++ b/tests/test-utils/factory/toolLaunchRequestFactory.ts
@@ -1,3 +1,4 @@
+import { LaunchType } from "@/serverApi/v3";
import {
ToolLaunchRequest,
ToolLaunchRequestMethodEnum,
@@ -9,6 +10,6 @@ export const toolLaunchRequestFactory = Factory.define(
method: ToolLaunchRequestMethodEnum.Get,
payload: '{ "key": "value" }',
url: "https://example.com/tool-launch",
- isDeepLink: false,
+ launchType: LaunchType.Basic,
})
);
diff --git a/tests/test-utils/factory/toolLaunchRequestResponseFactory.ts b/tests/test-utils/factory/toolLaunchRequestResponseFactory.ts
index 72ee1b30fb..0e4f195642 100644
--- a/tests/test-utils/factory/toolLaunchRequestResponseFactory.ts
+++ b/tests/test-utils/factory/toolLaunchRequestResponseFactory.ts
@@ -1,5 +1,6 @@
import { Factory } from "fishery";
import {
+ LaunchType,
ToolLaunchRequestResponse,
ToolLaunchRequestResponseMethodEnum,
} from "@/serverApi/v3";
@@ -9,5 +10,5 @@ export const toolLaunchRequestResponseFactory =
method: ToolLaunchRequestResponseMethodEnum.Get,
payload: '{ "key": "value" }',
url: "https://example.com/tool-launch",
- isDeepLink: false,
+ launchType: LaunchType.Basic,
}));
diff --git a/tests/test-utils/factory/toolReferenceResponseFactory.ts b/tests/test-utils/factory/toolReferenceResponseFactory.ts
index bd5aef3092..742cbbcfa5 100644
--- a/tests/test-utils/factory/toolReferenceResponseFactory.ts
+++ b/tests/test-utils/factory/toolReferenceResponseFactory.ts
@@ -8,4 +8,5 @@ export const toolReferenceResponseFactory =
status: contextExternalToolConfigurationStatusFactory.build(),
openInNewTab: true,
displayName: `Tool ${sequence}`,
+ isLtiDeepLinkingTool: false,
}));