From c266cb85fb6d923d6d7a490c3f27ae187a43e1bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marvin=20=C3=96hlerking?= <103562092+MarvinOehlerkingCap@users.noreply.github.com> Date: Thu, 4 Jul 2024 12:28:43 +0200 Subject: [PATCH 1/3] N21-1996 Remove dynamic values from school external tool persistence (#3309) --- .../ExternalToolSection.unit.ts | 2 +- .../external-tool-section-utils.composable.ts | 4 +- ...rnal-tool-section-utils.composable.unit.ts | 87 ++++++------------- .../SchoolExternalToolConfigurator.page.vue | 3 +- src/serverApi/v3/api.ts | 16 ++-- .../mapper/school-external-tool.mapper.ts | 4 +- ...hool-external-tool-configuration-status.ts | 2 +- .../schoolExternalToolConfigurationFactory.ts | 4 +- ...lToolConfigurationStatusResponseFactory.ts | 4 +- .../schoolExternalToolResponseFactory.ts | 1 + 10 files changed, 48 insertions(+), 79 deletions(-) diff --git a/src/components/administration/ExternalToolSection.unit.ts b/src/components/administration/ExternalToolSection.unit.ts index 11c86b6843..8c975d869b 100644 --- a/src/components/administration/ExternalToolSection.unit.ts +++ b/src/components/administration/ExternalToolSection.unit.ts @@ -158,7 +158,7 @@ describe("ExternalToolSection", () => { parameters: [], name: "Test3", status: schoolToolConfigurationStatusFactory.build({ - isDeactivated: true, + isGloballyDeactivated: true, }), isDeactivated: true, }, diff --git a/src/components/administration/external-tool-section-utils.composable.ts b/src/components/administration/external-tool-section-utils.composable.ts index 14b4048cfa..045e26bba6 100644 --- a/src/components/administration/external-tool-section-utils.composable.ts +++ b/src/components/administration/external-tool-section-utils.composable.ts @@ -35,7 +35,7 @@ export function useExternalToolsSectionUtils( schoolExternalToolsModule.getSchoolExternalTools; return schoolExternalTools.map((tool: SchoolExternalTool) => { let statusTranslationKey = "components.externalTools.status.latest"; - if (tool.status.isDeactivated) { + if (tool.isDeactivated || tool.status.isGloballyDeactivated) { statusTranslationKey = "components.externalTools.status.deactivated"; } else if (tool.status.isOutdatedOnScopeSchool) { statusTranslationKey = "components.externalTools.status.outdated"; @@ -47,7 +47,7 @@ export function useExternalToolsSectionUtils( name: tool.name, statusText: t(statusTranslationKey), isOutdated: tool.status.isOutdatedOnScopeSchool, - isDeactivated: tool.status.isDeactivated, + isDeactivated: tool.isDeactivated || tool.status.isGloballyDeactivated, }; }); }; diff --git a/src/components/administration/external-tool-section-utils.composable.unit.ts b/src/components/administration/external-tool-section-utils.composable.unit.ts index 371edc817a..45c41edbed 100644 --- a/src/components/administration/external-tool-section-utils.composable.unit.ts +++ b/src/components/administration/external-tool-section-utils.composable.unit.ts @@ -2,37 +2,16 @@ import { SchoolExternalToolResponse, SchoolExternalToolSearchListResponse, } from "@/serverApi/v3"; -import { schoolExternalToolsModule } from "@/store"; import SchoolExternalToolsModule from "@/store/school-external-tools"; import { DataTableHeader } from "@/store/types/data-table-header"; -import { contextExternalToolConfigurationStatusFactory } from "@@/tests/test-utils"; +import { createModuleMocks } from "@/utils/mock-store-module"; +import { + schoolExternalToolFactory, + schoolExternalToolResponseFactory, +} from "@@/tests/test-utils"; import { useExternalToolsSectionUtils } from "./external-tool-section-utils.composable"; import { SchoolExternalToolItem } from "./school-external-tool-item"; -const schoolExternalToolsModuleMock = - (): Partial => { - return { - getSchoolExternalTools: [ - { - id: "id", - name: "toolName", - isDeactivated: false, - toolId: "toolId", - schoolId: "schoolId", - parameters: [], - status: { - isOutdatedOnScopeSchool: false, - isDeactivated: false, - }, - }, - ], - }; - }; - -jest.mock("@/store", () => ({ - schoolExternalToolsModule: schoolExternalToolsModuleMock(), -})); - describe("useSchoolExternalToolUtils", () => { const setup = () => { const expectedTranslation = "translated"; @@ -40,36 +19,20 @@ describe("useSchoolExternalToolUtils", () => { const { getHeaders, getItems } = useExternalToolsSectionUtils(tMock); - const toolResponse: SchoolExternalToolResponse = { - id: "id", - name: "toolName", - toolId: "toolId", - schoolId: "schoolId", - parameters: [ - { - name: "name", - value: "value", - }, - ], - status: contextExternalToolConfigurationStatusFactory.build({ - isOutdatedOnScopeSchool: false, - isDeactivated: false, - }), - }; + const schoolExternalTool = schoolExternalToolFactory.build(); + const schoolExternalToolsModule = createModuleMocks( + SchoolExternalToolsModule, + { + getSchoolExternalTools: [schoolExternalTool], + } + ); + + const toolResponse: SchoolExternalToolResponse = + schoolExternalToolResponseFactory.build(); const listResponse: SchoolExternalToolSearchListResponse = { data: [toolResponse], }; - const schoolExternaToolItem: SchoolExternalToolItem = - new SchoolExternalToolItem({ - name: toolResponse.name, - id: toolResponse.id, - externalToolId: toolResponse.toolId, - statusText: "translationKey", - isOutdated: false, - isDeactivated: false, - }); - return { getHeaders, getItems, @@ -77,7 +40,8 @@ describe("useSchoolExternalToolUtils", () => { toolResponse, tMock, expectedTranslation, - schoolExternaToolItem, + schoolExternalToolsModule, + schoolExternalTool, }; }; @@ -126,7 +90,12 @@ describe("useSchoolExternalToolUtils", () => { describe("getItems is called", () => { it("should return schoolExternalToolItems", () => { - const { getItems } = setup(); + const { + getItems, + schoolExternalToolsModule, + schoolExternalTool, + expectedTranslation, + } = setup(); const items: SchoolExternalToolItem[] = getItems( schoolExternalToolsModule @@ -134,11 +103,11 @@ describe("useSchoolExternalToolUtils", () => { expect(items).toEqual([ { - id: "id", - externalToolId: "toolId", - name: "toolName", - statusText: "translated", - isOutdated: false, + id: schoolExternalTool.id, + externalToolId: schoolExternalTool.toolId, + name: schoolExternalTool.name, + statusText: expectedTranslation, + isOutdated: schoolExternalTool.status.isOutdatedOnScopeSchool, isDeactivated: false, }, ]); diff --git a/src/pages/administration/school-external-tool/SchoolExternalToolConfigurator.page.vue b/src/pages/administration/school-external-tool/SchoolExternalToolConfigurator.page.vue index d01b2eb96e..55304eeb79 100644 --- a/src/pages/administration/school-external-tool/SchoolExternalToolConfigurator.page.vue +++ b/src/pages/administration/school-external-tool/SchoolExternalToolConfigurator.page.vue @@ -190,8 +190,7 @@ export default defineComponent({ props.configId ); - isDeactivated.value = - configuration.value?.status.isDeactivated ?? false; + isDeactivated.value = configuration.value?.isDeactivated ?? false; } else if (authModule.getSchool) { await schoolExternalToolsModule.loadAvailableToolsForSchool( authModule.getSchool.id diff --git a/src/serverApi/v3/api.ts b/src/serverApi/v3/api.ts index 37fa268f4c..64d75df109 100644 --- a/src/serverApi/v3/api.ts +++ b/src/serverApi/v3/api.ts @@ -6024,11 +6024,11 @@ export interface SchoolExternalToolConfigurationStatusResponse { */ isOutdatedOnScopeSchool: boolean; /** - * Is the tool deactivated, because of school administrator? + * Is the tool deactivated, because of instance administrator? * @type {boolean} * @memberof SchoolExternalToolConfigurationStatusResponse */ - isDeactivated: boolean; + isGloballyDeactivated: boolean; } /** * @@ -6150,22 +6150,22 @@ export interface SchoolExternalToolResponse { schoolId: string; /** * - * @type {Array} + * @type {boolean} * @memberof SchoolExternalToolResponse */ - parameters: Array; + isDeactivated: boolean; /** * - * @type {SchoolExternalToolConfigurationStatusResponse} + * @type {Array} * @memberof SchoolExternalToolResponse */ - status: SchoolExternalToolConfigurationStatusResponse; + parameters: Array; /** * - * @type {string} + * @type {SchoolExternalToolConfigurationStatusResponse} * @memberof SchoolExternalToolResponse */ - logoUrl?: string; + status: SchoolExternalToolConfigurationStatusResponse; } /** * diff --git a/src/store/external-tool/mapper/school-external-tool.mapper.ts b/src/store/external-tool/mapper/school-external-tool.mapper.ts index bcad295132..c1bcd432a4 100644 --- a/src/store/external-tool/mapper/school-external-tool.mapper.ts +++ b/src/store/external-tool/mapper/school-external-tool.mapper.ts @@ -79,7 +79,7 @@ export class SchoolExternalToolMapper { (parameter): ToolParameterEntry => CommonToolMapper.mapToToolParameterEntry(parameter) ), - isDeactivated: response.status.isDeactivated, + isDeactivated: response.isDeactivated, }; return mapped; @@ -128,7 +128,7 @@ export class SchoolExternalToolMapper { ): SchoolExternalToolConfigurationStatus { const mapped: SchoolExternalToolConfigurationStatus = { isOutdatedOnScopeSchool: schoolToolStatus.isOutdatedOnScopeSchool, - isDeactivated: schoolToolStatus.isDeactivated, + isGloballyDeactivated: schoolToolStatus.isGloballyDeactivated, }; return mapped; diff --git a/src/store/external-tool/school-external-tool-configuration-status.ts b/src/store/external-tool/school-external-tool-configuration-status.ts index 7cd621c754..d00e1fe5d5 100644 --- a/src/store/external-tool/school-external-tool-configuration-status.ts +++ b/src/store/external-tool/school-external-tool-configuration-status.ts @@ -1,4 +1,4 @@ export interface SchoolExternalToolConfigurationStatus { isOutdatedOnScopeSchool: boolean; - isDeactivated: boolean; + isGloballyDeactivated: boolean; } diff --git a/tests/test-utils/factory/schoolExternalToolConfigurationFactory.ts b/tests/test-utils/factory/schoolExternalToolConfigurationFactory.ts index cdcd87c569..0713ce40e1 100644 --- a/tests/test-utils/factory/schoolExternalToolConfigurationFactory.ts +++ b/tests/test-utils/factory/schoolExternalToolConfigurationFactory.ts @@ -1,5 +1,5 @@ -import { Factory } from "fishery"; import { SchoolExternalToolConfigurationStatus } from "@/store/external-tool/school-external-tool-configuration-status"; +import { Factory } from "fishery"; export const schoolToolConfigurationStatusFactory = Factory.define(() => { @@ -8,6 +8,6 @@ export const schoolToolConfigurationStatusFactory = isOutdatedOnScopeSchool: false, isIncompleteOperationalOnScopeContext: false, isIncompleteOnScopeContext: false, - isDeactivated: false, + isGloballyDeactivated: false, }; }); diff --git a/tests/test-utils/factory/schoolExternalToolConfigurationStatusResponseFactory.ts b/tests/test-utils/factory/schoolExternalToolConfigurationStatusResponseFactory.ts index 90a2ac9fe9..4359638cab 100644 --- a/tests/test-utils/factory/schoolExternalToolConfigurationStatusResponseFactory.ts +++ b/tests/test-utils/factory/schoolExternalToolConfigurationStatusResponseFactory.ts @@ -1,10 +1,10 @@ -import { Factory } from "fishery"; import { SchoolExternalToolConfigurationStatusResponse } from "@/serverApi/v3"; +import { Factory } from "fishery"; export const schoolExternalToolConfigurationStatusResponseFactory = Factory.define(() => { return { isOutdatedOnScopeSchool: false, - isDeactivated: false, + isGloballyDeactivated: false, }; }); diff --git a/tests/test-utils/factory/schoolExternalToolResponseFactory.ts b/tests/test-utils/factory/schoolExternalToolResponseFactory.ts index 2aa7fca8af..12fd3d91ca 100644 --- a/tests/test-utils/factory/schoolExternalToolResponseFactory.ts +++ b/tests/test-utils/factory/schoolExternalToolResponseFactory.ts @@ -8,6 +8,7 @@ export const schoolExternalToolResponseFactory = schoolId: `school-${sequence}`, toolId: `tool-${sequence}`, name: `SchoolExternalTool${sequence}`, + isDeactivated: false, status: schoolExternalToolConfigurationStatusResponseFactory.build(), parameters: [], })); From 106331630e74a2d8a3456d84011cdad0cf68965a Mon Sep 17 00:00:00 2001 From: Igor Richter <93926487+IgorCapCoder@users.noreply.github.com> Date: Fri, 5 Jul 2024 10:00:25 +0200 Subject: [PATCH 2/3] N21-2019 show media shelf tool usages (#3298) --- .../ExternalToolSection.unit.ts | 210 +++++++++++++++++- .../administration/ExternalToolSection.vue | 70 +++++- src/locales/de.ts | 12 +- src/locales/en.ts | 12 +- src/locales/es.ts | 12 +- src/locales/uk.ts | 12 +- .../SchoolExternalToolApi.composable.unit.ts | 7 +- src/serverApi/v3/api.ts | 6 + .../mapper/school-external-tool.mapper.ts | 1 + .../school-external-tool-metadata.ts | 1 + .../schoolExternalToolMetadataFactory.ts | 1 + ...hoolExternalToolMetadataResponseFactory.ts | 3 +- 12 files changed, 326 insertions(+), 21 deletions(-) diff --git a/src/components/administration/ExternalToolSection.unit.ts b/src/components/administration/ExternalToolSection.unit.ts index 8c975d869b..cf1b64649d 100644 --- a/src/components/administration/ExternalToolSection.unit.ts +++ b/src/components/administration/ExternalToolSection.unit.ts @@ -1,13 +1,16 @@ import AuthModule from "@/store/auth"; +import EnvConfigModule from "@/store/env-config"; import NotifierModule from "@/store/notifier"; import SchoolExternalToolsModule from "@/store/school-external-tools"; import { AUTH_MODULE_KEY, + ENV_CONFIG_MODULE_KEY, NOTIFIER_MODULE_KEY, SCHOOL_EXTERNAL_TOOLS_MODULE_KEY, } from "@/utils/inject"; import { createModuleMocks } from "@/utils/mock-store-module"; import { + envsFactory, meResponseFactory, schoolExternalToolFactory, schoolExternalToolMetadataFactory, @@ -20,11 +23,13 @@ import { import { useSchoolExternalToolUsage } from "@data-external-tool"; import { createMock, DeepMocked } from "@golevelup/ts-jest"; import { mdiAlert, mdiCheckCircle } from "@mdi/js"; -import { mount } from "@vue/test-utils"; +import { mount, VueWrapper } from "@vue/test-utils"; import { nextTick, ref } from "vue"; import vueDompurifyHTMLPlugin from "vue-dompurify-html"; import { Router, useRouter } from "vue-router"; import ExternalToolSection from "./ExternalToolSection.vue"; +import { SchoolExternalToolMetadata } from "@/store/external-tool"; +import { ConfigResponse } from "@/serverApi/v3"; jest.mock("@data-external-tool"); @@ -40,7 +45,10 @@ describe("ExternalToolSection", () => { const createDatasheetButtonIndex = 1; - const getWrapper = (getters: Partial = {}) => { + const getWrapper = ( + getters: Partial = {}, + envs: Partial = {} + ) => { el = document.createElement("div"); el.setAttribute("data-app", "true"); document.body.appendChild(el); @@ -60,6 +68,10 @@ describe("ExternalToolSection", () => { getSchool: mockMe.school, }); + const envConfigModule = createModuleMocks(EnvConfigModule, { + getEnv: envsFactory.build(envs), + }); + const router = createMock(); useRouterMock.mockReturnValue(router); @@ -76,6 +88,7 @@ describe("ExternalToolSection", () => { schoolExternalToolsModule, [NOTIFIER_MODULE_KEY.valueOf()]: notifierModule, [AUTH_MODULE_KEY.valueOf()]: authModule, + [ENV_CONFIG_MODULE_KEY.valueOf()]: envConfigModule, }, }, @@ -444,7 +457,7 @@ describe("ExternalToolSection", () => { expect(dialog.isVisible()).toBeTruthy(); }); - it("should display tool usage count", async () => { + it("should display tool usage count for courses and board elements", async () => { const { wrapper, schoolExternalToolMetadata } = setup(); const tableRows = wrapper.find("tbody").findAll("tr"); @@ -452,11 +465,22 @@ describe("ExternalToolSection", () => { await deleteButton.trigger("click"); - const dialogContent = wrapper.findComponent({ name: "renderHTML" }); + const expectedDialogContents = [ + "components.administration.externalToolsSection.dialog.content.header", + "components.administration.externalToolsSection.dialog.content.courses", + "components.administration.externalToolsSection.dialog.content.boardElements", + "components.administration.externalToolsSection.dialog.content.warning", + ]; + const dialogContents = wrapper.findAllComponents({ + name: "renderHTML", + }); - expect(dialogContent.props("html")).toEqual( - "components.administration.externalToolsSection.dialog.content" + expect(dialogContents.length).toBeGreaterThanOrEqual( + expectedDialogContents.length ); + for (const content of dialogContents) { + expect(expectedDialogContents).toContain(content.props().html); + } expect(wrapper.vm.getItemName).toEqual("name"); expect(wrapper.vm.metadata).toEqual(schoolExternalToolMetadata); @@ -474,6 +498,180 @@ describe("ExternalToolSection", () => { }); }); + const setupMediaBoardMetadataAndEnv = ( + toolUsageMetadata: SchoolExternalToolMetadata, + enableMediaShelf: boolean + ) => { + const schoolExternalToolMetadata = + schoolExternalToolMetadataFactory.build(toolUsageMetadata); + + useSchoolExternalToolUsageMock.metadata = ref(schoolExternalToolMetadata); + + const envs: Partial = { + FEATURE_MEDIA_SHELF_ENABLED: enableMediaShelf, + }; + const { wrapper } = getWrapper( + { + getSchoolExternalTools: [ + schoolExternalToolFactory.build(), + schoolExternalToolFactory.build(), + ], + }, + envs + ); + + return { + wrapper, + schoolExternalToolMetadata, + }; + }; + + const expectMediaBoardDialogIsShown = (deleteDialogWrapper: VueWrapper) => { + const dialogContents = deleteDialogWrapper.findAllComponents({ + name: "renderHTML", + }); + + const mediaBoardDialogContentIndex = dialogContents.findIndex( + (content) => + content.attributes()["data-testid"] === + "delete-dialog-content-media-shelves" + ); + expect(mediaBoardDialogContentIndex).toBeGreaterThan(0); + + const mediaBoardDialogContent = + dialogContents[mediaBoardDialogContentIndex]; + const dialogContentBeforeMediaBoard = + dialogContents[mediaBoardDialogContentIndex - 1]; + + expect(mediaBoardDialogContent.text()).toEqual( + "components.administration.externalToolsSection.dialog.content.mediaShelves" + ); + + expect(dialogContentBeforeMediaBoard.classes()).toContain("mb-0"); + }; + + const expectMediaBoardDialogIsHidden = ( + deleteDialogWrapper: VueWrapper + ) => { + const dialogContents = deleteDialogWrapper.findAllComponents({ + name: "renderHTML", + }); + + const mediaBoardDialogContentIndex = dialogContents.findIndex( + (content) => + content.attributes()["data-testid"] === + "delete-dialog-content-media-shelves" + ); + expect(mediaBoardDialogContentIndex).toEqual(-1); + + const dialogContentBeforeWarning = + dialogContents[dialogContents.length - 2]; + + expect(dialogContentBeforeWarning.classes()).not.toContain("mb-0"); + }; + + describe("when metadata with media board > 0 is given", () => { + const setup = (enabledMediaShelf: boolean) => { + const metadataWithNonZeroMediaBoard: SchoolExternalToolMetadata = { + course: 3, + boardElement: 2, + mediaBoard: 1, + }; + const { wrapper, schoolExternalToolMetadata } = + setupMediaBoardMetadataAndEnv( + metadataWithNonZeroMediaBoard, + enabledMediaShelf + ); + return { + wrapper, + schoolExternalToolMetadata, + }; + }; + + describe("when FEATURE_MEDIA_SHELF_ENABLED is true", () => { + it("should show tool usage count for media board", async () => { + const { wrapper, schoolExternalToolMetadata } = setup(true); + + const tableRows = wrapper.find("tbody").findAll("tr"); + const deleteButton = tableRows[0].get('[data-testid="deleteAction"]'); + + await deleteButton.trigger("click"); + + expectMediaBoardDialogIsShown(wrapper); + + expect(wrapper.vm.getItemName).toEqual("name"); + expect(wrapper.vm.metadata).toEqual(schoolExternalToolMetadata); + }); + }); + + describe("when FEATURE_MEDIA_SHELF_ENABLED is false", () => { + it("should show tool usage count for media board", async () => { + const { wrapper, schoolExternalToolMetadata } = setup(false); + + const tableRows = wrapper.find("tbody").findAll("tr"); + const deleteButton = tableRows[0].get('[data-testid="deleteAction"]'); + + await deleteButton.trigger("click"); + + expectMediaBoardDialogIsShown(wrapper); + + expect(wrapper.vm.getItemName).toEqual("name"); + expect(wrapper.vm.metadata).toEqual(schoolExternalToolMetadata); + }); + }); + }); + + describe("when metadata with 0 media board is given", () => { + const setup = (enabledMediaShelf: boolean) => { + const metadataWithNonZeroMediaBoard: SchoolExternalToolMetadata = { + course: 3, + boardElement: 2, + mediaBoard: 0, + }; + const { wrapper, schoolExternalToolMetadata } = + setupMediaBoardMetadataAndEnv( + metadataWithNonZeroMediaBoard, + enabledMediaShelf + ); + return { + wrapper, + schoolExternalToolMetadata, + }; + }; + + describe("when FEATURE_MEDIA_SHELF_ENABLED is true", () => { + it("should show tool usage count for media board", async () => { + const { wrapper, schoolExternalToolMetadata } = setup(true); + + const tableRows = wrapper.find("tbody").findAll("tr"); + const deleteButton = tableRows[0].get('[data-testid="deleteAction"]'); + + await deleteButton.trigger("click"); + + expectMediaBoardDialogIsShown(wrapper); + + expect(wrapper.vm.getItemName).toEqual("name"); + expect(wrapper.vm.metadata).toEqual(schoolExternalToolMetadata); + }); + }); + + describe("when FEATURE_MEDIA_SHELF_ENABLED is false", () => { + it("should not show tool usage count for media board", async () => { + const { wrapper, schoolExternalToolMetadata } = setup(false); + + const tableRows = wrapper.find("tbody").findAll("tr"); + const deleteButton = tableRows[0].get('[data-testid="deleteAction"]'); + + await deleteButton.trigger("click"); + + expectMediaBoardDialogIsHidden(wrapper); + + expect(wrapper.vm.getItemName).toEqual("name"); + expect(wrapper.vm.metadata).toEqual(schoolExternalToolMetadata); + }); + }); + }); + describe("when metadata is undefined", () => { const setup = () => { useSchoolExternalToolUsageMock.metadata = ref(undefined); diff --git a/src/components/administration/ExternalToolSection.vue b/src/components/administration/ExternalToolSection.vue index 71a2e3e927..1514055985 100644 --- a/src/components/administration/ExternalToolSection.vue +++ b/src/components/administration/ExternalToolSection.vue @@ -68,20 +68,68 @@ + + + + @@ -120,6 +168,7 @@ import { injectStrict, NOTIFIER_MODULE_KEY, SCHOOL_EXTERNAL_TOOLS_MODULE_KEY, + ENV_CONFIG_MODULE_KEY, } from "@/utils/inject"; import { useSchoolExternalToolUsage } from "@data-external-tool"; import { RenderHTML } from "@feature-render-html"; @@ -137,6 +186,7 @@ import { useRouter } from "vue-router"; import { useExternalToolsSectionUtils } from "./external-tool-section-utils.composable"; import ExternalToolToolbar from "./ExternalToolToolbar.vue"; import { SchoolExternalToolItem } from "./school-external-tool-item"; +import EnvConfigModule from "@/store/env-config"; export default defineComponent({ name: "ExternalToolSection", @@ -145,6 +195,9 @@ export default defineComponent({ const schoolExternalToolsModule: SchoolExternalToolsModule = injectStrict( SCHOOL_EXTERNAL_TOOLS_MODULE_KEY ); + const envConfigModule: EnvConfigModule = injectStrict( + ENV_CONFIG_MODULE_KEY + ); const notifierModule: NotifierModule = injectStrict(NOTIFIER_MODULE_KEY); const authModule: AuthModule = injectStrict(AUTH_MODULE_KEY); @@ -235,6 +288,16 @@ export default defineComponent({ isDeleteDialogOpen.value = false; }; + const isMediaBoardUsageVisible: ComputedRef = computed(() => { + if (!metadata.value) { + return false; + } + const isVisible = + metadata.value.mediaBoard > 0 || + envConfigModule.getEnv.FEATURE_MEDIA_SHELF_ENABLED; + return isVisible; + }); + return { t, headers, @@ -251,6 +314,7 @@ export default defineComponent({ mdiAlert, mdiCheckCircle, metadata, + isMediaBoardUsageVisible, }; }, }); diff --git a/src/locales/de.ts b/src/locales/de.ts index 1e6f984107..371dbcba93 100644 --- a/src/locales/de.ts +++ b/src/locales/de.ts @@ -243,8 +243,16 @@ export default { 'Die schulspezifischen Parameter für das externe Tool werden hier konfiguriert. Nach dem Speichern der Konfiguration ist das Tool innerhalb der Schule verfügbar.

\nWeitere Informationen sind in unserem Hilfebereich zu externen Tools zu finden.', "components.administration.externalToolsSection.dialog.content.metadata.error": "Die Verwendung des Tools konnte nicht ermittelt werden.", - "components.administration.externalToolsSection.dialog.content": - "Sind Sie sich sicher, dass Sie das Tool {itemName} löschen wollen?

Zurzeit wird das Tool wie folgt genutzt:
{courseCount} Kurs(e)
{boardElementCount} Spalten-Board(s)

Achtung: Wenn das Tool entfernt wird, kann es für diese Schule nicht mehr genutzt werden.", + "components.administration.externalToolsSection.dialog.content.header": + "Sind Sie sich sicher, dass Sie das Tool {itemName} löschen wollen?

Zurzeit wird das Tool wie folgt genutzt:", + "components.administration.externalToolsSection.dialog.content.courses": + "{courseCount} Kurs(e)", + "components.administration.externalToolsSection.dialog.content.boardElements": + "{boardElementCount} Spalten-Board(s)", + "components.administration.externalToolsSection.dialog.content.mediaShelves": + "{mediaBoardCount} Medienregal(e)", + "components.administration.externalToolsSection.dialog.content.warning": + "Achtung: Wenn das Tool entfernt wird, kann es für diese Schule nicht mehr genutzt werden.", "components.administration.externalToolsSection.dialog.title": "Externes Tool entfernen?", "components.administration.externalToolsSection.header": "Externe Tools", diff --git a/src/locales/en.ts b/src/locales/en.ts index aac1810394..654dc3545d 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -241,8 +241,16 @@ export default { 'The school-specific parameters for the external tool are configured here. After saving the configuration, the tool will be available within the school.

\nFurther information is available in our Help section on external tools.', "components.administration.externalToolsSection.dialog.content.metadata.error": "The usage of the tool could not be determined.", - "components.administration.externalToolsSection.dialog.content": - "Are you sure you want to delete the {itemName} tool?

Currently the tool is used as follows:
{courseCount} Course(s)
{boardElementCount} Column board(s)

Attention: If the tool is removed, it can no longer be used for this school.", + "components.administration.externalToolsSection.dialog.content.header": + "Are you sure you want to delete the {itemName} tool?

Currently, the tool is used as follows:", + "components.administration.externalToolsSection.dialog.content.courses": + "{courseCount} Course(s)", + "components.administration.externalToolsSection.dialog.content.boardElements": + "{boardElementCount} Column board(s)", + "components.administration.externalToolsSection.dialog.content.mediaShelves": + "{mediaBoardCount} Media shelf(s)", + "components.administration.externalToolsSection.dialog.content.warning": + "Attention: If the tool is removed, it can no longer be used for this school.", "components.administration.externalToolsSection.dialog.title": "Remove External Tool", "components.administration.externalToolsSection.header": "External Tools", diff --git a/src/locales/es.ts b/src/locales/es.ts index 690f0dc8d9..31e0a52628 100644 --- a/src/locales/es.ts +++ b/src/locales/es.ts @@ -246,8 +246,16 @@ export default { 'Los parámetros específicos de la escuela para la herramienta externa se configuran aquí. Después de guardar la configuración, la herramienta estará disponible dentro de la escuela.

\nMás información está disponible en nuestro Sección de ayuda sobre herramientas externas.', "components.administration.externalToolsSection.dialog.content.metadata.error": "No se pudo determinar el uso de la herramienta.", - "components.administration.externalToolsSection.dialog.content": - "¿Está seguro de que desea eliminar la herramienta {itemName}?

Actualmente la herramienta se utiliza de la siguiente manera:
{courseCount} Curso(s)
{boardElementCount} Tablero(s) de columnas

Atención: Si se retira la herramienta, ya no se podrá utilizar para esta escuela.", + "components.administration.externalToolsSection.dialog.content.header": + "¿Está seguro de que desea eliminar la herramienta {itemName}?

Actualmente la herramienta se utiliza de la siguiente manera:", + "components.administration.externalToolsSection.dialog.content.courses": + "{courseCount} Curso(s)", + "components.administration.externalToolsSection.dialog.content.boardElements": + "{boardElementCount} Tablero(s) de columnas", + "components.administration.externalToolsSection.dialog.content.mediaShelves": + "{mediaBoardCount} Estante(s) multimedia", + "components.administration.externalToolsSection.dialog.content.warning": + "Atención: Si se retira la herramienta, ya no se podrá utilizar para esta escuela.", "components.administration.externalToolsSection.dialog.title": "Quitar Herramienta Externa", "components.administration.externalToolsSection.header": diff --git a/src/locales/uk.ts b/src/locales/uk.ts index ff5daec53b..dde52b6b28 100644 --- a/src/locales/uk.ts +++ b/src/locales/uk.ts @@ -247,8 +247,16 @@ export default { 'Тут налаштовуються спеціальні параметри зовнішнього інструменту для школи. Після збереження конфігурації інструмент буде доступний у школі.

\nДодаткову інформацію можна знайти на нашому сайті Розділ довідки щодо зовнішніх інструментів.', "components.administration.externalToolsSection.dialog.content.metadata.error": "Неможливо визначити використання інструменту.", - "components.administration.externalToolsSection.dialog.content": - "Ви впевнені, що хочете видалити інструмент {itemName}?

Наразі інструмент використовується таким чином:
{courseCount} Курс(и)
{boardElementCount} Дошка(и) стовпців

Увага: якщо інструмент видалено, його більше не можна використовувати для цієї школи.", + "components.administration.externalToolsSection.dialog.content.header": + "Ви впевнені, що хочете видалити інструмент {itemName}?

Наразі інструмент використовується таким чином:", + "components.administration.externalToolsSection.dialog.content.courses": + "{courseCount} Курс(и)", + "components.administration.externalToolsSection.dialog.content.boardElements": + "{boardElementCount} Дошка(и) стовпців", + "components.administration.externalToolsSection.dialog.content.mediaShelves": + "{mediaBoardCount} Медіаполичка(и)", + "components.administration.externalToolsSection.dialog.content.warning": + "Увага: якщо інструмент видалено, його більше не можна використовувати для цієї школи.", "components.administration.externalToolsSection.dialog.title": "Видаліть зовнішній інструмент", "components.administration.externalToolsSection.header": diff --git a/src/modules/data/external-tool/SchoolExternalToolApi.composable.unit.ts b/src/modules/data/external-tool/SchoolExternalToolApi.composable.unit.ts index 8710b596c9..0011cc90ce 100644 --- a/src/modules/data/external-tool/SchoolExternalToolApi.composable.unit.ts +++ b/src/modules/data/external-tool/SchoolExternalToolApi.composable.unit.ts @@ -1,11 +1,11 @@ -import { createMock, DeepMocked } from "@golevelup/ts-jest"; -import * as serverApi from "@/serverApi/v3/api"; import { SchoolExternalToolMetadataResponse } from "@/serverApi/v3"; +import * as serverApi from "@/serverApi/v3/api"; +import { SchoolExternalToolMetadata } from "@/store/external-tool"; import { mockApiResponse, schoolExternalToolMetadataResponseFactory, } from "@@/tests/test-utils"; -import { SchoolExternalToolMetadata } from "@/store/external-tool"; +import { createMock, DeepMocked } from "@golevelup/ts-jest"; import { useSchoolExternalToolApi } from "./SchoolExternalToolApi.composable"; describe("SchoolExternalToolApi.composable", () => { @@ -58,6 +58,7 @@ describe("SchoolExternalToolApi.composable", () => { expect(result).toEqual({ course: 5, boardElement: 6, + mediaBoard: 0, }); }); }); diff --git a/src/serverApi/v3/api.ts b/src/serverApi/v3/api.ts index 64d75df109..cc68bfda7a 100644 --- a/src/serverApi/v3/api.ts +++ b/src/serverApi/v3/api.ts @@ -1474,6 +1474,12 @@ export interface ContextExternalToolCountPerContextResponse { * @memberof ContextExternalToolCountPerContextResponse */ boardElement: number; + /** + * + * @type {number} + * @memberof ContextExternalToolCountPerContextResponse + */ + mediaBoard: number; } /** * diff --git a/src/store/external-tool/mapper/school-external-tool.mapper.ts b/src/store/external-tool/mapper/school-external-tool.mapper.ts index c1bcd432a4..ea530cb08c 100644 --- a/src/store/external-tool/mapper/school-external-tool.mapper.ts +++ b/src/store/external-tool/mapper/school-external-tool.mapper.ts @@ -118,6 +118,7 @@ export class SchoolExternalToolMapper { const mapped: SchoolExternalToolMetadata = { course: response.contextExternalToolCountPerContext.course, boardElement: response.contextExternalToolCountPerContext.boardElement, + mediaBoard: response.contextExternalToolCountPerContext.mediaBoard, }; return mapped; diff --git a/src/store/external-tool/school-external-tool-metadata.ts b/src/store/external-tool/school-external-tool-metadata.ts index 22adb99864..73b5924e7e 100644 --- a/src/store/external-tool/school-external-tool-metadata.ts +++ b/src/store/external-tool/school-external-tool-metadata.ts @@ -1,4 +1,5 @@ export interface SchoolExternalToolMetadata { course: number; boardElement: number; + mediaBoard: number; } diff --git a/tests/test-utils/factory/schoolExternalToolMetadataFactory.ts b/tests/test-utils/factory/schoolExternalToolMetadataFactory.ts index 94fb48e5b4..56c68a8de6 100644 --- a/tests/test-utils/factory/schoolExternalToolMetadataFactory.ts +++ b/tests/test-utils/factory/schoolExternalToolMetadataFactory.ts @@ -5,4 +5,5 @@ export const schoolExternalToolMetadataFactory: Factory(() => ({ course: 5, boardElement: 6, + mediaBoard: 0, })); diff --git a/tests/test-utils/factory/schoolExternalToolMetadataResponseFactory.ts b/tests/test-utils/factory/schoolExternalToolMetadataResponseFactory.ts index 4a4cc8b97d..4e5cda104b 100644 --- a/tests/test-utils/factory/schoolExternalToolMetadataResponseFactory.ts +++ b/tests/test-utils/factory/schoolExternalToolMetadataResponseFactory.ts @@ -1,10 +1,11 @@ -import { Factory } from "fishery"; import { SchoolExternalToolMetadataResponse } from "@/serverApi/v3"; +import { Factory } from "fishery"; export const schoolExternalToolMetadataResponseFactory: Factory = Factory.define(() => ({ contextExternalToolCountPerContext: { course: 5, boardElement: 6, + mediaBoard: 0, }, })); From 6c1cff0f1b09c497735cada27ee527b2cf3324e4 Mon Sep 17 00:00:00 2001 From: Martin Schuhmacher <55735359+MartinSchuhmacher@users.noreply.github.com> Date: Fri, 5 Jul 2024 15:16:35 +0200 Subject: [PATCH 3/3] BC-7575 - Fix route help for "Was ist neu?" (#3316) * adjusting links to release notes from vue side --- src/components/topbar/HelpDropdown.vue | 2 +- src/modules/ui/layout/sidebar/SidebarItems.composable.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/topbar/HelpDropdown.vue b/src/components/topbar/HelpDropdown.vue index 2b80511510..3c11df023e 100644 --- a/src/components/topbar/HelpDropdown.vue +++ b/src/components/topbar/HelpDropdown.vue @@ -38,7 +38,7 @@ const menuItems = [ { label: "global.topbar.actions.releaseNotes", icon: mdiGiftOutline, - action: "/help/releases", + action: "/system/releases", target: "_self", }, { diff --git a/src/modules/ui/layout/sidebar/SidebarItems.composable.ts b/src/modules/ui/layout/sidebar/SidebarItems.composable.ts index 05fe5687fd..90383aecb6 100644 --- a/src/modules/ui/layout/sidebar/SidebarItems.composable.ts +++ b/src/modules/ui/layout/sidebar/SidebarItems.composable.ts @@ -160,7 +160,7 @@ export const useSidebarItems = () => { }, { title: "global.topbar.actions.releaseNotes", - href: "/help/releases", + href: "/system/releases", target: "_self", testId: "releases", },