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-2052 adjust ctl autocomplete #3313

Merged
merged 30 commits into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
ea07696
N21-2052 generate api, adds baseUrl and change autocomplete wip
arnegns Jul 3, 2024
3978a27
added check for valid url & hide "no data" when url is inputted
GordonNicholasCap Jul 3, 2024
16f5116
Merge branch 'refs/heads/main' into N21-2052-ctl-url-insertion
arnegns Jul 3, 2024
b8613a5
Merge branch 'refs/heads/main' into N21-2052-ctl-url-insertion
arnegns Jul 3, 2024
26820ca
N21-2052 some logic
arnegns Jul 3, 2024
99c51eb
N21-2052 fixes escaping
arnegns Jul 4, 2024
c1ed9ce
N21-2052 fixes test
arnegns Jul 4, 2024
92f7efa
N21-2052 changes ExternalToolSelectionRow.vue to script setup
arnegns Jul 4, 2024
cd373b2
N21-2052 some changes
arnegns Jul 4, 2024
9a040a8
N21-2052 adds clipboard logic
arnegns Jul 4, 2024
6938535
N21-2052 fixes linter error
arnegns Jul 4, 2024
8872d6d
fixed settings still showing when box is cleared, minor cleanup
GordonNicholasCap Jul 4, 2024
1c26507
moved code for url into composable, added query param extractor
GordonNicholasCap Jul 4, 2024
eaa0728
added hint below combobox, changed paste url icon
GordonNicholasCap Jul 5, 2024
e22917c
adjusted valid url regex, fixed minor bugs in composable
GordonNicholasCap Jul 5, 2024
b538fa6
wip unit tests for configurator & composable
GordonNicholasCap Jul 5, 2024
e7368bb
full unit tests for composable
GordonNicholasCap Jul 8, 2024
abe2ccb
refactored script -> script setup, fixed missing baseUrl
GordonNicholasCap Jul 8, 2024
feb15a2
cleanup unit tests, skip tests involving combobox's selection menu
GordonNicholasCap Jul 9, 2024
7b54bc9
added proper error handling for clipboard, adjusted code for checking…
GordonNicholasCap Jul 9, 2024
4109dcd
Merge branch 'refs/heads/main' into N21-2052-ctl-url-insertion
GordonNicholasCap Jul 9, 2024
c73dc00
fixed tests
GordonNicholasCap Jul 9, 2024
73806b5
make search box testable
MarvinOehlerkingCap Jul 10, 2024
e204700
N21-2052 refactored composable unit tests to be simpler
GordonNicholasCap Jul 10, 2024
5439fa4
N21-2052 renamed comboboxRef, added test for selection list filter
GordonNicholasCap Jul 10, 2024
a9b34c5
remove v-if from slot
MarvinOehlerkingCap Jul 11, 2024
5e58111
change order of execution for paste-icon
MarvinOehlerkingCap Jul 11, 2024
f2cfc93
minor adjustments, fixed typos
GordonNicholasCap Jul 11, 2024
8c9716b
Merge branch 'main' into N21-2052-ctl-url-insertion
GordonNicholasCap Jul 11, 2024
9bf5b83
fix focus and accessibility for past-icon
MarvinOehlerkingCap Jul 11, 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
Original file line number Diff line number Diff line change
@@ -1,20 +1,27 @@
<template>
<div>
<v-autocomplete
<v-combobox
:label="$t('pages.tool.select.label')"
item-title="name"
item-value="id"
hide-selected
clearable
open-on-clear
:items="configurationTemplates"
v-model="selectedTemplate"
:no-data-text="$t('common.nodata')"
:no-data-text="$t('pages.tool.select.nodata')"
return-object
:disabled="isInEditMode"
:loading="loading"
data-testId="configuration-select"
@update:modelValue="onChangeSelection"
variant="underlined"
:append-icon="mdiClipboardFileOutline"
@update:search="search"
:hide-no-data="hideNoData"
:custom-filter="
(value, query, item) => customFilter(value, query, item?.raw)
"
>
<template #selection="{ item }">
<external-tool-selection-row
Expand All @@ -31,7 +38,7 @@
:item="item.raw"
/>
</template>
</v-autocomplete>
</v-combobox>
<h2
v-if="
displaySettingsTitle &&
Expand All @@ -44,7 +51,11 @@
</h2>
<slot name="aboveParameters" :selectedTemplate="selectedTemplate" />
<external-tool-config-settings
v-if="selectedTemplate && selectedTemplate.parameters.length > 0"
v-if="
selectedTemplate &&
selectedTemplate.parameters &&
selectedTemplate.parameters.length > 0
"
:template="selectedTemplate"
v-model="parameterConfiguration"
/>
Expand Down Expand Up @@ -85,6 +96,7 @@
<script lang="ts">
import ExternalToolConfigSettings from "@/components/external-tools/configuration/ExternalToolConfigSettings.vue";
import { mdiAlertCircle } from "@/components/icons/material";
import { mdiClipboardFileOutline } from "@mdi/js";
import { useExternalToolMappings } from "@/composables/external-tool-mappings.composable";
import {
SchoolExternalTool,
Expand Down Expand Up @@ -199,6 +211,7 @@

const onChangeSelection = async () => {
fillParametersWithDefaultValues();
extractAndSetParametersFromUrl(selectedTemplate.value?.baseUrl);

emit("change", selectedTemplate.value);
};
Expand All @@ -215,8 +228,7 @@

const fillParametersWithDefaultValues = () => {
parameterConfiguration.value = [];

selectedTemplate.value?.parameters.forEach((parameter, index) => {
selectedTemplate.value?.parameters?.forEach((parameter, index) => {
parameterConfiguration.value[index] = parameter.defaultValue;
});
};
Expand All @@ -236,6 +248,84 @@
});
};

