Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

N21-1507 copy ctl tools #2988

Merged
merged 36 commits into from
Jan 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
071be2f
extend locales for incomplete tool status
IgorCapCoder Jan 3, 2024
dc20401
N21-1421 WIP
arnegns Jan 3, 2024
ad24fc9
filter parameters with undefined values before saving a context and s…
MarvinOehlerkingCap Jan 3, 2024
1c9b9f4
tests
MarvinOehlerkingCap Jan 4, 2024
3ddf59f
N21-1421 WIP
arnegns Jan 4, 2024
0cfb64d
N21-1421 WIP
arnegns Jan 4, 2024
17d48cc
N21-1421 fixes tests
arnegns Jan 4, 2024
cd53933
N21-1421 fixes tests 2
arnegns Jan 4, 2024
f537985
N21-1421 increases coverage
arnegns Jan 4, 2024
db503dc
N21-1421 fixes deactivation translation
arnegns Jan 4, 2024
36b7059
render ctl tool copy info when feature flag is true
IgorCapCoder Jan 4, 2024
90d04e8
Merge remote-tracking branch 'origin/N21-1507-copy-ctl-tools' into N2…
IgorCapCoder Jan 4, 2024
a875eb2
N21-1421 extracts error dialog of RoomExternalToolsSection.vue
arnegns Jan 4, 2024
62d2d39
Merge branch 'main' into N21-1507-copy-ctl-tools
IgorCapCoder Jan 5, 2024
6481439
generate api
IgorCapCoder Jan 5, 2024
bb8571f
Merge branch 'main' into N21-1421-deactivation-of-ctl-tools
arnegns Jan 5, 2024
afa5601
N21-1421 review changes
arnegns Jan 5, 2024
42dc43b
N21-1421 review changes 2
arnegns Jan 5, 2024
2be79b9
N21-1421 fixes test
arnegns Jan 5, 2024
b5857a2
N21-1421 linter
arnegns Jan 5, 2024
ffd3506
Merge remote-tracking branch 'origin/N21-1421-deactivation-of-ctl-too…
IgorCapCoder Jan 5, 2024
44c1f41
N21-1421 linter 2
arnegns Jan 5, 2024
54b4995
N21-1421 fixes test
arnegns Jan 5, 2024
88e98bd
add incomplete tool status
IgorCapCoder Jan 5, 2024
c0b53ce
add launch logic to board
IgorCapCoder Jan 5, 2024
6cbc66a
Merge remote-tracking branch 'origin/N21-1421-deactivation-of-ctl-too…
IgorCapCoder Jan 5, 2024
6eb5e25
merge N21-1421
IgorCapCoder Jan 5, 2024
11288ac
test and logic fix
IgorCapCoder Jan 8, 2024
299d9b4
Merge branch 'main' into N21-1507-copy-ctl-tools-new
IgorCapCoder Jan 9, 2024
fa074d0
Merge branch 'main' into N21-1507-copy-ctl-tools-new
IgorCapCoder Jan 9, 2024
f240dfa
requested changes
IgorCapCoder Jan 9, 2024
80564e7
fix status logic and data testid
IgorCapCoder Jan 9, 2024
e970cb4
Merge branch 'main' into N21-1507-copy-ctl-tools-new
IgorCapCoder Jan 11, 2024
73b5e83
Merge branch 'main' into N21-1507-copy-ctl-tools-new
IgorCapCoder Jan 12, 2024
5f76619
merge main, fix api.ts indentations
IgorCapCoder Jan 12, 2024
7d83c2f
N21-1507 datatest-ids
mrikallab Jan 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/components/administration/ExternalToolSection.vue
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
class="mt-8 mb-4 button-save float-right"
color="primary"
depressed
data-testid="add-external-tool-button"
:to="{ name: 'administration-tool-config-overview' }"
>
{{ t("components.administration.externalToolsSection.action.add") }}
Expand Down
35 changes: 34 additions & 1 deletion src/components/copy-result-modal/CopyResultModal.unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,18 @@ const getWrapper = (props?: any) => {
};

