{"version":3,"file":"app-3954a708.f584a1446b2fc034d810.bundle.js","mappings":"AAGA","sources":["webpack://lernplattform-admin-frontend/./src/resources/pages/settings-page/settings-page.html","webpack://lernplattform-admin-frontend/./src/resources/pages/skill-matrix-page/skill-matrix-page.html","webpack://lernplattform-admin-frontend/./src/resources/pages/skills-edit-page/skills-edit-page.html","webpack://lernplattform-admin-frontend/./src/resources/pages/skills-page/skills-page.html","webpack://lernplattform-admin-frontend/./src/resources/pages/settings-page/settings-page.ts","webpack://lernplattform-admin-frontend/./src/resources/pages/skill-matrix-page/skill-matrix-page.ts","webpack://lernplattform-admin-frontend/./src/resources/pages/skills-edit-page/skills-edit-page.ts","webpack://lernplattform-admin-frontend/./src/resources/pages/skills-page/skills-page.ts"],"sourcesContent":["// Module\nvar code = \"<template> <div class=\\\"page-header\\\"> <h1 class=\\\"page-title\\\" t=\\\"pages.settings.title\\\"></h1> </div> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <div class=\\\"page-header\\\"> <h1 class=\\\"page-title\\\" t=\\\"pages.skill-matrix.title\\\"></h1> </div> <div class=\\\"row\\\"> <div class=\\\"col-12\\\"> <skill-matrix-filter-form filter-changed.trigger=\\\"updateTable($event)\\\"></skill-matrix-filter-form> </div> <div class=\\\"col-12\\\"> <p if.to-view=\\\"!tableRefreshVersion\\\" class=\\\"text-center mt-8 mb-4 text-muted\\\" t=\\\"elements.skillMatrixFilterForm.selectUsersOrSkills\\\"></p> <matrix-table else column-data.to-view=\\\"matrixTableColumnData\\\" row-data.to-view=\\\"matrixTableRowData\\\" column-config.to-view=\\\"matrixTableColumnConfig\\\" row-config.to-view=\\\"matrixTableRowConfig\\\" refresh-version.to-view=\\\"tableRefreshVersion\\\"></matrix-table> </div> <div if.to-view=\\\"tableRefreshVersion\\\" class=\\\"col-12 d-flex mt-5\\\"> <div class=\\\"d-flex mr-5\\\"> <safe-icon icon-name=\\\"System/Tabler/Check\\\" class=\\\"text-primary mr-2\\\"></safe-icon> <span class=\\\"text-muted\\\" t=\\\"pages.skill-matrix.legend.acquired\\\"></span> </div> <div class=\\\"d-flex mr-5\\\"> <safe-icon icon-name=\\\"System/Tabler/Double-Check\\\" class=\\\"text-warning mr-2\\\"></safe-icon> <span class=\\\"text-muted\\\" t=\\\"pages.skill-matrix.legend.assigned\\\"></span> </div> <div class=\\\"d-flex\\\"> <safe-icon icon-name=\\\"System/Tabler/X\\\" class=\\\"text-danger mr-2\\\"></safe-icon> <span class=\\\"text-muted\\\" t=\\\"pages.skill-matrix.legend.notAcquired\\\"></span> </div> </div> </div> </template> \";\n// Exports\nexport default code;","// Module\nvar code = \"<template class=\\\"skills-edit-page\\\"> <button-standard click.delegate=\\\"navigateBack()\\\" t=\\\"[btnText]globals.back\\\" icon-name=\\\"System/Tabler/Chevron-Left\\\" btn-size=\\\"btn-sm\\\" btn-color=\\\"secondary\\\"></button-standard> <div class=\\\"page-header\\\"> <h1 class=\\\"page-title\\\"> <span if.to-view=\\\"!skillId\\\" t=\\\"pages.skills.newSkill\\\"></span> <span else>${skill.title}</span> </h1> </div> <div class=\\\"row\\\"> <div class=\\\"col-12\\\"> <form class=\\\"card\\\"> <div class=\\\"card-header\\\"> <h2 class=\\\"card-title\\\" t=\\\"globals.basics\\\"></h2> </div> <div class=\\\"card-body two-column-grid\\\"> <div> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"globals.title\\\"></label> <input type=\\\"text\\\" class=\\\"form-control\\\" required value.two-way=\\\"skill.title\\\"> </div> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"pages.skills.icon\\\"></label> <search-and-select if.to-view=\\\"searchSelectEmojiis\\\" class=\\\"w-100 skills-edit-page__sas\\\" data.to-view=\\\"searchSelectEmojiis\\\" max-items.to-view=\\\"20\\\" sas-item-changed.trigger=\\\"onEmojiSelected($event)\\\" t=\\\"[label]globals.searchSelect\\\"></search-and-select> </div> <div class=\\\"two-column-grid\\\"> <div> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"pages.skills.validityDurationInMonths\\\"></label> <input type=\\\"number\\\" class=\\\"form-control\\\" disabled.to-view=\\\"skill.unlimitedValidity\\\" min=\\\"1\\\" value.two-way=\\\"skill.validityDurationInMonths | number\\\"> </div> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"pages.skills.offerRenewalAfterPeriodInMonths\\\"></label> <input type=\\\"number\\\" class=\\\"form-control\\\" disabled.to-view=\\\"skill.unlimitedValidity\\\" min=\\\"1\\\" value.two-way=\\\"skill.offerRenewalAfterPeriodInMonths | number\\\"> </div> </div> <label class=\\\"custom-control custom-checkbox custom-control-inline form-check mt-6 skills-edit-page__checkbox\\\"> <input class=\\\"custom-control-input\\\" type=\\\"checkbox\\\" checked.two-way=\\\"skill.unlimitedValidity\\\"> <span class=\\\"custom-control-label\\\" t=\\\"globals.unlimited\\\"></span> </label> </div> </div> <div class=\\\"form-group\\\"> <label class=\\\"form-label\\\" t=\\\"globals.description\\\"></label> <textarea type=\\\"text\\\" class=\\\"form-control\\\" rows=\\\"8\\\" value.two-way=\\\"skill.description\\\"></textarea> </div> </div> <div class=\\\"card-footer text-right\\\"> <button class=\\\"btn btn-primary\\\" click.delegate=\\\"handleSaveClick()\\\" t=\\\"globals.save\\\"></button> </div> </form> </div> </div> </template>\";\n// Exports\nexport default code;","// Module\nvar code = \"<template> <div class=\\\"page-header\\\"> <h1 class=\\\"page-title\\\" t=\\\"globals.skills\\\"></h1> <div class=\\\"ml-auto\\\"> <button-standard click.delegate=\\\"handleCreateSkillClick()\\\" class=\\\"mb-2 d-inline-block\\\" t=\\\"[btnText]pages.skills.createSkill\\\" icon-name=\\\"System/Tabler/Plus\\\" btn-color=\\\"primary\\\"></button-standard> </div> </div> <div class=\\\"row row-cards row-deck\\\"> <div class=\\\"col-12\\\"> <custom-table columns.to-view=\\\"tableColumns\\\" extendable.to-view=\\\"true\\\" table-id=\\\"skills-page\\\" refresh-version.to-view=\\\"tableRefreshVersion\\\" get-shown-entries-data.call=\\\"fetchTableData(limit, offset)\\\"></custom-table> </div> </div> </template>\";\n// Exports\nexport default code;","import { autoinject } from 'aurelia-framework';\n\n@autoinject\nexport class SettingsPage {\n}\n","import { autoinject } from 'aurelia-framework';\nimport { ISkillDto, IStudentWithSkillsDto, SkillAwardReason } from 'common/dto/skill/management/skill.management.interface';\nimport { NicknameUtils } from 'common/utils/NicknameUtils';\nimport { SkillUtils } from 'common/utils/SkillUtils';\nimport { SkillManagementApiService } from '../../../services/api/SkillManagementApiService';\nimport { StudentService } from '../../../services/StudentService';\nimport { ToastService } from '../../../services/ToastService';\nimport { VirtualFilterField } from '../../elements/custom-table/custom-table-helpers';\nimport { IMatrixTableColumnConfig, IMatrixTableRowConfig, IMatrixTableStatusFlair } from '../../elements/matrix-table/matrix-table';\nimport { SkillMatrixFilterFormFilterChangeEvent } from '../../elements/skill-matrix-filter-form/skill-matrix-filter-form';\nimport { CheckedState } from '../../elements/tri-state-checkbox/tri-state-checkbox';\nimport { ENavigationTab } from '../student-invitations-page/student-invitations-page';\n\n@autoinject()\nexport class SkillMatrixPage {\n  private matrixTableRowData: IStudentWithSkillsDto[] = [];\n  private matrixTableRowConfig: IMatrixTableRowConfig<ISkillDto, IStudentWithSkillsDto> = {\n    labelTransformer: student => NicknameUtils.getFullName(student),\n    statusFlairTransformer: this.getStatusFlair,\n    countableTransformer: this.countableTransformer,\n    avatarSvgDownloadLink: student => student.avatarSvgDownloadLink,\n    dataClickCallback: (skill, student) => this.assignOrUnAssignStudentSkill(skill, student),\n    labelClickCallback: student => void this.studentService.navigateToStudentInvitationsPage(student.id, ENavigationTab.SKILLS)\n  };\n\n  private matrixTableColumnData: ISkillDto[] = [];\n  private matrixTableColumnConfig: IMatrixTableColumnConfig<ISkillDto> = {\n    labelTransformer: skill => skill.title,\n    iconKeyTransformer: skill => skill.iconKey,\n  };\n\n  private currentFilter: SkillMatrixFilterFormFilterChangeEvent['detail'] | null = null;\n\n  private tableRefreshVersion: number = 0;\n\n  constructor(\n    private skillManagementApiService: SkillManagementApiService,\n    private toastService: ToastService,\n    private studentService: StudentService\n  ) { }\n\n  private countableTransformer(skill: ISkillDto, student: IStudentWithSkillsDto): boolean {\n    const skillOfStudent = student.skills?.find(sS => sS.skillId === skill.id);\n    return skillOfStudent != null && SkillUtils.hasSkill(skillOfStudent);\n  }\n\n  private getStatusFlair(skill: ISkillDto, student: IStudentWithSkillsDto): IMatrixTableStatusFlair {\n    const studentSkill = student.skills?.find(s => s.skillId === skill.id);\n\n    const hasSkill = studentSkill && SkillUtils.hasSkill(studentSkill);\n\n    if(hasSkill) {\n      if(studentSkill.awardedReason === SkillAwardReason.Manual) {\n        return {\n          iconClass: 'text-warning',\n          iconName: 'System/Tabler/Double-Check',\n          checkedState: CheckedState.CHECKED,\n        };\n      }\n\n      return {\n        iconName: 'System/Tabler/Check',\n        iconClass: 'text-primary',\n        checkedState: CheckedState.INTERMEDIATE,\n      };\n    }\n\n    return {\n      iconClass: 'text-danger',\n      iconName: 'System/Tabler/X',\n      checkedState: CheckedState.UNCHECKED,\n    };\n  }\n\n  private async assignOrUnAssignStudentSkill(skill: ISkillDto, student: IStudentWithSkillsDto): Promise<void> {\n    const skillOfStudent = student.skills?.find(sS => sS.skillId === skill.id);\n\n    if(skillOfStudent != null && SkillUtils.hasSkill(skillOfStudent)) {\n      await this.skillManagementApiService.awardSkillToStudent(student.id, skill.id, {\n        overrideExpirationDate: new Date().toISOString(),\n        overrideRenewabilityDate: new Date().toISOString(),\n      });\n    } else {\n      await this.skillManagementApiService.awardSkillToStudent(student.id, skill.id, {\n        overrideExpirationDate: null,\n        overrideRenewabilityDate: null,\n      });\n    }\n    this.toastService.success('pages.skills.saveSuccess');\n    await this.refreshTable();\n  }\n\n  private async updateTable(event: SkillMatrixFilterFormFilterChangeEvent): Promise<void> {\n    this.currentFilter = event.detail;\n    await this.refreshTable();\n  }\n\n  private async refreshTable(): Promise<void> {\n    this.matrixTableColumnData = (await this.skillManagementApiService.getSkills(this.currentFilter?.filterForSkills ?? {})).rows;\n\n    // splice skill ids from result into user skill filter\n    const skillFilter = this.currentFilter?.filterForStudents.filter?.find(f => f.field === 'skillIds' as VirtualFilterField);\n    if(skillFilter) skillFilter.value = this.matrixTableColumnData.map(col => col.id);\n    this.matrixTableRowData = (await this.skillManagementApiService.getStudentsWithSkills(this.currentFilter?.filterForStudents ?? {})).rows;\n    this.tableRefreshVersion++;\n  }\n}\n","import { autoinject } from 'aurelia-framework';\nimport { Router } from 'aurelia-router';\nimport { DEFAULT_SKILL_TIME_IN_MONTHS } from 'common/constants/course.constants';\nimport { TWEMOJIIS } from 'common/constants/twemoji.constants';\nimport { ICreateSkillDto } from 'common/dto/skill/management/skill.management.interface';\nimport { ToastService } from '../../../services/ToastService';\nimport { SkillManagementApiService } from '../../../services/api/SkillManagementApiService';\nimport { ISearchSelectData, SasSelectedItemChangedEvent, SearchSelectGroupDisplayMode } from '../../elements/search-and-select/search-and-select';\n\ninterface IParams {\n  skillId?: string;\n}\n\n@autoinject()\nexport class SkillsEditPage {\n  private skillId: number | null = null;\n  private searchSelectEmojiis: ISearchSelectData | null = null;\n  private twemojis = TWEMOJIIS;\n  private skill: ICreateSkillDto = {\n    title: '',\n    description: '',\n    iconKey: this.twemojis[0].codepoint,\n    validityDurationInMonths: DEFAULT_SKILL_TIME_IN_MONTHS,\n    offerRenewalAfterPeriodInMonths: DEFAULT_SKILL_TIME_IN_MONTHS,\n    unlimitedValidity: false,\n  };\n\n  constructor(\n    private skillManagementApiService: SkillManagementApiService,\n    private router: Router,\n    private toastService: ToastService,\n  ) { }\n\n  protected activate(params: IParams): void {\n    this.skillId = params.skillId != null ? parseInt(params.skillId, 10) : null;\n    this.updateSkill();\n  }\n\n  private async updateSkill(): Promise<void> {\n    if(this.skillId) {\n      const skill = await this.skillManagementApiService.getSkill(this.skillId);\n      this.skill = {\n        title: skill.title,\n        description: skill.description,\n        iconKey: skill.iconKey,\n        validityDurationInMonths: skill.validityDurationInMonths,\n        offerRenewalAfterPeriodInMonths: skill.offerRenewalAfterPeriodInMonths,\n        unlimitedValidity: skill.unlimitedValidity,\n      };\n    }\n    this.updateSearchSelect();\n  }\n\n  private updateSearchSelect(): void {\n    const selectedIcon = this.twemojis.find(twemoji => twemoji.codepoint === this.skill?.iconKey) ?? this.twemojis[0];\n    this.searchSelectEmojiis = {\n      defaultItemId: selectedIcon.codepoint,\n      searchIndex: [\n        {\n          displaySettings: {\n            displayMode: SearchSelectGroupDisplayMode.None,\n          },\n          items: TWEMOJIIS.map(twemoji => ({\n            text: twemoji.name,\n            id: twemoji.codepoint,\n            iconName: twemoji.iconName\n          }))\n        },\n      ],\n      noResultsTextTk: 'globals.noResults',\n    };\n  }\n\n  private onEmojiSelected(event: SasSelectedItemChangedEvent<string>): void {\n    this.skill.iconKey = event.detail.id;\n  }\n\n  private async handleSaveClick(): Promise<void> {\n    if(this.skillId) {\n      await this.skillManagementApiService.updateSkill(this.skillId, this.skill);\n    } else {\n      await this.skillManagementApiService.createSkill(this.skill);\n    }\n    this.toastService.success('pages.skills.saveSuccess');\n    this.navigateBack();\n  }\n\n  private navigateBack(): void {\n    this.router.navigateToRoute('skills');\n  }\n}\n","import { autoinject } from 'aurelia-framework';\nimport { Router } from 'aurelia-router';\nimport { ColumnSortDirection, FilterOperationType } from 'common/dto/filter/filter.enum';\nimport { IFilterDto } from 'common/dto/filter/filter.interface';\nimport { ISkillDto } from 'common/dto/skill/management/skill.management.interface';\nimport { CustomDialogService } from '../../../services/CustomDialogService';\nimport { SkillManagementApiService } from '../../../services/api/SkillManagementApiService';\nimport { ActionsCell } from '../../elements/custom-table/actions-cell/actions-cell';\nimport { CustomTableCell } from '../../elements/custom-table/custom-table-cell/custom-table-cell';\nimport { createPrepareServersideSortingFunction, prepareServersideFiltering } from '../../elements/custom-table/custom-table-helpers';\nimport { IColumnDefinition } from '../../elements/custom-table/custom-table-interfaces';\nimport { IconCell } from '../../elements/custom-table/icon-cell/icon-cell';\nimport { SkillIconCell } from '../../elements/custom-table/skill-icon-cell/skill-icon-cell';\n\n@autoinject()\nexport class SkillsPage {\n  private tableRefreshVersion: number = 0;\n  private filter: IFilterDto<ISkillDto> = {\n    offset: 0,\n    limit: 10,\n    order: [{\n      field: 'title',\n      dir: ColumnSortDirection.ASC,\n    }],\n    filter: []\n  };\n\n  private tableColumns: Array<IColumnDefinition<CustomTableCell<ISkillDto> | SkillIconCell<ISkillDto> | IconCell<ISkillDto> | ActionsCell<ISkillDto>>> = [\n    {\n      id: 'title',\n      nameTk: 'globals.name',\n      cellViewModel: SkillIconCell,\n      cellOptions: {\n        skillTransformer: skill => skill,\n        callback: skill => this.handleEditSkillClick(skill)\n      },\n      prepareSorting: createPrepareServersideSortingFunction(() => this.filter, 'title'),\n      filter: {\n        placeholderTk: 'globals.filter',\n        prepare: v => prepareServersideFiltering(this.filter, 'title', v),\n      },\n      shrink: true,\n    },\n    {\n      id: 'description',\n      nameTk: 'globals.description',\n      cellViewModel: CustomTableCell,\n      cellOptions: {\n        transformer: skill => skill.description\n      },\n      prepareSorting: createPrepareServersideSortingFunction(() => this.filter, 'description'),\n      filter: {\n        placeholderTk: 'globals.filter',\n        prepare: v => prepareServersideFiltering(this.filter, 'description', v),\n      },\n      wrap: true,\n    },\n    {\n      id: 'validityDurationInMonths',\n      nameTk: 'pages.skills.validityDurationInMonths',\n      cellViewModel: CustomTableCell,\n      cellOptions: {\n        transformer: skill => `${skill.validityDurationInMonths}`,\n      },\n      prepareSorting: createPrepareServersideSortingFunction(() => this.filter, 'validityDurationInMonths'),\n      filter: {\n        placeholderTk: 'globals.filter',\n        prepare: v => prepareServersideFiltering(this.filter, 'validityDurationInMonths', String(v), FilterOperationType.EqFloor),\n      },\n    },\n    {\n      id: 'offerRenewalAfterPeriodInMonths',\n      nameTk: 'pages.skills.offerRenewalAfterPeriodInMonths',\n      cellViewModel: CustomTableCell,\n      cellOptions: {\n        transformer: skill => `${skill.offerRenewalAfterPeriodInMonths}`,\n      },\n      prepareSorting: createPrepareServersideSortingFunction(() => this.filter, 'offerRenewalAfterPeriodInMonths'),\n      filter: {\n        placeholderTk: 'globals.filter',\n        prepare: v => prepareServersideFiltering(this.filter, 'offerRenewalAfterPeriodInMonths', String(v), FilterOperationType.EqFloor),\n      },\n    },\n    {\n      id: 'unlimitedValidity',\n      nameTk: 'globals.unlimited',\n      cellViewModel: IconCell,\n      cellOptions: {\n        classes: 'text-left text-success',\n        iconTransformer: skill => skill.unlimitedValidity ? 'System/Tabler/Check' : '',\n      },\n      shrink: true,\n    },\n    {\n      id: 'actions',\n      nameTk: '',\n      cellViewModel: ActionsCell,\n      shrink: true,\n      cellOptions: {\n        entries: [\n          {\n            labelTk: 'globals.edit',\n            icon: 'fe-edit',\n            clickCallback: skill => { this.handleEditSkillClick(skill); },\n          },\n          {\n            labelTk: 'globals.delete',\n            icon: 'fe-delete',\n            additionalClasses: 'text-danger',\n            clickCallback: skill => { this.handleDeleteSkillClick(skill); },\n          },\n        ],\n      }\n    },\n  ];\n\n  constructor(\n    private skillManagementApiService: SkillManagementApiService,\n    private router: Router,\n    private customDialogService: CustomDialogService,\n  ) { }\n\n  private async fetchTableData(limit: number, offset: number): Promise<{ total: number; data: ISkillDto[] }> {\n    this.filter.limit = limit;\n    this.filter.offset = offset;\n\n    const response = await this.skillManagementApiService.getSkills(this.filter);\n\n    return {\n      data: response.rows,\n      total: response.count,\n    };\n  }\n\n  private handleEditSkillClick(skill: ISkillDto): void {\n    this.router.navigateToRoute('skills-edit/id', { skillId: skill.id });\n  }\n\n  private handleCreateSkillClick(): void {\n    this.router.navigateToRoute('skills-edit/id');\n  }\n\n  private async handleDeleteSkillClick(skill: ISkillDto): Promise<void> {\n    const confirmed = await this.customDialogService?.confirmAction({\n      icon: { name: 'alert-triangle', color: 'var(--warning)' },\n      titleTk: 'pages.skills.deleteWarningTitle',\n      textTk: 'pages.skills.deleteWarningText',\n      confirmTk: 'globals.ok',\n    });\n    if(!confirmed) return;\n    await this.skillManagementApiService.deleteSkill(skill.id);\n    this.tableRefreshVersion++;\n  }\n}\n"],"names":[],"sourceRoot":""}