const isValidUrl = (text: string): boolean => {
const urlRegex = new RegExp(
"(https?:\\/\\/(?:www\\.|(?!www))[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\\.[^\\s]{2,}|www\\.[a-zA-Z0-9][a-zA-Z0-9-]+[a-zA-Z0-9]\\.[^\\s]{2,}|https?:\\/\\/(?:www\\.|(?!www))[a-zA-Z0-9]+\\.[^\\s]{2,}|www\\.[a-zA-Z0-9]+\\.[^\\s]{2,})"
);
return urlRegex.test(text);
};

const checkUrl = (
searchText: string
): ExternalToolConfigurationTemplate | undefined => {
try {
const url = new URL(searchText);
const matchedTemplate = configurationTemplates.value.find(
(template) => {
const baseUrlRegex = new RegExp(
`^${template.baseUrl.replace(/:\w+/g, "\\w+")}$`
);
return baseUrlRegex.test(url.href);
}
);
if (matchedTemplate) {
return matchedTemplate;
}
} catch (e) {
// TODO: Handle error
}
return undefined;
};

// TODO: remove comments and make it easier to understand
const extractAndSetParametersFromUrl = (baseUrl: string | undefined) => {
if (!baseUrl || !searchString.value) return;

// params aus baseUrl holen
const urlParts = baseUrl.split("/");
const templateParams = urlParts
.filter((part) => part.startsWith(":"))
.map((part) => part.substring(1)); // : entfernen

// regex, um parameter werte aus url holen
const urlRegex = new RegExp(
`${baseUrl.replace(/:\w+/g, "(\\w+)").replace(/\//g, "\\/")}`
Fixed Show fixed Hide fixed
);

// params aus searchString holen
const match = searchString.value.match(urlRegex);
if (match) {
// match[0] full hit, match[1] bis match[n] values der caputure groups
const parameterValues = match.slice(1);

// index im template suchen mit param name und wert setzen
parameterValues.forEach((value, index) => {
const paramName = templateParams[index];
const paramIndex = selectedTemplate.value?.parameters.findIndex(
(param) => param.name === paramName
);

if (paramIndex !== undefined && paramIndex >= 0) {
parameterConfiguration.value[paramIndex] = value;
}
});
}
};

const hideNoData: Ref<boolean> = ref(false);

const searchString: Ref<string> = ref("");

