Skip to content

Commit

Permalink
Merge branch 'main' into BC-8011-evaluate-disabled-linter-rules
Browse files Browse the repository at this point in the history
  • Loading branch information
odalys-dataport authored Feb 26, 2025
2 parents f9d785a + f11895c commit ddcc128
Show file tree
Hide file tree
Showing 100 changed files with 3,052 additions and 1,367 deletions.
2 changes: 1 addition & 1 deletion eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ module.exports = [
"error",
{ allowInterfaces: "with-single-extends" },
],
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/no-inferrable-types": "error",
"@typescript-eslint/no-require-imports": "warn",
"@typescript-eslint/no-restricted-imports": [
Expand Down
128 changes: 92 additions & 36 deletions src/components/administration/ExternalToolSection.unit.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ConfigResponse } from "@/serverApi/v3";
import { ConfigResponse, MediaSourceLicenseType } from "@/serverApi/v3";
import AuthModule from "@/store/auth";
import EnvConfigModule from "@/store/env-config";
import { SchoolExternalToolMetadata } from "@/store/external-tool";
Expand All @@ -10,6 +10,7 @@ import {
NOTIFIER_MODULE_KEY,
SCHOOL_EXTERNAL_TOOLS_MODULE_KEY,
} from "@/utils/inject";
import { mockedPiniaStoreTyping, MockedStore } from "@@/tests/test-utils";
import {
envsFactory,
meResponseFactory,
Expand All @@ -23,9 +24,12 @@ import {
createTestingVuetify,
} from "@@/tests/test-utils/setup";
import { useSchoolExternalToolUsage } from "@data-external-tool";
import { useSchoolLicenseStore } from "@data-license";
import { createMock, DeepMocked } from "@golevelup/ts-jest";
import { mdiAlert, mdiCheckCircle } from "@icons/material";
import { createTestingPinia } from "@pinia/testing";
import { mount } from "@vue/test-utils";
import { setActivePinia } from "pinia";
import { nextTick, ref } from "vue";
import { Router, useRouter } from "vue-router";
import { VCardText } from "vuetify/lib/components/index.mjs";
Expand All @@ -43,6 +47,13 @@ describe("ExternalToolSection", () => {
let useSchoolExternalToolUsageMock: DeepMocked<
ReturnType<typeof useSchoolExternalToolUsage>
>;
let schoolLicenseStore: MockedStore<typeof useSchoolLicenseStore>;

beforeAll(() => {
setActivePinia(createTestingPinia());

schoolLicenseStore = mockedPiniaStoreTyping(useSchoolLicenseStore);
});

const createDatasheetButtonIndex = 1;

Expand Down Expand Up @@ -79,7 +90,6 @@ describe("ExternalToolSection", () => {
const wrapper = mount(ExternalToolSection, {
global: {
plugins: [createTestingVuetify(), createTestingI18n()],

provide: {
[SCHOOL_EXTERNAL_TOOLS_MODULE_KEY.valueOf()]:
schoolExternalToolsModule,
Expand All @@ -88,7 +98,6 @@ describe("ExternalToolSection", () => {
[ENV_CONFIG_MODULE_KEY.valueOf()]: envConfigModule,
},
},

stubs: {
VIcon: true,
},
Expand Down Expand Up @@ -130,6 +139,12 @@ describe("ExternalToolSection", () => {
schoolExternalToolsModule.loadSchoolExternalTools
).toHaveBeenCalledWith("schoolId");
});

it("should load the school licenses", () => {
getWrapper();

expect(schoolLicenseStore.fetchMediaSchoolLicenses).toHaveBeenCalled();
});
});
});

Expand All @@ -145,35 +160,56 @@ describe("ExternalToolSection", () => {
name: firstToolName,
status: schoolToolConfigurationStatusFactory.build(),
isDeactivated: false,
medium: {
mediumId: "tool1",
mediaSourceId: "licensedSource",
mediaSourceName: "Medium Source Name",
mediaSourceLicenseType: MediaSourceLicenseType.SchoolLicense,
},
});

const { wrapper, schoolExternalToolsModule } = getWrapper({
getSchoolExternalTools: [
schoolExternalTool,
{
id: "testId2",
toolId: "toolId",
schoolId: "schoolId",
parameters: [],
name: secondToolName,
status: schoolToolConfigurationStatusFactory.build({
isOutdatedOnScopeSchool: true,
}),
isDeactivated: false,
},
{
id: "testId3",
toolId: "toolId",
schoolId: "schoolId",
parameters: [],
name: "Test3",
status: schoolToolConfigurationStatusFactory.build({
isGloballyDeactivated: true,
}),
isDeactivated: true,
},
],
});
schoolLicenseStore.isLicensed.mockReturnValueOnce(true);
schoolLicenseStore.isLicensed.mockReturnValue(false);

const { wrapper, schoolExternalToolsModule } = getWrapper(
{
getSchoolExternalTools: [
schoolExternalTool,
{
id: "testId2",
toolId: "toolId",
schoolId: "schoolId",
parameters: [],
name: secondToolName,
status: schoolToolConfigurationStatusFactory.build({
isOutdatedOnScopeSchool: true,
}),
isDeactivated: false,
medium: {
mediumId: "tool2",
mediaSourceId: "notLicensedSource",
mediaSourceName: undefined,
mediaSourceLicenseType: MediaSourceLicenseType.SchoolLicense,
},
},
{
id: "testId3",
toolId: "toolId",
schoolId: "schoolId",
parameters: [],
name: "Test3",
status: schoolToolConfigurationStatusFactory.build({
isGloballyDeactivated: true,
}),
isDeactivated: true,
medium: undefined,
},
],
},
{
FEATURE_SCHULCONNEX_MEDIA_LICENSE_ENABLED: true,
}
);

const windowMock = createMock<Window>();
jest.spyOn(window, "open").mockImplementation(() => windowMock);
Expand Down Expand Up @@ -204,9 +240,12 @@ describe("ExternalToolSection", () => {
"components.administration.externalToolsSection.table.header.status"
);
expect(vueWrapperArray[2].find("span").text()).toEqual(
"components.administration.externalToolsSection.table.header.medium"
);
expect(vueWrapperArray[3].find("span").text()).toEqual(
"components.administration.externalToolsSection.table.header.restrictedTo"
);
expect(vueWrapperArray[3].find("span").text()).toEqual("");
expect(vueWrapperArray[4].find("span").text()).toEqual("");
});
});

Expand Down Expand Up @@ -235,24 +274,41 @@ describe("ExternalToolSection", () => {
const secondRow = tableRows[1].findAll("td");
const thirdRow = tableRows[2].findAll("td");

expect(true).toBeTruthy();
expect(firstRow[1].html()).toContain(mdiCheckCircle);
expect(firstRow[1].find("span").text()).toEqual(
"components.externalTools.status.latest"
);
expect(firstRow[1].html()).toContain(mdiCheckCircle);
expect(secondRow[1].find("span").text()).toEqual(
"components.externalTools.status.outdated"
);

expect(secondRow[1].html()).toContain(mdiAlert);
expect(secondRow[1].find("span").text()).toEqual(
"components.externalTools.status.outdated"
);

expect(thirdRow[1].html()).toContain(mdiAlert);
expect(thirdRow[1].find("span").text()).toEqual(
"components.externalTools.status.deactivated"
);
});

it("medium status should be rendered in the datatable", () => {
const { wrapper } = setupItems();

const tableRows = wrapper.find("tbody").findAll("tr");

const firstRow = tableRows[0].findAll("td");
const secondRow = tableRows[1].findAll("td");
const thirdRow = tableRows[2].findAll("td");

expect(firstRow[2].html()).toContain(mdiCheckCircle);
expect(firstRow[2].find("span").text()).toEqual("Medium Source Name");

expect(secondRow[2].html()).toContain(mdiAlert);
expect(secondRow[2].find("span").text()).toEqual("");

expect(thirdRow[2].html()).not.toContain("v-icon");
expect(thirdRow[2].find("span").text()).toEqual("-");
});

describe("when actions buttons are rendered", () => {
it("the buttons should be displayed", () => {
const { wrapper } = setupItems();
Expand Down
76 changes: 70 additions & 6 deletions src/components/administration/ExternalToolSection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,50 @@
</span>
</div>
</template>
<template #[`item.medium`]="{ item }">
<div
v-if="item.medium"
class="text-no-wrap"
data-testid="external-tool-medium"
>
<VProgressCircular v-if="isLicensesLoading" />
<VIcon
v-else-if="
item.medium.mediaSourceLicenseType !==
MediaSourceLicenseType.SchoolLicense ||
isLicensedToSchool(
item.medium.mediumId,
item.medium.mediaSourceId
)
"
start
color="success"
aria-hidden="false"
:aria-label="
t(
'components.administration.externalToolsSection.table.ariaLabel.mediumAvailable'
)
"
>
{{ mdiCheckCircle }}
</VIcon>
<VIcon
v-else
start
color="warning"
aria-hidden="false"
:aria-label="
t(
'components.administration.externalToolsSection.table.ariaLabel.mediumUnavailable'
)
"
>
{{ mdiAlert }}
</VIcon>
<span>{{ item.medium.mediaSourceName || "" }}</span>
</div>
<span v-else data-testid="external-tool-medium"> - </span>
</template>
<template #[`item.restrictToContexts`]="{ item }">
<span data-testid="external-tool-context-restriction">
{{ item.restrictToContexts }}
Expand Down Expand Up @@ -145,13 +189,16 @@
</template>

<script setup lang="ts">
import { ToolApiAxiosParamCreator } from "@/serverApi/v3";
import {
MediaSourceLicenseType,
ToolApiAxiosParamCreator,
} from "@/serverApi/v3";
import { RequestArgs } from "@/serverApi/v3/base";
import AuthModule from "@/store/auth";
import EnvConfigModule from "@/store/env-config";
import NotifierModule from "@/store/notifier";
import SchoolExternalToolsModule from "@/store/school-external-tools";
import { DataTableHeader } from "@/store/types/data-table-header";
import { DataTableHeader } from "@/types/vuetify";
import {
AUTH_MODULE_KEY,
ENV_CONFIG_MODULE_KEY,
Expand All @@ -160,6 +207,7 @@ import {
SCHOOL_EXTERNAL_TOOLS_MODULE_KEY,
} from "@/utils/inject";
import { useSchoolExternalToolUsage } from "@data-external-tool";
import { useSchoolLicenseStore } from "@data-license";
import { mdiAlert, mdiCheckCircle } from "@icons/material";
import { computed, ComputedRef, onMounted, Ref, ref } from "vue";
import { useI18n } from "vue-i18n";
Expand All @@ -178,17 +226,22 @@ const authModule: AuthModule = injectStrict(AUTH_MODULE_KEY);
const router = useRouter();
const schoolLicenseStore = useSchoolLicenseStore();
onMounted(async () => {
if (authModule.getSchool) {
await schoolExternalToolsModule.loadSchoolExternalTools(
authModule.getSchool.id
);
schoolExternalToolsModule.loadSchoolExternalTools(authModule.getSchool.id);
schoolLicenseStore.fetchMediaSchoolLicenses();
}
});
const { t } = useI18n();
const { getHeaders, getItems } = useExternalToolsSectionUtils(t);
const { getHeaders, getItems } = useExternalToolsSectionUtils(
t,
envConfigModule.getEnv.FEATURE_SCHULCONNEX_MEDIA_LICENSE_ENABLED
);
const { fetchSchoolExternalToolUsage, metadata } = useSchoolExternalToolUsage();
const headers: DataTableHeader[] = getHeaders;
Expand Down Expand Up @@ -275,6 +328,17 @@ const isMediaBoardUsageVisible: ComputedRef<boolean> = computed(() => {
const isVidisEnabled: ComputedRef<boolean> = computed(() => {
return envConfigModule.getEnv.FEATURE_VIDIS_MEDIA_ACTIVATIONS_ENABLED;
});
const isLicensedToSchool = (
mediumId: string,
mediaSourceId?: string
): boolean => {
return schoolLicenseStore.isLicensed(mediumId, mediaSourceId);
};
const isLicensesLoading: ComputedRef<boolean> = computed(() => {
return schoolLicenseStore.isLoading;
});
</script>

<style lang="scss" scoped>
Expand Down
30 changes: 30 additions & 0 deletions src/components/administration/VidisMediaSyncSection.unit.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import NotifierModule from "@/store/notifier";
import { NOTIFIER_MODULE_KEY } from "@/utils/inject";
import { axiosErrorFactory } from "@@/tests/test-utils";
import { createModuleMocks } from "@@/tests/test-utils/mock-store-module";
import {
createTestingI18n,
Expand All @@ -8,6 +9,7 @@ import {
import { useSchoolLicenseApi } from "@data-license";
import { createMock, DeepMocked } from "@golevelup/ts-jest";
import { mount } from "@vue/test-utils";
import { HttpStatusCode } from "../../store/types/http-status-code.enum";
import VidisMediaSyncSection from "./VidisMediaSyncSection.vue";

jest.mock("@data-license");
Expand Down Expand Up @@ -78,6 +80,34 @@ describe("VidisMediaSyncSection", () => {
});
});

describe("when the request fails with a timeout", () => {
const setup = () => {
const { wrapper } = getWrapper();

useSchoolLicenseApiMock.updateSchoolLicenses.mockRejectedValueOnce(
axiosErrorFactory
.withStatusCode(HttpStatusCode.RequestTimeout)
.build()
);

return {
wrapper,
};
};

it("should show a failure notification", async () => {
const { wrapper } = setup();

const button = wrapper.find('[data-testid="sync-vidis-media-button"]');
await button.trigger("click");

expect(notifierModule.show).toHaveBeenCalledWith({
status: "info",
text: "components.administration.externalToolsSection.vidis.notification.timeout",
});
});
});

describe("when the request fails", () => {
const setup = () => {
const { wrapper } = getWrapper();
Expand Down
Loading

0 comments on commit ddcc128

Please sign in to comment.