describe("@/components/copy-result-modal/CopyResultModal", () => {
beforeEach(() => {
beforeAll(() => {
// Avoids console warnings "[Vuetify] Unable to locate target [data-app]"
document.body.setAttribute("data-app", "true");
setupStores({
envConfigModule: EnvConfigModule,
});
});

afterEach(() => {
jest.clearAllMocks();
});

describe("basic functions", () => {
it("Should render component", () => {
const wrapper = getWrapper();
Expand Down Expand Up @@ -152,6 +156,35 @@ describe("@/components/copy-result-modal/CopyResultModal", () => {
);
});

describe("when root item is a Course, has no failed file and CTL_TOOLS_COPY feature flag is enabled", () => {
const setup = () => {
const copyResultItems = mockResultItems([]);
const wrapper = getWrapper({
isOpen: true,
copyResultItems,
copyResultRootItemType: CopyApiResponseTypeEnum.Course,
});

return { wrapper };
};

it("should render ctl tools copy info ", () => {
envConfigModule.setEnvs({
FEATURE_CTL_TOOLS_TAB_ENABLED: true,
FEATURE_CTL_TOOLS_COPY_ENABLED: true,
} as Envs);
const { wrapper } = setup();

expect(
wrapper.find('[data-testid="copy-result-notifications"]').text()
).toContain(
wrapper.vm.$i18n.t(
"components.molecules.copyResult.ctlTools.withFeature.info"
)
);
});
});

it("should merge file error and coursefiles info if root item is a Course and has a failed file ", () => {
const copyResultItems = mockResultItems([fileItem]);

Expand Down
4 changes: 3 additions & 1 deletion src/components/copy-result-modal/CopyResultModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,9 @@ export default {
: this.$t("components.molecules.copyResult.nexboardCopy.infoTldraw");
},
externalToolsInfoText() {
return this.$t("components.molecules.copyResult.ctlTools.info");
return envConfigModule.getCtlToolsCopyEnabled
? this.$t("components.molecules.copyResult.ctlTools.withFeature.info")
: this.$t("components.molecules.copyResult.ctlTools.info");
},
},
methods: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,18 @@ export const useContextExternalToolConfigurationStatus = () => {
}
};

const determineIncompleteTranslationKey = (): string => {
const userRoles = authModule.getUserRoles;

if (userRoles.includes("teacher")) {
return "common.tool.information.incompleteOnContext.teacher";
} else {
return "common.tool.information.incomplete.student";
}
};

return {
determineOutdatedTranslationKey,
determineIncompleteTranslationKey,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ describe("ToolConfigurationStatus.composable", () => {
};
};

it("should return translationkey for outdated on scope school and context", () => {
it("should return translationkey for outdated", () => {
const { determineOutdatedTranslationKey, toolConfigurationStatus } =
setup();

Expand Down Expand Up @@ -187,7 +187,7 @@ describe("ToolConfigurationStatus.composable", () => {
};
};

it("should return translationkey for outdated on scope school ", () => {
it("should return translationkey for outdated ", () => {
const { determineOutdatedTranslationKey, toolConfigurationStatus } =
setup();

Expand Down Expand Up @@ -222,7 +222,7 @@ describe("ToolConfigurationStatus.composable", () => {
};
};

it("should return translationkey for outdated on scope context ", () => {
it("should return translationkey for outdated", () => {
const { determineOutdatedTranslationKey, toolConfigurationStatus } =
setup();

Expand All @@ -232,4 +232,63 @@ describe("ToolConfigurationStatus.composable", () => {
});
});
});

describe("determineIncompleteTranslationKey", () => {
describe("when user is teacher and tool is incomplete on scope context", () => {
const setup = () => {
const authModule = createModuleMocks(AuthModule, {
getUserRoles: ["teacher"],
});

const composable = mountComposable(
() => useContextExternalToolConfigurationStatus(),
{
[AUTH_MODULE_KEY.valueOf()]: authModule,
}
);

return {
...composable,
authModule,
};
};

it("should return translationkey for incomplete tool on scope context ", () => {
const { determineIncompleteTranslationKey } = setup();

const result = determineIncompleteTranslationKey();

expect(result).toEqual(
"common.tool.information.incompleteOnContext.teacher"
);
});
});

describe("when user is student and tool is incomplete on scope context", () => {
const setup = () => {
const authModule = createModuleMocks(AuthModule, {
getUserRoles: ["student"],
});

const composable = mountComposable(
() => useContextExternalToolConfigurationStatus(),
{
[AUTH_MODULE_KEY.valueOf()]: authModule,
}
);

return {
...composable,
};
};

it("should return translationkey for incomplete on scope context ", () => {
const { determineIncompleteTranslationKey } = setup();

const result = determineIncompleteTranslationKey();

expect(result).toEqual("common.tool.information.incomplete.student");
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</template>

<script lang="ts">
import { SchoolExternalToolConfigurationTemplate } from "@/store/external-tool";
import { ExternalToolConfigurationTemplate } from "@/store/external-tool";
import { computed, defineComponent, PropType, WritableComputedRef } from "vue";
import ExternalToolConfigParameter from "./ExternalToolConfigParameter.vue";

Expand All @@ -19,7 +19,7 @@ export default defineComponent({
components: { ExternalToolConfigParameter },
props: {
template: {
type: Object as PropType<SchoolExternalToolConfigurationTemplate>,
type: Object as PropType<ExternalToolConfigurationTemplate>,
IgorCapCoder marked this conversation as resolved.
Show resolved Hide resolved
required: true,
},
value: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as useExternalToolUtilsComposable from "@/composables/external-tool-mappings.composable";
import { mount, MountOptions, Wrapper } from "@vue/test-utils";
import createComponentMocks from "@@/tests/test-utils/componentMocks";
import Vue from "vue";
Expand All @@ -9,12 +10,11 @@ import {
ExternalToolConfigurationTemplate,
SchoolExternalTool,
} from "@/store/external-tool";
import { i18nMock } from "@@/tests/test-utils";
import { ContextExternalTool } from "@/store/external-tool/context-external-tool";
import { BusinessError } from "@/store/types/commons";
import ExternalToolConfigurator from "./ExternalToolConfigurator.vue";
import * as useExternalToolUtilsComposable from "@/composables/external-tool-mappings.composable";
import { I18N_KEY } from "@/utils/inject";
import { i18nMock } from "@@/tests/test-utils";
import ExternalToolConfigurator from "./ExternalToolConfigurator.vue";

describe("ExternalToolConfigurator", () => {
jest
Expand Down Expand Up @@ -168,9 +168,11 @@ describe("ExternalToolConfigurator", () => {
const { wrapper } = getWrapper({
templates:
schoolExternalToolConfigurationTemplateFactory.buildList(1),
configuration: schoolExternalToolFactory.build(),
});

await wrapper.find('[data-testId="save-button"]').vm.$emit("click");
wrapper.find('[data-testId="save-button"]').vm.$emit("click");
IgorCapCoder marked this conversation as resolved.
Show resolved Hide resolved
await Vue.nextTick();

expect(wrapper.emitted("save")).toBeDefined();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ import { useI18n } from "@/composables/i18n.composable";
import {
ExternalToolConfigurationTemplate,
SchoolExternalTool,
ToolParameter,
ToolParameterEntry,
} from "@/store/external-tool";
import { ContextExternalTool } from "@/store/external-tool/context-external-tool";
import { BusinessError } from "@/store/types/commons";
Expand Down Expand Up @@ -162,7 +164,31 @@ export default defineComponent({
};

const onSave = async () => {
emit("save", selectedTemplate.value, parameterConfiguration.value);
if (selectedTemplate.value) {
IgorCapCoder marked this conversation as resolved.
Show resolved Hide resolved
const parameterEntries: ToolParameterEntry[] = mapValidParameterEntries(
selectedTemplate.value
);

emit("save", selectedTemplate.value, parameterEntries);
}
};

const mapValidParameterEntries = (
template: ExternalToolConfigurationTemplate
) => {
const parameterEntries: ToolParameterEntry[] = template.parameters
.map(
(parameter: ToolParameter, index: number): ToolParameterEntry => ({
name: parameter.name,
value: parameterConfiguration.value[index],
})
)
.filter(
(parameterEntry: ToolParameterEntry) =>
parameterEntry.value !== undefined && parameterEntry.value !== ""
);

return parameterEntries;
};

const onChangeSelection = async () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,31 @@ describe("ExternalToolElement", () => {
});
});

describe("when the element has a tool attached, but it is incomplete", () => {
it("should not load the launch request", async () => {
getWrapper(
{
element: {
...EMPTY_TEST_ELEMENT,
content: { contextExternalToolId: "contextExternalToolId" },
},
isEditMode: false,
},
externalToolDisplayDataFactory.build({
status: ContextExternalToolConfigurationStatusFactory.build({
isIncompleteOnScopeContext: true,
}),
})
);

await Vue.nextTick();

expect(
useExternalToolLaunchStateMock.fetchLaunchRequest
).not.toHaveBeenCalled();
});
});

describe("when the element does not have a tool attached", () => {
it("should open the configuration dialog immediately", async () => {
const { wrapper } = getWrapper({
Expand Down Expand Up @@ -736,5 +761,39 @@ describe("ExternalToolElement", () => {
expect(alert.props("error")).toEqual(error);
});
});

describe("when the tool is incomplete", () => {
const setup = () => {
const toolIncompleteStatus =
ContextExternalToolConfigurationStatusFactory.build({
isIncompleteOnScopeContext: true,
});

const { wrapper } = getWrapper(
{
element: EMPTY_TEST_ELEMENT,
isEditMode: true,
},
externalToolDisplayDataFactory.build({
status: toolIncompleteStatus,
})
);

return {
wrapper,
toolIncompleteStatus,
};
};

it("should display an incomplete alert", async () => {
const { wrapper, toolIncompleteStatus } = setup();

const alert = wrapper.find(
'[data-testid="board-external-tool-element-alert"]'
);

expect(alert.props("toolStatus")).toEqual(toolIncompleteStatus);
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -149,12 +149,17 @@ export default defineComponent({
!!displayData.value?.status.isOutdatedOnScopeContext
);

const isToolIncomplete: ComputedRef<boolean> = computed(
() => !!displayData.value?.status.isIncompleteOnScopeContext
);

const toolConfigurationStatus: ComputedRef<ContextExternalToolConfigurationStatus> =
computed(() => {
return (
displayData.value?.status ?? {
isOutdatedOnScopeSchool: false,
isOutdatedOnScopeContext: false,
isIncompleteOnScopeContext: false,
isDeactivated: false,
}
);
Expand Down Expand Up @@ -212,7 +217,7 @@ export default defineComponent({
if (modelValue.value.contextExternalToolId) {
await fetchDisplayData(modelValue.value.contextExternalToolId);

if (!isToolOutdated.value) {
if (!isToolOutdated.value && !isToolIncomplete.value) {
await fetchLaunchRequest(modelValue.value.contextExternalToolId);
}
}
Expand All @@ -228,6 +233,7 @@ export default defineComponent({
error,
isLoading,
isToolOutdated,
isToolIncomplete,
isConfigurationDialogOpen,
toolConfigurationStatus,
mdiPuzzleOutline,
Expand Down
Loading
Loading