const search = (text: string) => {
searchString.value = text;
if (isValidUrl(text)) {
hideNoData.value = true;
checkUrl(text);
} else {
hideNoData.value = false;
}
};

if (loadedConfiguration.value) {
populateEditMode(loadedConfiguration.value);
}
Expand All @@ -246,7 +336,21 @@
}
});

const customFilter = (
_value: string,
query: string,
item: ExternalToolConfigurationTemplate | undefined
): boolean => {
return item
? checkUrl(query)?.baseUrl === item.baseUrl ||
item.name.toLowerCase().includes(query.toLowerCase())
: false;
};

return {
searchString,
search,
customFilter,
configurationTemplates,
loadedConfiguration,
getBusinessErrorTranslationKey,
Expand All @@ -260,6 +364,8 @@
parameterConfiguration,
isAboveParametersSlotEmpty,
mdiAlertCircle,
mdiClipboardFileOutline,
hideNoData,
};
},
});
Expand Down
3 changes: 2 additions & 1 deletion src/locales/de.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1620,7 +1620,8 @@ export default {
"pages.tool.deactivate.label": "Tool in der Schule deaktivieren",
"pages.tool.description":
'Die kursspezifischen Parameter für das externe Tool werden hier konfiguriert. Nach dem Speichern der Konfiguration ist das Tool innerhalb des Kurses verfügbar.<br><br>\nDurch das Löschen einer Konfiguration wird das Tool dem Kurs wieder entzogen.<br><br>\nWeitere Informationen sind in unserem <a href="https://docs.dbildungscloud.de/pages/viewpage.action?pageId=246055610" target="_blank">Hilfebereich zu externen Tools</a> zu finden.',
"pages.tool.select.label": "Tool-Auswahl",
"pages.tool.select.label": "Tool-Auswahl / Tool-URL",
"pages.tool.select.nodata": "Kein Tool vorhanden",
"pages.tool.settings": "Einstellungen",
"pages.tool.title": "Konfiguration externer Tools",
"pages.userMigration.backToLogin": "Zurück zur Anmeldeseite",
Expand Down
3 changes: 2 additions & 1 deletion src/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1593,7 +1593,8 @@ export default {
"pages.tool.deactivate.label": "Deactivate tool at school",
"pages.tool.description":
'The course-specific parameters for the external tool are configured here. After saving the configuration, the tool is available inside the course.<br><br>\nDeleting a configuration removes the tool from the course.<br><br>\nMore information can be found in our <a href="https://docs.dbildungscloud.de/pages/viewpage.action?pageId=246055610" target="_blank">Help section on external tools</a>.',
"pages.tool.select.label": "Tool selection",
"pages.tool.select.label": "Tool selection / Tool-URL",
"pages.tool.select.nodata": "No tool available",
"pages.tool.settings": "Settings",
"pages.tool.title": "External Tools Configuration",
"pages.userMigration.backToLogin": "Return to login page",
Expand Down
3 changes: 2 additions & 1 deletion src/locales/es.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1638,7 +1638,8 @@ export default {
"pages.tool.deactivate.label": "Desactivar herramienta en la escuela",
"pages.tool.description":
'Los parámetros específicos del curso para la herramienta externa se configuran aquí. Después de guardar la configuración, la herramienta está disponible dentro del curso.<br><br>\nEliminar una configuración elimina la herramienta de el curso.<br><br>\nPuede encontrar más información en nuestro <a href="https://docs.dbildungscloud.de/pages/viewpage.action?pageId=246055610" target="_blank">Sección de ayuda sobre herramientas externas</a>.',
"pages.tool.select.label": "Selección de Herramientas",
"pages.tool.select.label": "Selección de Herramientas / URL de herramienta",
"pages.tool.select.nodata": "No hay herramienta disponible",
"pages.tool.settings": "Configuración",
"pages.tool.title": "Configuración de herramientas externas",
"pages.userMigration.backToLogin": "Volver a la página de inicio de sesión",
Expand Down
3 changes: 2 additions & 1 deletion src/locales/uk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1614,7 +1614,8 @@ export default {
"pages.tool.deactivate.label": "Деактивуйте інструмент у школі",
"pages.tool.description":
'Тут налаштовуються специфічні для курсу параметри зовнішнього інструменту. Після збереження конфігурації інструмент стає доступним у курсі.<br><br>\nВидалення конфігурації видаляє інструмент із курс.<br><br>\nБільше інформації можна знайти в нашому <a href="https://docs.dbildungscloud.de/pages/viewpage.action?pageId=246055610" target="_blank">Розділ довідки щодо зовнішніх інструментів</a>.',
"pages.tool.select.label": "вибір інструменту",
"pages.tool.select.label": "вибір інструменту / Інструмент-URL",
"pages.tool.select.nodata": "Інструмент відсутній",
"pages.tool.settings": "Параметри",
"pages.tool.title": "Конфігурація зовнішніх інструментів",
"pages.userMigration.backToLogin": "Повернутися на сторінку входу",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export class ContextExternalToolMapper {
schoolExternalToolId: response.schoolExternalToolId,
logoUrl: response.logoUrl,
name: response.name,
baseUrl: response.baseUrl,
parameters: response.parameters.map(
(parameter): ToolParameter =>
ExternalToolMapper.mapToToolParameter(parameter)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ export interface ExternalToolConfigurationTemplate {

name: string;

baseUrl: string;

logoUrl?: string;

parameters: ToolParameter[];
Expand Down
12 changes: 12 additions & 0 deletions src/serverApi/v3/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1443,6 +1443,12 @@ export interface ContextExternalToolConfigurationTemplateResponse {
* @memberof ContextExternalToolConfigurationTemplateResponse
*/
name: string;
/**
*
* @type {string}
* @memberof ContextExternalToolConfigurationTemplateResponse
*/
baseUrl: string;
/**
*
* @type {string}
Expand Down Expand Up @@ -6061,6 +6067,12 @@ export interface SchoolExternalToolConfigurationTemplateResponse {
* @memberof SchoolExternalToolConfigurationTemplateResponse
*/
name: string;
/**
*
* @type {string}
* @memberof SchoolExternalToolConfigurationTemplateResponse
*/
baseUrl: string;
/**
*
* @type {string}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export class SchoolExternalToolMapper {
externalToolId: response.externalToolId,
logoUrl: response.logoUrl,
name: response.name,
baseUrl: response.baseUrl,
parameters: response.parameters.map(
(parameter): ToolParameter =>
ExternalToolMapper.mapToToolParameter(parameter)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export const contextExternalToolConfigurationTemplateFactory =
Factory.define<ContextExternalToolConfigurationTemplate>(({ sequence }) => ({
externalToolId: `externalTool${sequence}`,
schoolExternalToolId: `schoolExternalTool${sequence}`,
baseUrl: `https://context-external-tool-${sequence}.com`,
name: "Template Name",
parameters: [],
}));
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const contextExternalToolConfigurationTemplateResponseFactory =
externalToolId: `external-tool-${sequence}`,
schoolExternalToolId: `school-external-tool-${sequence}`,
name: `SchoolExternalTool${sequence}`,
baseUrl: `https://school-external-tool-${sequence}.com`,
parameters: [],
})
);
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export const schoolExternalToolConfigurationTemplateFactory =
Factory.define<SchoolExternalToolConfigurationTemplate>(({ sequence }) => ({
externalToolId: `externalTool${sequence}`,
name: "Template Name",
baseUrl: `https://school-external-tool-${sequence}.com`,
parameters: [],
isDeactivated: false,
}));
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const schoolExternalToolConfigurationTemplateResponseFactory =
({ sequence }) => ({
externalToolId: `tool-${sequence}`,
name: `SchoolExternalTool${sequence}`,
baseUrl: `https://school-external-tool-${sequence}.com`,
parameters: [],
})
);
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const schoolExternalToolConfigurationTemplate =
externalToolId: `tool${sequence}`,
configId: "configId",
name: "toolName",
baseUrl: `https://school-external-tool-${sequence}.com`,
logoUrl: "logoUrl",
parameters: [],
isDeactivated: false,
Expand Down
Loading